Skip to content

Commit a28daa8

Browse files
committed
Added support for Json type in sqlServe and Oracle
1 parent 53cdf6e commit a28daa8

File tree

5 files changed

+72
-58
lines changed

5 files changed

+72
-58
lines changed

cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/OracleAdapter.java

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,7 @@
3535
import org.apache.cayenne.access.sqlbuilder.sqltree.SQLTreeProcessor;
3636
import org.apache.cayenne.access.translator.ParameterBinding;
3737
import org.apache.cayenne.access.translator.ejbql.EJBQLTranslatorFactory;
38-
import org.apache.cayenne.access.types.ByteType;
39-
import org.apache.cayenne.access.types.ExtendedType;
40-
import org.apache.cayenne.access.types.ExtendedTypeFactory;
41-
import org.apache.cayenne.access.types.ExtendedTypeMap;
42-
import org.apache.cayenne.access.types.ShortType;
43-
import org.apache.cayenne.access.types.ValueObjectTypeRegistry;
38+
import org.apache.cayenne.access.types.*;
4439
import org.apache.cayenne.configuration.Constants;
4540
import org.apache.cayenne.configuration.RuntimeProperties;
4641
import org.apache.cayenne.dba.JdbcAdapter;
@@ -180,7 +175,7 @@ public OracleAdapter(@Inject RuntimeProperties runtimeProperties,
180175
*/
181176
@Override
182177
public SQLTreeProcessor getSqlTreeProcessor() {
183-
return new OracleSQLTreeProcessor();
178+
return OracleSQLTreeProcessor.getInstance();
184179
}
185180

186181
/**
@@ -200,7 +195,8 @@ protected void configureExtendedTypes(ExtendedTypeMap map) {
200195
super.configureExtendedTypes(map);
201196

202197
// create specially configured CharType handler
203-
map.registerType(new OracleCharType());
198+
CharType charType = new OracleCharType();
199+
map.registerType(charType);
204200

205201
// create specially configured ByteArrayType handler
206202
map.registerType(new OracleByteArrayType());
@@ -212,6 +208,7 @@ protected void configureExtendedTypes(ExtendedTypeMap map) {
212208
map.registerType(new ShortType(true));
213209
map.registerType(new ByteType(true));
214210
map.registerType(new OracleBooleanType());
211+
map.registerType(new JsonType(charType, true));
215212
}
216213

217214
/**

cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/OracleSQLTreeProcessor.java

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -21,51 +21,56 @@
2121

2222
import java.util.ArrayList;
2323
import java.util.List;
24+
import java.util.Optional;
2425

2526
import org.apache.cayenne.access.sqlbuilder.ExpressionNodeBuilder;
2627
import org.apache.cayenne.access.sqlbuilder.QuotingAppendable;
2728
import org.apache.cayenne.access.sqlbuilder.SelectBuilder;
28-
import org.apache.cayenne.access.sqlbuilder.sqltree.ColumnNode;
29-
import org.apache.cayenne.access.sqlbuilder.sqltree.EmptyNode;
30-
import org.apache.cayenne.access.sqlbuilder.sqltree.FunctionNode;
31-
import org.apache.cayenne.access.sqlbuilder.sqltree.InNode;
32-
import org.apache.cayenne.access.sqlbuilder.sqltree.LimitOffsetNode;
33-
import org.apache.cayenne.access.sqlbuilder.sqltree.Node;
34-
import org.apache.cayenne.access.sqlbuilder.sqltree.NodeType;
35-
import org.apache.cayenne.access.sqlbuilder.sqltree.OpExpressionNode;
36-
import org.apache.cayenne.access.sqlbuilder.sqltree.TextNode;
37-
import org.apache.cayenne.access.sqlbuilder.sqltree.ValueNode;
38-
import org.apache.cayenne.access.sqlbuilder.sqltree.TrimmingColumnNode;
39-
import org.apache.cayenne.access.translator.select.BaseSQLTreeProcessor;
29+
import org.apache.cayenne.access.sqlbuilder.sqltree.*;
30+
import org.apache.cayenne.access.translator.select.TypeAwareSQLTreeProcessor;
4031
import org.apache.cayenne.util.ArrayUtil;
32+
import org.apache.cayenne.value.GeoJson;
33+
import org.apache.cayenne.value.Json;
34+
import org.apache.cayenne.value.Wkt;
4135

4236
import static org.apache.cayenne.access.sqlbuilder.SQLBuilder.*;
4337

4438
/**
4539
* @since 4.2
4640
*/
47-
public class OracleSQLTreeProcessor extends BaseSQLTreeProcessor {
41+
public class OracleSQLTreeProcessor extends TypeAwareSQLTreeProcessor {
4842

4943
private static final int ORACLE_IN_BATCH_SIZE = 1000;
5044

5145
private SelectBuilder selectBuilder;
5246

5347
private Node root;
5448

55-
@Override
56-
protected void onResultNode(Node parent, Node child, int index) {
57-
for(int i=0; i<child.getChildrenCount(); i++) {
58-
child.replaceChild(i, aliased(child.getChild(i), "c" + i).build());
59-
}
49+
private static final OracleSQLTreeProcessor INSTANCE = new OracleSQLTreeProcessor();
50+
51+
public static OracleSQLTreeProcessor getInstance() {
52+
return INSTANCE;
6053
}
6154

62-
@Override
63-
protected void onColumnNode(Node parent, ColumnNode child, int index) {
64-
replaceChild(parent, index, new TrimmingColumnNode(child));
55+
protected OracleSQLTreeProcessor() {
56+
registerProcessor(NodeType.IN, (ChildProcessor<InNode>) this::onInNode);
57+
registerProcessor(NodeType.LIMIT_OFFSET, (ChildProcessor<LimitOffsetNode>) this::onLimitOffsetNode);
58+
registerProcessor(NodeType.FUNCTION, (ChildProcessor<FunctionNode>) this::onFunctionNode);
59+
60+
registerColumnProcessor(Wkt.class, (parent, child, i)
61+
-> Optional.of(wrapInFunction(child, "ST_AsText")));
62+
registerColumnProcessor(GeoJson.class, (parent, child, i)
63+
-> Optional.of(wrapInFunction(child, "ST_AsGeoJSON")));
64+
65+
registerValueProcessor(Wkt.class, (parent, child, i)
66+
-> Optional.of(wrapInFunction(child, "ST_GeomFromText")));
67+
registerValueProcessor(GeoJson.class, (parent, child, i)
68+
-> Optional.of(wrapInFunction(child, "ST_GeomFromGeoJSON")));
69+
registerValueProcessor(Json.class, (parent, child, i)
70+
-> Optional.of(wrapInFunction(child, "ST_AsCLOB")));
6571
}
6672

67-
@Override
68-
protected void onLimitOffsetNode(Node parent, LimitOffsetNode child, int index) {
73+
protected Optional<Node> onLimitOffsetNode(Node parent, LimitOffsetNode child, int index) {
6974
if(child.getLimit() > 0 || child.getOffset() > 0) {
7075
int limit = child.getLimit();
7176
int offset = child.getOffset();
@@ -86,21 +91,21 @@ protected void onLimitOffsetNode(Node parent, LimitOffsetNode child, int index)
8691
.where(exp(text(" rnum")).gt(value(offset)));
8792
}
8893
parent.replaceChild(index, new EmptyNode());
94+
return Optional.of(new LimitOffsetNode(child.getLimit(), child.getOffset()));
8995
}
9096

91-
@Override
92-
protected void onInNode(Node parent, InNode child, int index) {
97+
protected Optional<Node> onInNode(Node parent, InNode child, int index) {
9398
boolean not = child.isNot();
9499
Node arg = child.getChild(0);
95100
Node childNode = child.getChild(1);
96101
if(childNode.getType() != NodeType.VALUE) {
97-
return;
102+
return Optional.of(child);
98103
}
99104

100105
ValueNode valueNode = (ValueNode)childNode;
101106
Object value = valueNode.getValue();
102107
if(!value.getClass().isArray()) {
103-
return;
108+
return Optional.of(child);
104109
}
105110

106111
List<Node> newChildren = new ArrayList<>();
@@ -153,6 +158,7 @@ protected void onInNode(Node parent, InNode child, int index) {
153158
}
154159
}
155160
parent.replaceChild(index, exp.build());
161+
return Optional.of(child);
156162
}
157163

158164
private InNode newSliceNode(InNode child, Node arg, ValueNode valueNode, Object slice) {
@@ -162,8 +168,7 @@ private InNode newSliceNode(InNode child, Node arg, ValueNode valueNode, Object
162168
return nextNode;
163169
}
164170

165-
@Override
166-
protected void onFunctionNode(Node parent, FunctionNode child, int index) {
171+
protected Optional<Node> onFunctionNode(Node parent, FunctionNode child, int index) {
167172
String functionName = child.getFunctionName();
168173
Node functionReplacement = null;
169174
switch (functionName) {
@@ -173,7 +178,7 @@ protected void onFunctionNode(Node parent, FunctionNode child, int index) {
173178
functionReplacement.addChild(child.getChild(1-i));
174179
}
175180
parent.replaceChild(index, functionReplacement);
176-
return;
181+
return Optional.of(child);
177182

178183
case "DAY_OF_YEAR":
179184
case "DAY_OF_WEEK":
@@ -189,7 +194,7 @@ protected void onFunctionNode(Node parent, FunctionNode child, int index) {
189194
}
190195
functionReplacement.addChild(new TextNode(functionName));
191196
parent.replaceChild(index, functionReplacement);
192-
return;
197+
return Optional.of(child);
193198

194199
case "SUBSTRING":
195200
functionReplacement = new FunctionNode("SUBSTR", child.getAlias(), true);
@@ -227,9 +232,9 @@ public void appendChildrenSeparator(QuotingAppendable buffer, int childIdx) {
227232
if(functionReplacement != null) {
228233
replaceChild(parent, index, functionReplacement);
229234
}
235+
return Optional.of(child);
230236
}
231237

232-
@Override
233238
public Node process(Node node) {
234239
root = node;
235240
super.process(node);

cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerAdapter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public boolean supportsGeneratedKeysForBatchInserts() {
109109
*/
110110
@Override
111111
public SQLTreeProcessor getSqlTreeProcessor() {
112-
return new SQLServerTreeProcessor();
112+
return SQLServerTreeProcessor.getInstance();
113113
}
114114

115115
/**

cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTreeProcessor.java

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,35 @@
1919

2020
package org.apache.cayenne.dba.sqlserver;
2121

22-
import org.apache.cayenne.access.sqlbuilder.sqltree.ColumnNode;
23-
import org.apache.cayenne.access.sqlbuilder.sqltree.Node;
24-
import org.apache.cayenne.dba.sqlserver.sqltree.SQLServerColumnNode;
25-
import org.apache.cayenne.dba.sybase.SybaseSQLTreeProcessor;
22+
import org.apache.cayenne.access.translator.select.TypeAwareSQLTreeProcessor;
23+
import org.apache.cayenne.value.GeoJson;
24+
import org.apache.cayenne.value.Json;
25+
import org.apache.cayenne.value.Wkt;
26+
27+
import java.util.Optional;
2628

2729
/**
2830
* @since 4.2
2931
*/
30-
public class SQLServerTreeProcessor extends SybaseSQLTreeProcessor {
32+
public class SQLServerTreeProcessor extends TypeAwareSQLTreeProcessor {
33+
34+
private static final SQLServerTreeProcessor INSTANCE = new SQLServerTreeProcessor();
35+
36+
public static SQLServerTreeProcessor getInstance() {
37+
return INSTANCE;
38+
}
39+
40+
protected SQLServerTreeProcessor() {
41+
registerColumnProcessor(Wkt.class, (parent, child, i)
42+
-> Optional.of(wrapInFunction(child, "ST_AsText")));
43+
registerColumnProcessor(GeoJson.class, (parent, child, i)
44+
-> Optional.of(wrapInFunction(child, "ST_AsGeoJSON")));
3145

32-
@Override
33-
protected void onColumnNode(Node parent, ColumnNode child, int index) {
34-
replaceChild(parent, index, new SQLServerColumnNode(child));
46+
registerValueProcessor(Wkt.class, (parent, child, i)
47+
-> Optional.of(wrapInFunction(child, "ST_GeomFromText")));
48+
registerValueProcessor(GeoJson.class, (parent, child, i)
49+
-> Optional.of(wrapInFunction(child, "ST_GeomFromGeoJSON")));
50+
registerValueProcessor(Json.class, (parent, child, i)
51+
-> Optional.of(wrapInFunction(child, "ST_AsNVARCHAR")));
3552
}
3653
}

cayenne-server/src/main/java/org/apache/cayenne/dba/sybase/SybaseAdapter.java

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,7 @@
2626
import org.apache.cayenne.access.sqlbuilder.sqltree.SQLTreeProcessor;
2727
import org.apache.cayenne.access.translator.ParameterBinding;
2828
import org.apache.cayenne.access.translator.ejbql.EJBQLTranslatorFactory;
29-
import org.apache.cayenne.access.types.ByteArrayType;
30-
import org.apache.cayenne.access.types.ByteType;
31-
import org.apache.cayenne.access.types.CharType;
32-
import org.apache.cayenne.access.types.ExtendedType;
33-
import org.apache.cayenne.access.types.ExtendedTypeFactory;
34-
import org.apache.cayenne.access.types.ExtendedTypeMap;
35-
import org.apache.cayenne.access.types.ShortType;
36-
import org.apache.cayenne.access.types.ValueObjectTypeRegistry;
29+
import org.apache.cayenne.access.types.*;
3730
import org.apache.cayenne.configuration.Constants;
3831
import org.apache.cayenne.configuration.RuntimeProperties;
3932
import org.apache.cayenne.dba.DefaultQuotingStrategy;
@@ -100,7 +93,8 @@ protected void configureExtendedTypes(ExtendedTypeMap map) {
10093
super.configureExtendedTypes(map);
10194

10295
// create specially configured CharType handler
103-
map.registerType(new CharType(true, false));
96+
CharType charType = new CharType(false, false);
97+
map.registerType(charType);
10498

10599
// create specially configured ByteArrayType handler
106100
map.registerType(new ByteArrayType(true, false));
@@ -109,6 +103,7 @@ protected void configureExtendedTypes(ExtendedTypeMap map) {
109103
// java.lang.Byte
110104
map.registerType(new ShortType(true));
111105
map.registerType(new ByteType(true));
106+
map.registerType(new JsonType(charType, true));
112107
}
113108

114109
/**

0 commit comments

Comments
 (0)