Skip to content

Commit 3d48835

Browse files
feat: JsonExpression supports Expressions rather than Char/Long only
- fixes #2054 Signed-off-by: Andreas Reichel <[email protected]>
1 parent 90adf82 commit 3d48835

File tree

4 files changed

+61
-27
lines changed

4 files changed

+61
-27
lines changed

src/main/java/net/sf/jsqlparser/expression/JsonExpression.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import java.util.Map;
1919

2020
public class JsonExpression extends ASTNodeAccessImpl implements Expression {
21-
private final List<Map.Entry<String, String>> idents = new ArrayList<>();
21+
private final List<Map.Entry<Expression, String>> idents = new ArrayList<>();
2222
private Expression expr;
2323

2424
public JsonExpression() {
@@ -29,7 +29,7 @@ public JsonExpression(Expression expr) {
2929
this.expr = expr;
3030
}
3131

32-
public JsonExpression(Expression expr, List<Map.Entry<String, String>> idents) {
32+
public JsonExpression(Expression expr, List<Map.Entry<Expression, String>> idents) {
3333
this.expr = expr;
3434
this.idents.addAll(idents);
3535
}
@@ -47,26 +47,26 @@ public void setExpression(Expression expr) {
4747
this.expr = expr;
4848
}
4949

50-
public void addIdent(String ident, String operator) {
50+
public void addIdent(Expression ident, String operator) {
5151
idents.add(new AbstractMap.SimpleEntry<>(ident, operator));
5252
}
5353

54-
public void addAllIdents(Collection<Map.Entry<String, String>> idents) {
54+
public void addAllIdents(Collection<Map.Entry<Expression, String>> idents) {
5555
this.idents.addAll(idents);
5656
}
5757

58-
public List<Map.Entry<String, String>> getIdentList() {
58+
public List<Map.Entry<Expression, String>> getIdentList() {
5959
return idents;
6060
}
6161

62-
public Map.Entry<String, String> getIdent(int index) {
62+
public Map.Entry<Expression, String> getIdent(int index) {
6363
return idents.get(index);
6464
}
6565

6666
@Deprecated
67-
public List<String> getIdents() {
68-
ArrayList<String> l = new ArrayList<>();
69-
for (Map.Entry<String, String> ident : idents) {
67+
public List<Expression> getIdents() {
68+
ArrayList<Expression> l = new ArrayList<>();
69+
for (Map.Entry<Expression, String> ident : idents) {
7070
l.add(ident.getKey());
7171
}
7272

@@ -76,7 +76,7 @@ public List<String> getIdents() {
7676
@Deprecated
7777
public List<String> getOperators() {
7878
ArrayList<String> l = new ArrayList<>();
79-
for (Map.Entry<String, String> ident : idents) {
79+
for (Map.Entry<Expression, String> ident : idents) {
8080
l.add(ident.getValue());
8181
}
8282
return l;
@@ -86,7 +86,7 @@ public List<String> getOperators() {
8686
public String toString() {
8787
StringBuilder b = new StringBuilder();
8888
b.append(expr.toString());
89-
for (Map.Entry<String, String> ident : idents) {
89+
for (Map.Entry<Expression, String> ident : idents) {
9090
b.append(ident.getValue()).append(ident.getKey());
9191
}
9292
return b.toString();

src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4706,6 +4706,7 @@ Expression ArrayExpression(Expression obj): {
47064706
Expression PrimaryExpression() #PrimaryExpression:
47074707
{
47084708
Expression retval = null;
4709+
Expression expression = null;
47094710
CastExpression castExpr = null;
47104711
TimezoneExpression timezoneExpr = null;
47114712
Expression timezoneRightExpr = null;
@@ -4718,7 +4719,7 @@ Expression PrimaryExpression() #PrimaryExpression:
47184719
boolean dateExpressionAllowed = true;
47194720
ExpressionList list;
47204721

4721-
final List<Map.Entry<String, String>> jsonIdents = new ArrayList<Map.Entry<String, String>>();
4722+
final List<Map.Entry<Expression, String>> jsonIdents = new ArrayList<Map.Entry<Expression, String>>();
47224723
}
47234724
{
47244725
[ <K_NOT> { not=true; } | "!" { not=true; exclamationMarkNot=true; } ]
@@ -4846,14 +4847,17 @@ Expression PrimaryExpression() #PrimaryExpression:
48464847
[
48474848
LOOKAHEAD(2) (
48484849
LOOKAHEAD(2) (
4849-
"->" ( token=<S_CHAR_LITERAL> | token=<S_LONG>) { jsonIdents.add(new AbstractMap.SimpleEntry<String, String>(token.image,"->")); }
4850+
token="->" expression=Expression()
48504851
|
4851-
"->>" (token=<S_CHAR_LITERAL> | token=<S_LONG>) { jsonIdents.add(new AbstractMap.SimpleEntry<String, String>(token.image,"->>")); }
4852+
token="->>" expression=Expression()
48524853
|
4853-
"#>" token=<S_CHAR_LITERAL> { jsonIdents.add(new AbstractMap.SimpleEntry<String, String>(token.image,"#>")); }
4854+
token="#>" expression=Expression()
48544855
|
4855-
"#>>" token=<S_CHAR_LITERAL> { jsonIdents.add(new AbstractMap.SimpleEntry<String, String>(token.image,"#>>")); }
4856+
token="#>>" expression=Expression()
48564857
)
4858+
{
4859+
jsonIdents.add(new AbstractMap.SimpleEntry<Expression, String>(expression, token.image ));
4860+
}
48574861
)+
48584862
retval = JsonExpression(retval, jsonIdents)
48594863
]
@@ -5083,8 +5087,9 @@ StructType StructType() #StruckType:
50835087
}
50845088
}
50855089

5086-
JsonExpression JsonExpression(Expression expr, List<Map.Entry<String, String>> idents) : {
5090+
JsonExpression JsonExpression(Expression expr, List<Map.Entry<Expression, String>> idents) : {
50875091
JsonExpression result = new JsonExpression(expr, idents);
5092+
Expression expression;
50885093
Token token;
50895094
ColDataType type = null;
50905095
CastExpression castExpr = null;
@@ -5111,15 +5116,18 @@ JsonExpression JsonExpression(Expression expr, List<Map.Entry<String, String>> i
51115116
}
51125117

51135118
(
5114-
LOOKAHEAD(2) (
5115-
"->" (token=<S_CHAR_LITERAL> | token=<S_LONG>) {result.addIdent(token.image,"->");}
5116-
|
5117-
"->>" (token=<S_CHAR_LITERAL> | token=<S_LONG>) {result.addIdent(token.image,"->>");}
5118-
|
5119-
"#>" token=<S_CHAR_LITERAL> {result.addIdent(token.image,"#>");}
5120-
|
5121-
"#>>" token=<S_CHAR_LITERAL> {result.addIdent(token.image,"#>>");}
5122-
)
5119+
LOOKAHEAD(2) (
5120+
token="->" expression=Expression()
5121+
|
5122+
token="->>" expression=Expression()
5123+
|
5124+
token="#>" expression=Expression()
5125+
|
5126+
token="#>>" expression=Expression()
5127+
)
5128+
{
5129+
result.addIdent( expression, token.image );
5130+
}
51235131
)*
51245132
)*
51255133

src/test/java/net/sf/jsqlparser/expression/JsonExpressionTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
import net.sf.jsqlparser.JSQLParserException;
1313
import org.junit.jupiter.api.Test;
14+
import org.junit.jupiter.params.ParameterizedTest;
15+
import org.junit.jupiter.params.provider.ValueSource;
1416

1517
import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed;
1618

@@ -108,4 +110,27 @@ void testParenthesedJsonExpressionsIssue1792() throws JSQLParserException {
108110

109111
assertSqlCanBeParsedAndDeparsed(sqlStr, true);
110112
}
113+
114+
@ParameterizedTest
115+
@ValueSource(strings = {
116+
"SELECT ( JSONB_AGG(variables) " +
117+
" FILTER (WHERE variables IS NOT NULL) " +
118+
" OVER (PARTITION BY deviceid ORDER BY time)->>-1 )::JSONB AS variables\n" +
119+
"FROM devices\n" +
120+
";",
121+
"SELECT ( JSONB_AGG(variables) " +
122+
" FILTER (WHERE variables IS NOT NULL) " +
123+
" OVER (PARTITION BY deviceid ORDER BY time)->>(0-1) )::JSONB AS variables\n"
124+
+
125+
"FROM devices\n" +
126+
";",
127+
"SELECT ( JSONB_AGG(variables) " +
128+
" FILTER (WHERE variables IS NOT NULL) " +
129+
" OVER (PARTITION BY deviceid ORDER BY time)->>(jsonb_array_length(JSONB_AGG(variables) FILTER (WHERE variables IS NOT NULL) OVER (PARTITION BY deviceid ORDER BY time))-1) )::JSONB AS variables\n"
130+
+
131+
"FROM devices\n" +
132+
";"})
133+
void testIssue2054(String sqlStr) throws JSQLParserException {
134+
assertSqlCanBeParsedAndDeparsed(sqlStr, true);
135+
}
111136
}

src/test/java/net/sf/jsqlparser/statement/select/PostgresTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import net.sf.jsqlparser.JSQLParserException;
1313
import net.sf.jsqlparser.expression.JsonExpression;
14+
import net.sf.jsqlparser.expression.StringValue;
1415
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
1516
import net.sf.jsqlparser.schema.Column;
1617
import net.sf.jsqlparser.statement.Statements;
@@ -58,7 +59,7 @@ public void testJSonExpressionIssue1696() throws JSQLParserException {
5859
PlainSelect plainSelect = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sqlStr, true);
5960
SelectItem<?> selectExpressionItem =
6061
plainSelect.getSelectItems().get(0);
61-
Assertions.assertEquals("'key'",
62+
Assertions.assertEquals(new StringValue("key"),
6263
selectExpressionItem.getExpression(JsonExpression.class).getIdent(0).getKey());
6364
}
6465

0 commit comments

Comments
 (0)