Skip to content

Commit afb385f

Browse files
committed
unit tests
Signed-off-by: Kenrick Yap <[email protected]>
1 parent cd78ddd commit afb385f

File tree

2 files changed

+107
-1
lines changed

2 files changed

+107
-1
lines changed

core/src/main/java/org/opensearch/sql/utils/JsonUtils.java

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.fasterxml.jackson.databind.ObjectMapper;
1010
import com.jayway.jsonpath.Configuration;
1111
import com.jayway.jsonpath.InvalidJsonException;
12+
import com.jayway.jsonpath.InvalidPathException;
1213
import com.jayway.jsonpath.JsonPath;
1314

1415
import java.util.LinkedHashMap;
@@ -84,6 +85,9 @@ public static ExprValue extractJson(ExprValue json, ExprValue path) {
8485
}
8586
} catch (PathNotFoundException e) {
8687
return LITERAL_NULL;
88+
} catch (InvalidPathException e) {
89+
final String errorFormat = "JSON path '%s' is not valid. Error details: %s";
90+
throw new SemanticCheckException(String.format(errorFormat, path, e.getMessage()), e);
8791
} catch (InvalidJsonException e) {
8892
final String errorFormat = "JSON string '%s' is not valid. Error details: %s";
8993
throw new SemanticCheckException(String.format(errorFormat, json, e.getMessage()), e);

core/src/test/java/org/opensearch/sql/expression/json/JsonFunctionsTest.java

+103-1
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616
import java.util.LinkedHashMap;
1717
import java.util.List;
1818
import java.util.Map;
19+
1920
import org.junit.jupiter.api.Test;
2021
import org.junit.jupiter.api.extension.ExtendWith;
2122
import org.mockito.junit.jupiter.MockitoExtension;
2223
import org.opensearch.sql.data.model.ExprBooleanValue;
2324
import org.opensearch.sql.data.model.ExprCollectionValue;
2425
import org.opensearch.sql.data.model.ExprDoubleValue;
26+
import org.opensearch.sql.data.model.ExprFloatValue;
2527
import org.opensearch.sql.data.model.ExprIntegerValue;
2628
import org.opensearch.sql.data.model.ExprLongValue;
2729
import org.opensearch.sql.data.model.ExprNullValue;
@@ -32,6 +34,7 @@
3234
import org.opensearch.sql.exception.ExpressionEvaluationException;
3335
import org.opensearch.sql.exception.SemanticCheckException;
3436
import org.opensearch.sql.expression.DSL;
37+
import org.opensearch.sql.expression.Expression;
3538
import org.opensearch.sql.expression.FunctionExpression;
3639

3740
@ExtendWith(MockitoExtension.class)
@@ -159,8 +162,107 @@ void json_returnsSemanticCheckException() {
159162
// missing bracket
160163
assertThrows(SemanticCheckException.class, () -> DSL.castJson(DSL.literal("{{[}}")).valueOf());
161164

162-
// mnissing quote
165+
// missing quote
163166
assertThrows(
164167
SemanticCheckException.class, () -> DSL.castJson(DSL.literal("\"missing quote")).valueOf());
165168
}
169+
170+
@Test
171+
void json_extract_return_object() {
172+
List<String> validJsonStrings =
173+
List.of(
174+
// test json objects are valid
175+
"{\"a\":\"1\",\"b\":\"2\"}",
176+
"{\"a\":1,\"b\":{\"c\":2,\"d\":3}}",
177+
"{\"arr1\": [1,2,3], \"arr2\": [4,5,6]}",
178+
179+
// test json arrays are valid
180+
"[1, 2, 3, 4]",
181+
"[{\"a\":1,\"b\":2}, {\"c\":3,\"d\":2}]",
182+
183+
// test json scalars are valid
184+
"\"abc\"",
185+
"1234",
186+
"12.34",
187+
"true",
188+
"false",
189+
"null",
190+
191+
// test empty string is valid
192+
"");
193+
194+
validJsonStrings.stream()
195+
.forEach(
196+
str ->
197+
assertEquals(
198+
LITERAL_TRUE,
199+
DSL.jsonValid(DSL.literal((ExprValueUtils.stringValue(str)))).valueOf(),
200+
String.format("String %s must be valid json", str)));
201+
}
202+
203+
@Test
204+
void json_extract_search_arrays() {
205+
Expression jsonArray = DSL.literal(ExprValueUtils.stringValue("{\"a\":[1,2.3,\"abc\",true,null,{\"c\":1},[1,2,3]]}"));
206+
List<ExprValue> expectedExprValue = List.of(
207+
new ExprIntegerValue(1),
208+
new ExprFloatValue(2.3),
209+
new ExprStringValue("abc"),
210+
LITERAL_TRUE,
211+
LITERAL_NULL,
212+
ExprTupleValue.fromExprValueMap(Map.of("c", new ExprIntegerValue(1))),
213+
new ExprCollectionValue(List.of(new ExprIntegerValue(1), new ExprIntegerValue(2), new ExprIntegerValue(3)))
214+
);
215+
216+
// extract specific index from JSON list
217+
for (int i = 0 ; i < expectedExprValue.size() ; i++ ) {
218+
String path = String.format("$.a[%d]", i);
219+
Expression pathExpr = DSL.literal(ExprValueUtils.stringValue(path));
220+
FunctionExpression expression = DSL.jsonExtract(jsonArray, pathExpr);
221+
assertEquals(expectedExprValue.get(i), expression.valueOf());
222+
}
223+
224+
// extract * from JSON list
225+
Expression starPath = DSL.literal(ExprValueUtils.stringValue("$.a[*]"));
226+
FunctionExpression starExpression = DSL.castInt(DSL.jsonExtract(jsonArray, starPath));
227+
assertEquals(
228+
new ExprCollectionValue(expectedExprValue), starExpression.valueOf());
229+
}
230+
231+
@Test
232+
void json_extract_returns_null() {
233+
List<String> jsonStrings =
234+
List.of(
235+
"{\"a\":\"1\",\"b\":\"2\"}",
236+
"{\"a\":1,\"b\":{\"c\":2,\"d\":3}}",
237+
"{\"arr1\": [1,2,3], \"arr2\": [4,5,6]}",
238+
"[1, 2, 3, 4]",
239+
"[{\"a\":1,\"b\":2}, {\"c\":3,\"d\":2}]",
240+
"\"abc\"",
241+
"1234",
242+
"12.34",
243+
"true",
244+
"false",
245+
"null",
246+
"");
247+
248+
jsonStrings.stream()
249+
.forEach(
250+
str ->
251+
assertEquals(
252+
LITERAL_NULL,
253+
DSL.jsonExtract(
254+
DSL.literal((ExprValueUtils.stringValue(str))),
255+
DSL.literal("$.a.path_not_found_key")).valueOf(),
256+
String.format("JSON string %s should return null", str)));
257+
}
258+
259+
@Test
260+
void json_returns_SemanticCheckException() {
261+
// invalid path
262+
assertThrows(
263+
SemanticCheckException.class, () -> DSL.jsonExtract(DSL.literal("invalid"), DSL.literal("invalid")).valueOf());
264+
265+
// invalid json
266+
assertThrows(SemanticCheckException.class, () -> DSL.jsonExtract(DSL.literal("{\"invalid\":\"json\", \"string\"}"), DSL.literal("invalid")).valueOf());
267+
}
166268
}

0 commit comments

Comments
 (0)