This is an automated email from the ASF dual-hosted git repository. ntimofeev pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/cayenne.git
The following commit(s) were added to refs/heads/master by this push: new a6f80d0 CAY-2659 Use new SQLBuilder utility to generate SQL for batch queries new 5c291b0 Merge pull request #425 from stariy95/4.2-FEATURE-sql-builder-batch-queries-translator a6f80d0 is described below commit a6f80d058a2b0c80485f04f8175b75ef38f7c8da Author: Nikita Timofeev <stari...@gmail.com> AuthorDate: Thu May 28 14:22:42 2020 +0300 CAY-2659 Use new SQLBuilder utility to generate SQL for batch queries --- .../apache/cayenne/access/jdbc/BatchAction.java | 4 + .../ExpressionNode.java => BaseBuilder.java} | 55 +++--- ...QLGenerationContext.java => DeleteBuilder.java} | 24 ++- .../cayenne/access/sqlbuilder/InsertBuilder.java | 54 ++++++ .../cayenne/access/sqlbuilder/SQLBuilder.java | 12 ++ .../access/sqlbuilder/SQLGenerationContext.java | 6 + .../cayenne/access/sqlbuilder/SelectBuilder.java | 38 +--- ...QLGenerationContext.java => UpdateBuilder.java} | 32 ++- .../sqltree/{NodeType.java => DeleteNode.java} | 26 ++- .../access/sqlbuilder/sqltree/EqualNode.java | 5 +- .../access/sqlbuilder/sqltree/ExpressionNode.java | 10 +- ...{ExpressionNode.java => InsertColumnsNode.java} | 30 ++- .../sqltree/{NodeType.java => InsertNode.java} | 25 ++- .../access/sqlbuilder/sqltree/NodeType.java | 5 +- .../sqltree/{EqualNode.java => SetNode.java} | 24 ++- .../sqlbuilder/sqltree/TrimmingColumnNode.java | 18 +- .../sqltree/{NodeType.java => UpdateNode.java} | 26 +-- .../{ExpressionNode.java => ValuesNode.java} | 32 +-- .../translator/batch/BaseBatchTranslator.java | 89 +++++++++ .../translator/batch/BatchTranslatorContext.java | 72 +++++++ .../batch/DefaultBatchTranslatorFactory.java | 14 +- .../translator/batch/DeleteBatchTranslator.java | 94 +++------ .../translator/batch/InsertBatchTranslator.java | 136 ++++--------- .../batch/SoftDeleteBatchTranslator.java | 180 +++++++---------- .../batch/SoftDeleteTranslatorFactory.java | 138 ++++++------- .../translator/batch/UpdateBatchTranslator.java | 129 ++++--------- .../batch/{ => legacy}/DefaultBatchTranslator.java | 5 +- .../DefaultBatchTranslatorFactory.java | 6 +- .../batch/{ => legacy}/DeleteBatchTranslator.java | 4 +- .../batch/{ => legacy}/InsertBatchTranslator.java | 4 +- .../{ => legacy}/SoftDeleteBatchTranslator.java | 215 +++++++++++---------- .../{ => legacy}/SoftDeleteTranslatorFactory.java | 142 +++++++------- .../batch/{ => legacy}/UpdateBatchTranslator.java | 4 +- .../select/DefaultQuotingAppendable.java | 7 +- .../translator/select/TranslatorContext.java | 2 +- .../dba/oracle/Oracle8LOBBatchTranslator.java | 4 +- .../cayenne/access/jdbc/BatchActionLockingIT.java | 8 +- .../access/sqlbuilder/DeleteBuilderTest.java | 57 ++++++ .../access/sqlbuilder/InsertBuilderTest.java | 87 +++++++++ .../access/sqlbuilder/UpdateBuilderTest.java | 73 +++++++ .../translator/batch/DeleteBatchTranslatorIT.java | 44 +++-- .../translator/batch/InsertBatchTranslatorIT.java | 22 ++- .../batch/SoftDeleteBatchTranslatorIT.java | 12 +- .../translator/batch/UpdateBatchTranslatorIT.java | 66 ++++--- .../{ => legacy}/DefaultBatchTranslatorIT.java | 3 +- .../{ => legacy}/DeleteBatchTranslatorIT.java | 3 +- .../{ => legacy}/InsertBatchTranslatorIT.java | 3 +- .../{ => legacy}/SoftDeleteBatchTranslatorIT.java | 4 +- .../{ => legacy}/UpdateBatchTranslatorIT.java | 3 +- 49 files changed, 1180 insertions(+), 876 deletions(-) diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BatchAction.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BatchAction.java index ad54cbb..6f798e3 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BatchAction.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BatchAction.java @@ -158,6 +158,10 @@ public class BatchAction extends BaseSQLAction { protected void runAsIndividualQueries(Connection connection, BatchTranslator translator, OperationObserver delegate, boolean generatesKeys) throws SQLException, Exception { + if(query.getRows().isEmpty()) { + return; + } + JdbcEventLogger logger = dataNode.getJdbcEventLogger(); boolean useOptimisticLock = query.isUsingOptimisticLocking(); diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ExpressionNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/BaseBuilder.java similarity index 52% copy from cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ExpressionNode.java copy to cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/BaseBuilder.java index 0199ec3..1f8ea45 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ExpressionNode.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/BaseBuilder.java @@ -17,49 +17,50 @@ * under the License. ****************************************************************/ -package org.apache.cayenne.access.sqlbuilder.sqltree; +package org.apache.cayenne.access.sqlbuilder; +import java.util.function.Supplier; -import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; /** * @since 4.2 */ -public class ExpressionNode extends Node { +public abstract class BaseBuilder implements NodeBuilder { + /** + * Main root of this query + */ + protected final Node root; - public ExpressionNode() { - } + /* + * Following nodes are all children of root, + * but we keep them here for quick access. + */ + protected final Node[] nodes; - public ExpressionNode(NodeType nodeType) { - super(nodeType); + public BaseBuilder(Node root, int size) { + this.root = root; + this.nodes = new Node[size]; } - @Override - public QuotingAppendable append(QuotingAppendable buffer) { - return buffer; - } - - @Override - public void appendChildrenStart(QuotingAppendable buffer) { - if(parent != null && parent.type != NodeType.WHERE && parent.type != NodeType.JOIN) { - buffer.append(" ("); + protected Node node(int idx, Supplier<Node> nodeSupplier) { + if(nodes[idx] == null) { + nodes[idx] = nodeSupplier.get(); } + return nodes[idx]; } @Override - public void appendChildrenEnd(QuotingAppendable buffer) { - if(parent != null && parent.type != NodeType.WHERE && parent.type != NodeType.JOIN) { - buffer.append(" )"); + public Node build() { + for (Node next : nodes) { + if (next != null) { + root.addChild(next); + } } + return root; } - @Override - public String toString() { - return "{ExpressionNode}"; - } - - @Override - public Node copy() { - return new ExpressionNode(); + public Node getRoot() { + return root; } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/SQLGenerationContext.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/DeleteBuilder.java similarity index 59% copy from cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/SQLGenerationContext.java copy to cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/DeleteBuilder.java index 02090c5..9d00f2e 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/SQLGenerationContext.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/DeleteBuilder.java @@ -19,17 +19,27 @@ package org.apache.cayenne.access.sqlbuilder; -import java.util.Collection; - -import org.apache.cayenne.access.translator.DbAttributeBinding; -import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.access.sqlbuilder.sqltree.DeleteNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.TableNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.WhereNode; /** * @since 4.2 */ -public interface SQLGenerationContext { +public class DeleteBuilder extends BaseBuilder { + + private static final int TABLE_NODE = 0; + private static final int WHERE_NODE = 1; - DbAdapter getAdapter(); + public DeleteBuilder(String table) { + super(new DeleteNode(), WHERE_NODE + 1); + node(TABLE_NODE, () -> new TableNode(table, null)); + } - Collection<DbAttributeBinding> getBindings(); + public DeleteBuilder where(NodeBuilder expression) { + if(expression != null) { + node(WHERE_NODE, WhereNode::new).addChild(expression.build()); + } + return this; + } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/InsertBuilder.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/InsertBuilder.java new file mode 100644 index 0000000..2c112f5 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/InsertBuilder.java @@ -0,0 +1,54 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.access.sqlbuilder; + +import org.apache.cayenne.access.sqlbuilder.sqltree.InsertColumnsNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.InsertNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.TableNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.ValuesNode; + +/** + * @since 4.2 + */ +public class InsertBuilder extends BaseBuilder { + + /* + INSERT INTO AUTO_PK_SUPPORT (TABLE_NAME, NEXT_ID) VALUES ('X_AUTHOR', 200) + */ + + private static final int TABLE_NODE = 0; + private static final int COLUMNS_NODE = 1; + private static final int VALUES_NODE = 2; + + public InsertBuilder(String table) { + super(new InsertNode(), VALUES_NODE + 1); + node(TABLE_NODE, () -> new TableNode(table, null)); + } + + public InsertBuilder column(ColumnNodeBuilder columnNode) { + node(COLUMNS_NODE, InsertColumnsNode::new).addChild(columnNode.build()); + return this; + } + + public InsertBuilder value(ValueNodeBuilder valueNode) { + node(VALUES_NODE, ValuesNode::new).addChild(valueNode.build()); + return this; + } +} diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/SQLBuilder.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/SQLBuilder.java index ac84aeb..b5b92b3 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/SQLBuilder.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/SQLBuilder.java @@ -36,6 +36,18 @@ public final class SQLBuilder { return new SelectBuilder(params); } + public static InsertBuilder insert(String table) { + return new InsertBuilder(table); + } + + public static UpdateBuilder update(String table) { + return new UpdateBuilder(table); + } + + public static DeleteBuilder delete(String table) { + return new DeleteBuilder(table); + } + public static TableNodeBuilder table(String table) { return new TableNodeBuilder(table); } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/SQLGenerationContext.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/SQLGenerationContext.java index 02090c5..7e0b759 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/SQLGenerationContext.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/SQLGenerationContext.java @@ -23,6 +23,8 @@ import java.util.Collection; import org.apache.cayenne.access.translator.DbAttributeBinding; import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.dba.QuotingStrategy; +import org.apache.cayenne.map.DbEntity; /** * @since 4.2 @@ -32,4 +34,8 @@ public interface SQLGenerationContext { DbAdapter getAdapter(); Collection<DbAttributeBinding> getBindings(); + + QuotingStrategy getQuotingStrategy(); + + DbEntity getRootDbEntity(); } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/SelectBuilder.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/SelectBuilder.java index 702a68c..6517d0d 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/SelectBuilder.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/SelectBuilder.java @@ -19,8 +19,6 @@ package org.apache.cayenne.access.sqlbuilder; -import java.util.function.Supplier; - import org.apache.cayenne.access.sqlbuilder.sqltree.DistinctNode; import org.apache.cayenne.access.sqlbuilder.sqltree.FromNode; import org.apache.cayenne.access.sqlbuilder.sqltree.GroupByNode; @@ -36,7 +34,7 @@ import org.apache.cayenne.access.sqlbuilder.sqltree.WhereNode; /** * @since 4.2 */ -public class SelectBuilder implements NodeBuilder { +public class SelectBuilder extends BaseBuilder { private static final int SELECT_NODE = 0; private static final int FROM_NODE = 1; @@ -47,19 +45,8 @@ public class SelectBuilder implements NodeBuilder { private static final int ORDERBY_NODE = 6; private static final int LIMIT_NODE = 7; - /** - * Main root of this query - */ - private Node root; - - /* - * Following nodes are all children of root, - * but we keep them here for quick access. - */ - private Node[] nodes = new Node[LIMIT_NODE + 1]; - SelectBuilder(NodeBuilder... selectExpressions) { - root = new SelectNode(); + super(new SelectNode(), LIMIT_NODE + 1); for(NodeBuilder exp : selectExpressions) { node(SELECT_NODE, SelectResultNode::new).addChild(exp.build()); } @@ -145,25 +132,4 @@ public class SelectBuilder implements NodeBuilder { return this; } - @Override - public Node build() { - for (Node next : nodes) { - if (next != null) { - root.addChild(next); - } - } - return root; - } - - public Node getRoot() { - return root; - } - - private Node node(int idx, Supplier<Node> nodeSupplier) { - if(nodes[idx] == null) { - nodes[idx] = nodeSupplier.get(); - } - return nodes[idx]; - } - } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/SQLGenerationContext.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/UpdateBuilder.java similarity index 51% copy from cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/SQLGenerationContext.java copy to cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/UpdateBuilder.java index 02090c5..429ac8f 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/SQLGenerationContext.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/UpdateBuilder.java @@ -19,17 +19,35 @@ package org.apache.cayenne.access.sqlbuilder; -import java.util.Collection; - -import org.apache.cayenne.access.translator.DbAttributeBinding; -import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.access.sqlbuilder.sqltree.SetNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.TableNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.UpdateNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.WhereNode; /** * @since 4.2 */ -public interface SQLGenerationContext { +public class UpdateBuilder extends BaseBuilder { + + private static final int TABLE_NODE = 0; + private static final int SET_NODE = 1; + private static final int WHERE_NODE = 2; + + public UpdateBuilder(String table) { + super(new UpdateNode(), WHERE_NODE + 1); + node(TABLE_NODE, () -> new TableNode(table, null)); + } + + public UpdateBuilder set(NodeBuilder setExpression) { + node(SET_NODE, SetNode::new).addChild(setExpression.build()); + return this; + } - DbAdapter getAdapter(); + public UpdateBuilder where(NodeBuilder expression) { + if(expression != null) { + node(WHERE_NODE, WhereNode::new).addChild(expression.build()); + } + return this; + } - Collection<DbAttributeBinding> getBindings(); } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/DeleteNode.java similarity index 76% copy from cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java copy to cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/DeleteNode.java index b5a6a63..98f73d9 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/DeleteNode.java @@ -16,23 +16,21 @@ * specific language governing permissions and limitations * under the License. ****************************************************************/ - package org.apache.cayenne.access.sqlbuilder.sqltree; +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + /** * @since 4.2 */ -public enum NodeType { - UNDEFINED, - VALUE, - COLUMN, - LIMIT_OFFSET, - FUNCTION, - EQUALITY, - LIKE, - DISTINCT, - IN, - RESULT, - WHERE, - JOIN, FROM +public class DeleteNode extends Node { + @Override + public Node copy() { + return new DeleteNode(); + } + + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + return buffer.append("DELETE FROM"); + } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/EqualNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/EqualNode.java index 50b4ba0..fc64616 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/EqualNode.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/EqualNode.java @@ -33,7 +33,10 @@ public class EqualNode extends ExpressionNode { @Override public void appendChildrenSeparator(QuotingAppendable buffer, int childIdx) { Node child = getChild(1); - if (child.getType() == NodeType.VALUE && ((ValueNode) child).getValue() == null) { + if (child.getType() == NodeType.VALUE + && ((ValueNode) child).getValue() == null + && getParent() != null + && getParent().getType() != NodeType.UPDATE_SET) { buffer.append(" IS"); } else { buffer.append(" ="); diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ExpressionNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ExpressionNode.java index 0199ec3..cf4a219 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ExpressionNode.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ExpressionNode.java @@ -41,14 +41,20 @@ public class ExpressionNode extends Node { @Override public void appendChildrenStart(QuotingAppendable buffer) { - if(parent != null && parent.type != NodeType.WHERE && parent.type != NodeType.JOIN) { + if(parent != null + && parent.type != NodeType.WHERE + && parent.type != NodeType.JOIN + && parent.type != NodeType.UPDATE_SET) { buffer.append(" ("); } } @Override public void appendChildrenEnd(QuotingAppendable buffer) { - if(parent != null && parent.type != NodeType.WHERE && parent.type != NodeType.JOIN) { + if(parent != null + && parent.type != NodeType.WHERE + && parent.type != NodeType.JOIN + && parent.type != NodeType.UPDATE_SET) { buffer.append(" )"); } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ExpressionNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/InsertColumnsNode.java similarity index 73% copy from cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ExpressionNode.java copy to cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/InsertColumnsNode.java index 0199ec3..6b6aaa9 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ExpressionNode.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/InsertColumnsNode.java @@ -19,19 +19,20 @@ package org.apache.cayenne.access.sqlbuilder.sqltree; - import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; /** * @since 4.2 */ -public class ExpressionNode extends Node { +public class InsertColumnsNode extends Node { - public ExpressionNode() { + public InsertColumnsNode() { + super(NodeType.INSERT_COLUMNS); } - public ExpressionNode(NodeType nodeType) { - super(nodeType); + @Override + public Node copy() { + return new InsertColumnsNode(); } @Override @@ -40,26 +41,17 @@ public class ExpressionNode extends Node { } @Override - public void appendChildrenStart(QuotingAppendable buffer) { - if(parent != null && parent.type != NodeType.WHERE && parent.type != NodeType.JOIN) { - buffer.append(" ("); - } + public void appendChildrenSeparator(QuotingAppendable buffer, int childInd) { + buffer.append(','); } @Override public void appendChildrenEnd(QuotingAppendable buffer) { - if(parent != null && parent.type != NodeType.WHERE && parent.type != NodeType.JOIN) { - buffer.append(" )"); - } + buffer.append(')'); } @Override - public String toString() { - return "{ExpressionNode}"; - } - - @Override - public Node copy() { - return new ExpressionNode(); + public void appendChildrenStart(QuotingAppendable buffer) { + buffer.append('('); } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/InsertNode.java similarity index 76% copy from cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java copy to cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/InsertNode.java index b5a6a63..69a8f1d 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/InsertNode.java @@ -19,20 +19,19 @@ package org.apache.cayenne.access.sqlbuilder.sqltree; +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + /** * @since 4.2 */ -public enum NodeType { - UNDEFINED, - VALUE, - COLUMN, - LIMIT_OFFSET, - FUNCTION, - EQUALITY, - LIKE, - DISTINCT, - IN, - RESULT, - WHERE, - JOIN, FROM +public class InsertNode extends Node { + @Override + public Node copy() { + return new InsertNode(); + } + + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + return buffer.append("INSERT INTO"); + } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java index b5a6a63..af5b222 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java @@ -34,5 +34,8 @@ public enum NodeType { IN, RESULT, WHERE, - JOIN, FROM + JOIN, + FROM, + UPDATE_SET, + INSERT_COLUMNS } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/EqualNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SetNode.java similarity index 78% copy from cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/EqualNode.java copy to cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SetNode.java index 50b4ba0..eb57d2d 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/EqualNode.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SetNode.java @@ -24,20 +24,24 @@ import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; /** * @since 4.2 */ -public class EqualNode extends ExpressionNode { +public class SetNode extends Node { - public EqualNode() { - super(NodeType.EQUALITY); + public SetNode() { + super(NodeType.UPDATE_SET); } @Override - public void appendChildrenSeparator(QuotingAppendable buffer, int childIdx) { - Node child = getChild(1); - if (child.getType() == NodeType.VALUE && ((ValueNode) child).getValue() == null) { - buffer.append(" IS"); - } else { - buffer.append(" ="); - } + public Node copy() { + return new SetNode(); + } + + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + return buffer.append(" SET"); } + @Override + public void appendChildrenSeparator(QuotingAppendable buffer, int childIdx) { + buffer.append(','); + } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/TrimmingColumnNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/TrimmingColumnNode.java index d8830f0..d409064 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/TrimmingColumnNode.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/TrimmingColumnNode.java @@ -55,6 +55,9 @@ public class TrimmingColumnNode extends Node { } private boolean isComparisionWithClob() { + if(isInsertOrUpdateSet()) { + return false; + } return (getParent().getType() == NodeType.EQUALITY || getParent().getType() == NodeType.LIKE) && columnNode.getAttribute() != null @@ -75,7 +78,10 @@ public class TrimmingColumnNode extends Node { protected boolean isAllowedForTrimming() { Node parent = getParent(); while(parent != null) { - if(parent.getType() == NodeType.JOIN || parent.getType() == NodeType.FUNCTION) { + if(parent.getType() == NodeType.JOIN + || parent.getType() == NodeType.FUNCTION + || parent.getType() == NodeType.UPDATE_SET + || parent.getType() == NodeType.INSERT_COLUMNS) { return false; } parent = parent.getParent(); @@ -84,9 +90,17 @@ public class TrimmingColumnNode extends Node { } protected boolean isResultNode() { + return isParentOfType(NodeType.RESULT); + } + + protected boolean isInsertOrUpdateSet() { + return isParentOfType(NodeType.UPDATE_SET) || isParentOfType(NodeType.INSERT_COLUMNS); + } + + protected boolean isParentOfType(NodeType nodeType) { Node parent = getParent(); while(parent != null) { - if(parent.getType() == NodeType.RESULT) { + if(parent.getType() == nodeType) { return true; } parent = parent.getParent(); diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/UpdateNode.java similarity index 77% copy from cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java copy to cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/UpdateNode.java index b5a6a63..a5f0782 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/UpdateNode.java @@ -19,20 +19,20 @@ package org.apache.cayenne.access.sqlbuilder.sqltree; +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + /** * @since 4.2 */ -public enum NodeType { - UNDEFINED, - VALUE, - COLUMN, - LIMIT_OFFSET, - FUNCTION, - EQUALITY, - LIKE, - DISTINCT, - IN, - RESULT, - WHERE, - JOIN, FROM +public class UpdateNode extends Node { + + @Override + public Node copy() { + return new UpdateNode(); + } + + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + return buffer.append("UPDATE"); + } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ExpressionNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ValuesNode.java similarity index 71% copy from cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ExpressionNode.java copy to cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ValuesNode.java index 0199ec3..fb82fc7 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ExpressionNode.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ValuesNode.java @@ -19,47 +19,35 @@ package org.apache.cayenne.access.sqlbuilder.sqltree; - import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; /** * @since 4.2 */ -public class ExpressionNode extends Node { - - public ExpressionNode() { - } +public class ValuesNode extends Node { - public ExpressionNode(NodeType nodeType) { - super(nodeType); + @Override + public Node copy() { + return new ValuesNode(); } @Override public QuotingAppendable append(QuotingAppendable buffer) { - return buffer; + return buffer.append(" VALUES"); } @Override public void appendChildrenStart(QuotingAppendable buffer) { - if(parent != null && parent.type != NodeType.WHERE && parent.type != NodeType.JOIN) { - buffer.append(" ("); - } + buffer.append('('); } @Override - public void appendChildrenEnd(QuotingAppendable buffer) { - if(parent != null && parent.type != NodeType.WHERE && parent.type != NodeType.JOIN) { - buffer.append(" )"); - } + public void appendChildrenSeparator(QuotingAppendable buffer, int childInd) { + buffer.append(','); } @Override - public String toString() { - return "{ExpressionNode}"; - } - - @Override - public Node copy() { - return new ExpressionNode(); + public void appendChildrenEnd(QuotingAppendable buffer) { + buffer.append(')'); } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/BaseBatchTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/BaseBatchTranslator.java new file mode 100644 index 0000000..93da8e8 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/BaseBatchTranslator.java @@ -0,0 +1,89 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.access.translator.batch; + +import java.util.List; + +import org.apache.cayenne.access.sqlbuilder.ExpressionNodeBuilder; +import org.apache.cayenne.access.sqlbuilder.NodeBuilder; +import org.apache.cayenne.access.sqlbuilder.SQLBuilder; +import org.apache.cayenne.access.sqlbuilder.SQLGenerationVisitor; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; +import org.apache.cayenne.access.translator.DbAttributeBinding; +import org.apache.cayenne.access.translator.select.DefaultQuotingAppendable; +import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.query.BatchQuery; + +/** + * @since 4.2 + * @param <T> type of the batch query to translate + */ +public abstract class BaseBatchTranslator<T extends BatchQuery> { + + protected final BatchTranslatorContext<T> context; + + protected DbAttributeBinding[] bindings; + + public BaseBatchTranslator(T query, DbAdapter adapter) { + this.context = new BatchTranslatorContext<>(query, adapter); + } + + public DbAttributeBinding[] getBindings() { + return bindings; + } + + /** + * This method applies {@link org.apache.cayenne.access.translator.select.BaseSQLTreeProcessor} to the + * provided SQL tree node and generates SQL string from it. + * + * @param nodeBuilder SQL tree node builder + * @return SQL string + */ + protected String doTranslate(NodeBuilder nodeBuilder) { + Node node = nodeBuilder.build(); + // convert to database flavour + node = context.getAdapter().getSqlTreeProcessor().apply(node); + // generate SQL + SQLGenerationVisitor visitor = new SQLGenerationVisitor(new DefaultQuotingAppendable(context)); + node.visit(visitor); + + bindings = context.getBindings().toArray(new DbAttributeBinding[0]); + return visitor.getSQLString(); + } + + abstract protected boolean isNullAttribute(DbAttribute attribute); + + protected ExpressionNodeBuilder buildQualifier(List<DbAttribute> attributeList) { + ExpressionNodeBuilder eq = null; + for (DbAttribute attr : attributeList) { + Integer value = isNullAttribute(attr) ? null : 1; + ExpressionNodeBuilder next = SQLBuilder + .column(attr.getName()).attribute(attr) + .eq(SQLBuilder.value(value).attribute(attr)); + if(eq == null) { + eq = next; + } else { + eq = eq.and(next); + } + } + return eq; + } +} diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/BatchTranslatorContext.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/BatchTranslatorContext.java new file mode 100644 index 0000000..17352dd --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/BatchTranslatorContext.java @@ -0,0 +1,72 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.access.translator.batch; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.apache.cayenne.access.sqlbuilder.SQLGenerationContext; +import org.apache.cayenne.access.translator.DbAttributeBinding; +import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.dba.QuotingStrategy; +import org.apache.cayenne.map.DbEntity; +import org.apache.cayenne.query.BatchQuery; + +/** + * @since 4.2 + * @param <T> type of the {@link BatchQuery} + */ +class BatchTranslatorContext<T extends BatchQuery> implements SQLGenerationContext { + + private final T query; + private final DbAdapter adapter; + private final List<DbAttributeBinding> bindings; + + BatchTranslatorContext(T query, DbAdapter adapter) { + this.query = query; + this.adapter = adapter; + this.bindings = new ArrayList<>(); + } + + @Override + public DbAdapter getAdapter() { + return adapter; + } + + @Override + public Collection<DbAttributeBinding> getBindings() { + return bindings; + } + + @Override + public QuotingStrategy getQuotingStrategy() { + return adapter.getQuotingStrategy(); + } + + @Override + public DbEntity getRootDbEntity() { + return query.getDbEntity(); + } + + public T getQuery() { + return query; + } +} diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/DefaultBatchTranslatorFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/DefaultBatchTranslatorFactory.java index 639bded..b0d8f3c 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/DefaultBatchTranslatorFactory.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/DefaultBatchTranslatorFactory.java @@ -28,7 +28,7 @@ import org.apache.cayenne.query.UpdateBatchQuery; /** * Default implementation of {@link BatchTranslatorFactory}. * - * @since 4.0 + * @since 4.2 */ public class DefaultBatchTranslatorFactory implements BatchTranslatorFactory { @@ -37,24 +37,24 @@ public class DefaultBatchTranslatorFactory implements BatchTranslatorFactory { if (query instanceof InsertBatchQuery) { return insertTranslator((InsertBatchQuery) query, adapter); } else if (query instanceof UpdateBatchQuery) { - return updateTranslator((UpdateBatchQuery) query, adapter, trimFunction); + return updateTranslator((UpdateBatchQuery) query, adapter); } else if (query instanceof DeleteBatchQuery) { - return deleteTranslator((DeleteBatchQuery) query, adapter, trimFunction); + return deleteTranslator((DeleteBatchQuery) query, adapter); } else { throw new CayenneRuntimeException("Unsupported batch query: %s", query); } } - protected BatchTranslator deleteTranslator(DeleteBatchQuery query, DbAdapter adapter, String trimFunction) { - return new DeleteBatchTranslator(query, adapter, trimFunction); + protected BatchTranslator deleteTranslator(DeleteBatchQuery query, DbAdapter adapter) { + return new DeleteBatchTranslator(query, adapter); } protected BatchTranslator insertTranslator(InsertBatchQuery query, DbAdapter adapter) { return new InsertBatchTranslator(query, adapter); } - protected BatchTranslator updateTranslator(UpdateBatchQuery query, DbAdapter adapter, String trimFunction) { - return new UpdateBatchTranslator(query, adapter, trimFunction); + protected BatchTranslator updateTranslator(UpdateBatchQuery query, DbAdapter adapter) { + return new UpdateBatchTranslator(query, adapter); } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/DeleteBatchTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/DeleteBatchTranslator.java index e5915a3..87441ac 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/DeleteBatchTranslator.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/DeleteBatchTranslator.java @@ -19,98 +19,52 @@ package org.apache.cayenne.access.translator.batch; -import java.util.Iterator; -import java.util.List; - +import org.apache.cayenne.access.sqlbuilder.DeleteBuilder; +import org.apache.cayenne.access.sqlbuilder.SQLBuilder; import org.apache.cayenne.access.translator.DbAttributeBinding; import org.apache.cayenne.access.types.ExtendedType; import org.apache.cayenne.dba.DbAdapter; -import org.apache.cayenne.dba.QuotingStrategy; import org.apache.cayenne.map.DbAttribute; import org.apache.cayenne.query.BatchQueryRow; import org.apache.cayenne.query.DeleteBatchQuery; /** - * Translator for delete BatchQueries. Creates parameterized DELETE SQL - * statements. + * @since 4.2 */ -public class DeleteBatchTranslator extends DefaultBatchTranslator { +public class DeleteBatchTranslator extends BaseBatchTranslator<DeleteBatchQuery> implements BatchTranslator { - public DeleteBatchTranslator(DeleteBatchQuery query, DbAdapter adapter, String trimFunction) { - super(query, adapter, trimFunction); + public DeleteBatchTranslator(DeleteBatchQuery query, DbAdapter adapter) { + super(query, adapter); } @Override - protected String createSql() { - - QuotingStrategy strategy = adapter.getQuotingStrategy(); - - StringBuilder buffer = new StringBuilder("DELETE FROM "); - buffer.append(strategy.quotedFullyQualifiedName(query.getDbEntity())); - - applyQualifier(buffer); - - return buffer.toString(); + public String getSql() { + DeleteBuilder deleteBuilder = SQLBuilder + .delete(context.getRootDbEntity().getFullyQualifiedName()) + .where(buildQualifier(context.getQuery().getDbAttributes())); + return doTranslate(deleteBuilder); } - /** - * Appends WHERE clause to SQL string - */ - protected void applyQualifier(StringBuilder buffer) { - buffer.append(" WHERE "); - - DeleteBatchQuery deleteBatch = (DeleteBatchQuery) query; - Iterator<DbAttribute> i = deleteBatch.getDbAttributes().iterator(); - while (i.hasNext()) { - DbAttribute attribute = i.next(); - appendDbAttribute(buffer, attribute); - buffer.append(deleteBatch.isNull(attribute) ? " IS NULL" : " = ?"); - - if (i.hasNext()) { - buffer.append(" AND "); - } - } + @Override + protected boolean isNullAttribute(DbAttribute attribute) { + return context.getQuery().isNull(attribute); } @Override - protected DbAttributeBinding[] createBindings() { - DeleteBatchQuery deleteBatch = (DeleteBatchQuery) query; - List<DbAttribute> attributes = deleteBatch.getDbAttributes(); - int len = attributes.size(); - - DbAttributeBinding[] bindings = new DbAttributeBinding[len]; - - for (int i = 0; i < len; i++) { - bindings[i] = new DbAttributeBinding(attributes.get(i)); + public DbAttributeBinding[] updateBindings(BatchQueryRow row) { + DeleteBatchQuery deleteBatch = context.getQuery(); + for(int i=0, position=0; i<deleteBatch.getDbAttributes().size(); i++) { + position = updateBinding(row.getValue(i), position); } - return bindings; } - @Override - protected DbAttributeBinding[] doUpdateBindings(BatchQueryRow row) { - - int len = bindings.length; - - DeleteBatchQuery deleteBatch = (DeleteBatchQuery) query; - - for (int i = 0, j = 1; i < len; i++) { - - DbAttributeBinding b = bindings[i]; - - // skip null attributes... they are translated as "IS NULL" - if (deleteBatch.isNull(b.getAttribute())) { - b.exclude(); - } else { - Object value = row.getValue(i); - ExtendedType extendedType = value != null - ? adapter.getExtendedTypes().getRegisteredType(value.getClass()) - : adapter.getExtendedTypes().getDefaultType(); - - b.include(j++, value, extendedType); - } + protected int updateBinding(Object value, int position) { + // skip null attributes... they are translated as "IS NULL" + if(value != null) { + ExtendedType<?> extendedType = context.getAdapter().getExtendedTypes().getRegisteredType(value.getClass()); + bindings[position].include(++position, value, extendedType); } - - return bindings; + return position; } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/InsertBatchTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/InsertBatchTranslator.java index 8c70532..aff48d7 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/InsertBatchTranslator.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/InsertBatchTranslator.java @@ -19,129 +19,73 @@ package org.apache.cayenne.access.translator.batch; -import java.util.List; - +import org.apache.cayenne.access.sqlbuilder.InsertBuilder; +import org.apache.cayenne.access.sqlbuilder.SQLBuilder; import org.apache.cayenne.access.translator.DbAttributeBinding; import org.apache.cayenne.access.types.ExtendedType; import org.apache.cayenne.dba.DbAdapter; -import org.apache.cayenne.dba.QuotingStrategy; import org.apache.cayenne.map.DbAttribute; import org.apache.cayenne.query.BatchQueryRow; import org.apache.cayenne.query.InsertBatchQuery; /** - * Translator of InsertBatchQueries. + * @since 4.2 */ -public class InsertBatchTranslator extends DefaultBatchTranslator { +public class InsertBatchTranslator extends BaseBatchTranslator<InsertBatchQuery> implements BatchTranslator { public InsertBatchTranslator(InsertBatchQuery query, DbAdapter adapter) { - // no trimming is needed here, so passing hardcoded NULL for trim - // function - super(query, adapter, null); + super(query, adapter); } @Override - protected String createSql() { - - List<DbAttribute> dbAttributes = query.getDbAttributes(); - QuotingStrategy strategy = adapter.getQuotingStrategy(); - - StringBuilder buffer = new StringBuilder("INSERT INTO "); - buffer.append(strategy.quotedFullyQualifiedName(query.getDbEntity())); - buffer.append(" ("); - - int columnCount = 0; - for (DbAttribute attribute : dbAttributes) { - - // attribute inclusion rule - one of the rules below must be true: - // (1) attribute not generated - // (2) attribute is generated and PK and adapter does not support - // generated - // keys - - if (includeInBatch(attribute)) { - - if (columnCount > 0) { - buffer.append(", "); - } - buffer.append(strategy.quotedName(attribute)); - columnCount++; + public String getSql() { + InsertBatchQuery query = context.getQuery(); + InsertBuilder insertBuilder = SQLBuilder.insert(context.getRootDbEntity().getFullyQualifiedName()); + + for(DbAttribute attribute : query.getDbAttributes()) { + // skip generated attributes, if needed + if(excludeInBatch(attribute)) { + continue; } + insertBuilder + .column(SQLBuilder.column(attribute.getName()).attribute(attribute)) + // We can use here any non-null value, to create attribute binding, + // actual value and ExtendedType will be set at updateBindings() call. + .value(SQLBuilder.value(1).attribute(attribute)); } - buffer.append(") VALUES ("); - - for (int i = 0; i < columnCount; i++) { - if (i > 0) { - buffer.append(", "); - } - - buffer.append('?'); - } - buffer.append(')'); - return buffer.toString(); + return doTranslate(insertBuilder); } @Override - protected DbAttributeBinding[] createBindings() { - List<DbAttribute> attributes = query.getDbAttributes(); - int len = attributes.size(); - - DbAttributeBinding[] bindings = new DbAttributeBinding[len]; - - for (int i = 0; i < len; i++) { - DbAttribute a = attributes.get(i); - - bindings[i] = new DbAttributeBinding(a); - - // include/exclude state depends on DbAttribute only and can be - // precompiled here - if (includeInBatch(a)) { - // setting fake position here... all we care about is that it is - // > -1 - bindings[i].include(1, null, null); - } else { - bindings[i].exclude(); + public DbAttributeBinding[] updateBindings(BatchQueryRow row) { + InsertBatchQuery query = context.getQuery(); + int i=0; + int j=0; + for(DbAttribute attribute : query.getDbAttributes()) { + if(excludeInBatch(attribute)) { + i++; + continue; } - } - - return bindings; - } - - @Override - protected DbAttributeBinding[] doUpdateBindings(BatchQueryRow row) { - int len = bindings.length; - for (int i = 0, j = 1; i < len; i++) { - - DbAttributeBinding b = bindings[i]; - - // exclusions are permanent - if (!b.isExcluded()) { - Object value = row.getValue(i); - ExtendedType extendedType = value != null - ? adapter.getExtendedTypes().getRegisteredType(value.getClass()) - : adapter.getExtendedTypes().getDefaultType(); - - b.include(j++, value, extendedType); - } + Object value = row.getValue(i++); + ExtendedType<?> extendedType = value != null + ? context.getAdapter().getExtendedTypes().getRegisteredType(value.getClass()) + : context.getAdapter().getExtendedTypes().getDefaultType(); + bindings[j].include(++j, value, extendedType); } - return bindings; } - /** - * Returns true if an attribute should be included in the batch. - * - * @since 1.2 - */ - protected boolean includeInBatch(DbAttribute attribute) { + protected boolean excludeInBatch(DbAttribute attribute) { // attribute inclusion rule - one of the rules below must be true: - // (1) attribute not generated - // (2) attribute is generated and PK and adapter does not support - // generated - // keys + // (1) attribute not generated + // (2) attribute is generated and PK and adapter does not support generated keys + return attribute.isGenerated() && (!attribute.isPrimaryKey() || context.getAdapter().supportsGeneratedKeys()); + } - return !attribute.isGenerated() || (attribute.isPrimaryKey() && !adapter.supportsGeneratedKeys()); + @Override + protected boolean isNullAttribute(DbAttribute attribute) { + return false; } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslator.java index 12dfe8d..5c1bc2a 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslator.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslator.java @@ -1,105 +1,75 @@ -/***************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - ****************************************************************/ -package org.apache.cayenne.access.translator.batch; - -import org.apache.cayenne.access.translator.DbAttributeBinding; -import org.apache.cayenne.access.types.ExtendedType; -import org.apache.cayenne.dba.DbAdapter; -import org.apache.cayenne.dba.QuotingStrategy; -import org.apache.cayenne.dba.TypesMapping; -import org.apache.cayenne.map.DbAttribute; -import org.apache.cayenne.query.BatchQueryRow; -import org.apache.cayenne.query.DeleteBatchQuery; - -/** - * Implementation of {@link DeleteBatchTranslator}, which uses 'soft' delete - * (runs UPDATE and sets 'deleted' field to true instead-of running SQL DELETE) - */ -public class SoftDeleteBatchTranslator extends DeleteBatchTranslator { - - private String deletedFieldName; - - public SoftDeleteBatchTranslator(DeleteBatchQuery query, DbAdapter adapter, String trimFunction, - String deletedFieldName) { - super(query, adapter, trimFunction); - this.deletedFieldName = deletedFieldName; - } - - @Override - protected String createSql() { - - QuotingStrategy strategy = adapter.getQuotingStrategy(); - - StringBuilder buffer = new StringBuilder("UPDATE "); - buffer.append(strategy.quotedFullyQualifiedName(query.getDbEntity())); - buffer.append(" SET ").append(strategy.quotedIdentifier(query.getDbEntity(), deletedFieldName)).append(" = ?"); - - applyQualifier(buffer); - - return buffer.toString(); - } - - @Override - protected DbAttributeBinding[] createBindings() { - - DbAttributeBinding[] superBindings = super.createBindings(); - - int slen = superBindings.length; - - DbAttributeBinding[] bindings = new DbAttributeBinding[slen + 1]; - - DbAttribute deleteAttribute = query.getDbEntity().getAttribute(deletedFieldName); - String typeName = TypesMapping.getJavaBySqlType(deleteAttribute.getType()); - ExtendedType extendedType = adapter.getExtendedTypes().getRegisteredType(typeName); - - bindings[0] = new DbAttributeBinding(deleteAttribute); - bindings[0].include(1, true, extendedType); - - System.arraycopy(superBindings, 0, bindings, 1, slen); - - return bindings; - } - - @Override - protected DbAttributeBinding[] doUpdateBindings(BatchQueryRow row) { - int len = bindings.length; - - DeleteBatchQuery deleteBatch = (DeleteBatchQuery) query; - - // skip position 0... Otherwise follow super algorithm - for (int i = 1, j = 2; i < len; i++) { - - DbAttributeBinding b = bindings[i]; - - // skip null attributes... they are translated as "IS NULL" - if (deleteBatch.isNull(b.getAttribute())) { - b.exclude(); - } else { - Object value = row.getValue(i - 1); - ExtendedType extendedType = value != null - ? adapter.getExtendedTypes().getRegisteredType(value.getClass()) - : adapter.getExtendedTypes().getDefaultType(); - - b.include(j++, value, extendedType); - } - } - - return bindings; - } -} +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.access.translator.batch; + +import org.apache.cayenne.access.sqlbuilder.SQLBuilder; +import org.apache.cayenne.access.sqlbuilder.UpdateBuilder; +import org.apache.cayenne.access.translator.DbAttributeBinding; +import org.apache.cayenne.access.types.ExtendedType; +import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.dba.TypesMapping; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.query.BatchQueryRow; +import org.apache.cayenne.query.DeleteBatchQuery; + +import static org.apache.cayenne.access.sqlbuilder.SQLBuilder.*; + +/** + * @since 4.2 + */ +public class SoftDeleteBatchTranslator extends DeleteBatchTranslator { + + private final String deletedFieldName; + + public SoftDeleteBatchTranslator(DeleteBatchQuery query, DbAdapter adapter, String deletedFieldName) { + super(query, adapter); + this.deletedFieldName = deletedFieldName; + } + + @Override + public String getSql() { + DeleteBatchQuery query = context.getQuery(); + DbAttribute deleteAttribute = query.getDbEntity().getAttribute(deletedFieldName); + + UpdateBuilder updateBuilder = update(context.getRootDbEntity().getFullyQualifiedName()) + .set(column(deletedFieldName).attribute(deleteAttribute) + .eq(SQLBuilder.value(true).attribute(deleteAttribute))) + .where(buildQualifier(query.getDbAttributes())); + + String sql = doTranslate(updateBuilder); + + String typeName = TypesMapping.getJavaBySqlType(deleteAttribute.getType()); + ExtendedType<?> extendedType = context.getAdapter().getExtendedTypes().getRegisteredType(typeName); + bindings[0].include(1, true, extendedType); + + return sql; + } + + @Override + public DbAttributeBinding[] updateBindings(BatchQueryRow row) { + DeleteBatchQuery deleteBatch = context.getQuery(); + + for(int i=0, position=1; i<deleteBatch.getDbAttributes().size(); i++) { + position = updateBinding(row.getValue(i), position); + } + + return bindings; + } +} diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteTranslatorFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteTranslatorFactory.java index 10054ba..c0eec5a 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteTranslatorFactory.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteTranslatorFactory.java @@ -1,69 +1,69 @@ -/***************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - ****************************************************************/ -package org.apache.cayenne.access.translator.batch; - -import java.sql.Types; - -import org.apache.cayenne.access.translator.batch.BatchTranslator; -import org.apache.cayenne.dba.DbAdapter; -import org.apache.cayenne.map.DbAttribute; -import org.apache.cayenne.query.DeleteBatchQuery; - -/** - * Implementation of {link #BatchTranslator}, which uses 'soft' delete - * (runs UPDATE and sets 'deleted' field to true instead-of running SQL DELETE) - * - * @since 4.0 - */ -public class SoftDeleteTranslatorFactory extends DefaultBatchTranslatorFactory { - /** - * Default name of 'deleted' field - */ - public static final String DEFAULT_DELETED_FIELD_NAME = "DELETED"; - - /** - * Name of 'deleted' field - */ - private String deletedFieldName; - - public SoftDeleteTranslatorFactory() { - this(DEFAULT_DELETED_FIELD_NAME); - } - - public SoftDeleteTranslatorFactory(String deletedFieldName) { - this.deletedFieldName = deletedFieldName; - } - - @Override - protected BatchTranslator deleteTranslator(DeleteBatchQuery query, DbAdapter adapter, String trimFunction) { - - DbAttribute attr = query.getDbEntity().getAttribute(deletedFieldName); - boolean needsSoftDelete = attr != null && attr.getType() == Types.BOOLEAN; - - return needsSoftDelete ? new SoftDeleteBatchTranslator(query, adapter, trimFunction, deletedFieldName) : super - .deleteTranslator(query, adapter, trimFunction); - } - - /** - * @return name of 'deleted' field - */ - public String getDeletedFieldName() { - return deletedFieldName; - } -} +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ +package org.apache.cayenne.access.translator.batch; + +import java.sql.Types; + +import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.query.DeleteBatchQuery; + +/** + * Implementation of {link #BatchTranslator}, which uses 'soft' delete + * (runs UPDATE and sets 'deleted' field to true instead-of running SQL DELETE) + * + * @since 4.2 + */ +public class SoftDeleteTranslatorFactory extends DefaultBatchTranslatorFactory { + /** + * Default name of 'deleted' field + */ + public static final String DEFAULT_DELETED_FIELD_NAME = "DELETED"; + + /** + * Name of 'deleted' field + */ + private String deletedFieldName; + + public SoftDeleteTranslatorFactory() { + this(DEFAULT_DELETED_FIELD_NAME); + } + + public SoftDeleteTranslatorFactory(String deletedFieldName) { + this.deletedFieldName = deletedFieldName; + } + + @Override + protected BatchTranslator deleteTranslator(DeleteBatchQuery query, DbAdapter adapter) { + + DbAttribute attr = query.getDbEntity().getAttribute(deletedFieldName); + boolean needsSoftDelete = attr != null && attr.getType() == Types.BOOLEAN; + + return needsSoftDelete + ? new SoftDeleteBatchTranslator(query, adapter, deletedFieldName) + : super.deleteTranslator(query, adapter); + } + + /** + * @return name of 'deleted' field + */ + public String getDeletedFieldName() { + return deletedFieldName; + } +} diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/UpdateBatchTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/UpdateBatchTranslator.java index 8b1c558..0f4e385 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/UpdateBatchTranslator.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/UpdateBatchTranslator.java @@ -19,128 +19,69 @@ package org.apache.cayenne.access.translator.batch; -import java.util.Iterator; -import java.util.List; - +import org.apache.cayenne.access.sqlbuilder.SQLBuilder; +import org.apache.cayenne.access.sqlbuilder.UpdateBuilder; import org.apache.cayenne.access.translator.DbAttributeBinding; import org.apache.cayenne.access.types.ExtendedType; import org.apache.cayenne.dba.DbAdapter; -import org.apache.cayenne.dba.QuotingStrategy; import org.apache.cayenne.map.DbAttribute; import org.apache.cayenne.query.BatchQueryRow; import org.apache.cayenne.query.UpdateBatchQuery; /** - * A translator for UpdateBatchQueries that produces parameterized SQL. + * @since 4.2 */ -public class UpdateBatchTranslator extends DefaultBatchTranslator { +public class UpdateBatchTranslator extends BaseBatchTranslator<UpdateBatchQuery> implements BatchTranslator { - public UpdateBatchTranslator(UpdateBatchQuery query, DbAdapter adapter, String trimFunction) { - super(query, adapter, trimFunction); + public UpdateBatchTranslator(UpdateBatchQuery query, DbAdapter adapter) { + super(query, adapter); } @Override - protected String createSql() { - UpdateBatchQuery updateBatch = (UpdateBatchQuery) query; - - QuotingStrategy strategy = adapter.getQuotingStrategy(); - - List<DbAttribute> qualifierAttributes = updateBatch.getQualifierAttributes(); - List<DbAttribute> updatedDbAttributes = updateBatch.getUpdatedAttributes(); - - StringBuilder buffer = new StringBuilder("UPDATE "); - buffer.append(strategy.quotedFullyQualifiedName(query.getDbEntity())); - buffer.append(" SET "); - - int len = updatedDbAttributes.size(); - for (int i = 0; i < len; i++) { - if (i > 0) { - buffer.append(", "); - } - - DbAttribute attribute = updatedDbAttributes.get(i); - buffer.append(strategy.quotedName(attribute)); - buffer.append(" = ?"); - } - - buffer.append(" WHERE "); - - Iterator<DbAttribute> i = qualifierAttributes.iterator(); - while (i.hasNext()) { - DbAttribute attribute = i.next(); - appendDbAttribute(buffer, attribute); - buffer.append(updateBatch.isNull(attribute) ? " IS NULL" : " = ?"); - - if (i.hasNext()) { - buffer.append(" AND "); - } + public String getSql() { + UpdateBatchQuery query = context.getQuery(); + + UpdateBuilder updateBuilder = SQLBuilder.update(context.getRootDbEntity().getFullyQualifiedName()); + for (DbAttribute attr : query.getUpdatedAttributes()) { + updateBuilder.set(SQLBuilder + .column(attr.getName()).attribute(attr) + .eq(SQLBuilder.value(1).attribute(attr)) + ); } + updateBuilder.where(buildQualifier(query.getQualifierAttributes())); - return buffer.toString(); + return doTranslate(updateBuilder); } @Override - protected DbAttributeBinding[] createBindings() { - UpdateBatchQuery updateBatch = (UpdateBatchQuery) query; - - List<DbAttribute> updatedDbAttributes = updateBatch.getUpdatedAttributes(); - List<DbAttribute> qualifierAttributes = updateBatch.getQualifierAttributes(); - - int ul = updatedDbAttributes.size(); - int ql = qualifierAttributes.size(); - - DbAttributeBinding[] bindings = new DbAttributeBinding[ul + ql]; - - for (int i = 0; i < ul; i++) { - bindings[i] = new DbAttributeBinding(updatedDbAttributes.get(i)); - } - - for (int i = 0; i < ql; i++) { - bindings[ul + i] = new DbAttributeBinding(qualifierAttributes.get(i)); - } - - return bindings; + protected boolean isNullAttribute(DbAttribute attribute) { + return context.getQuery().isNull(attribute); } @Override - protected DbAttributeBinding[] doUpdateBindings(BatchQueryRow row) { - - UpdateBatchQuery updateBatch = (UpdateBatchQuery) query; - - List<DbAttribute> updatedDbAttributes = updateBatch.getUpdatedAttributes(); - List<DbAttribute> qualifierAttributes = updateBatch.getQualifierAttributes(); - - int ul = updatedDbAttributes.size(); - int ql = qualifierAttributes.size(); + public DbAttributeBinding[] updateBindings(BatchQueryRow row) { + UpdateBatchQuery updateBatch = context.getQuery(); - int j = 1; - - for (int i = 0; i < ul; i++) { + int i = 0; + int j = 0; + for(; i < updateBatch.getUpdatedAttributes().size(); i++) { Object value = row.getValue(i); - ExtendedType extendedType = value != null - ? adapter.getExtendedTypes().getRegisteredType(value.getClass()) - : adapter.getExtendedTypes().getDefaultType(); - - bindings[i].include(j++, value, extendedType); + ExtendedType<?> extendedType = value == null + ? context.getAdapter().getExtendedTypes().getDefaultType() + : context.getAdapter().getExtendedTypes().getRegisteredType(value.getClass()); + bindings[j].include(++j, value, extendedType); } - for (int i = 0; i < ql; i++) { - - DbAttribute a = qualifierAttributes.get(i); - - // skip null attributes... they are translated as "IS NULL" - if (updateBatch.isNull(a)) { + for(DbAttribute attribute : updateBatch.getQualifierAttributes()) { + if(updateBatch.isNull(attribute)) { + i++; continue; } - - Object value = row.getValue(ul + i); - ExtendedType extendedType = value != null - ? adapter.getExtendedTypes().getRegisteredType(value.getClass()) - : adapter.getExtendedTypes().getDefaultType(); - - bindings[ul + i].include(j++, value, extendedType); + Object value = row.getValue(i); + ExtendedType<?> extendedType = context.getAdapter().getExtendedTypes().getRegisteredType(value.getClass()); + bindings[j].include(++j, value, extendedType); + i++; } - return bindings; } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/DefaultBatchTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/DefaultBatchTranslator.java similarity index 95% rename from cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/DefaultBatchTranslator.java rename to cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/DefaultBatchTranslator.java index 79e749c..381db10 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/DefaultBatchTranslator.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/DefaultBatchTranslator.java @@ -16,11 +16,12 @@ * specific language governing permissions and limitations * under the License. ****************************************************************/ -package org.apache.cayenne.access.translator.batch; +package org.apache.cayenne.access.translator.batch.legacy; import java.sql.Types; import org.apache.cayenne.access.translator.DbAttributeBinding; +import org.apache.cayenne.access.translator.batch.BatchTranslator; import org.apache.cayenne.dba.DbAdapter; import org.apache.cayenne.dba.QuotingStrategy; import org.apache.cayenne.map.DbAttribute; @@ -31,7 +32,9 @@ import org.apache.cayenne.query.BatchQueryRow; * Superclass of batch query translators. * * @since 4.0 + * @deprecated since 4.2 */ +@Deprecated public abstract class DefaultBatchTranslator implements BatchTranslator { protected BatchQuery query; diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/DefaultBatchTranslatorFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/DefaultBatchTranslatorFactory.java similarity index 91% copy from cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/DefaultBatchTranslatorFactory.java copy to cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/DefaultBatchTranslatorFactory.java index 639bded..d246fe3 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/DefaultBatchTranslatorFactory.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/DefaultBatchTranslatorFactory.java @@ -16,9 +16,11 @@ * specific language governing permissions and limitations * under the License. ****************************************************************/ -package org.apache.cayenne.access.translator.batch; +package org.apache.cayenne.access.translator.batch.legacy; import org.apache.cayenne.CayenneRuntimeException; +import org.apache.cayenne.access.translator.batch.BatchTranslator; +import org.apache.cayenne.access.translator.batch.BatchTranslatorFactory; import org.apache.cayenne.dba.DbAdapter; import org.apache.cayenne.query.BatchQuery; import org.apache.cayenne.query.DeleteBatchQuery; @@ -29,7 +31,9 @@ import org.apache.cayenne.query.UpdateBatchQuery; * Default implementation of {@link BatchTranslatorFactory}. * * @since 4.0 + * @deprecated since 4.2 */ +@Deprecated public class DefaultBatchTranslatorFactory implements BatchTranslatorFactory { @Override diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/DeleteBatchTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/DeleteBatchTranslator.java similarity index 97% copy from cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/DeleteBatchTranslator.java copy to cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/DeleteBatchTranslator.java index e5915a3..afe7196 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/DeleteBatchTranslator.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/DeleteBatchTranslator.java @@ -17,7 +17,7 @@ * under the License. ****************************************************************/ -package org.apache.cayenne.access.translator.batch; +package org.apache.cayenne.access.translator.batch.legacy; import java.util.Iterator; import java.util.List; @@ -33,7 +33,9 @@ import org.apache.cayenne.query.DeleteBatchQuery; /** * Translator for delete BatchQueries. Creates parameterized DELETE SQL * statements. + * @deprecated since 4.2 */ +@Deprecated public class DeleteBatchTranslator extends DefaultBatchTranslator { public DeleteBatchTranslator(DeleteBatchQuery query, DbAdapter adapter, String trimFunction) { diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/InsertBatchTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/InsertBatchTranslator.java similarity index 98% copy from cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/InsertBatchTranslator.java copy to cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/InsertBatchTranslator.java index 8c70532..3bc5927 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/InsertBatchTranslator.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/InsertBatchTranslator.java @@ -17,7 +17,7 @@ * under the License. ****************************************************************/ -package org.apache.cayenne.access.translator.batch; +package org.apache.cayenne.access.translator.batch.legacy; import java.util.List; @@ -31,7 +31,9 @@ import org.apache.cayenne.query.InsertBatchQuery; /** * Translator of InsertBatchQueries. + * @deprecated since 4.2 */ +@Deprecated public class InsertBatchTranslator extends DefaultBatchTranslator { public InsertBatchTranslator(InsertBatchQuery query, DbAdapter adapter) { diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/SoftDeleteBatchTranslator.java similarity index 92% copy from cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslator.java copy to cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/SoftDeleteBatchTranslator.java index 12dfe8d..b68017f 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslator.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/SoftDeleteBatchTranslator.java @@ -1,105 +1,110 @@ -/***************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - ****************************************************************/ -package org.apache.cayenne.access.translator.batch; - -import org.apache.cayenne.access.translator.DbAttributeBinding; -import org.apache.cayenne.access.types.ExtendedType; -import org.apache.cayenne.dba.DbAdapter; -import org.apache.cayenne.dba.QuotingStrategy; -import org.apache.cayenne.dba.TypesMapping; -import org.apache.cayenne.map.DbAttribute; -import org.apache.cayenne.query.BatchQueryRow; -import org.apache.cayenne.query.DeleteBatchQuery; - -/** - * Implementation of {@link DeleteBatchTranslator}, which uses 'soft' delete - * (runs UPDATE and sets 'deleted' field to true instead-of running SQL DELETE) - */ -public class SoftDeleteBatchTranslator extends DeleteBatchTranslator { - - private String deletedFieldName; - - public SoftDeleteBatchTranslator(DeleteBatchQuery query, DbAdapter adapter, String trimFunction, - String deletedFieldName) { - super(query, adapter, trimFunction); - this.deletedFieldName = deletedFieldName; - } - - @Override - protected String createSql() { - - QuotingStrategy strategy = adapter.getQuotingStrategy(); - - StringBuilder buffer = new StringBuilder("UPDATE "); - buffer.append(strategy.quotedFullyQualifiedName(query.getDbEntity())); - buffer.append(" SET ").append(strategy.quotedIdentifier(query.getDbEntity(), deletedFieldName)).append(" = ?"); - - applyQualifier(buffer); - - return buffer.toString(); - } - - @Override - protected DbAttributeBinding[] createBindings() { - - DbAttributeBinding[] superBindings = super.createBindings(); - - int slen = superBindings.length; - - DbAttributeBinding[] bindings = new DbAttributeBinding[slen + 1]; - - DbAttribute deleteAttribute = query.getDbEntity().getAttribute(deletedFieldName); - String typeName = TypesMapping.getJavaBySqlType(deleteAttribute.getType()); - ExtendedType extendedType = adapter.getExtendedTypes().getRegisteredType(typeName); - - bindings[0] = new DbAttributeBinding(deleteAttribute); - bindings[0].include(1, true, extendedType); - - System.arraycopy(superBindings, 0, bindings, 1, slen); - - return bindings; - } - - @Override - protected DbAttributeBinding[] doUpdateBindings(BatchQueryRow row) { - int len = bindings.length; - - DeleteBatchQuery deleteBatch = (DeleteBatchQuery) query; - - // skip position 0... Otherwise follow super algorithm - for (int i = 1, j = 2; i < len; i++) { - - DbAttributeBinding b = bindings[i]; - - // skip null attributes... they are translated as "IS NULL" - if (deleteBatch.isNull(b.getAttribute())) { - b.exclude(); - } else { - Object value = row.getValue(i - 1); - ExtendedType extendedType = value != null - ? adapter.getExtendedTypes().getRegisteredType(value.getClass()) - : adapter.getExtendedTypes().getDefaultType(); - - b.include(j++, value, extendedType); - } - } - - return bindings; - } -} +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ +package org.apache.cayenne.access.translator.batch.legacy; + +import java.util.Objects; + +import org.apache.cayenne.access.translator.DbAttributeBinding; +import org.apache.cayenne.access.types.ExtendedType; +import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.dba.QuotingStrategy; +import org.apache.cayenne.dba.TypesMapping; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.query.BatchQueryRow; +import org.apache.cayenne.query.DeleteBatchQuery; + +/** + * Implementation of {@link DeleteBatchTranslator}, which uses 'soft' delete + * (runs UPDATE and sets 'deleted' field to true instead-of running SQL DELETE) + * + * @deprecated since 4.2 + */ +@Deprecated +public class SoftDeleteBatchTranslator extends DeleteBatchTranslator { + + private String deletedFieldName; + + public SoftDeleteBatchTranslator(DeleteBatchQuery query, DbAdapter adapter, String trimFunction, + String deletedFieldName) { + super(query, adapter, trimFunction); + this.deletedFieldName = Objects.requireNonNull(deletedFieldName); + } + + @Override + protected String createSql() { + + QuotingStrategy strategy = adapter.getQuotingStrategy(); + + StringBuilder buffer = new StringBuilder("UPDATE "); + buffer.append(strategy.quotedFullyQualifiedName(query.getDbEntity())); + buffer.append(" SET ").append(strategy.quotedIdentifier(query.getDbEntity(), deletedFieldName)).append(" = ?"); + + applyQualifier(buffer); + + return buffer.toString(); + } + + @Override + protected DbAttributeBinding[] createBindings() { + + DbAttributeBinding[] superBindings = super.createBindings(); + + int slen = superBindings.length; + + DbAttributeBinding[] bindings = new DbAttributeBinding[slen + 1]; + + DbAttribute deleteAttribute = Objects.requireNonNull(query.getDbEntity().getAttribute(deletedFieldName)); + String typeName = TypesMapping.getJavaBySqlType(deleteAttribute.getType()); + ExtendedType extendedType = adapter.getExtendedTypes().getRegisteredType(typeName); + + bindings[0] = new DbAttributeBinding(deleteAttribute); + bindings[0].include(1, true, extendedType); + + System.arraycopy(superBindings, 0, bindings, 1, slen); + + return bindings; + } + + @Override + protected DbAttributeBinding[] doUpdateBindings(BatchQueryRow row) { + int len = bindings.length; + + DeleteBatchQuery deleteBatch = (DeleteBatchQuery) query; + + // skip position 0... Otherwise follow super algorithm + for (int i = 1, j = 2; i < len; i++) { + + DbAttributeBinding b = bindings[i]; + + // skip null attributes... they are translated as "IS NULL" + if (deleteBatch.isNull(b.getAttribute())) { + b.exclude(); + } else { + Object value = row.getValue(i - 1); + ExtendedType extendedType = value != null + ? adapter.getExtendedTypes().getRegisteredType(value.getClass()) + : adapter.getExtendedTypes().getDefaultType(); + + b.include(j++, value, extendedType); + } + } + + return bindings; + } +} diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteTranslatorFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/SoftDeleteTranslatorFactory.java similarity index 85% copy from cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteTranslatorFactory.java copy to cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/SoftDeleteTranslatorFactory.java index 10054ba..1fa838e 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteTranslatorFactory.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/SoftDeleteTranslatorFactory.java @@ -1,69 +1,73 @@ -/***************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - ****************************************************************/ -package org.apache.cayenne.access.translator.batch; - -import java.sql.Types; - -import org.apache.cayenne.access.translator.batch.BatchTranslator; -import org.apache.cayenne.dba.DbAdapter; -import org.apache.cayenne.map.DbAttribute; -import org.apache.cayenne.query.DeleteBatchQuery; - -/** - * Implementation of {link #BatchTranslator}, which uses 'soft' delete - * (runs UPDATE and sets 'deleted' field to true instead-of running SQL DELETE) - * - * @since 4.0 - */ -public class SoftDeleteTranslatorFactory extends DefaultBatchTranslatorFactory { - /** - * Default name of 'deleted' field - */ - public static final String DEFAULT_DELETED_FIELD_NAME = "DELETED"; - - /** - * Name of 'deleted' field - */ - private String deletedFieldName; - - public SoftDeleteTranslatorFactory() { - this(DEFAULT_DELETED_FIELD_NAME); - } - - public SoftDeleteTranslatorFactory(String deletedFieldName) { - this.deletedFieldName = deletedFieldName; - } - - @Override - protected BatchTranslator deleteTranslator(DeleteBatchQuery query, DbAdapter adapter, String trimFunction) { - - DbAttribute attr = query.getDbEntity().getAttribute(deletedFieldName); - boolean needsSoftDelete = attr != null && attr.getType() == Types.BOOLEAN; - - return needsSoftDelete ? new SoftDeleteBatchTranslator(query, adapter, trimFunction, deletedFieldName) : super - .deleteTranslator(query, adapter, trimFunction); - } - - /** - * @return name of 'deleted' field - */ - public String getDeletedFieldName() { - return deletedFieldName; - } -} +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ +package org.apache.cayenne.access.translator.batch.legacy; + +import java.sql.Types; +import java.util.Objects; + +import org.apache.cayenne.access.translator.batch.BatchTranslator; +import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.map.DbAttribute; +import org.apache.cayenne.query.DeleteBatchQuery; + +/** + * Implementation of {link #BatchTranslator}, which uses 'soft' delete + * (runs UPDATE and sets 'deleted' field to true instead-of running SQL DELETE) + * + * @since 4.0 + * @deprecated since 4.2 + */ +@Deprecated +public class SoftDeleteTranslatorFactory extends DefaultBatchTranslatorFactory { + /** + * Default name of 'deleted' field + */ + public static final String DEFAULT_DELETED_FIELD_NAME = "DELETED"; + + /** + * Name of 'deleted' field + */ + private String deletedFieldName; + + public SoftDeleteTranslatorFactory() { + this(DEFAULT_DELETED_FIELD_NAME); + } + + public SoftDeleteTranslatorFactory(String deletedFieldName) { + this.deletedFieldName = Objects.requireNonNull(deletedFieldName); + } + + @Override + protected BatchTranslator deleteTranslator(DeleteBatchQuery query, DbAdapter adapter, String trimFunction) { + + DbAttribute attr = query.getDbEntity().getAttribute(deletedFieldName); + boolean needsSoftDelete = attr != null && attr.getType() == Types.BOOLEAN; + + return needsSoftDelete + ? new SoftDeleteBatchTranslator(query, adapter, trimFunction, deletedFieldName) + : super.deleteTranslator(query, adapter, trimFunction); + } + + /** + * @return name of 'deleted' field + */ + public String getDeletedFieldName() { + return deletedFieldName; + } +} diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/UpdateBatchTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/UpdateBatchTranslator.java similarity index 98% copy from cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/UpdateBatchTranslator.java copy to cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/UpdateBatchTranslator.java index 8b1c558..36e851b 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/UpdateBatchTranslator.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/batch/legacy/UpdateBatchTranslator.java @@ -17,7 +17,7 @@ * under the License. ****************************************************************/ -package org.apache.cayenne.access.translator.batch; +package org.apache.cayenne.access.translator.batch.legacy; import java.util.Iterator; import java.util.List; @@ -32,7 +32,9 @@ import org.apache.cayenne.query.UpdateBatchQuery; /** * A translator for UpdateBatchQueries that produces parameterized SQL. + * @deprecated since 4.2 */ +@Deprecated public class UpdateBatchTranslator extends DefaultBatchTranslator { public UpdateBatchTranslator(UpdateBatchQuery query, DbAdapter adapter, String trimFunction) { diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultQuotingAppendable.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultQuotingAppendable.java index 6d35c64..134fd36 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultQuotingAppendable.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultQuotingAppendable.java @@ -20,6 +20,7 @@ package org.apache.cayenne.access.translator.select; import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; +import org.apache.cayenne.access.sqlbuilder.SQLGenerationContext; import org.apache.cayenne.access.sqlbuilder.StringBuilderAppendable; /** @@ -27,9 +28,9 @@ import org.apache.cayenne.access.sqlbuilder.StringBuilderAppendable; */ public class DefaultQuotingAppendable extends StringBuilderAppendable { - private final TranslatorContext context; + private final SQLGenerationContext context; - public DefaultQuotingAppendable(TranslatorContext context) { + public DefaultQuotingAppendable(SQLGenerationContext context) { super(); this.context = context; } @@ -41,7 +42,7 @@ public class DefaultQuotingAppendable extends StringBuilderAppendable { } @Override - public TranslatorContext getContext() { + public SQLGenerationContext getContext() { return context; } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/TranslatorContext.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/TranslatorContext.java index 2928257..702bc3a 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/TranslatorContext.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/TranslatorContext.java @@ -188,7 +188,7 @@ public class TranslatorContext implements SQLGenerationContext { return adapter; } - DbEntity getRootDbEntity() { + public DbEntity getRootDbEntity() { return metadata.getDbEntity(); } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/Oracle8LOBBatchTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/Oracle8LOBBatchTranslator.java index 822dde7..eb58e71 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/Oracle8LOBBatchTranslator.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/Oracle8LOBBatchTranslator.java @@ -25,7 +25,7 @@ import java.util.List; import org.apache.cayenne.CayenneRuntimeException; import org.apache.cayenne.access.translator.DbAttributeBinding; -import org.apache.cayenne.access.translator.batch.DefaultBatchTranslator; +import org.apache.cayenne.access.translator.batch.legacy.DefaultBatchTranslator; import org.apache.cayenne.access.types.ExtendedType; import org.apache.cayenne.dba.DbAdapter; import org.apache.cayenne.dba.QuotingStrategy; @@ -36,7 +36,7 @@ import org.apache.cayenne.query.BatchQueryRow; /** * Superclass of query builders for the DML operations involving LOBs. - * + * TODO: update to the new batch translation logic */ abstract class Oracle8LOBBatchTranslator extends DefaultBatchTranslator { diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/BatchActionLockingIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/BatchActionLockingIT.java index 7a7bdda..be1314d 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/BatchActionLockingIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/BatchActionLockingIT.java @@ -79,13 +79,13 @@ public class BatchActionLockingIT extends ServerCase { Collection<String> nullAttributeNames = Collections.singleton("NAME"); Map<String, Object> qualifierSnapshot = new HashMap<>(); - qualifierSnapshot.put("LOCKING_TEST_ID", new Integer(1)); + qualifierSnapshot.put("LOCKING_TEST_ID", 1); DeleteBatchQuery batchQuery = new DeleteBatchQuery(dbEntity, qualifierAttributes, nullAttributeNames, 5); batchQuery.setUsingOptimisticLocking(true); batchQuery.add(qualifierSnapshot); - DeleteBatchTranslator batchQueryBuilder = new DeleteBatchTranslator(batchQuery, adapter, null); + DeleteBatchTranslator batchQueryBuilder = new DeleteBatchTranslator(batchQuery, adapter); MockConnection mockConnection = new MockConnection(); PreparedStatementResultSetHandler preparedStatementResultSetHandler = mockConnection @@ -127,7 +127,7 @@ public class BatchActionLockingIT extends ServerCase { batchQuery.setUsingOptimisticLocking(true); batchQuery.add(qualifierSnapshot); - DeleteBatchTranslator batchQueryBuilder = new DeleteBatchTranslator(batchQuery, adapter, null); + DeleteBatchTranslator batchQueryBuilder = new DeleteBatchTranslator(batchQuery, adapter); MockConnection mockConnection = new MockConnection(); PreparedStatementResultSetHandler preparedStatementResultSetHandler = mockConnection @@ -145,7 +145,7 @@ public class BatchActionLockingIT extends ServerCase { try { action.runAsIndividualQueries(mockConnection, batchQueryBuilder, new MockOperationObserver(), generatesKeys); fail("No OptimisticLockingFailureException thrown."); - } catch (OptimisticLockException e) { + } catch (OptimisticLockException ignore) { } assertEquals(0, mockConnection.getNumberCommits()); assertEquals(0, mockConnection.getNumberRollbacks()); diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/sqlbuilder/DeleteBuilderTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/sqlbuilder/DeleteBuilderTest.java new file mode 100644 index 0000000..be6aaba --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/access/sqlbuilder/DeleteBuilderTest.java @@ -0,0 +1,57 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.access.sqlbuilder; + +import org.apache.cayenne.access.sqlbuilder.sqltree.DeleteNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; +import org.junit.Test; + +import static org.apache.cayenne.access.sqlbuilder.SQLBuilder.*; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.*; + +public class DeleteBuilderTest { + + @Test + public void testDelete() { + DeleteBuilder builder = new DeleteBuilder("test"); + Node node = builder.build(); + assertThat(node, instanceOf(DeleteNode.class)); + assertSQL("DELETE FROM test", node); + } + + @Test + public void testDeleteWithQualifier() { + DeleteBuilder builder = new DeleteBuilder("test"); + Node node = builder.where( + column("col1").eq(value(1)) + .and(column("col2").eq(value("test"))) + .and(column("col3").eq(value(null))) + ).build(); + assertThat(node, instanceOf(DeleteNode.class)); + assertSQL("DELETE FROM test WHERE ( ( col1 = 1 ) AND ( col2 = 'test' ) ) AND ( col3 IS NULL )", node); + } + + private void assertSQL(String expected, Node node) { + SQLGenerationVisitor visitor = new SQLGenerationVisitor(new StringBuilderAppendable()); + node.visit(visitor); + assertEquals(expected, visitor.getSQLString()); + } +} \ No newline at end of file diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/sqlbuilder/InsertBuilderTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/sqlbuilder/InsertBuilderTest.java new file mode 100644 index 0000000..229d6a1 --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/access/sqlbuilder/InsertBuilderTest.java @@ -0,0 +1,87 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.access.sqlbuilder; + +import org.apache.cayenne.access.sqlbuilder.sqltree.InsertNode; +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; +import org.junit.Test; + +import static org.apache.cayenne.access.sqlbuilder.SQLBuilder.*; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.*; + +public class InsertBuilderTest { + + @Test + public void testInsert() { + InsertBuilder builder = new InsertBuilder("test"); + Node node = builder.build(); + assertThat(node, instanceOf(InsertNode.class)); + assertSQL("INSERT INTO test", node); + } + + @Test + public void testInsertWithColumns() { + InsertBuilder builder = new InsertBuilder("test"); + builder + .column(column("col1")) + .column(column("col2")) + .column(column("col3")); + Node node = builder.build(); + + assertThat(node, instanceOf(InsertNode.class)); + assertSQL("INSERT INTO test( col1, col2, col3)", node); + } + + @Test + public void testInsertWithValues() { + InsertBuilder builder = new InsertBuilder("test"); + builder + .value(value(1)) + .value(value("test")) + .value(value(null)); + Node node = builder.build(); + + assertThat(node, instanceOf(InsertNode.class)); + assertSQL("INSERT INTO test VALUES( 1, 'test', NULL)", node); + } + + @Test + public void testInsertWithColumnsAndValues() { + InsertBuilder builder = new InsertBuilder("test"); + builder + .column(column("col1")) + .value(value(1)) + .column(column("col2")) + .value(value("test")) + .column(column("col3")) + .value(value(null)); + Node node = builder.build(); + + assertThat(node, instanceOf(InsertNode.class)); + assertSQL("INSERT INTO test( col1, col2, col3) VALUES( 1, 'test', NULL)", node); + } + + private void assertSQL(String expected, Node node) { + SQLGenerationVisitor visitor = new SQLGenerationVisitor(new StringBuilderAppendable()); + node.visit(visitor); + assertEquals(expected, visitor.getSQLString()); + } +} \ No newline at end of file diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/sqlbuilder/UpdateBuilderTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/sqlbuilder/UpdateBuilderTest.java new file mode 100644 index 0000000..d0c1133 --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/access/sqlbuilder/UpdateBuilderTest.java @@ -0,0 +1,73 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.access.sqlbuilder; + +import org.apache.cayenne.access.sqlbuilder.sqltree.Node; +import org.apache.cayenne.access.sqlbuilder.sqltree.UpdateNode; +import org.junit.Test; + +import static org.apache.cayenne.access.sqlbuilder.SQLBuilder.*; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.*; + +/** + * @since 4.2 + */ +public class UpdateBuilderTest { + + @Test + public void testUpdate() { + UpdateBuilder builder = new UpdateBuilder("test"); + Node node = builder.build(); + assertThat(node, instanceOf(UpdateNode.class)); + assertSQL("UPDATE test", node); + } + + @Test + public void testUpdateWithFields() { + UpdateBuilder builder = new UpdateBuilder("test"); + builder + .set(column("col1").eq(value(1))) + .set(column("col2").eq(value("test"))) + .set(column("col3").eq(value(null))); + Node node = builder.build(); + + assertThat(node, instanceOf(UpdateNode.class)); + assertSQL("UPDATE test SET col1 = 1, col2 = 'test', col3 = NULL", node); + } + + @Test + public void testUpdateWithWhere() { + UpdateBuilder builder = new UpdateBuilder("test"); + builder + .set(column("col1").eq(value(1))) + .where(column("id").eq(value(123L))); + Node node = builder.build(); + + assertThat(node, instanceOf(UpdateNode.class)); + assertSQL("UPDATE test SET col1 = 1 WHERE id = 123", node); + } + + private void assertSQL(String expected, Node node) { + SQLGenerationVisitor visitor = new SQLGenerationVisitor(new StringBuilderAppendable()); + node.visit(visitor); + assertEquals(expected, visitor.getSQLString()); + } +} \ No newline at end of file diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/DeleteBatchTranslatorIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/DeleteBatchTranslatorIT.java index 262c4a6..a921a04 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/DeleteBatchTranslatorIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/DeleteBatchTranslatorIT.java @@ -19,6 +19,11 @@ package org.apache.cayenne.access.translator.batch; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + import org.apache.cayenne.configuration.server.ServerRuntime; import org.apache.cayenne.dba.DbAdapter; import org.apache.cayenne.dba.JdbcAdapter; @@ -34,11 +39,6 @@ import org.apache.cayenne.unit.di.server.ServerCase; import org.apache.cayenne.unit.di.server.UseServerRuntime; import org.junit.Test; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; @@ -60,32 +60,34 @@ public class DeleteBatchTranslatorIT extends ServerCase { private AdhocObjectFactory objectFactory; @Test - public void testConstructor() throws Exception { + public void testConstructor() { DbAdapter adapter = objectFactory.newInstance(DbAdapter.class, JdbcAdapter.class.getName()); - DeleteBatchTranslator builder = new DeleteBatchTranslator(mock(DeleteBatchQuery.class), adapter, null); + DeleteBatchQuery query = mock(DeleteBatchQuery.class); + DeleteBatchTranslator builder = new DeleteBatchTranslator(query, adapter); - assertSame(adapter, builder.adapter); + assertSame(adapter, builder.context.getAdapter()); + assertSame(query, builder.context.getQuery()); } @Test - public void testCreateSqlString() throws Exception { + public void testCreateSqlString() { DbEntity entity = runtime.getDataDomain().getEntityResolver().getObjEntity(SimpleLockingTestEntity.class) .getDbEntity(); List<DbAttribute> idAttributes = Collections.singletonList(entity.getAttribute("LOCKING_TEST_ID")); - DeleteBatchQuery deleteQuery = new DeleteBatchQuery(entity, idAttributes, Collections.<String> emptySet(), 1); + DeleteBatchQuery deleteQuery = new DeleteBatchQuery(entity, idAttributes, Collections.emptySet(), 1); DbAdapter adapter = objectFactory.newInstance(DbAdapter.class, JdbcAdapter.class.getName()); - DeleteBatchTranslator builder = new DeleteBatchTranslator(deleteQuery, adapter, null); + DeleteBatchTranslator builder = new DeleteBatchTranslator(deleteQuery, adapter); String generatedSql = builder.getSql(); assertNotNull(generatedSql); assertEquals("DELETE FROM " + entity.getName() + " WHERE LOCKING_TEST_ID = ?", generatedSql); } @Test - public void testCreateSqlStringWithNulls() throws Exception { + public void testCreateSqlStringWithNulls() { DbEntity entity = runtime.getDataDomain().getEntityResolver().getObjEntity(SimpleLockingTestEntity.class) .getDbEntity(); @@ -97,14 +99,14 @@ public class DeleteBatchTranslatorIT extends ServerCase { DeleteBatchQuery deleteQuery = new DeleteBatchQuery(entity, idAttributes, nullAttributes, 1); DbAdapter adapter = objectFactory.newInstance(DbAdapter.class, JdbcAdapter.class.getName()); - DeleteBatchTranslator builder = new DeleteBatchTranslator(deleteQuery, adapter, null); + DeleteBatchTranslator builder = new DeleteBatchTranslator(deleteQuery, adapter); String generatedSql = builder.getSql(); assertNotNull(generatedSql); - assertEquals("DELETE FROM " + entity.getName() + " WHERE LOCKING_TEST_ID = ? AND NAME IS NULL", generatedSql); + assertEquals("DELETE FROM " + entity.getName() + " WHERE ( LOCKING_TEST_ID = ? ) AND ( NAME IS NULL )", generatedSql); } @Test - public void testCreateSqlStringWithIdentifiersQuote() throws Exception { + public void testCreateSqlStringWithIdentifiersQuote() { DbEntity entity = runtime.getDataDomain().getEntityResolver().getObjEntity(SimpleLockingTestEntity.class) .getDbEntity(); try { @@ -112,9 +114,9 @@ public class DeleteBatchTranslatorIT extends ServerCase { entity.getDataMap().setQuotingSQLIdentifiers(true); List<DbAttribute> idAttributes = Collections.singletonList(entity.getAttribute("LOCKING_TEST_ID")); - DeleteBatchQuery deleteQuery = new DeleteBatchQuery(entity, idAttributes, Collections.<String> emptySet(), 1); + DeleteBatchQuery deleteQuery = new DeleteBatchQuery(entity, idAttributes, Collections.emptySet(), 1); JdbcAdapter adapter = (JdbcAdapter) this.adapter; - DeleteBatchTranslator builder = new DeleteBatchTranslator(deleteQuery, adapter, null); + DeleteBatchTranslator builder = new DeleteBatchTranslator(deleteQuery, adapter); String generatedSql = builder.getSql(); String charStart = unitAdapter.getIdentifiersStartQuote(); @@ -130,7 +132,7 @@ public class DeleteBatchTranslatorIT extends ServerCase { } @Test - public void testCreateSqlStringWithNullsWithIdentifiersQuote() throws Exception { + public void testCreateSqlStringWithNullsWithIdentifiersQuote() { DbEntity entity = runtime.getDataDomain().getEntityResolver().getObjEntity(SimpleLockingTestEntity.class) .getDbEntity(); try { @@ -146,15 +148,15 @@ public class DeleteBatchTranslatorIT extends ServerCase { JdbcAdapter adapter = (JdbcAdapter) this.adapter; - DeleteBatchTranslator builder = new DeleteBatchTranslator(deleteQuery, adapter, null); + DeleteBatchTranslator builder = new DeleteBatchTranslator(deleteQuery, adapter); String generatedSql = builder.getSql(); String charStart = unitAdapter.getIdentifiersStartQuote(); String charEnd = unitAdapter.getIdentifiersEndQuote(); assertNotNull(generatedSql); - assertEquals("DELETE FROM " + charStart + entity.getName() + charEnd + " WHERE " + charStart - + "LOCKING_TEST_ID" + charEnd + " = ? AND " + charStart + "NAME" + charEnd + " IS NULL", + assertEquals("DELETE FROM " + charStart + entity.getName() + charEnd + " WHERE ( " + charStart + + "LOCKING_TEST_ID" + charEnd + " = ? ) AND ( " + charStart + "NAME" + charEnd + " IS NULL )", generatedSql); } finally { entity.getDataMap().setQuotingSQLIdentifiers(false); diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/InsertBatchTranslatorIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/InsertBatchTranslatorIT.java index e130199..bf29cda 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/InsertBatchTranslatorIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/InsertBatchTranslatorIT.java @@ -53,17 +53,20 @@ public class InsertBatchTranslatorIT extends ServerCase { private AdhocObjectFactory objectFactory; @Test - public void testConstructor() throws Exception { + public void testConstructor() { DbAdapter adapter = objectFactory.newInstance(DbAdapter.class, JdbcAdapter.class.getName()); - InsertBatchTranslator builder = new InsertBatchTranslator(mock(InsertBatchQuery.class), adapter); + InsertBatchQuery query = mock(InsertBatchQuery.class); + InsertBatchTranslator builder = new InsertBatchTranslator(query, adapter); - assertSame(adapter, builder.adapter); + assertSame(adapter, builder.context.getAdapter()); + assertSame(query, builder.context.getQuery()); } @Test - public void testCreateSqlString() throws Exception { - DbEntity entity = runtime.getDataDomain().getEntityResolver().getObjEntity(SimpleLockingTestEntity.class) + public void testCreateSqlString() { + DbEntity entity = runtime.getDataDomain().getEntityResolver() + .getObjEntity(SimpleLockingTestEntity.class) .getDbEntity(); DbAdapter adapter = objectFactory.newInstance(DbAdapter.class, JdbcAdapter.class.getName()); @@ -71,12 +74,13 @@ public class InsertBatchTranslatorIT extends ServerCase { InsertBatchTranslator builder = new InsertBatchTranslator(insertQuery, adapter); String generatedSql = builder.getSql(); assertNotNull(generatedSql); - assertEquals("INSERT INTO " + entity.getName() + " (DESCRIPTION, INT_COLUMN_NOTNULL, INT_COLUMN_NULL, LOCKING_TEST_ID, NAME) VALUES (?, ?, ?, ?, ?)", + assertEquals("INSERT INTO " + entity.getName() + "( DESCRIPTION, INT_COLUMN_NOTNULL, INT_COLUMN_NULL, LOCKING_TEST_ID, NAME) " + + "VALUES( ?, ?, ?, ?, ?)", generatedSql); } @Test - public void testCreateSqlStringWithIdentifiersQuote() throws Exception { + public void testCreateSqlStringWithIdentifiersQuote() { DbEntity entity = runtime.getDataDomain().getEntityResolver().getObjEntity(SimpleLockingTestEntity.class) .getDbEntity(); try { @@ -92,11 +96,11 @@ public class InsertBatchTranslatorIT extends ServerCase { String charEnd = unitAdapter.getIdentifiersEndQuote(); assertNotNull(generatedSql); assertEquals("INSERT INTO " + charStart + entity.getName() + charEnd - + " (" + charStart + "DESCRIPTION" + charEnd + ", " + + "( " + charStart + "DESCRIPTION" + charEnd + ", " + charStart + "INT_COLUMN_NOTNULL" + charEnd + ", " + charStart + "INT_COLUMN_NULL" + charEnd + ", " + charStart + "LOCKING_TEST_ID" + charEnd + ", " - + charStart + "NAME" + charEnd + ") VALUES (?, ?, ?, ?, ?)", generatedSql); + + charStart + "NAME" + charEnd + ") VALUES( ?, ?, ?, ?, ?)", generatedSql); } finally { entity.getDataMap().setQuotingSQLIdentifiers(false); } diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslatorIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslatorIT.java index d32b849..e66fb58 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslatorIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslatorIT.java @@ -18,6 +18,11 @@ ****************************************************************/ package org.apache.cayenne.access.translator.batch; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + import org.apache.cayenne.ObjectContext; import org.apache.cayenne.PersistenceState; import org.apache.cayenne.access.DataNode; @@ -40,11 +45,6 @@ import org.apache.cayenne.unit.di.server.ServerCase; import org.apache.cayenne.unit.di.server.UseServerRuntime; import org.junit.Test; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -100,7 +100,7 @@ public class SoftDeleteBatchTranslatorIT extends ServerCase { DeleteBatchTranslator builder = createTranslator(deleteQuery); String generatedSql = builder.getSql(); assertNotNull(generatedSql); - assertEquals("UPDATE " + entity.getName() + " SET DELETED = ? WHERE ID = ? AND NAME IS NULL", generatedSql); + assertEquals("UPDATE " + entity.getName() + " SET DELETED = ? WHERE ( ID = ? ) AND ( NAME IS NULL )", generatedSql); } @Test diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/UpdateBatchTranslatorIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/UpdateBatchTranslatorIT.java index e604c77..03719c5 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/UpdateBatchTranslatorIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/UpdateBatchTranslatorIT.java @@ -19,11 +19,17 @@ package org.apache.cayenne.access.translator.batch; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + import org.apache.cayenne.configuration.server.ServerRuntime; import org.apache.cayenne.dba.DbAdapter; import org.apache.cayenne.dba.JdbcAdapter; import org.apache.cayenne.di.AdhocObjectFactory; import org.apache.cayenne.di.Inject; +import org.apache.cayenne.map.DbAttribute; import org.apache.cayenne.map.DbEntity; import org.apache.cayenne.query.UpdateBatchQuery; import org.apache.cayenne.testdo.locking.SimpleLockingTestEntity; @@ -33,11 +39,6 @@ import org.apache.cayenne.unit.di.server.ServerCase; import org.apache.cayenne.unit.di.server.UseServerRuntime; import org.junit.Test; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; @@ -59,67 +60,70 @@ public class UpdateBatchTranslatorIT extends ServerCase { private AdhocObjectFactory objectFactory; @Test - public void testConstructor() throws Exception { + public void testConstructor() { DbAdapter adapter = objectFactory.newInstance(DbAdapter.class, JdbcAdapter.class.getName()); - UpdateBatchTranslator builder = new UpdateBatchTranslator(mock(UpdateBatchQuery.class), adapter, null); - assertSame(adapter, builder.adapter); + UpdateBatchQuery query = mock(UpdateBatchQuery.class); + UpdateBatchTranslator builder = new UpdateBatchTranslator(query, adapter); + + assertSame(adapter, builder.context.getAdapter()); + assertSame(query, builder.context.getQuery()); } @Test - public void testCreateSqlString() throws Exception { + public void testCreateSqlString() { DbEntity entity = runtime.getDataDomain().getEntityResolver().getObjEntity(SimpleLockingTestEntity.class) .getDbEntity(); - List idAttributes = Collections.singletonList(entity.getAttribute("LOCKING_TEST_ID")); - List updatedAttributes = Collections.singletonList(entity.getAttribute("DESCRIPTION")); + List<DbAttribute> idAttributes = Collections.singletonList(entity.getAttribute("LOCKING_TEST_ID")); + List<DbAttribute> updatedAttributes = Collections.singletonList(entity.getAttribute("DESCRIPTION")); UpdateBatchQuery updateQuery = new UpdateBatchQuery(entity, idAttributes, updatedAttributes, - Collections.<String> emptySet(), 1); + Collections.emptySet(), 1); DbAdapter adapter = objectFactory.newInstance(DbAdapter.class, JdbcAdapter.class.getName()); - UpdateBatchTranslator builder = new UpdateBatchTranslator(updateQuery, adapter, null); + UpdateBatchTranslator builder = new UpdateBatchTranslator(updateQuery, adapter); String generatedSql = builder.getSql(); assertNotNull(generatedSql); assertEquals("UPDATE " + entity.getName() + " SET DESCRIPTION = ? WHERE LOCKING_TEST_ID = ?", generatedSql); } @Test - public void testCreateSqlStringWithNulls() throws Exception { + public void testCreateSqlStringWithNulls() { DbEntity entity = runtime.getDataDomain().getEntityResolver().getObjEntity(SimpleLockingTestEntity.class) .getDbEntity(); - List idAttributes = Arrays.asList(entity.getAttribute("LOCKING_TEST_ID"), entity.getAttribute("NAME")); + List<DbAttribute> idAttributes = Arrays.asList(entity.getAttribute("LOCKING_TEST_ID"), entity.getAttribute("NAME")); - List updatedAttributes = Collections.singletonList(entity.getAttribute("DESCRIPTION")); + List<DbAttribute> updatedAttributes = Collections.singletonList(entity.getAttribute("DESCRIPTION")); - Collection nullAttributes = Collections.singleton("NAME"); + Collection<String> nullAttributes = Collections.singleton("NAME"); UpdateBatchQuery updateQuery = new UpdateBatchQuery(entity, idAttributes, updatedAttributes, nullAttributes, 1); DbAdapter adapter = objectFactory.newInstance(DbAdapter.class, JdbcAdapter.class.getName()); - UpdateBatchTranslator builder = new UpdateBatchTranslator(updateQuery, adapter, null); + UpdateBatchTranslator builder = new UpdateBatchTranslator(updateQuery, adapter); String generatedSql = builder.getSql(); assertNotNull(generatedSql); - assertEquals("UPDATE " + entity.getName() + " SET DESCRIPTION = ? WHERE LOCKING_TEST_ID = ? AND NAME IS NULL", + assertEquals("UPDATE " + entity.getName() + " SET DESCRIPTION = ? WHERE ( LOCKING_TEST_ID = ? ) AND ( NAME IS NULL )", generatedSql); } @Test - public void testCreateSqlStringWithIdentifiersQuote() throws Exception { + public void testCreateSqlStringWithIdentifiersQuote() { DbEntity entity = runtime.getDataDomain().getEntityResolver().getObjEntity(SimpleLockingTestEntity.class) .getDbEntity(); try { entity.getDataMap().setQuotingSQLIdentifiers(true); - List idAttributes = Collections.singletonList(entity.getAttribute("LOCKING_TEST_ID")); - List updatedAttributes = Collections.singletonList(entity.getAttribute("DESCRIPTION")); + List<DbAttribute> idAttributes = Collections.singletonList(entity.getAttribute("LOCKING_TEST_ID")); + List<DbAttribute> updatedAttributes = Collections.singletonList(entity.getAttribute("DESCRIPTION")); UpdateBatchQuery updateQuery = new UpdateBatchQuery(entity, idAttributes, updatedAttributes, - Collections.<String> emptySet(), 1); + Collections.emptySet(), 1); JdbcAdapter adapter = (JdbcAdapter) this.adapter; - UpdateBatchTranslator builder = new UpdateBatchTranslator(updateQuery, adapter, null); + UpdateBatchTranslator builder = new UpdateBatchTranslator(updateQuery, adapter); String generatedSql = builder.getSql(); String charStart = unitAdapter.getIdentifiersStartQuote(); @@ -135,31 +139,31 @@ public class UpdateBatchTranslatorIT extends ServerCase { } @Test - public void testCreateSqlStringWithNullsWithIdentifiersQuote() throws Exception { + public void testCreateSqlStringWithNullsWithIdentifiersQuote() { DbEntity entity = runtime.getDataDomain().getEntityResolver().getObjEntity(SimpleLockingTestEntity.class) .getDbEntity(); try { entity.getDataMap().setQuotingSQLIdentifiers(true); - List idAttributes = Arrays.asList(entity.getAttribute("LOCKING_TEST_ID"), entity.getAttribute("NAME")); + List<DbAttribute> idAttributes = Arrays.asList(entity.getAttribute("LOCKING_TEST_ID"), entity.getAttribute("NAME")); - List updatedAttributes = Collections.singletonList(entity.getAttribute("DESCRIPTION")); + List<DbAttribute> updatedAttributes = Collections.singletonList(entity.getAttribute("DESCRIPTION")); - Collection nullAttributes = Collections.singleton("NAME"); + Collection<String> nullAttributes = Collections.singleton("NAME"); UpdateBatchQuery updateQuery = new UpdateBatchQuery(entity, idAttributes, updatedAttributes, nullAttributes, 1); JdbcAdapter adapter = (JdbcAdapter) this.adapter; - UpdateBatchTranslator builder = new UpdateBatchTranslator(updateQuery, adapter, null); + UpdateBatchTranslator builder = new UpdateBatchTranslator(updateQuery, adapter); String generatedSql = builder.getSql(); assertNotNull(generatedSql); String charStart = unitAdapter.getIdentifiersStartQuote(); String charEnd = unitAdapter.getIdentifiersEndQuote(); assertEquals("UPDATE " + charStart + entity.getName() + charEnd + " SET " + charStart + "DESCRIPTION" - + charEnd + " = ? WHERE " + charStart + "LOCKING_TEST_ID" + charEnd + " = ? AND " + charStart - + "NAME" + charEnd + " IS NULL", generatedSql); + + charEnd + " = ? WHERE ( " + charStart + "LOCKING_TEST_ID" + charEnd + " = ? ) AND ( " + charStart + + "NAME" + charEnd + " IS NULL )", generatedSql); } finally { entity.getDataMap().setQuotingSQLIdentifiers(false); diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/DefaultBatchTranslatorIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/legacy/DefaultBatchTranslatorIT.java similarity index 98% rename from cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/DefaultBatchTranslatorIT.java rename to cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/legacy/DefaultBatchTranslatorIT.java index 581ebfc..f200872 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/DefaultBatchTranslatorIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/legacy/DefaultBatchTranslatorIT.java @@ -17,7 +17,7 @@ * under the License. ****************************************************************/ -package org.apache.cayenne.access.translator.batch; +package org.apache.cayenne.access.translator.batch.legacy; import org.apache.cayenne.access.translator.DbAttributeBinding; import org.apache.cayenne.dba.DbAdapter; @@ -39,6 +39,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.mockito.Mockito.mock; +@Deprecated @UseServerRuntime(CayenneProjects.TESTMAP_PROJECT) public class DefaultBatchTranslatorIT extends ServerCase { diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/DeleteBatchTranslatorIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/legacy/DeleteBatchTranslatorIT.java similarity index 98% copy from cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/DeleteBatchTranslatorIT.java copy to cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/legacy/DeleteBatchTranslatorIT.java index 262c4a6..2af52db 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/DeleteBatchTranslatorIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/legacy/DeleteBatchTranslatorIT.java @@ -17,7 +17,7 @@ * under the License. ****************************************************************/ -package org.apache.cayenne.access.translator.batch; +package org.apache.cayenne.access.translator.batch.legacy; import org.apache.cayenne.configuration.server.ServerRuntime; import org.apache.cayenne.dba.DbAdapter; @@ -44,6 +44,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.mockito.Mockito.mock; +@Deprecated @UseServerRuntime(CayenneProjects.LOCKING_PROJECT) public class DeleteBatchTranslatorIT extends ServerCase { diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/InsertBatchTranslatorIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/legacy/InsertBatchTranslatorIT.java similarity index 98% copy from cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/InsertBatchTranslatorIT.java copy to cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/legacy/InsertBatchTranslatorIT.java index e130199..dad5bd4 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/InsertBatchTranslatorIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/legacy/InsertBatchTranslatorIT.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. ****************************************************************/ -package org.apache.cayenne.access.translator.batch; +package org.apache.cayenne.access.translator.batch.legacy; import org.apache.cayenne.configuration.server.ServerRuntime; import org.apache.cayenne.dba.DbAdapter; @@ -37,6 +37,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.mockito.Mockito.mock; +@Deprecated @UseServerRuntime(CayenneProjects.LOCKING_PROJECT) public class InsertBatchTranslatorIT extends ServerCase { diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslatorIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/legacy/SoftDeleteBatchTranslatorIT.java similarity index 98% copy from cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslatorIT.java copy to cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/legacy/SoftDeleteBatchTranslatorIT.java index d32b849..36efd4c 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslatorIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/legacy/SoftDeleteBatchTranslatorIT.java @@ -16,11 +16,12 @@ * specific language governing permissions and limitations * under the License. ****************************************************************/ -package org.apache.cayenne.access.translator.batch; +package org.apache.cayenne.access.translator.batch.legacy; import org.apache.cayenne.ObjectContext; import org.apache.cayenne.PersistenceState; import org.apache.cayenne.access.DataNode; +import org.apache.cayenne.access.translator.batch.BatchTranslatorFactory; import org.apache.cayenne.dba.DbAdapter; import org.apache.cayenne.dba.JdbcAdapter; import org.apache.cayenne.di.AdhocObjectFactory; @@ -48,6 +49,7 @@ import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +@Deprecated @UseServerRuntime(CayenneProjects.SOFT_DELETE_PROJECT) public class SoftDeleteBatchTranslatorIT extends ServerCase { diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/UpdateBatchTranslatorIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/legacy/UpdateBatchTranslatorIT.java similarity index 99% copy from cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/UpdateBatchTranslatorIT.java copy to cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/legacy/UpdateBatchTranslatorIT.java index e604c77..1a10261 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/UpdateBatchTranslatorIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/legacy/UpdateBatchTranslatorIT.java @@ -17,7 +17,7 @@ * under the License. ****************************************************************/ -package org.apache.cayenne.access.translator.batch; +package org.apache.cayenne.access.translator.batch.legacy; import org.apache.cayenne.configuration.server.ServerRuntime; import org.apache.cayenne.dba.DbAdapter; @@ -43,6 +43,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.mockito.Mockito.mock; +@Deprecated @UseServerRuntime(CayenneProjects.LOCKING_PROJECT) public class UpdateBatchTranslatorIT extends ServerCase {