You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2018/12/26 12:19:06 UTC
[2/6] cayenne git commit: CAY-2467 New type-aware Property API core
API
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2050c2e1/cayenne-server/src/main/java/org/apache/cayenne/exp/property/DateProperty.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/property/DateProperty.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/DateProperty.java
new file mode 100644
index 0000000..8c32512
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/DateProperty.java
@@ -0,0 +1,140 @@
+/*****************************************************************
+ * 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.exp.property;
+
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.FunctionExpressionFactory;
+
+/**
+ * Property that represents date/time attribute.
+ * <pre>{@code
+ * ObjectSelect.query(Artist.class)
+ * .where(Artist.DATE_OF_BIRTH.year().lte(1900))
+ * .or(Artist.DATE_OF_BIRTH.month().between(6, 8))
+ * }</pre>
+ *
+ * @see org.apache.cayenne.exp.property
+ * @since 4.2
+ */
+public class DateProperty<E> extends BaseProperty<E> implements ComparableProperty<E> {
+
+ /**
+ * Constructs a new property with the given name and expression
+ *
+ * @param name of the property (will be used as alias for the expression)
+ * @param expression expression for property
+ * @param type of the property
+ */
+ protected DateProperty(String name, Expression expression, Class<E> type) {
+ super(name, expression, type);
+ }
+
+ /**
+ * It is a caller responsibility to check that underlying attribute has year component
+ *
+ * @return new property that represents year component of this date property
+ * @see FunctionExpressionFactory#yearExp(Expression)
+ */
+ public NumericProperty<Integer> year() {
+ return PropertyFactory.createNumeric(FunctionExpressionFactory.yearExp(getExpression()), Integer.class);
+ }
+
+ /**
+ * It is a caller responsibility to check that underlying attribute has month component
+ *
+ * @return new property that represents month component of this date property
+ * @see FunctionExpressionFactory#monthExp(Expression)
+ */
+ public NumericProperty<Integer> month() {
+ return PropertyFactory.createNumeric(FunctionExpressionFactory.monthExp(getExpression()), Integer.class);
+ }
+
+ /**
+ * It is a caller responsibility to check that underlying attribute has day component
+ *
+ * @return new property that represents day of month component of this date property
+ * @see FunctionExpressionFactory#dayOfMonthExp(Expression)
+ */
+ public NumericProperty<Integer> dayOfMonth() {
+ return PropertyFactory.createNumeric(FunctionExpressionFactory.dayOfMonthExp(getExpression()), Integer.class);
+ }
+
+ /**
+ * It is a caller responsibility to check that underlying attribute has day component
+ *
+ * @return new property that represents day of year component of this date property
+ * @see FunctionExpressionFactory#dayOfMonthExp(Expression)
+ */
+ public NumericProperty<Integer> dayOfYear() {
+ return PropertyFactory.createNumeric(FunctionExpressionFactory.dayOfYearExp(getExpression()), Integer.class);
+ }
+
+ /**
+ * It is a caller responsibility to check that underlying attribute has time component
+ *
+ * @return new property that represents hour component of this time property
+ * @see FunctionExpressionFactory#hourExp(Expression)
+ */
+ public NumericProperty<Integer> hour() {
+ return PropertyFactory.createNumeric(FunctionExpressionFactory.hourExp(getExpression()), Integer.class);
+ }
+
+ /**
+ * It is a caller responsibility to check that underlying attribute has time component
+ *
+ * @return new property that represents minute component of this time property
+ * @see FunctionExpressionFactory#minuteExp(Expression)
+ */
+ public NumericProperty<Integer> minute() {
+ return PropertyFactory.createNumeric(FunctionExpressionFactory.minuteExp(getExpression()), Integer.class);
+ }
+
+ /**
+ * It is a caller responsibility to check that underlying attribute has time component
+ *
+ * @return new property that represents second component of this time property
+ * @see FunctionExpressionFactory#secondExp(Expression)
+ */
+ public NumericProperty<Integer> second() {
+ return PropertyFactory.createNumeric(FunctionExpressionFactory.secondExp(getExpression()), Integer.class);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DateProperty<E> alias(String alias) {
+ return PropertyFactory.createDate(alias, this.getExpression(), this.getType());
+ }
+
+ /**
+ * @see FunctionExpressionFactory#maxExp(Expression)
+ */
+ public DateProperty<E> max() {
+ return PropertyFactory.createDate(FunctionExpressionFactory.maxExp(getExpression()), getType());
+ }
+
+ /**
+ * @see FunctionExpressionFactory#minExp(Expression)
+ */
+ public DateProperty<E> min() {
+ return PropertyFactory.createDate(FunctionExpressionFactory.minExp(getExpression()), getType());
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2050c2e1/cayenne-server/src/main/java/org/apache/cayenne/exp/property/EntityProperty.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/property/EntityProperty.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/EntityProperty.java
new file mode 100644
index 0000000..6398a22
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/EntityProperty.java
@@ -0,0 +1,71 @@
+/*****************************************************************
+ * 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.exp.property;
+
+import org.apache.cayenne.Persistent;
+import org.apache.cayenne.exp.Expression;
+
+/**
+ * Property that represents to-one relationships.
+ * <p>
+ * Usage examples in where clause: <pre>{@code
+ * ObjectSelect.query(Paintings.class)
+ * .where(Painting.TO_ARTIST.dot(Artist.ARTIST_NAME).eq("Pablo Picasso"));}</pre>
+ * <p>
+ * Usage examples in column select, in this case full Artist entity will be
+ * returned in the result: <pre>{@code
+ * ObjectSelect
+ * .columnQuery(Paintings.class, Painting.PAINTING_TITLE, Painting.TO_ARTIST);}</pre>
+ *
+ * @see org.apache.cayenne.exp.property
+ * @since 4.2
+ */
+public class EntityProperty<E extends Persistent> extends BaseProperty<E> implements RelationshipProperty<E> {
+
+ /**
+ * Constructs a new property with the given name and expression
+ *
+ * @param name of the property (will be used as alias for the expression)
+ * @param expression expression for property
+ * @param type of the property
+ * @see PropertyFactory#createBase(String, Expression, Class)
+ */
+ protected EntityProperty(String name, Expression expression, Class<E> type) {
+ super(name, expression, type);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EntityProperty<E> alias(String alias) {
+ return PropertyFactory.createEntity(alias, getExpression(), getType());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EntityProperty<E> outer() {
+ return getName().endsWith("+")
+ ? this
+ : PropertyFactory.createEntity(getName() + "+", getType());
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2050c2e1/cayenne-server/src/main/java/org/apache/cayenne/exp/property/ListProperty.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/property/ListProperty.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/ListProperty.java
new file mode 100644
index 0000000..410d6db
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/ListProperty.java
@@ -0,0 +1,67 @@
+/*****************************************************************
+ * 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.exp.property;
+
+import java.util.List;
+
+import org.apache.cayenne.Persistent;
+import org.apache.cayenne.exp.Expression;
+
+/**
+ * Property that represents to-many relationship mapped on {@link List}.
+ * <pre>{@code
+ * ObjectSelect.query(Artist.class)
+ * .where(Artist.PAINTING_ARRAY.contains(painting));
+ * }</pre>
+ *
+ * @see org.apache.cayenne.exp.property
+ * @since 4.2
+ */
+public class ListProperty<V extends Persistent> extends CollectionProperty<V, List<V>> {
+
+ /**
+ * Constructs a new property with the given name and expression
+ *
+ * @param name of the property (will be used as alias for the expression)
+ * @param expression expression for property
+ * @param entityType type of related entity
+ */
+ protected ListProperty(String name, Expression expression, Class<V> entityType) {
+ super(name, expression, List.class, entityType);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ListProperty<V> alias(String alias) {
+ return PropertyFactory.createList(alias, this.getExpression(), this.getEntityType());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ListProperty<V> outer() {
+ return getName().endsWith("+")
+ ? this
+ : PropertyFactory.createList(getName() + "+", getEntityType());
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2050c2e1/cayenne-server/src/main/java/org/apache/cayenne/exp/property/MapProperty.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/property/MapProperty.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/MapProperty.java
new file mode 100644
index 0000000..0137659
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/MapProperty.java
@@ -0,0 +1,233 @@
+/*****************************************************************
+ * 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.exp.property;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.cayenne.Persistent;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionFactory;
+
+/**
+ * Property that represents to-many relationship mapped on {@link Map}.
+ *
+ * @see org.apache.cayenne.exp.property
+ * @since 4.2
+ */
+public class MapProperty<K, V extends Persistent> extends BaseProperty<Map<K, V>> implements RelationshipProperty<Map<K, V>> {
+
+ protected Class<K> keyType;
+
+ protected Class<V> entityType;
+
+ /**
+ * Constructs a new property with the given name and expression
+ *
+ * @param name of the property (will be used as alias for the expression)
+ * @param expression expression for property
+ * @param keyType type of keys of the property
+ * @param entityType type of related entities
+ * @see PropertyFactory#createMap(String, Expression, Class, Class)
+ */
+ protected MapProperty(String name, Expression expression, Class<K> keyType, Class<V> entityType) {
+ super(name, expression, Map.class);
+ this.keyType = keyType;
+ this.entityType = entityType;
+ }
+
+ /**
+ * <p>Create new "flat" property for toMany relationship.</p>
+ * <p>
+ * Example:
+ * <pre>{@code
+ * List<Object[]> result = ObjectSelect
+ * .columnQuery(Artist.class, Artist.ARTIST_NAME, Artist.PAINTING_ARRAY.flat(Painting.class))
+ * .select(context);
+ * }</pre>
+ * </p>
+ */
+ public EntityProperty<V> flat() {
+ return PropertyFactory.createEntity(ExpressionFactory.fullObjectExp(getExpression()), getEntityType());
+ }
+
+ // TODO: move all *contains* methods to RelationshipProperty once Property class is removed
+
+ /**
+ * @return An expression representing equality to a value.
+ */
+ public Expression contains(V value) {
+ return ExpressionFactory.matchExp(getExpression(), value);
+ }
+
+
+ /**
+ * @return An expression representing inequality to a value.
+ */
+ public Expression notContains(V value) {
+ return ExpressionFactory.noMatchExp(getExpression(), value);
+ }
+
+ /**
+ * @return An expression for finding objects with values in the given set.
+ */
+ @SafeVarargs
+ public final Expression contains(V firstValue, V... moreValues) {
+
+ int moreValuesLength = moreValues != null ? moreValues.length : 0;
+
+ Object[] values = new Object[moreValuesLength + 1];
+ values[0] = firstValue;
+
+ if (moreValuesLength > 0) {
+ System.arraycopy(moreValues, 0, values, 1, moreValuesLength);
+ }
+
+ return ExpressionFactory.inExp(getExpression(), values);
+ }
+
+ /**
+ * @return An expression for finding objects with values in the given set.
+ */
+ public Expression contains(Collection<V> values) {
+ return ExpressionFactory.inExp(getExpression(), values);
+ }
+
+ /**
+ * @return An expression for finding objects with values not in the given set.
+ */
+ public Expression notContains(Collection<V> values) {
+ return ExpressionFactory.notInExp(getExpression(), values);
+ }
+
+ /**
+ * @return An expression for finding objects with values not in the given set.
+ */
+ @SafeVarargs
+ public final Expression notContains(V firstValue, V... moreValues) {
+
+ int moreValuesLength = moreValues != null ? moreValues.length : 0;
+
+ Object[] values = new Object[moreValuesLength + 1];
+ values[0] = firstValue;
+
+ if (moreValuesLength > 0) {
+ System.arraycopy(moreValues, 0, values, 1, moreValuesLength);
+ }
+
+ return ExpressionFactory.notInExp(getExpression(), values);
+ }
+
+ /**
+ * @param id object id
+ * @return An expression for finding object with given id.
+ */
+ public Expression containsId(Object id) {
+ return ExpressionFactory.matchExp(getExpression(), id);
+ }
+
+ /**
+ * @return An expression for finding objects with given id set
+ */
+ public Expression containsId(Object firstId, Object... moreId) {
+
+ int moreValuesLength = moreId != null ? moreId.length : 0;
+
+ Object[] values = new Object[moreValuesLength + 1];
+ values[0] = firstId;
+
+ if (moreValuesLength > 0) {
+ System.arraycopy(moreId, 0, values, 1, moreValuesLength);
+ }
+
+ return ExpressionFactory.inExp(getExpression(), values);
+ }
+
+ /**
+ * @return An expression for finding objects with given id set.
+ */
+ public Expression containsId(Collection<Object> ids) {
+ return ExpressionFactory.inExp(getExpression(), ids);
+ }
+
+ /**
+ * @param id object id
+ * @return An expression for finding object without given id.
+ */
+ public Expression notContainsId(Object id) {
+ return ExpressionFactory.noMatchExp(getExpression(), id);
+ }
+
+ /**
+ * @return An expression for finding objects without given id set.
+ */
+ public Expression notContainsId(Object firstId, Object... moreId) {
+
+ int moreValuesLength = moreId != null ? moreId.length : 0;
+
+ Object[] values = new Object[moreValuesLength + 1];
+ values[0] = firstId;
+
+ if (moreValuesLength > 0) {
+ System.arraycopy(moreId, 0, values, 1, moreValuesLength);
+ }
+
+ return ExpressionFactory.notInExp(getExpression(), values);
+ }
+
+ /**
+ * @return An expression for finding objects without given id set.
+ */
+ public Expression notContainsId(Collection<Object> ids) {
+ return ExpressionFactory.notInExp(getExpression(), ids);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public MapProperty<K, V> alias(String alias) {
+ return PropertyFactory.createMap(alias, this.getExpression(), getKeyType(), getEntityType());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public MapProperty<K, V> outer() {
+ return getName().endsWith("+")
+ ? this
+ : PropertyFactory.createMap(getName() + "+", getKeyType(), getEntityType());
+ }
+
+ /**
+ * @return type of keys in represented attribute
+ */
+ protected Class<K> getKeyType() {
+ return keyType;
+ }
+
+ /**
+ * @return type of object entity in represented attribute
+ */
+ protected Class<V> getEntityType() {
+ return entityType;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2050c2e1/cayenne-server/src/main/java/org/apache/cayenne/exp/property/NumericProperty.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/property/NumericProperty.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/NumericProperty.java
new file mode 100644
index 0000000..14e07d1
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/NumericProperty.java
@@ -0,0 +1,186 @@
+/*****************************************************************
+ * 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.exp.property;
+
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.FunctionExpressionFactory;
+import org.apache.cayenne.exp.parser.ASTAdd;
+import org.apache.cayenne.exp.parser.ASTDivide;
+import org.apache.cayenne.exp.parser.ASTMultiply;
+import org.apache.cayenne.exp.parser.ASTNegate;
+import org.apache.cayenne.exp.parser.ASTSubtract;
+
+/**
+ * Property that represents attributes mapped on numeric types
+ * <p>
+ * Numeric type is an any type inherited from {@link Number}.
+ * <p>
+ * Provides basic math functions like {@link #mod(Number)}, {@link #abs()} and {@link #sqrt()}.
+ * It is also implements {@link ComparableProperty} interface.
+ *
+ * @see org.apache.cayenne.exp.property
+ * @since 4.2
+ */
+public class NumericProperty<E extends Number> extends BaseProperty<E> implements ComparableProperty<E> {
+
+ /**
+ * Constructs a new property with the given name and expression
+ *
+ * @param name of the property (will be used as alias for the expression)
+ * @param expression expression for property
+ * @param type of the property
+ * @see PropertyFactory#createNumeric(String, Expression, Class)
+ */
+ protected NumericProperty(String name, Expression expression, Class<E> type) {
+ super(name, expression, type);
+ }
+
+ /**
+ * @see FunctionExpressionFactory#avgExp(Expression)
+ */
+ public NumericProperty<E> avg() {
+ return PropertyFactory.createNumeric(FunctionExpressionFactory.avgExp(getExpression()), getType());
+ }
+
+ /**
+ * @see FunctionExpressionFactory#sumExp(Expression)
+ */
+ public NumericProperty<E> sum() {
+ return PropertyFactory.createNumeric(FunctionExpressionFactory.sumExp(getExpression()), getType());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public NumericProperty<E> max() {
+ return PropertyFactory.createNumeric(FunctionExpressionFactory.maxExp(getExpression()), getType());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public NumericProperty<E> min() {
+ return PropertyFactory.createNumeric(FunctionExpressionFactory.minExp(getExpression()), getType());
+ }
+
+ /**
+ * @see FunctionExpressionFactory#modExp(Expression, Number)
+ */
+ public NumericProperty<E> mod(Number number) {
+ return PropertyFactory.createNumeric(FunctionExpressionFactory.modExp(getExpression(), number), getType());
+ }
+
+ /**
+ * @see FunctionExpressionFactory#modExp(Expression, Number)
+ */
+ public NumericProperty<E> mod(NumericProperty<?> number) {
+ return PropertyFactory.createNumeric(FunctionExpressionFactory.modExp(getExpression(), number.getExpression()), getType());
+ }
+
+ /**
+ * @see FunctionExpressionFactory#absExp(Expression)
+ *
+ * @return new property that represents abs() function call with current property as argument
+ */
+ public NumericProperty<E> abs() {
+ return PropertyFactory.createNumeric(FunctionExpressionFactory.absExp(getExpression()), getType());
+ }
+
+ /**
+ * @see FunctionExpressionFactory#sqrtExp(Expression)
+ *
+ * @return new property that represents sqrt() function call with current property as argument
+ */
+ public NumericProperty<E> sqrt() {
+ return PropertyFactory.createNumeric(FunctionExpressionFactory.sqrtExp(getExpression()), getType());
+ }
+
+ /**
+ * @return new property that represents '+' operator with current property as argument
+ */
+ public NumericProperty<E> add(E value) {
+ return PropertyFactory.createNumeric(new ASTAdd(getExpression(), value), getType());
+ }
+
+ /**
+ * @return new property that represents '+' operator with current property as argument
+ */
+ public NumericProperty<E> add(NumericProperty<?> value) {
+ return PropertyFactory.createNumeric(new ASTAdd(getExpression(), value.getExpression()), getType());
+ }
+
+ /**
+ * @return new property that represents '-' operator with current property as argument
+ */
+ public NumericProperty<E> sub(E value) {
+ return PropertyFactory.createNumeric(new ASTSubtract(getExpression(), value), getType());
+ }
+
+ /**
+ * @return new property that represents '-' operator with current property as argument
+ */
+ public NumericProperty<E> sub(NumericProperty<?> value) {
+ return PropertyFactory.createNumeric(new ASTSubtract(getExpression(), value.getExpression()), getType());
+ }
+
+ /**
+ * @return new property that represents '/' operator with current property as argument
+ */
+ public NumericProperty<E> div(E value) {
+ return PropertyFactory.createNumeric(new ASTDivide(getExpression(), value), getType());
+ }
+
+ /**
+ * @return new property that represents '/' operator with current property as argument
+ */
+ public NumericProperty<E> div(NumericProperty<?> value) {
+ return PropertyFactory.createNumeric(new ASTDivide(getExpression(), value.getExpression()), getType());
+ }
+
+ /**
+ * @return new property that represents '*' operator with current property as argument
+ */
+ public NumericProperty<E> mul(E value) {
+ return PropertyFactory.createNumeric(new ASTMultiply(getExpression(), value), getType());
+ }
+
+ /**
+ * @return new property that represents '*' operator with current property as argument
+ */
+ public NumericProperty<E> mul(NumericProperty<?> value) {
+ return PropertyFactory.createNumeric(new ASTMultiply(getExpression(), value.getExpression()), getType());
+ }
+
+ /**
+ * @return new property that represents negative value of current property
+ */
+ public NumericProperty<E> neg() {
+ return PropertyFactory.createNumeric(new ASTNegate(getExpression()), getType());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public NumericProperty<E> alias(String alias) {
+ return PropertyFactory.createNumeric(alias, this.getExpression(), this.getType());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2050c2e1/cayenne-server/src/main/java/org/apache/cayenne/exp/property/Property.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/property/Property.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/Property.java
new file mode 100644
index 0000000..50e69fe
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/Property.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.exp.property;
+
+import org.apache.cayenne.exp.Expression;
+
+/**
+ * Base interface for all types of properties
+ * @since 4.2
+ */
+public interface Property<E> {
+
+ /**
+ * @return name of this property, can be null
+ */
+ String getName();
+
+ /**
+ * @return expression that defines this property, not null
+ */
+ Expression getExpression();
+
+ /**
+ * @return java type of this property, can be null
+ */
+ Class<E> getType();
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2050c2e1/cayenne-server/src/main/java/org/apache/cayenne/exp/property/PropertyFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/property/PropertyFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/PropertyFactory.java
new file mode 100644
index 0000000..c355d73
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/PropertyFactory.java
@@ -0,0 +1,375 @@
+/*****************************************************************
+ * 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.exp.property;
+
+import java.time.LocalDateTime;
+
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.Persistent;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.exp.FunctionExpressionFactory;
+
+/**
+ *
+ * Factory class that produces all property types.
+ *
+ * @see org.apache.cayenne.exp.property
+ * @since 4.2
+ */
+public class PropertyFactory {
+
+ /**
+ * Property that can be used to select {@code COUNT(*)}
+ * <p>
+ * Usage:<pre>{@code
+ * ObjectSelect.columnQuery(Artist.class, Artist.ARTIST_NAME, PropertyFactory.COUNT);
+ * }</pre>
+ * @see org.apache.cayenne.query.ObjectSelect#selectCount(ObjectContext)
+ */
+ public static final NumericProperty<Long> COUNT = createNumeric(FunctionExpressionFactory.countExp(), Long.class);
+
+ /**
+ * Property that corresponds to SQL function {@code NOW()}
+ * <p>
+ * Usage:<pre>{@code
+ * ObjectSelect.query(Artist.class).where(Artist.DATE_OF_BIRTH.year().lt(PropertyFactory.NOW.year().sub(100)));
+ * }</pre>
+ */
+ public static final DateProperty<LocalDateTime> NOW = createDate(FunctionExpressionFactory.currentTimestamp(), LocalDateTime.class);
+
+ // BaseProperty
+
+ /**
+ * Create base property
+ *
+ * @param name of the property
+ * @param expression that property will use
+ * @param type type of represented attribute
+ * @param <T> type of represented attribute
+ * @return new property with custom expression
+ */
+ public static <T> BaseProperty<T> createBase(String name, Expression expression, Class<T> type) {
+ return new BaseProperty<>(name, expression, type);
+ }
+
+ /**
+ * Create base property
+ *
+ * @param name of the property, will be used as value for path expression
+ * @param type type of represented attribute
+ * @param <T> type of represented attribute
+ * @return new path property
+ */
+ public static <T> BaseProperty<T> createBase(String name, Class<T> type) {
+ return createBase(name, null, type);
+ }
+
+ /**
+ * Create base property
+ *
+ * @param expression that property will use
+ * @param type type of represented attribute
+ * @param <T> type of represented attribute
+ * @return new property with custom expression without name
+ */
+ public static <T> BaseProperty<T> createBase(Expression expression, Class<T> type) {
+ return createBase(null, expression, type);
+ }
+
+ // StringProperty
+
+ /**
+ * Create string property
+ *
+ * @param name of the property
+ * @param expression that property will use
+ * @param type type of represented attribute
+ * @param <T> type of represented attribute
+ * @return new property with custom expression
+ */
+ public static <T extends CharSequence> StringProperty<T> createString(String name, Expression expression, Class<T> type) {
+ return new StringProperty<>(name, expression, type);
+ }
+
+ /**
+ * Create string property
+ *
+ * @param name of the property, will be used as value for path expression
+ * @param type type of represented attribute
+ * @param <T> type of represented attribute
+ * @return new path property
+ */
+ public static <T extends CharSequence> StringProperty<T> createString(String name, Class<T> type) {
+ return createString(name, null, type);
+ }
+
+ /**
+ * Create string property
+ *
+ * @param expression that property will use
+ * @param type type of represented attribute
+ * @param <T> type of represented attribute
+ * @return new property with custom expression without name
+ */
+ public static <T extends CharSequence> StringProperty<T> createString(Expression expression, Class<T> type) {
+ return createString(null, expression, type);
+ }
+
+ // NumericProperty
+
+ /**
+ * Create numeric property
+ *
+ * @param name of the property
+ * @param expression that property will use
+ * @param type type of represented attribute
+ * @param <T> type of represented attribute
+ * @return new property with custom expression
+ */
+ public static <T extends Number> NumericProperty<T> createNumeric(String name, Expression expression, Class<T> type) {
+ return new NumericProperty<>(name, expression, type);
+ }
+
+ /**
+ * Create numeric property
+ *
+ * @param name of the property, will be used as value for path expression
+ * @param type type of represented attribute
+ * @param <T> type of represented attribute
+ * @return new path property
+ */
+ public static <T extends Number> NumericProperty<T> createNumeric(String name, Class<T> type) {
+ return createNumeric(name, null, type);
+ }
+
+ /**
+ * Create numeric property
+ *
+ * @param expression that property will use
+ * @param type type of represented attribute
+ * @param <T> type of represented attribute
+ * @return new property with custom expression without name
+ */
+ public static <T extends Number> NumericProperty<T> createNumeric(Expression expression, Class<T> type) {
+ return createNumeric(null, expression, type);
+ }
+
+ // DateProperty
+
+ /**
+ * Create date property
+ *
+ * @param name of the property
+ * @param expression that property will use
+ * @param type type of represented attribute
+ * @param <T> type of represented attribute
+ * @return new property with custom expression
+ */
+ public static <T> DateProperty<T> createDate(String name, Expression expression, Class<T> type) {
+ return new DateProperty<>(name, expression, type);
+ }
+
+ /**
+ * Create date property
+ *
+ * @param name of the property, will be used as value for path expression
+ * @param type type of represented attribute
+ * @param <T> type of represented attribute
+ * @return new path property
+ */
+ public static <T> DateProperty<T> createDate(String name, Class<T> type) {
+ return createDate(name, null, type);
+ }
+
+ /**
+ * Create date property
+ *
+ * @param expression that property will use
+ * @param type type of represented attribute
+ * @param <T> type of represented attribute
+ * @return new property with custom expression without name
+ */
+ public static <T> DateProperty<T> createDate(Expression expression, Class<T> type) {
+ return createDate(null, expression, type);
+ }
+
+ // ToOne relationship property
+
+ /**
+ * Create entity property
+ *
+ * @param name of the property
+ * @param expression that property will use
+ * @param entityType type of represented relationship entity
+ * @param <T> type of represented relationship entity
+ * @return new property with custom expression
+ */
+ public static <T extends Persistent> EntityProperty<T> createEntity(String name, Expression expression, Class<T> entityType) {
+ return new EntityProperty<>(name, expression, entityType);
+ }
+
+ /**
+ * Create entity property
+ *
+ * @param name of the property, will be used as value for path expression
+ * @param type type of represented relationship entity
+ * @param <T> type of represented relationship entity
+ * @return new path property
+ */
+ public static <T extends Persistent> EntityProperty<T> createEntity(String name, Class<T> type) {
+ return createEntity(name, null, type);
+ }
+
+ /**
+ * Create entity property
+ *
+ * @param expression that property will use
+ * @param type type of represented relationship entity
+ * @param <T> type of represented relationship entity
+ * @return new property with custom expression without name
+ */
+ public static <T extends Persistent> EntityProperty<T> createEntity(Expression expression, Class<T> type) {
+ return createEntity(null, expression, type);
+ }
+
+ // Self properties
+
+ /**
+ * <b>Self</b> property allows to create column queries that return
+ * full objects along with custom column set.
+ * <p>
+ * Usage example, query will return object with dependent objects count:<pre>{@code
+ * List<Object[]> result = ObjectSelect.columnQuery(Artist.class,
+ * PropertyFactory.createSelf(Artist.class),
+ * Artist.PAINTING_ARRAY.count())
+ * .select(context); }</pre>
+ *
+ * @param type of represented entity
+ * @param <T> type of represented entity
+ * @return new 'self' property
+ */
+ public static <T extends Persistent> EntityProperty<T> createSelf(Class<T> type) {
+ return createEntity(ExpressionFactory.fullObjectExp(), type);
+ }
+
+ /**
+ * <b>Self</b> property allows to create column queries that return
+ * full objects along with custom column set.
+ * <p>
+ * This method is not much useful, as to-one property can be used as is in this case,
+ * example is purely for demonstration purpose only. See {@link EntityProperty} usage examples.
+ * <p>
+ * Usage example, query will return object with dependent objects count:<pre>{@code
+ * List<Object[]> result = ObjectSelect.columnQuery(Painting.class,
+ * Painting.PAINTING_TITLE,
+ * PropertyFactory.createSelf(Painting.TO_ARTIST.getExpression(), Painting.class))
+ * .select(context); }</pre>
+ *
+ * @param expression expression to be used for this property (usually it will be path from other property)
+ * @param type of represented entity
+ * @param <T> type of represented entity
+ * @return new 'self' property
+ */
+ public static <T extends Persistent> EntityProperty<T> createSelf(Expression expression, Class<T> type) {
+ return createEntity(ExpressionFactory.fullObjectExp(expression), type);
+ }
+
+ // ToMany relationship properties
+
+ /**
+ * Create to-many relationship mapped on list property
+ *
+ * @param name of the property
+ * @param expression that property will use
+ * @param entityType type of represented relationship entity
+ * @param <T> type of represented relationship entity
+ * @return new property with custom expression
+ */
+ public static <T extends Persistent> ListProperty<T> createList(String name, Expression expression, Class<T> entityType) {
+ return new ListProperty<>(name, expression, entityType);
+ }
+
+ /**
+ * Create to-many relationship mapped on list property
+ *
+ * @param name of the property, will be used as value for path expression
+ * @param entityType type of represented relationship entity
+ * @param <T> type of represented relationship entity
+ * @return new path property
+ */
+ public static <T extends Persistent> ListProperty<T> createList(String name, Class<T> entityType) {
+ return createList(name, null, entityType);
+ }
+
+ /**
+ * Create to-many relationship mapped on set property
+ *
+ * @param name of the property
+ * @param expression that property will use
+ * @param entityType type of represented attribute
+ * @param <T> type of represented attribute
+ * @return new property with custom expression
+ */
+ public static <T extends Persistent> SetProperty<T> createSet(String name, Expression expression, Class<T> entityType) {
+ return new SetProperty<>(name, expression, entityType);
+ }
+
+ /**
+ * Create to-many relationship mapped on set property
+ *
+ * @param name of the property, will be used as value for path expression
+ * @param entityType type of represented relationship entity
+ * @param <T> type of represented relationship entity
+ * @return new path property
+ */
+ public static <T extends Persistent> SetProperty<T> createSet(String name, Class<T> entityType) {
+ return createSet(name, null, entityType);
+ }
+
+ /**
+ * Create to-many relationship mapped on map property
+ *
+ * @param name of the property
+ * @param expression that property will use
+ * @param keyType type of represented relationship keys
+ * @param entityType type of represented relationship values
+ * @param <K> type of represented relationship keys
+ * @param <V> type of represented relationship values
+ * @return new property with custom expression
+ */
+ public static <K, V extends Persistent> MapProperty<K, V> createMap(String name, Expression expression, Class<K> keyType, Class<V> entityType) {
+ return new MapProperty<>(name, expression, keyType, entityType);
+ }
+
+ /**
+ * Create to-many relationship mapped on map property
+ *
+ * @param name of the property, will be used as value for path expression
+ * @param keyType type of represented relationship keys
+ * @param entityType type of represented relationship values
+ * @param <K> type of represented relationship keys
+ * @param <V> type of represented relationship values
+ * @return new path property
+ */
+ public static <K, V extends Persistent> MapProperty<K, V> createMap(String name, Class<K> keyType, Class<V> entityType) {
+ return createMap(name, null, keyType, entityType);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2050c2e1/cayenne-server/src/main/java/org/apache/cayenne/exp/property/RelationshipProperty.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/property/RelationshipProperty.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/RelationshipProperty.java
new file mode 100644
index 0000000..13b9fdc
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/RelationshipProperty.java
@@ -0,0 +1,158 @@
+/*****************************************************************
+ * 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.exp.property;
+
+import org.apache.cayenne.Persistent;
+import org.apache.cayenne.query.PrefetchTreeNode;
+
+/**
+ * Interface (or "Trait") that provides basic functionality for all types of relationships.
+ * <p>
+ * Provides "dot", prefetch and "outer" functionality.
+ *
+ * @see org.apache.cayenne.exp.property
+ * @since 4.2
+ */
+public interface RelationshipProperty<E> extends Property<E> {
+
+ /**
+ * Constructs a property path by appending the argument to the existing property separated by a dot.
+ *
+ * @return a newly created Property object.
+ */
+ default BaseProperty<Object> dot(String property) {
+ return PropertyFactory.createBase(getName() + "." + property, null);
+ }
+
+ /**
+ * Constructs a new property path by appending the argument to the existing property separated by a dot.
+ *
+ * @param property to append to path
+ * @return a newly created Property object.
+ */
+ default <T> BaseProperty<T> dot(BaseProperty<T> property) {
+ return PropertyFactory.createBase(getName() + "." + property.getName(), property.getType());
+ }
+
+ /**
+ * Constructs a new property path by appending the argument to the existing property separated by a dot.
+ *
+ * @param property to append to path
+ * @return a newly created Property object.
+ */
+ default <T extends Number> NumericProperty<T> dot(NumericProperty<T> property) {
+ return PropertyFactory.createNumeric(getName() + "." + property.getName(), property.getType());
+ }
+
+ /**
+ * Constructs a new property path by appending the argument to the existing property separated by a dot.
+ *
+ * @param property to append to path
+ * @return a newly created Property object.
+ */
+ default <T extends CharSequence> StringProperty<T> dot(StringProperty<T> property) {
+ return PropertyFactory.createString(getName() + "." + property.getName(), property.getType());
+ }
+
+ /**
+ * Constructs a new property path by appending the argument to the existing property separated by a dot.
+ *
+ * @param property to append to path
+ * @return a newly created Property object.
+ */
+ default <T> DateProperty<T> dot(DateProperty<T> property) {
+ return PropertyFactory.createDate(getName() + "." + property.getName(), property.getType());
+ }
+
+ /**
+ * Constructs a new property path by appending the argument to the existing property separated by a dot.
+ *
+ * @param property to append to path
+ * @return a newly created Property object.
+ */
+ default <T extends Persistent> EntityProperty<T> dot(EntityProperty<T> property) {
+ return PropertyFactory.createEntity(getName() + "." + property.getName(), property.getType());
+ }
+
+ /**
+ * Constructs a new property path by appending the argument to the existing property separated by a dot.
+ *
+ * @param property to append to path
+ * @return a newly created Property object.
+ */
+ default <T extends Persistent> ListProperty<T> dot(ListProperty<T> property) {
+ return PropertyFactory.createList(getName() + "." + property.getName(), property.getEntityType());
+ }
+
+ /**
+ * Constructs a new property path by appending the argument to the existing property separated by a dot.
+ *
+ * @param property to append to path
+ * @return a newly created Property object.
+ */
+ default <T extends Persistent> SetProperty<T> dot(SetProperty<T> property) {
+ return PropertyFactory.createSet(getName() + "." + property.getName(), property.getEntityType());
+ }
+
+ /**
+ * Constructs a new property path by appending the argument to the existing property separated by a dot.
+ *
+ * @param property to append to path
+ * @return a newly created Property object.
+ */
+ default <K, V extends Persistent> MapProperty<K, V> dot(MapProperty<K, V> property) {
+ return PropertyFactory.createMap(getName() + "." + property.getName(), property.getKeyType(), property.getEntityType());
+ }
+
+ /**
+ * Returns a version of this property that represents an OUTER join. It is
+ * up to caller to ensure that the property corresponds to a relationship,
+ * as "outer" attributes make no sense.
+ */
+ BaseProperty<E> outer();
+
+ /**
+ * Returns a prefetch tree that follows this property path, potentially
+ * spanning a number of phantom nodes, and having a single leaf with "joint"
+ * prefetch semantics.
+ */
+ default PrefetchTreeNode joint() {
+ return PrefetchTreeNode.withPath(getName(), PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
+ }
+
+ /**
+ * Returns a prefetch tree that follows this property path, potentially
+ * spanning a number of phantom nodes, and having a single leaf with
+ * "disjoint" prefetch semantics.
+ */
+ default PrefetchTreeNode disjoint() {
+ return PrefetchTreeNode.withPath(getName(), PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS);
+ }
+
+ /**
+ * Returns a prefetch tree that follows this property path, potentially
+ * spanning a number of phantom nodes, and having a single leaf with
+ * "disjoint by id" prefetch semantics.
+ */
+ default PrefetchTreeNode disjointById() {
+ return PrefetchTreeNode.withPath(getName(), PrefetchTreeNode.DISJOINT_BY_ID_PREFETCH_SEMANTICS);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2050c2e1/cayenne-server/src/main/java/org/apache/cayenne/exp/property/SetProperty.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/property/SetProperty.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/SetProperty.java
new file mode 100644
index 0000000..f7ded0b
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/SetProperty.java
@@ -0,0 +1,63 @@
+/*****************************************************************
+ * 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.exp.property;
+
+import java.util.Set;
+
+import org.apache.cayenne.Persistent;
+import org.apache.cayenne.exp.Expression;
+
+/**
+ * Property that represents to-many relationship mapped on {@link Set}.
+ *
+ * @see org.apache.cayenne.exp.property
+ * @since 4.2
+ */
+public class SetProperty<V extends Persistent> extends CollectionProperty<V, Set<V>> {
+
+ /**
+ * Constructs a new property with the given name and expression
+ *
+ * @param name of the property (will be used as alias for the expression)
+ * @param expression expression for property
+ * @param entityType type of related entity
+ */
+ protected SetProperty(String name, Expression expression, Class<V> entityType) {
+ super(name, expression, Set.class, entityType);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public SetProperty<V> alias(String alias) {
+ return PropertyFactory.createSet(alias, this.getExpression(), this.getEntityType());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public SetProperty<V> outer() {
+ return getName().endsWith("+")
+ ? this
+ : PropertyFactory.createSet(getName() + "+", getEntityType());
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2050c2e1/cayenne-server/src/main/java/org/apache/cayenne/exp/property/StringProperty.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/property/StringProperty.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/StringProperty.java
new file mode 100644
index 0000000..87a6e0f
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/StringProperty.java
@@ -0,0 +1,304 @@
+/*****************************************************************
+ * 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.exp.property;
+
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.exp.FunctionExpressionFactory;
+
+/**
+ * Property that represents attributes mapped on string types
+ * <p>
+ * String type is an any type inherited from {@link CharSequence}.
+ * <p>
+ * Provides basic string functions like {@link #like(String)}, {@link #concat(Object...)}, {@link #upper()}
+ * and {@link #contains(String)}}.
+ * <p>
+ * Example:<pre>{@code
+ * ObjectSelect.query(Artist.class)
+ * .where(Artist.FIRST_NAME.trim().concat(Artist.LAST_NAME.trim()).length().gt(30))
+ * }</pre>
+ *
+ * @see org.apache.cayenne.exp.property
+ * @since 4.2
+ */
+public class StringProperty<E extends CharSequence> extends BaseProperty<E> {
+
+ /**
+ * Constructs a new property with the given name and expression
+ *
+ * @param name of the property (will be used as alias for the expression)
+ * @param expression expression for property
+ * @param type of the property
+ * @see PropertyFactory#createString(String, Expression, Class)
+ */
+ protected StringProperty(String name, Expression expression, Class<E> type) {
+ super(name, expression, type);
+ }
+
+ /**
+ * @param pattern a pattern matching property value. Pattern may include "_" and
+ * "%" wildcard symbols to match any single character or a
+ * sequence of characters. To prevent "_" and "%" from being
+ * treated as wildcards, they need to be escaped and escape char
+ * passed with {@link #like(String, char)} method.
+ * @return An expression for a Database "LIKE" query.
+ */
+ public Expression like(String pattern) {
+ return ExpressionFactory.likeExp(getExpression(), pattern);
+ }
+
+ /**
+ * @param pattern a pattern matching property value. Pattern may include "_" and
+ * "%" wildcard symbols to match any single character or a
+ * sequence of characters.
+ * @return An expression for a Database "LIKE" query.
+ */
+ public Expression like(StringProperty<?> pattern) {
+ return ExpressionFactory.likeExp(getExpression(), pattern.getExpression());
+ }
+
+ /**
+ * @param pattern a properly escaped pattern matching property value. Pattern
+ * may include "_" and "%" wildcard symbols to match any single
+ * character or a sequence of characters.
+ * @param escapeChar an escape character used in the pattern to escape "%" and "_".
+ * @return An expression for a Database "LIKE" query.
+ */
+ public Expression like(String pattern, char escapeChar) {
+ return ExpressionFactory.likeExp(getExpression(), pattern, escapeChar);
+ }
+
+ /**
+ * @return An expression for a case insensitive "LIKE" query.
+ */
+ public Expression likeIgnoreCase(String pattern) {
+ return ExpressionFactory.likeIgnoreCaseExp(getExpression(), pattern);
+ }
+
+ /**
+ * @return An expression for a case insensitive "LIKE" query.
+ */
+ public Expression likeIgnoreCase(StringProperty<?> pattern) {
+ return ExpressionFactory.likeIgnoreCaseExp(getExpression(), pattern.getExpression());
+ }
+
+ /**
+ * @return An expression for a Database "NOT LIKE" query.
+ */
+ public Expression nlike(String value) {
+ return ExpressionFactory.notLikeExp(getExpression(), value);
+ }
+
+ /**
+ * @return An expression for a Database "NOT LIKE" query.
+ */
+ public Expression nlike(StringProperty<?> value) {
+ return ExpressionFactory.notLikeExp(getExpression(), value.getExpression());
+ }
+
+ /**
+ * @return An expression for a case insensitive "NOT LIKE" query.
+ */
+ public Expression nlikeIgnoreCase(String value) {
+ return ExpressionFactory.notLikeIgnoreCaseExp(getExpression(), value);
+ }
+
+ /**
+ * @return An expression for a case insensitive "NOT LIKE" query.
+ */
+ public Expression nlikeIgnoreCase(StringProperty<?> value) {
+ return ExpressionFactory.notLikeIgnoreCaseExp(getExpression(), value.getExpression());
+ }
+
+ /**
+ * Creates an expression for a database "LIKE" query with the value converted to a pattern matching anywhere in the
+ * String.
+ *
+ * @param substring a String to match against property value. "_" and "%" symbols
+ * are NOT treated as wildcards and are escaped when converted to
+ * a LIKE expression.
+ * @return a newly created expression.
+ */
+ public Expression contains(String substring) {
+ return ExpressionFactory.containsExp(getExpression(), substring);
+ }
+
+ /**
+ * Creates an expression for a database "LIKE" query with the value converted to a pattern matching the beginning of
+ * a String.
+ *
+ * @param value a String to match against property value. "_" and "%" symbols
+ * are NOT treated as wildcards and are escaped when converted to
+ * a LIKE expression.
+ * @return a newly created expression.
+ */
+ public Expression startsWith(String value) {
+ return ExpressionFactory.startsWithExp(getExpression(), value);
+ }
+
+ /**
+ * Creates an expression for a database "LIKE" query with the value
+ * converted to a pattern matching the tail of a String.
+ *
+ * @param value a String to match against property value. "_" and "%" symbols
+ * are NOT treated as wildcards and are escaped when converted to
+ * a LIKE expression.
+ * @return a newly created expression.
+ */
+ public Expression endsWith(String value) {
+ return ExpressionFactory.endsWithExp(getExpression(), value);
+ }
+
+ /**
+ * Same as {@link #contains(String)}, only using case-insensitive
+ * comparison.
+ */
+ public Expression containsIgnoreCase(String value) {
+ return ExpressionFactory.containsIgnoreCaseExp(getExpression(), value);
+ }
+
+ /**
+ * Same as {@link #startsWith(String)}, only using case-insensitive
+ * comparison.
+ */
+ public Expression startsWithIgnoreCase(String value) {
+ return ExpressionFactory.startsWithIgnoreCaseExp(getExpression(), value);
+ }
+
+ /**
+ * Same as {@link #endsWith(String)}, only using case-insensitive
+ * comparison.
+ */
+ public Expression endsWithIgnoreCase(String value) {
+ return ExpressionFactory.endsWithIgnoreCaseExp(getExpression(), value);
+ }
+
+ /**
+ * @see FunctionExpressionFactory#lengthExp(Expression)
+ */
+ public NumericProperty<Integer> length() {
+ return PropertyFactory.createNumeric(
+ FunctionExpressionFactory.lengthExp(getExpression()),
+ Integer.class
+ );
+ }
+
+ /**
+ * @see FunctionExpressionFactory#locateExp(String, Expression)
+ */
+ public NumericProperty<Integer> locate(String string) {
+ return PropertyFactory.createNumeric(
+ FunctionExpressionFactory.locateExp(ExpressionFactory.wrapScalarValue(string), getExpression()),
+ Integer.class
+ );
+ }
+
+ /**
+ * @see FunctionExpressionFactory#locateExp(Expression, Expression)
+ */
+ public NumericProperty<Integer> locate(StringProperty<? extends String> property) {
+ return PropertyFactory.createNumeric(
+ FunctionExpressionFactory.locateExp(property.getExpression(), getExpression()),
+ Integer.class
+ );
+ }
+
+ /**
+ * @see FunctionExpressionFactory#trimExp(Expression)
+ */
+ public StringProperty<String> trim() {
+ return PropertyFactory.createString(FunctionExpressionFactory.trimExp(getExpression()), String.class);
+ }
+
+ /**
+ * @see FunctionExpressionFactory#upperExp(Expression)
+ */
+ public StringProperty<String> upper() {
+ return PropertyFactory.createString(FunctionExpressionFactory.upperExp(getExpression()), String.class);
+ }
+
+ /**
+ * @see FunctionExpressionFactory#lowerExp(Expression)
+ */
+ public StringProperty<String> lower() {
+ return PropertyFactory.createString(FunctionExpressionFactory.lowerExp(getExpression()), String.class);
+ }
+
+ /**
+ * <p>Arguments will be converted as follows:
+ * <ul>
+ * <li>if argument is a {@link BaseProperty} than its expression will be used</li>
+ * <li>if argument is a {@link Expression} than it will be used as is </li>
+ * <li>all other values will be converted to String</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Usage:
+ * <pre>{@code
+ * Property<String> fullName = Artist.FIRST_NAME.concat(" ", Artist.SECOND_NAME);
+ * }</pre>
+ * </p>
+ * @see FunctionExpressionFactory#concatExp(Expression...)
+ */
+ public StringProperty<String> concat(Object... args) {
+ Expression[] exp = new Expression[args.length + 1];
+ int i = 0;
+ exp[i++] = getExpression();
+ for(Object arg : args) {
+ if(arg instanceof BaseProperty) {
+ exp[i++] = ((BaseProperty) arg).getExpression();
+ } else if(arg instanceof Expression) {
+ exp[i++] = (Expression) arg;
+ } else if(arg != null) {
+ exp[i++] = ExpressionFactory.wrapScalarValue(arg.toString());
+ }
+ }
+ return PropertyFactory.createString(FunctionExpressionFactory.concatExp(exp), String.class);
+ }
+
+ /**
+ * @see FunctionExpressionFactory#substringExp(Expression, int, int)
+ */
+ public StringProperty<String> substring(int offset, int length) {
+ return PropertyFactory.createString(
+ FunctionExpressionFactory.substringExp(getExpression(), offset, length),
+ String.class
+ );
+ }
+
+ /**
+ * @see FunctionExpressionFactory#substringExp(Expression, Expression, Expression)
+ */
+ public StringProperty<String> substring(NumericProperty<?> offset, NumericProperty<?> length) {
+ return PropertyFactory.createString(
+ FunctionExpressionFactory.substringExp(getExpression(), offset.getExpression(), length.getExpression()),
+ String.class
+ );
+ }
+
+ /**
+ * Creates alias with different name for this property
+ */
+ @Override
+ public StringProperty<E> alias(String alias) {
+ return PropertyFactory.createString(alias, this.getExpression(), this.getType());
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2050c2e1/cayenne-server/src/main/java/org/apache/cayenne/exp/property/package-info.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/property/package-info.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/package-info.java
new file mode 100644
index 0000000..79bc254
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/property/package-info.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.
+ ****************************************************************/
+
+/**
+ * <h3>Property API</h3>
+ * <p>
+ * This API allows to use type aware {@link org.apache.cayenne.exp.Expression expression} factories aka Properties.<br>
+ * These properties are normally generated as static constants in model classes, but they can also be created manually by
+ * {@link org.apache.cayenne.exp.property.PropertyFactory} if needed.
+ * <p>
+ * Typical usage in select queries:
+ * <pre>{@code
+ * Painting painting = ...
+ * Artist artist = ObjectSelect.query(Artist.class)
+ * .where(Artist.PAINTING_ARRAY.contains(painting))
+ * .and(Artist.DATE_OF_BIRTH.year().gt(1950))
+ * .and(Artist.ARTIST_NAME.like("Pablo%"))
+ * .orderBy(Artist.ARTIST_NAME.asc())
+ * .prefetch(Artist.PAINTING_ARRAY.disjointById())
+ * .selectOne(context);
+ * }</pre>
+ * <p>
+ * Currently supported Property types:
+ * <ul>
+ * <li>{@link org.apache.cayenne.exp.property.NumericProperty} for all data types inherited from {@link java.lang.Number}.<br>
+ * Supports comparision and math functions (like {@link org.apache.cayenne.exp.property.NumericProperty#sqrt() sqrt()}).
+ * <br>
+ * <li>{@link org.apache.cayenne.exp.property.StringProperty} for all data types inherited from {@link java.lang.CharSequence}.<br>
+ * Supports multiple string functions ({@link org.apache.cayenne.exp.property.StringProperty#like(java.lang.String) like()},
+ * {@link org.apache.cayenne.exp.property.StringProperty#concat(java.lang.Object...) concat()}, etc.)
+ * <br>
+ * <li>{@link org.apache.cayenne.exp.property.DateProperty} for {@link java.util.Date} (and {@link java.sql} variants)
+ * and {@link java.time.LocalDate}, {@link java.time.LocalTime}, {@link java.time.LocalDateTime}.<br>
+ * Supports date functions like {@link org.apache.cayenne.exp.property.DateProperty#year() year()}.
+ * <br>
+ * <li>{@link org.apache.cayenne.exp.property.EntityProperty} for to-one relationships.<br>
+ * Supports prefetch related methods, {@link org.apache.cayenne.exp.property.RelationshipProperty#dot(org.apache.cayenne.exp.property.BaseProperty) dot()} methods, etc.
+ * <br>
+ * <li>{@link org.apache.cayenne.exp.property.ListProperty}, {@link org.apache.cayenne.exp.property.SetProperty}
+ * and {@link org.apache.cayenne.exp.property.MapProperty} are for to-many relationships.<br>
+ * In addition to to-one related methods these properties support collection comparision methods
+ * like {@link org.apache.cayenne.exp.property.ListProperty#contains(org.apache.cayenne.Persistent) contains()}.
+ * <br>
+ * <li>{@link org.apache.cayenne.exp.property.BaseProperty} for all other data types, supports basic operations (equality, sorting).
+ * </ul>
+ *
+ * @since 4.2
+ */
+package org.apache.cayenne.exp.property;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2050c2e1/cayenne-server/src/main/java/org/apache/cayenne/query/ColumnSelect.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/query/ColumnSelect.java b/cayenne-server/src/main/java/org/apache/cayenne/query/ColumnSelect.java
index f72fc85..35c36f2 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/query/ColumnSelect.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/query/ColumnSelect.java
@@ -26,9 +26,13 @@ import java.util.Collection;
import java.util.Collections;
import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.exp.property.BaseProperty;
import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.exp.property.ComparableProperty;
+import org.apache.cayenne.exp.property.NumericProperty;
import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.PropertyFactory;
import org.apache.cayenne.map.DbEntity;
import org.apache.cayenne.map.EntityResolver;
import org.apache.cayenne.map.ObjEntity;
@@ -56,13 +60,13 @@ import org.apache.cayenne.map.ObjEntity;
* </pre>
* </p>
* <p><b>Note: this class can't be instantiated directly. Use {@link ObjectSelect}.</b></p>
- * @see ObjectSelect#columnQuery(Class, Property)
+ * @see ObjectSelect#columnQuery(Class, BaseProperty)
*
* @since 4.0
*/
public class ColumnSelect<T> extends FluentSelect<T> {
- private Collection<Property<?>> columns;
+ private Collection<BaseProperty<?>> columns;
private boolean havingExpressionIsActive = false;
// package private for tests
boolean singleColumn = true;
@@ -137,7 +141,6 @@ public class ColumnSelect<T> extends FluentSelect<T> {
return resetEntity(null, null, dbEntityName);
}
- @SuppressWarnings("unchecked")
private ColumnSelect<T> resetEntity(Class<?> entityType, String entityName, String dbEntityName) {
this.entityType = entityType;
this.entityName = entityName;
@@ -185,7 +188,6 @@ public class ColumnSelect<T> extends FluentSelect<T> {
*
* @return this object
*/
- @SuppressWarnings("unchecked")
public ColumnSelect<T> or(Expression... expressions) {
if (expressions == null || expressions.length == 0) {
return this;
@@ -440,11 +442,11 @@ public class ColumnSelect<T> extends FluentSelect<T> {
*
* @param firstProperty first property
* @param otherProperties array of properties to select
- * @see ColumnSelect#column(Property)
+ * @see ColumnSelect#column(BaseProperty)
* @see ColumnSelect#columns(Collection)
*/
@SuppressWarnings("unchecked")
- public ColumnSelect<Object[]> columns(Property<?> firstProperty, Property<?>... otherProperties) {
+ public ColumnSelect<Object[]> columns(BaseProperty<?> firstProperty, BaseProperty<?>... otherProperties) {
if (columns == null) {
columns = new ArrayList<>(otherProperties.length + 1);
}
@@ -461,10 +463,10 @@ public class ColumnSelect<T> extends FluentSelect<T> {
* (root entity properties, function call expressions, properties of relationships, etc).</p>
* <p>
* @param properties collection of properties, <b>must</b> contain at least one element
- * @see ColumnSelect#columns(Property, Property[])
+ * @see ColumnSelect#columns(BaseProperty, BaseProperty[])
*/
@SuppressWarnings("unchecked")
- public ColumnSelect<Object[]> columns(Collection<Property<?>> properties) {
+ public ColumnSelect<Object[]> columns(Collection<BaseProperty<?>> properties) {
if (properties == null){
throw new NullPointerException("properties is null");
}
@@ -483,7 +485,7 @@ public class ColumnSelect<T> extends FluentSelect<T> {
}
@SuppressWarnings("unchecked")
- protected <E> ColumnSelect<E> column(Property<E> property) {
+ protected <E> ColumnSelect<E> column(BaseProperty<E> property) {
if (this.columns == null) {
this.columns = new ArrayList<>(1);
} else {
@@ -495,10 +497,10 @@ public class ColumnSelect<T> extends FluentSelect<T> {
}
/**
- * <p>Shortcut for {@link #columns(Property, Property[])} columns}(Property.COUNT)</p>
+ * <p>Shortcut for {@link #columns(BaseProperty, BaseProperty[])} columns}(Property.COUNT)</p>
*/
public ColumnSelect<Object[]> count() {
- return columns(Property.COUNT);
+ return columns(PropertyFactory.COUNT);
}
/**
@@ -506,43 +508,63 @@ public class ColumnSelect<T> extends FluentSelect<T> {
* <p>Can return different result than COUNT(*) as it will count only non null values</p>
* @see ColumnSelect#count()
*/
- public ColumnSelect<Object[]> count(Property<?> property) {
+ public ColumnSelect<Object[]> count(BaseProperty<?> property) {
return columns(property.count());
}
/**
* <p>Select minimum value of property</p>
- * @see ColumnSelect#columns(Property, Property[])
+ * @see ColumnSelect#columns(BaseProperty, BaseProperty[])
*/
- public ColumnSelect<Object[]> min(Property<?> property) {
+ public ColumnSelect<Object[]> min(ComparableProperty<?> property) {
return columns(property.min());
}
/**
* <p>Select maximum value of property</p>
- * @see ColumnSelect#columns(Property, Property[])
+ * @see ColumnSelect#columns(BaseProperty, BaseProperty[])
*/
- public ColumnSelect<Object[]> max(Property<?> property) {
+ public ColumnSelect<Object[]> max(ComparableProperty<?> property) {
return columns(property.max());
}
/**
* <p>Select average value of property</p>
- * @see ColumnSelect#columns(Property, Property[])
+ * @see ColumnSelect#columns(BaseProperty, BaseProperty[])
+ * @deprecated since 4.2 use {@link #avg(NumericProperty)}
*/
+ @Deprecated
public ColumnSelect<Object[]> avg(Property<?> property) {
return columns(property.avg());
}
/**
+ * <p>Select average value of property</p>
+ * @see ColumnSelect#columns(BaseProperty, BaseProperty[])
+ */
+ public ColumnSelect<Object[]> avg(NumericProperty<?> property) {
+ return columns(property.avg());
+ }
+
+ /**
* <p>Select sum of values</p>
- * @see ColumnSelect#columns(Property, Property[])
+ * @see ColumnSelect#columns(BaseProperty, BaseProperty[])
+ * @deprecated since 4.2 use {@link #sum(NumericProperty)}
*/
+ @Deprecated
public <E extends Number> ColumnSelect<Object[]> sum(Property<E> property) {
return columns(property.sum());
}
/**
+ * <p>Select sum of values</p>
+ * @see ColumnSelect#columns(BaseProperty, BaseProperty[])
+ */
+ public <E extends Number> ColumnSelect<Object[]> sum(NumericProperty<E> property) {
+ return columns(property.sum());
+ }
+
+ /**
* Appends a having qualifier expression of this query. An equivalent to
* {@link #and(Expression...)} that can be used a syntactic sugar.
*
@@ -653,7 +675,7 @@ public class ColumnSelect<T> extends FluentSelect<T> {
}
}
- public Collection<Property<?>> getColumns() {
+ public Collection<BaseProperty<?>> getColumns() {
return columns;
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2050c2e1/cayenne-server/src/main/java/org/apache/cayenne/query/ObjectSelect.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/query/ObjectSelect.java b/cayenne-server/src/main/java/org/apache/cayenne/query/ObjectSelect.java
index f5e3c99..e1e6942 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/query/ObjectSelect.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/query/ObjectSelect.java
@@ -20,9 +20,13 @@ package org.apache.cayenne.query;
import org.apache.cayenne.DataRow;
import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.exp.property.BaseProperty;
import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.exp.property.ComparableProperty;
+import org.apache.cayenne.exp.property.NumericProperty;
import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.PropertyFactory;
import org.apache.cayenne.map.DbEntity;
import org.apache.cayenne.map.EntityResolver;
import org.apache.cayenne.map.ObjEntity;
@@ -131,7 +135,7 @@ public class ObjectSelect<T> extends FluentSelect<T> {
* @param entityType base persistent class that will be used as a root for this query
* @param column single column to select
*/
- public static <E> ColumnSelect<E> columnQuery(Class<?> entityType, Property<E> column) {
+ public static <E> ColumnSelect<E> columnQuery(Class<?> entityType, BaseProperty<E> column) {
return new ColumnSelect<>().entityType(entityType).column(column);
}
@@ -142,7 +146,7 @@ public class ObjectSelect<T> extends FluentSelect<T> {
* @param firstColumn column to select
* @param otherColumns columns to select
*/
- public static ColumnSelect<Object[]> columnQuery(Class<?> entityType, Property<?> firstColumn, Property<?>... otherColumns) {
+ public static ColumnSelect<Object[]> columnQuery(Class<?> entityType, BaseProperty<?> firstColumn, BaseProperty<?>... otherColumns) {
return new ColumnSelect<Object[]>().entityType(entityType).columns(firstColumn, otherColumns);
}
@@ -560,9 +564,9 @@ public class ObjectSelect<T> extends FluentSelect<T> {
* </pre>
*
* @param properties array of properties to select
- * @see ObjectSelect#column(Property)
+ * @see ObjectSelect#column(BaseProperty)
*/
- public ColumnSelect<Object[]> columns(Property<?> firstProperty, Property<?>... properties) {
+ public ColumnSelect<Object[]> columns(BaseProperty<?> firstProperty, BaseProperty<?>... properties) {
return new ColumnSelect<>(this).columns(firstProperty, properties);
}
@@ -570,7 +574,7 @@ public class ObjectSelect<T> extends FluentSelect<T> {
* <p>Select one specific property.</p>
* <p>Can be any property that can be resolved against root entity type
* (root entity's property, function call expression, property of relationships, etc)</p>
- * <p>If you need several columns use {@link ObjectSelect#columns(Property, Property[])} method.</p>
+ * <p>If you need several columns use {@link ObjectSelect#columns(BaseProperty, BaseProperty[])} method.</p>
* <p>
* <pre>
* {@code
@@ -581,63 +585,99 @@ public class ObjectSelect<T> extends FluentSelect<T> {
* </pre>
* </p>
* @param property single property to select
- * @see ObjectSelect#columns(Property, Property[])
+ * @see ObjectSelect#columns(BaseProperty, BaseProperty[])
*/
- public <E> ColumnSelect<E> column(Property<E> property) {
+ public <E> ColumnSelect<E> column(BaseProperty<E> property) {
return new ColumnSelect<>(this).column(property);
}
/**
* Select COUNT(*)
- * @see ObjectSelect#column(Property)
+ * @see ObjectSelect#column(BaseProperty)
*/
public ColumnSelect<Long> count() {
- return column(Property.COUNT);
+ return column(PropertyFactory.COUNT);
}
/**
* <p>Select COUNT(property)</p>
* <p>Can return different result than COUNT(*) as it will count only non null values</p>
* @see ObjectSelect#count()
- * @see ObjectSelect#column(Property)
+ * @see ObjectSelect#column(BaseProperty)
*/
- public ColumnSelect<Long> count(Property<?> property) {
+ public ColumnSelect<Long> count(BaseProperty<?> property) {
return column(property.count());
}
/**
* <p>Select minimum value of property</p>
- * @see ObjectSelect#column(Property)
+ * @see ObjectSelect#column(BaseProperty)
*/
- public <E> ColumnSelect<E> min(Property<E> property) {
+ public <E> ColumnSelect<E> min(ComparableProperty<E> property) {
return column(property.min());
}
/**
+ * <p>Select minimum value of property</p>
+ * @see ObjectSelect#column(BaseProperty)
+ */
+ public <E extends Number> ColumnSelect<E> min(NumericProperty<E> property) {
+ return column(property.min());
+ }
+
+ /**
+ * <p>Select maximum value of property</p>
+ * @see ObjectSelect#column(BaseProperty)
+ */
+ public <E> ColumnSelect<E> max(ComparableProperty<E> property) {
+ return column(property.max());
+ }
+
+ /**
* <p>Select maximum value of property</p>
- * @see ObjectSelect#column(Property)
+ * @see ObjectSelect#column(BaseProperty)
*/
- public <E> ColumnSelect<E> max(Property<E> property) {
+ public <E extends Number> ColumnSelect<E> max(NumericProperty<E> property) {
return column(property.max());
}
/**
* <p>Select average value of property</p>
- * @see ObjectSelect#column(Property)
+ * @see ObjectSelect#column(BaseProperty)
+ * @deprecated since 4.2 use {@link #avg(NumericProperty)}
*/
+ @Deprecated
public <E> ColumnSelect<E> avg(Property<E> property) {
return column(property.avg());
}
/**
+ * <p>Select average value of property</p>
+ * @see ObjectSelect#column(BaseProperty)
+ */
+ public <E extends Number> ColumnSelect<E> avg(NumericProperty<E> property) {
+ return column(property.avg());
+ }
+
+ /**
* <p>Select sum of values</p>
- * @see ObjectSelect#column(Property)
+ * @see ObjectSelect#column(BaseProperty)
+ * @deprecated since 4.2 use {@link #sum(NumericProperty)}
*/
+ @Deprecated
public <E extends Number> ColumnSelect<E> sum(Property<E> property) {
return column(property.sum());
}
/**
+ * <p>Select sum of values</p>
+ * @see ObjectSelect#column(BaseProperty)
+ */
+ public <E extends Number> ColumnSelect<E> sum(NumericProperty<E> property) {
+ return column(property.sum());
+ }
+
+ /**
* <p>Quick way to select count of records</p>
* <p>Usage:
* <pre>
http://git-wip-us.apache.org/repos/asf/cayenne/blob/2050c2e1/cayenne-server/src/main/java/org/apache/cayenne/query/SelectQuery.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/query/SelectQuery.java b/cayenne-server/src/main/java/org/apache/cayenne/query/SelectQuery.java
index 405ef2b..8534335 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/query/SelectQuery.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/query/SelectQuery.java
@@ -24,17 +24,12 @@ import org.apache.cayenne.ObjectContext;
import org.apache.cayenne.ResultBatchIterator;
import org.apache.cayenne.ResultIterator;
import org.apache.cayenne.ResultIteratorCallback;
-import org.apache.cayenne.configuration.ConfigurationNodeVisitor;
+import org.apache.cayenne.exp.property.BaseProperty;
import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.exp.ExpressionFactory;
-import org.apache.cayenne.exp.Property;
import org.apache.cayenne.map.DbEntity;
import org.apache.cayenne.map.EntityResolver;
import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.map.Procedure;
-import org.apache.cayenne.map.QueryDescriptor;
-import org.apache.cayenne.util.XMLEncoder;
-import org.apache.cayenne.util.XMLSerializable;
import java.util.ArrayList;
import java.util.Arrays;
@@ -63,7 +58,7 @@ public class SelectQuery<T> extends AbstractQuery implements ParameterizedQuery,
/**
* @since 4.0
*/
- protected Collection<Property<?>> columns;
+ protected Collection<BaseProperty<?>> columns;
/**
* @since 4.0
@@ -760,14 +755,14 @@ public class SelectQuery<T> extends AbstractQuery implements ParameterizedQuery,
* @since 4.0
* @see SelectQuery#setCanReturnScalarValue(boolean)
*/
- public void setColumns(Collection<Property<?>> columns) {
+ public void setColumns(Collection<BaseProperty<?>> columns) {
this.columns = columns;
}
/**
* @since 4.0
*/
- public void setColumns(Property<?>... columns) {
+ public void setColumns(BaseProperty<?>... columns) {
if(columns == null || columns.length == 0) {
return;
}
@@ -797,7 +792,7 @@ public class SelectQuery<T> extends AbstractQuery implements ParameterizedQuery,
/**
* @since 4.0
*/
- public Collection<Property<?>> getColumns() {
+ public Collection<BaseProperty<?>> getColumns() {
return columns;
}