Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,13 @@ configurations.configureEach {
}

compileJavacc {
arguments = [grammar_encoding: 'UTF-8', static: 'false', java_template_type: 'modern']
arguments = [
grammar_encoding: 'UTF-8',
static: 'false',
java_template_type: 'modern',
// Comment this in to build the parser with tracing.
DEBUG_PARSER: 'false'
]
}

java {
Expand Down
120 changes: 58 additions & 62 deletions src/main/java/net/sf/jsqlparser/expression/JsonFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,39 @@
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;

/**
* Represents a JSON-Function.<br>
* Currently supported are the types in {@link JsonFunctionType}.<br>
* <br>
* For JSON_OBJECT and JSON_OBJECTAGG the parameters are available from {@link #getKeyValuePairs()}<br>
* <br>
* For JSON_ARRAY and JSON_ARRAYAGG the parameters are availble from {@link #getExpressions()}.<br>
*
* @author <a href="mailto:andreas@manticore-projects.com">Andreas Reichel</a>
*/

public class JsonFunction extends ASTNodeAccessImpl implements Expression {
private final ArrayList<JsonKeyValuePair> keyValuePairs = new ArrayList<>();
private final ArrayList<JsonFunctionExpression> expressions = new ArrayList<>();
private JsonFunctionType functionType;
private JsonAggregateOnNullType onNullType;
private JsonAggregateUniqueKeysType uniqueKeysType;

private boolean isStrict = false;

/**
* Returns the Parameters of an JSON_OBJECT or JSON_OBJECTAGG<br>
* The KeyValuePairs may not have both key and value set, in some cases only the Key is set.
*
* @return A List of KeyValuePairs, never NULL
*/
public ArrayList<JsonKeyValuePair> getKeyValuePairs() {
return keyValuePairs;
}

/**
* Returns the parameters of JSON_ARRAY or JSON_ARRAYAGG<br>
*
* @return A List of {@link JsonFunctionExpression}s, never NULL
*/
public ArrayList<JsonFunctionExpression> getExpressions() {
return expressions;
}
Expand Down Expand Up @@ -114,6 +133,19 @@ public JsonFunction withType(String typeName) {
return this;
}

public boolean isStrict() {
return isStrict;
}

public void setStrict(boolean strict) {
isStrict = strict;
}

public JsonFunction withStrict(boolean strict) {
this.setStrict(strict);
return this;
}

@Override
public <T, S> T accept(ExpressionVisitor<T> expressionVisitor, S context) {
return expressionVisitor.visit(this, context);
Expand All @@ -123,13 +155,9 @@ public <T, S> T accept(ExpressionVisitor<T> expressionVisitor, S context) {
public StringBuilder append(StringBuilder builder) {
switch (functionType) {
case OBJECT:
appendObject(builder);
break;
case POSTGRES_OBJECT:
appendPostgresObject(builder);
break;
case MYSQL_OBJECT:
appendMySqlObject(builder);
appendObject(builder);
break;
case ARRAY:
appendArray(builder);
Expand All @@ -148,14 +176,14 @@ public StringBuilder appendObject(StringBuilder builder) {
if (i > 0) {
builder.append(", ");
}
if (keyValuePair.isUsingValueKeyword()) {
if (keyValuePair.isUsingKeyKeyword()) {
builder.append("KEY ");
}
builder.append(keyValuePair.getKey()).append(" VALUE ")
.append(keyValuePair.getValue());
} else {
builder.append(keyValuePair.getKey()).append(":").append(keyValuePair.getValue());
if (keyValuePair.isUsingKeyKeyword() && keyValuePair.getSeparator() == JsonKeyValuePairSeparator.VALUE) {
builder.append("KEY ");
}
builder.append(keyValuePair.getKey());

if (keyValuePair.getValue() != null) {
builder.append(keyValuePair.getSeparator().getSeparatorString());
builder.append(keyValuePair.getValue());
}

if (keyValuePair.isUsingFormatJson()) {
Expand All @@ -164,19 +192,33 @@ public StringBuilder appendObject(StringBuilder builder) {
i++;
}

appendOnNullType(builder);
if (isStrict) {
builder.append(" STRICT");
}
appendUniqueKeys(builder);

builder.append(" ) ");

return builder;
}

private void appendOnNullType(StringBuilder builder) {
if (onNullType != null) {
switch (onNullType) {
case NULL:
builder.append(" NULL ON NULL");
break;
case ABSENT:
builder.append(" ABSENT On NULL");
builder.append(" ABSENT ON NULL");
break;
default:
// this should never happen
}
}
}

private void appendUniqueKeys(StringBuilder builder) {
if (uniqueKeysType != null) {
switch (uniqueKeysType) {
case WITH:
Expand All @@ -189,41 +231,6 @@ public StringBuilder appendObject(StringBuilder builder) {
// this should never happen
}
}

builder.append(" ) ");

return builder;
}


@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"})
public StringBuilder appendPostgresObject(StringBuilder builder) {
builder.append("JSON_OBJECT( ");
for (JsonKeyValuePair keyValuePair : keyValuePairs) {
builder.append(keyValuePair.getKey());
if (keyValuePair.getValue() != null) {
builder.append(", ").append(keyValuePair.getValue());
}
}
builder.append(" ) ");

return builder;
}

public StringBuilder appendMySqlObject(StringBuilder builder) {
builder.append("JSON_OBJECT( ");
int i = 0;
for (JsonKeyValuePair keyValuePair : keyValuePairs) {
if (i > 0) {
builder.append(", ");
}
builder.append(keyValuePair.getKey());
builder.append(", ").append(keyValuePair.getValue());
i++;
}
builder.append(" ) ");

return builder;
}

@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"})
Expand All @@ -239,18 +246,7 @@ public StringBuilder appendArray(StringBuilder builder) {
i++;
}

if (onNullType != null) {
switch (onNullType) {
case NULL:
builder.append(" NULL ON NULL ");
break;
case ABSENT:
builder.append(" ABSENT ON NULL ");
break;
default:
// "ON NULL" was omitted
}
}
appendOnNullType(builder);
builder.append(") ");

return builder;
Expand Down
15 changes: 14 additions & 1 deletion src/main/java/net/sf/jsqlparser/expression/JsonFunctionType.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,20 @@
* @author <a href="mailto:andreas@manticore-projects.com">Andreas Reichel</a>
*/
public enum JsonFunctionType {
OBJECT, ARRAY, POSTGRES_OBJECT, MYSQL_OBJECT;
OBJECT,
ARRAY,

/**
* Not used anymore
*/
@Deprecated
POSTGRES_OBJECT,

/**
* Not used anymore
*/
@Deprecated
MYSQL_OBJECT;

public static JsonFunctionType from(String type) {
return Enum.valueOf(JsonFunctionType.class, type.toUpperCase());
Expand Down
45 changes: 39 additions & 6 deletions src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePair.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,24 @@
public class JsonKeyValuePair implements Serializable {
private final Object key;
private final Object value;
private boolean usingKeyKeyword = false;
private boolean usingValueKeyword = false;
private boolean usingKeyKeyword;
private JsonKeyValuePairSeparator separator;
private boolean usingFormatJson = false;

/**
* Please use the Constructor with {@link JsonKeyValuePairSeparator} parameter.
*/
@Deprecated
public JsonKeyValuePair(Object key, Object value, boolean usingKeyKeyword, boolean usingValueKeyword) {
this(key, value, usingKeyKeyword, usingValueKeyword ? JsonKeyValuePairSeparator.VALUE : JsonKeyValuePairSeparator.COLON);
}

public JsonKeyValuePair(Object key, Object value, boolean usingKeyKeyword,
boolean usingValueKeyword) {
JsonKeyValuePairSeparator separator) {
this.key = Objects.requireNonNull(key, "The KEY of the Pair must not be null");
this.value = value;
this.usingKeyKeyword = usingKeyKeyword;
this.usingValueKeyword = usingValueKeyword;
this.separator = separator;
}

public boolean isUsingKeyKeyword() {
Expand All @@ -45,19 +53,44 @@ public JsonKeyValuePair withUsingKeyKeyword(boolean usingKeyKeyword) {
return this;
}

/**
* Use {@link #getSeparator()}
*/
@Deprecated
public boolean isUsingValueKeyword() {
return usingValueKeyword;
return separator == JsonKeyValuePairSeparator.VALUE;
}

/**
* Use {@link #setSeparator(JsonKeyValuePairSeparator)}
*/
@Deprecated
public void setUsingValueKeyword(boolean usingValueKeyword) {
this.usingValueKeyword = usingValueKeyword;
separator = usingValueKeyword ? JsonKeyValuePairSeparator.VALUE : JsonKeyValuePairSeparator.COLON;
}

/**
* Use {@link #withSeparator(JsonKeyValuePairSeparator)}
*/
@Deprecated
public JsonKeyValuePair withUsingValueKeyword(boolean usingValueKeyword) {
this.setUsingValueKeyword(usingValueKeyword);
return this;
}

public JsonKeyValuePairSeparator getSeparator() {
return separator;
}

public void setSeparator(JsonKeyValuePairSeparator separator) {
this.separator = separator;
}

public JsonKeyValuePair withSeparator(JsonKeyValuePairSeparator separator) {
this.setSeparator(separator);
return this;
}

public boolean isUsingFormatJson() {
return usingFormatJson;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package net.sf.jsqlparser.expression;

/**
* Describes the string used to separate the key from the value.
*/
public enum JsonKeyValuePairSeparator {
VALUE(" VALUE "),
COLON(":"),

// Used in MySQL dialect
COMMA(","),

// Is used in case they KeyValuePair has only a key and no value
NOT_USED("");

private final String separator;

JsonKeyValuePairSeparator(String separator) {
this.separator = separator;
}

public String getSeparatorString() {
return separator;
}
}
Loading
Loading