Repository: cayenne Updated Branches: refs/heads/master 988937524 -> 89439015f
http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/InNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/InNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/InNode.java new file mode 100644 index 0000000..fd08903 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/InNode.java @@ -0,0 +1,65 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + +/** + * @since 4.2 + */ +public class InNode extends Node { + + private final boolean not; + + public InNode(boolean not) { + super(NodeType.IN); + this.not = not; + } + + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + return buffer; + } + + @Override + public void appendChildrenSeparator(QuotingAppendable buffer, int childInd) { + if (childInd == 0) { + if (not) { + buffer.append(" NOT"); + } + buffer.append(" IN ("); + } + } + + @Override + public void appendChildrenEnd(QuotingAppendable buffer) { + buffer.append(')'); + } + + @Override + public Node copy() { + return new InNode(not); + } + + public boolean isNot() { + return not; + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/JoinNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/JoinNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/JoinNode.java new file mode 100644 index 0000000..fcb556d --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/JoinNode.java @@ -0,0 +1,51 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import org.apache.cayenne.access.sqlbuilder.JoinType; +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + +/** + * @since 4.2 + */ +public class JoinNode extends Node { + + private final JoinType joinType; + + public JoinNode(JoinType joinType) { + super(NodeType.JOIN); + this.joinType = joinType; + } + + @Override + public Node copy() { + return new JoinNode(joinType); + } + + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + return buffer.append(joinType.getName()).append("JOIN"); + } + + @Override + public void appendChildrenSeparator(QuotingAppendable buffer, int childInd) { + buffer.append(" ON"); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/LikeNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/LikeNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/LikeNode.java new file mode 100644 index 0000000..5b4037c --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/LikeNode.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 + * + * http://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.sqltree; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + +/** + * expressions: LIKE, ILIKE, NOT LIKE, NOT ILIKE + ESCAPE + * + * @since 4.2 + */ +public class LikeNode extends ExpressionNode { + + protected final boolean ignoreCase; + protected final boolean not; + protected final char escape; + + public LikeNode(boolean ignoreCase, boolean not, char escape) { + super(NodeType.LIKE); + this.ignoreCase = ignoreCase; + this.not = not; + this.escape = escape; + } + + @Override + public void appendChildrenStart(QuotingAppendable buffer) { + if(ignoreCase) { + buffer.append(" UPPER("); + } + } + + @Override + public void appendChildrenSeparator(QuotingAppendable buffer, int childIdx) { + if(ignoreCase) { + buffer.append(')'); + } + if(not) { + buffer.append(" NOT"); + } + buffer.append(" LIKE"); + if(ignoreCase) { + buffer.append(" UPPER("); + } + } + + @Override + public void appendChildrenEnd(QuotingAppendable buffer) { + if(ignoreCase) { + buffer.append(')'); + } + if(escape != 0) { + buffer.append(" ESCAPE '").append(escape).append('\''); + } + } + + @Override + public Node copy() { + return new LikeNode(ignoreCase, not, escape); + } + + public boolean isIgnoreCase() { + return ignoreCase; + } + + public boolean isNot() { + return not; + } + + public char getEscape() { + return escape; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/LimitOffsetNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/LimitOffsetNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/LimitOffsetNode.java new file mode 100644 index 0000000..1141077 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/LimitOffsetNode.java @@ -0,0 +1,58 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + +/** + * @since 4.2 + */ +public class LimitOffsetNode extends Node { + + protected final int limit; + protected final int offset; + + public LimitOffsetNode(int limit, int offset) { + super(NodeType.LIMIT_OFFSET); + this.limit = limit; + this.offset = offset; + } + + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + if(limit == 0 && offset == 0) { + return buffer; + } + return buffer.append(" LIMIT ").append(limit).append(" OFFSET ").append(offset); + } + + public int getLimit() { + return limit; + } + + public int getOffset() { + return offset; + } + + @Override + public Node copy() { + return new LimitOffsetNode(limit, offset); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/Node.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/Node.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/Node.java new file mode 100644 index 0000000..d535028 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/Node.java @@ -0,0 +1,139 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.cayenne.access.sqlbuilder.NodeTreeVisitor; +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; +import org.apache.cayenne.access.sqlbuilder.StringBuilderAppendable; + + +/** + * @since 4.2 + */ +public abstract class Node { + + protected Node parent; + + protected List<Node> children; + + protected final NodeType type; + + public Node(NodeType type) { + this.type = type; + } + + public Node() { + this(NodeType.UNDEFINED); + } + + public Node addChild(int index, Node node) { + children.add(index, node); + node.setParent(this); + return this; + } + + public Node addChild(Node node) { + if(children == null) { + children = new ArrayList<>(4); + } + children.add(node); + node.setParent(this); + return this; + } + + public Node getChild(int idx) { + return children.get(idx); + } + + public int getChildrenCount() { + if(children == null) { + return 0; + } + return children.size(); + } + + public void replaceChild(int idx, Node node) { + children.set(idx, node).setParent(null); + node.setParent(this); + } + + public Node getParent() { + return parent; + } + + public void setParent(Node parent) { + this.parent = parent; + } + + public void visit(NodeTreeVisitor visitor) { + if(!visitor.onNodeStart(this)) { + return; + } + int count = getChildrenCount(); + for(int i=0; i<count; i++) { + if(!visitor.onChildNodeStart(this, getChild(i), i, i < (count - 1))) { + return; + } + getChild(i).visit(visitor); + visitor.onChildNodeEnd(this, getChild(i), i, i < (count - 1)); + } + visitor.onNodeEnd(this); + } + + /** + * @return deep copy(i.e. with copies of all children) of this node + */ + @SuppressWarnings("unchecked") + public <T extends Node> T deepCopy() { + Node node = this.copy(); + if(children != null) { + node.children = new ArrayList<>(children.size()); + for(Node child : children) { + node.children.add(child.deepCopy()); + } + } + return (T)node; + } + + @Override + public String toString() { + return "Node {" + append(new StringBuilderAppendable()).toString() + "}"; + } + + public NodeType getType() { + return type; + } + + public abstract Node copy(); + + public abstract QuotingAppendable append(QuotingAppendable buffer); + + public void appendChildrenSeparator(QuotingAppendable buffer, int childInd) { + } + + public void appendChildrenStart(QuotingAppendable buffer) { + } + + public void appendChildrenEnd(QuotingAppendable buffer) { + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java ---------------------------------------------------------------------- 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 new file mode 100644 index 0000000..8c6985a --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java @@ -0,0 +1,38 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +/** + * @since 4.2 + */ +public enum NodeType { + UNDEFINED, + VALUE, + COLUMN, + LIMIT_OFFSET, + FUNCTION, + EQUALITY, + LIKE, + DISTINCT, + IN, + RESULT, + WHERE, + JOIN, FROM +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NotEqualNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NotEqualNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NotEqualNode.java new file mode 100644 index 0000000..76f1342 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NotEqualNode.java @@ -0,0 +1,42 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + +/** + * @since 4.2 + */ +public class NotEqualNode extends ExpressionNode { + + public NotEqualNode() { + super(NodeType.EQUALITY); + } + + @Override + public void appendChildrenSeparator(QuotingAppendable buffer, int childIdx) { + String expStr = " <> "; + Node child = getChild(1); + if (child.getType() == NodeType.VALUE && ((ValueNode) child).getValue() == null) { + expStr = " IS NOT NULL"; + } + buffer.append(expStr); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NotNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NotNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NotNode.java new file mode 100644 index 0000000..780a7d4 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NotNode.java @@ -0,0 +1,37 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + +/** + * @since 4.2 + */ +public class NotNode extends Node { + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + return buffer.append(" NOT"); + } + + @Override + public Node copy() { + return new NotNode(); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/OffsetFetchNextNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/OffsetFetchNextNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/OffsetFetchNextNode.java new file mode 100644 index 0000000..b60498b --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/OffsetFetchNextNode.java @@ -0,0 +1,53 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + +/** + * @since 4.2 + */ +public class OffsetFetchNextNode extends LimitOffsetNode { + + public OffsetFetchNextNode(LimitOffsetNode node) { + super(node.getLimit(), node.getOffset()); + } + + private OffsetFetchNextNode(int limit, int offset) { + super(limit, offset); + } + + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + // OFFSET X ROWS FETCH NEXT Y ROWS ONLY + if(offset > 0) { + buffer.append(" OFFSET ").append(offset).append(" ROWS"); + } + if(limit > 0) { + buffer.append(" FETCH NEXT ").append(limit).append(" ROWS ONLY"); + } + return buffer; + } + + @Override + public Node copy() { + return new OffsetFetchNextNode(limit, offset); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/OffsetNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/OffsetNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/OffsetNode.java new file mode 100644 index 0000000..b43e593 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/OffsetNode.java @@ -0,0 +1,43 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + +/** + * @since 4.2 + */ +public class OffsetNode extends Node { + private final int offset; + + public OffsetNode(int offset) { + this.offset = offset; + } + + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + return buffer.append(" OFFSET ").append(offset); + } + + @Override + public Node copy() { + return new OffsetNode(offset); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/OpExpressionNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/OpExpressionNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/OpExpressionNode.java new file mode 100644 index 0000000..7099000 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/OpExpressionNode.java @@ -0,0 +1,44 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + +/** + * @since 4.2 + */ +public class OpExpressionNode extends ExpressionNode { + + private final String op; + + public OpExpressionNode(String op) { + this.op = op; + } + + @Override + public void appendChildrenSeparator(QuotingAppendable buffer, int childInd) { + buffer.append(' ').append(op); + } + + @Override + public Node copy() { + return new OpExpressionNode(op); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/OrderByNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/OrderByNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/OrderByNode.java new file mode 100644 index 0000000..86143f0 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/OrderByNode.java @@ -0,0 +1,43 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + +/** + * @since 4.2 + */ +public class OrderByNode extends Node { + + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + return buffer.append(" ORDER BY"); + } + + @Override + public void appendChildrenSeparator(QuotingAppendable buffer, int childInd) { + buffer.append(','); + } + + @Override + public Node copy() { + return new OrderByNode(); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SelectNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SelectNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SelectNode.java new file mode 100644 index 0000000..997de9f --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SelectNode.java @@ -0,0 +1,48 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + +/** + * @since 4.2 + */ +public class SelectNode extends Node { + + @Override + public QuotingAppendable append(QuotingAppendable builder) { + if(parent != null) { + builder.append(" ("); + } + return builder.append("SELECT"); + } + + @Override + public void appendChildrenEnd(QuotingAppendable buffer) { + if(parent != null) { + buffer.append(')'); + } + } + + @Override + public Node copy() { + return new SelectNode(); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SelectResultNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SelectResultNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SelectResultNode.java new file mode 100644 index 0000000..b500324 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SelectResultNode.java @@ -0,0 +1,52 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + +/** + * @since 4.2 + */ +public class SelectResultNode extends Node { + + public SelectResultNode() { + super(NodeType.RESULT); + } + + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + return buffer; + } + + @Override + public void appendChildrenSeparator(QuotingAppendable buffer, int childIdx) { + buffer.append(','); + } + + @Override + public String toString() { + return "{SelectResultNode}"; + } + + @Override + public Node copy() { + return new SelectResultNode(); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SimpleNodeTreeVisitor.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SimpleNodeTreeVisitor.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SimpleNodeTreeVisitor.java new file mode 100644 index 0000000..d619e2f --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SimpleNodeTreeVisitor.java @@ -0,0 +1,46 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import org.apache.cayenne.access.sqlbuilder.NodeTreeVisitor; + +/** + * @since 4.2 + */ +public abstract class SimpleNodeTreeVisitor implements NodeTreeVisitor { + + @Override + public boolean onNodeStart(Node node) { + return true; + } + + @Override + public boolean onChildNodeStart(Node parent, Node child, int index, boolean hasMore) { + return true; + } + + @Override + public void onChildNodeEnd(Node parent, Node child, int index, boolean hasMore) { + } + + @Override + public void onNodeEnd(Node node) { + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SubqueryNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SubqueryNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SubqueryNode.java new file mode 100644 index 0000000..86b753f --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SubqueryNode.java @@ -0,0 +1,45 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + +/** + * @since 4.2 + */ +public class SubqueryNode extends Node { + + private final String subqueryType; + + public SubqueryNode(String subqueryType) { + this.subqueryType = subqueryType; + } + + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + return buffer.append(subqueryType); + } + + @Override + public Node copy() { + return new SubqueryNode(subqueryType); + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/TableNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/TableNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/TableNode.java new file mode 100644 index 0000000..ed8661b --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/TableNode.java @@ -0,0 +1,50 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + +/** + * @since 4.2 + */ +public class TableNode extends Node { + + private final String tableName; + private final String alias; + + public TableNode(String tableName, String alias) { + this.tableName = tableName; + this.alias = alias; + } + + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + buffer.append(' ').appendQuoted(tableName); + if (alias != null) { + buffer.append(' ').appendQuoted(alias); + } + return buffer; + } + + @Override + public Node copy() { + return new TableNode(tableName, alias); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/TextNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/TextNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/TextNode.java new file mode 100644 index 0000000..45ee5cf --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/TextNode.java @@ -0,0 +1,44 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + +/** + * @since 4.2 + */ +public class TextNode extends Node { + + private final CharSequence text; + + public TextNode(CharSequence text) { + this.text = text; + } + + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + return buffer.append(text); + } + + @Override + public Node copy() { + return new TextNode(text); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/TopNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/TopNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/TopNode.java new file mode 100644 index 0000000..56b4629 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/TopNode.java @@ -0,0 +1,44 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + +/** + * @since 4.2 + */ +public class TopNode extends Node { + + private final int count; + + public TopNode(int count) { + this.count = count; + } + + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + return buffer.append(" TOP ").append(count); + } + + @Override + public Node copy() { + return new TopNode(count); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/TrimmingColumnNode.java ---------------------------------------------------------------------- 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 new file mode 100644 index 0000000..c4c252b --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/TrimmingColumnNode.java @@ -0,0 +1,134 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import java.sql.Types; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + +/** + * @since 4.2 + */ +public class TrimmingColumnNode extends Node { + + protected final ColumnNode columnNode ; + + public TrimmingColumnNode(ColumnNode columnNode) { + this.columnNode = columnNode; + } + + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + boolean isResult = isResultNode(); + if(columnNode.getAlias() == null || isResult) { + if(isCharType()) { + appendRtrim(buffer); + appendAlias(buffer, isResult); + } else if(isComparisionWithClob()) { + appendClobColumnNode(buffer); + appendAlias(buffer, isResult); + } else { + columnNode.append(buffer); + } + } else { + appendAlias(buffer, false); + } + + return buffer; + } + + private boolean isComparisionWithClob() { + return (getParent().getType() == NodeType.EQUALITY + || getParent().getType() == NodeType.LIKE) + && columnNode.getAttribute() != null + && columnNode.getAttribute().getType() == Types.CLOB; + } + + protected void appendRtrim(QuotingAppendable buffer) { + buffer.append(" RTRIM("); + appendColumnNode(buffer); + buffer.append(")"); + } + + private boolean isCharType() { + return columnNode.getAttribute() != null + && columnNode.getAttribute().getType() == Types.CHAR; + } + + protected boolean isResultNode() { + Node parent = getParent(); + while(parent != null) { + if(parent.getType() == NodeType.RESULT) { + return true; + } + parent = parent.getParent(); + } + return false; + } + + protected void appendClobColumnNode(QuotingAppendable buffer) { + buffer.append(" CAST("); + appendColumnNode(buffer); + buffer.append(" AS VARCHAR(").append(getColumnSize()).append("))"); + } + + protected void appendColumnNode(QuotingAppendable buffer) { + if (columnNode.getTable() != null) { + buffer.appendQuoted(columnNode.getTable()).append('.'); + } + buffer.appendQuoted(columnNode.getColumn()); + } + + protected void appendAlias(QuotingAppendable buffer, boolean isResult) { + if(!isResult) { + return; + } + if (columnNode.getAlias() != null) { + buffer.append(' ').appendQuoted(columnNode.getAlias()); + } + } + + protected int getColumnSize() { + int size = columnNode.getAttribute().getMaxLength(); + if(size > 0) { + return size; + } + + int siblings = getParent().getChildrenCount(); + for(int i=0; i<siblings; i++) { + Node sibling = getParent().getChild(i); + if(sibling == this) { + continue; + } + if(sibling.getType() == NodeType.VALUE) { + if(((ValueNode)sibling).getValue() instanceof CharSequence) { + return ((CharSequence) ((ValueNode)sibling).getValue()).length(); + } + } + } + + return 255; + } + + @Override + public Node copy() { + return new TrimmingColumnNode(columnNode.deepCopy()); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/UnescapedColumnNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/UnescapedColumnNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/UnescapedColumnNode.java new file mode 100644 index 0000000..c3c8b38 --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/UnescapedColumnNode.java @@ -0,0 +1,52 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; +import org.apache.cayenne.map.DbAttribute; + +/** + * @since 4.2 + */ +public class UnescapedColumnNode extends ColumnNode { + + public UnescapedColumnNode(String table, String column, String alias, DbAttribute attribute) { + super(table, column, alias, attribute); + } + + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + buffer.append(' '); + if (table != null) { + buffer.append(table).append('.'); + } + buffer.append(column); + if (alias != null) { + buffer.append(' ').appendQuoted(alias); + } + + return buffer; + } + + @Override + public Node copy() { + return new UnescapedColumnNode(table, column, alias, attribute); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ValueNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ValueNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ValueNode.java new file mode 100644 index 0000000..2ba5fbc --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ValueNode.java @@ -0,0 +1,246 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import org.apache.cayenne.CayenneRuntimeException; +import org.apache.cayenne.ObjectId; +import org.apache.cayenne.Persistent; +import org.apache.cayenne.access.sqlbuilder.SQLGenerationContext; +import org.apache.cayenne.access.translator.DbAttributeBinding; +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; +import org.apache.cayenne.access.types.ExtendedType; +import org.apache.cayenne.map.DbAttribute; + +/** + * @since 4.2 + */ +public class ValueNode extends Node { + + private final Object value; + // Used as hint for type of this value + private final DbAttribute attribute; + + public ValueNode(Object value, DbAttribute attribute) { + super(NodeType.VALUE); + this.value = value; + this.attribute = attribute; + } + + public Object getValue() { + return value; + } + + public DbAttribute getAttribute() { + return attribute; + } + + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + appendValue(value, buffer); + return buffer; + } + + private void appendValue(Object val, QuotingAppendable buffer) { + if(val == null) { + return; + } + + boolean isArray = val.getClass().isArray(); + if(isArray) { + if(val instanceof short[]) { + appendValue((short[])val, buffer); + } else if(val instanceof char[]) { + appendValue((char[])val, buffer); + } else if(val instanceof int[]) { + appendValue((int[])val, buffer); + } else if(val instanceof long[]) { + appendValue((long[])val, buffer); + } else if(val instanceof float[]) { + appendValue((float[])val, buffer); + } else if(val instanceof double[]) { + appendValue((double[])val, buffer); + } else if(val instanceof boolean[]) { + appendValue((boolean[])val, buffer); + } else if(val instanceof Object[]) { + appendValue((Object[]) val, buffer); + } else if(val instanceof byte[]) { + // append byte[] array as single object + appendObjectValue(buffer, val); + } else { + throw new CayenneRuntimeException("Unsupported array type %s", val.getClass().getName()); + } + } else { + if(val instanceof Persistent) { + appendValue((Persistent) val, buffer); + } else if(val instanceof ObjectId) { + appendValue((ObjectId) val, buffer); + } else if(val instanceof CharSequence) { + appendStringValue(buffer, (CharSequence)val); + } else { + appendObjectValue(buffer, val); + } + } + } + + protected void appendObjectValue(QuotingAppendable buffer, Object value) { + if(value == null) { + return; + } + if(buffer.getContext() == null) { + buffer.append(' ').append(value.toString()); + } else { + buffer.append(" ?"); + addValueBinding(buffer, value); + } + } + + protected void appendStringValue(QuotingAppendable buffer, CharSequence value) { + if(buffer.getContext() == null) { + buffer.append(" '").append(value).append("'"); + } else { + // value can't be null here + buffer.append(" ?"); + addValueBinding(buffer, value); + } + } + + protected void addValueBinding(QuotingAppendable buffer, Object value) { + // value can't be null here + SQLGenerationContext context = buffer.getContext(); + // allow translation in out-of-context scope, to be able to use as a standalone SQL generator + ExtendedType extendedType = context.getAdapter().getExtendedTypes().getRegisteredType(value.getClass()); + DbAttributeBinding binding = new DbAttributeBinding(attribute); + binding.setStatementPosition(context.getBindings().size() + 1); + binding.setExtendedType(extendedType); + binding.setValue(value); + context.getBindings().add(binding); + } + + private void appendValue(Persistent value, QuotingAppendable buffer) { + appendValue(value.getObjectId(), buffer); + } + + private void appendValue(ObjectId value, QuotingAppendable buffer) { + for(Object idVal: value.getIdSnapshot().values()) { + appendValue(idVal, buffer); + } + } + + private void appendValue(short[] val, QuotingAppendable buffer) { + boolean first = true; + for(short i : val) { + if(first) { + first = false; + } else { + buffer.append(','); + } + appendValue(i, buffer); + } + } + + private void appendValue(char[] val, QuotingAppendable buffer) { + boolean first = true; + for(char i : val) { + if(first) { + first = false; + } else { + buffer.append(','); + } + appendValue(i, buffer); + } + } + + private void appendValue(int[] val, QuotingAppendable buffer) { + boolean first = true; + for(int i : val) { + if(first) { + first = false; + } else { + buffer.append(','); + } + appendValue(i, buffer); + } + } + + private void appendValue(long[] val, QuotingAppendable buffer) { + boolean first = true; + for(long i : val) { + if(first) { + first = false; + } else { + buffer.append(','); + } + appendValue(i, buffer); + } + } + + private void appendValue(float[] val, QuotingAppendable buffer) { + boolean first = true; + for(float i : val) { + if(first) { + first = false; + } else { + buffer.append(','); + } + appendValue(i, buffer); + } + } + + private void appendValue(double[] val, QuotingAppendable buffer) { + boolean first = true; + for(double i : val) { + if(first) { + first = false; + } else { + buffer.append(','); + } + appendValue(i, buffer); + } + } + + private void appendValue(boolean[] val, QuotingAppendable buffer) { + boolean first = true; + for(boolean i : val) { + if(first) { + first = false; + } else { + buffer.append(','); + } + appendValue(i, buffer); + } + } + + private void appendValue(Object[] val, QuotingAppendable buffer) { + boolean first = true; + for(Object i : val) { + if(first) { + first = false; + } else { + buffer.append(','); + } + appendValue(i, buffer); + } + } + + @Override + public Node copy() { + return new ValueNode(value, attribute); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/WhereNode.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/WhereNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/WhereNode.java new file mode 100644 index 0000000..68cc65e --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/WhereNode.java @@ -0,0 +1,43 @@ +/***************************************************************** + * 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 + * + * http://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.sqltree; + +import org.apache.cayenne.access.sqlbuilder.QuotingAppendable; + +/** + * @since 4.2 + */ +public class WhereNode extends Node { + + public WhereNode() { + super(NodeType.WHERE); + } + + @Override + public QuotingAppendable append(QuotingAppendable buffer) { + return buffer.append(" WHERE"); + } + + @Override + public Node copy() { + return new WhereNode(); + } + +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/89439015/cayenne-server/src/test/java/org/apache/cayenne/access/sqlbuilder/SelectBuilderTest.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/sqlbuilder/SelectBuilderTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/sqlbuilder/SelectBuilderTest.java new file mode 100644 index 0000000..74e8fe3 --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/access/sqlbuilder/SelectBuilderTest.java @@ -0,0 +1,131 @@ +/***************************************************************** + * 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 + * + * http://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.SelectNode; +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 SelectBuilderTest { + + @Test + public void testSelect() { + SelectBuilder builder = new SelectBuilder(); + Node node = builder.build(); + assertThat(node, instanceOf(SelectNode.class)); + assertSQL("SELECT", node); + } + + @Test + public void testSelectColumns() { + SelectBuilder builder = new SelectBuilder(column("a"), table("c").column("b")); + Node node = builder.build(); + assertThat(node, instanceOf(SelectNode.class)); + assertSQL("SELECT a, c.b", node); + } + + @Test + public void testSelectFrom() { + SelectBuilder builder = new SelectBuilder(column("a")).from(table("b")); + Node node = builder.build(); + assertThat(node, instanceOf(SelectNode.class)); + assertSQL("SELECT a FROM b", node); + } + + @Test + public void testSelectFromWhere() { + SelectBuilder builder = new SelectBuilder(column("a")) + .from(table("b")) + .where(column("a").eq(value(123))); + Node node = builder.build(); + assertThat(node, instanceOf(SelectNode.class)); + assertSQL("SELECT a FROM b WHERE a = 123", node); + } + + @Test + public void testSelectFromWhereNull() { + SelectBuilder builder = new SelectBuilder(column("a")) + .from(table("b")) + .where(column("a").eq(value(null))); + Node node = builder.build(); + assertThat(node, instanceOf(SelectNode.class)); + assertSQL("SELECT a FROM b WHERE a IS NULL", node); + } + + @Test + public void testSelectFromWhereComplex() { + SelectBuilder builder = new SelectBuilder(column("a")) + .from(table("b")) + .where(column("a").eq(value(123)).and(column("c").lt(column("d")))); + Node node = builder.build(); + assertThat(node, instanceOf(SelectNode.class)); + assertSQL("SELECT a FROM b WHERE ( a = 123 ) AND ( c < d )", node); + } + + @Test + public void testComplexQuery() { + Node node = select( + table("a").column("ARTIST_ID").as("a_id"), + count(table("p").column("PAINTING_TITLE")).as("p_count")) + .distinct() + .from(table("ARTIST").as("a")) + .from(leftJoin(table("PAINTING").as("p")) + .on(table("a").column("ARTIST_ID") + .eq(table("p").column("ARTIST_ID")) + .and(table("p").column("ESTIMATED_PRICE").gt(value(10))))) + .where( + table("a").column("ARTIST_NAME") + .eq(value("Picasso")) + .and(exists(select(all()) + .from(table("GALLERY").as("g")) + .where(table("g").column("GALLERY_ID").eq(table("p").column("GALLERY_ID"))))) + .and(value(1).eq(value(1))) + .or(value(false)) + ) + .groupBy(table("a").column("ARTIST_ID")) + .having(not(count(table("p").column("PAINTING_TITLE")).gt(value(3)))) + .orderBy(column("p_count").desc(), column("a_id").asc()) + .build(); + assertThat(node, instanceOf(SelectNode.class)); + assertSQL("SELECT DISTINCT" + + " a.ARTIST_ID a_id, COUNT( p.PAINTING_TITLE ) AS p_count" + + " FROM ARTIST a" + + " LEFT JOIN PAINTING p ON ( a.ARTIST_ID = p.ARTIST_ID ) AND ( p.ESTIMATED_PRICE > 10 )" + + " WHERE ( ( ( a.ARTIST_NAME = 'Picasso' )" + + " AND EXISTS (SELECT * FROM GALLERY g WHERE g.GALLERY_ID = p.GALLERY_ID) )" + + " AND ( 1 = 1 ) ) OR false" + + " GROUP BY a.ARTIST_ID" + + " HAVING NOT ( COUNT( p.PAINTING_TITLE ) > 3 )" + + " ORDER BY p_count DESC, a_id", 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