Skip to content

Commit 9d38074

Browse files
committed
chore: adding JSON scalar
fixes: #63
1 parent 22f2b1f commit 9d38074

File tree

2 files changed

+203
-0
lines changed

2 files changed

+203
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package io.cloudquery.scalar;
2+
3+
import static io.cloudquery.scalar.ValidationException.NO_CONVERSION_AVAILABLE;
4+
5+
import com.fasterxml.jackson.databind.ObjectMapper;
6+
import io.cloudquery.types.JSONType;
7+
import java.io.ByteArrayOutputStream;
8+
import java.io.IOException;
9+
import java.util.Arrays;
10+
import org.apache.arrow.vector.types.pojo.ArrowType;
11+
12+
public class JSON extends Scalar<byte[]> {
13+
private static final JSONType dt = new JSONType();
14+
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
15+
16+
public JSON() {
17+
super();
18+
}
19+
20+
public JSON(Object value) throws ValidationException {
21+
super(value);
22+
}
23+
24+
@Override
25+
protected void setValue(Object value) throws ValidationException {
26+
if (value instanceof byte[] bytes) {
27+
if (bytes.length == 0) {
28+
return;
29+
}
30+
if (!isValidJSON(bytes)) {
31+
throw new ValidationException("invalid json", dt, value);
32+
}
33+
this.value = bytes;
34+
} else if (value instanceof java.lang.String string) {
35+
set(string.getBytes());
36+
} else {
37+
set(parseAsJSONBytes(value));
38+
}
39+
}
40+
41+
@Override
42+
public ArrowType dataType() {
43+
return dt;
44+
}
45+
46+
@Override
47+
public boolean equals(Object other) {
48+
if (other instanceof JSON o) {
49+
if (this.value == null) {
50+
return o.value == null;
51+
}
52+
return Arrays.equals(this.value, o.value);
53+
}
54+
return super.equals(other);
55+
}
56+
57+
@Override
58+
public java.lang.String toString() {
59+
if (this.value != null) {
60+
return new java.lang.String(this.value);
61+
}
62+
return NULL_VALUE_STRING;
63+
}
64+
65+
private byte[] parseAsJSONBytes(Object value) throws ValidationException {
66+
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
67+
OBJECT_MAPPER.writeValue(outputStream, value);
68+
return outputStream.toByteArray();
69+
} catch (IOException e) {
70+
throw new ValidationException(NO_CONVERSION_AVAILABLE, this.dataType(), value);
71+
}
72+
}
73+
74+
private boolean isValidJSON(byte[] bytes) {
75+
try {
76+
OBJECT_MAPPER.readTree(bytes);
77+
return true;
78+
} catch (IOException ex) {
79+
return false;
80+
}
81+
}
82+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package io.cloudquery.scalar;
2+
3+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
4+
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
5+
import static org.junit.jupiter.api.Assertions.assertEquals;
6+
import static org.junit.jupiter.api.Assertions.assertFalse;
7+
import static org.junit.jupiter.api.Assertions.assertNotEquals;
8+
import static org.junit.jupiter.api.Assertions.assertThrows;
9+
import static org.junit.jupiter.api.Assertions.assertTrue;
10+
11+
import io.cloudquery.types.JSONType;
12+
import java.util.Collections;
13+
import java.util.Map;
14+
import lombok.AllArgsConstructor;
15+
import org.junit.jupiter.api.Test;
16+
17+
public class JSONTest {
18+
@AllArgsConstructor
19+
public static class JsonData {
20+
public java.lang.String name;
21+
public int value;
22+
}
23+
24+
@Test
25+
public void testNew() {
26+
assertDoesNotThrow(() -> new JSON());
27+
}
28+
29+
@Test
30+
public void testNewWithValidParam() {
31+
assertDoesNotThrow(() -> new JSON("{}"));
32+
assertDoesNotThrow(() -> new JSON("{}".getBytes()));
33+
assertDoesNotThrow(() -> new JsonData("test", 1));
34+
assertDoesNotThrow(() -> new JSON(new JsonData("test", 1)));
35+
assertDoesNotThrow(() -> new JSON(new int[] {1, 2, 3}));
36+
}
37+
38+
@Test
39+
public void testNewWithInvalidParam() {
40+
assertThrows(ValidationException.class, () -> new JSON("{\"name\":\"test\", incomplete"));
41+
assertThrows(
42+
ValidationException.class, () -> new JSON("{\"name\":\"test\", incomplete".getBytes()));
43+
}
44+
45+
@Test
46+
public void testToString() throws ValidationException {
47+
JSON json = new JSON("{\"name\":\"test\", \"value\":1}");
48+
49+
assertEquals("{\"name\":\"test\", \"value\":1}", json.toString());
50+
}
51+
52+
@Test
53+
public void testDataType() {
54+
JSON json = new JSON();
55+
56+
assertEquals(new JSONType(), json.dataType());
57+
}
58+
59+
@Test
60+
public void testIsValid() throws ValidationException {
61+
assertTrue(new JSON("{}").isValid());
62+
63+
assertTrue(new JSON("{\"name\":\"test\", \"value\":1}").isValid());
64+
assertTrue(new JSON(new int[] {1, 2, 3}).isValid());
65+
assertTrue(new JSON(Collections.emptyList()).isValid());
66+
assertTrue(new JSON(Map.of("foo", "bar")).isValid());
67+
assertTrue(new JSON(Collections.emptyMap()).isValid());
68+
assertTrue(new JSON(new String("{\"name\":\"test\", \"value\":1}")).isValid());
69+
70+
assertFalse(new JSON("").isValid());
71+
assertFalse(new JSON(null).isValid());
72+
assertFalse(new JSON(new byte[] {}).isValid());
73+
}
74+
75+
@Test
76+
public void testSet() throws ValidationException {
77+
JSON json = new JSON();
78+
79+
json.set("{}");
80+
json.set(new JsonData("test", 1));
81+
json.set(new String("{\"name\":\"test\", \"value\":1}"));
82+
json.set(new int[] {1, 2, 3});
83+
}
84+
85+
@Test
86+
public void testSetWithInvalidParam() {}
87+
88+
@Test
89+
public void testGet() throws ValidationException {
90+
assertByteEquals("{}", new JSON("{}"));
91+
assertByteEquals("[1,2,3]", new JSON(new int[] {1, 2, 3}));
92+
assertByteEquals("[1,2,3]", new JSON(new int[] {1, 2, 3}));
93+
assertByteEquals("{\"name\":\"test\",\"value\":1}", new JSON(new JsonData("test", 1)));
94+
assertByteEquals("{\"foo\":\"bar\"}", new JSON(Map.of("foo", "bar")));
95+
assertByteEquals("{}", new JSON(Collections.emptyMap()));
96+
assertByteEquals("[]", new JSON(Collections.emptyList()));
97+
}
98+
99+
@Test
100+
public void testEquals() throws ValidationException {
101+
JSON json1 = new JSON();
102+
JSON json2 = new JSON();
103+
104+
assertEquals(json1, json2);
105+
assertNotEquals(json1, null);
106+
assertNotEquals(json1, new Bool());
107+
assertNotEquals(null, json1);
108+
109+
json1.set(new JsonData("test", 1));
110+
assertNotEquals(json1, json2);
111+
json2.set(new JsonData("test", 1));
112+
assertEquals(json1, json2);
113+
}
114+
115+
private void assertByteEquals(java.lang.String expected, JSON json) throws ValidationException {
116+
assertArrayEquals(
117+
expected.getBytes(),
118+
json.get(),
119+
"expected: " + expected + ", actual: " + new java.lang.String(json.get()));
120+
}
121+
}

0 commit comments

Comments
 (0)