You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2008/12/28 00:18:21 UTC
svn commit: r729693 - in
/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src:
main/java/org/apache/cayenne/access/select/ main/java/org/apache/cayenne/map/
test/java/org/apache/cayenne/access/select/
Author: aadamchik
Date: Sat Dec 27 15:18:20 2008
New Revision: 729693
URL: http://svn.apache.org/viewvc?rev=729693&view=rev
Log:
CAY-1162 SelectDescriptor concept
basic support for inheritance
Added:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/DiscriminatorBuilder.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntityTreeSegmentBuilder.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/MappedColumnBuilder.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/select/
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/select/EntityTreeSegmentBuilderTest.java
Modified:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntityRowReader.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntitySegment.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntitySegmentBuilder.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntitySelectColumn.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntityTreeRowReader.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/SelectDescriptorBuilder.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityInheritanceTree.java
Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/DiscriminatorBuilder.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/DiscriminatorBuilder.java?rev=729693&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/DiscriminatorBuilder.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/DiscriminatorBuilder.java Sat Dec 27 15:18:20 2008
@@ -0,0 +1,82 @@
+/*****************************************************************
+ * 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.select;
+
+import java.util.List;
+
+import org.apache.cayenne.access.types.ExtendedTypeMap;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.TraversalHelper;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.EntityInheritanceTree;
+import org.apache.cayenne.map.ObjEntity;
+
+/**
+ * @since 3.0
+ */
+class DiscriminatorBuilder extends MappedColumnBuilder {
+
+ private EntityInheritanceTree node;
+
+ DiscriminatorBuilder(ExtendedTypeMap extendedTypes, EntityInheritanceTree node) {
+ super(extendedTypes);
+ this.node = node;
+ }
+
+ List<EntitySelectColumn> buildColumns() {
+ appendColumns(node);
+ return columns;
+ }
+
+ private void appendColumns(EntityInheritanceTree node) {
+
+ ObjEntity entity = node.getEntity();
+ if (!entity.isAbstract()) {
+
+ Expression qualifier = entity.getDeclaredQualifier();
+ if (qualifier != null) {
+ appendColumns(qualifier);
+ }
+ }
+
+ for (EntityInheritanceTree childNode : node.getChildren()) {
+ appendColumns(childNode);
+ }
+ }
+
+ private void appendColumns(Expression expression) {
+
+ final ObjEntity entity = node.getEntity();
+ final DbEntity dbEntity = entity.getDbEntity();
+
+ // find and register discriminator columns
+ expression.traverse(new TraversalHelper() {
+
+ @Override
+ public void startNode(Expression node, Expression parentNode) {
+ if (node.getType() == Expression.DB_PATH) {
+ append(dbEntity, node);
+ }
+ else if (node.getType() == Expression.OBJ_PATH) {
+ append(entity, node);
+ }
+ }
+ });
+ }
+}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntityRowReader.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntityRowReader.java?rev=729693&r1=729692&r2=729693&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntityRowReader.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntityRowReader.java Sat Dec 27 15:18:20 2008
@@ -33,6 +33,7 @@
*/
class EntityRowReader implements RowReader<Object> {
+ private EntityRowReader superReader;
private ExtendedType[] converters;
private String[] dataRowKeys;
private int[] jdbcTypes;
@@ -41,25 +42,53 @@
private int mapCapacity;
EntityRowReader(String entityName, List<EntitySelectColumn> columns) {
+
int len = columns.size();
+ int[] columnIndexes = new int[len];
+
+ for (int i = 0; i < len; i++) {
+ columnIndexes[i] = i + 1;
+ }
+
+ init(entityName, columns, columnIndexes);
+ }
+ EntityRowReader(String entityName, List<EntitySelectColumn> columns,
+ int[] columnIndexes) {
+ init(entityName, columns, columnIndexes);
+ }
+
+ private void init(
+ String entityName,
+ List<EntitySelectColumn> columns,
+ int[] columnIndexes) {
+ this.entityName = entityName;
+
+ int len = columns.size();
this.mapCapacity = (int) Math.ceil(len / 0.75);
this.converters = new ExtendedType[len];
this.dataRowKeys = new String[len];
this.jdbcTypes = new int[len];
- this.columnIndexes = new int[len];
+ this.columnIndexes = columnIndexes;
for (int i = 0; i < len; i++) {
converters[i] = columns.get(i).getConverter();
dataRowKeys[i] = columns.get(i).getDataRowKey();
jdbcTypes[i] = columns.get(i).getJdbcType();
- columnIndexes[i] = i + 1;
+ }
+ }
+
+ void setSuperReader(EntityRowReader superReader) {
+ this.superReader = superReader;
+
+ if (superReader != null) {
+ mapCapacity += superReader.mapCapacity;
}
}
public void setColumnOffset(int offset) {
for (int i = 0; i < columnIndexes.length; i++) {
- columnIndexes[i] = i + offset + 1;
+ columnIndexes[i] = columnIndexes[i] + offset;
}
}
@@ -67,6 +96,16 @@
DataRow row = new DataRow(mapCapacity);
row.setEntityName(entityName);
+ if (superReader != null) {
+ superReader.fillRow(resultSet, row);
+ }
+
+ fillRow(resultSet, row);
+
+ return row;
+ }
+
+ private final void fillRow(ResultSet resultSet, DataRow row) throws CayenneException {
int len = converters.length;
try {
@@ -85,7 +124,6 @@
throw new CayenneException("Exception materializing row", Util
.unwindException(ex));
}
-
- return row;
}
+
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntitySegment.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntitySegment.java?rev=729693&r1=729692&r2=729693&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntitySegment.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntitySegment.java Sat Dec 27 15:18:20 2008
@@ -28,19 +28,23 @@
*/
class EntitySegment implements SelectDescriptor<Object> {
- private List<? extends SelectColumn> columns;
+ private List<EntitySelectColumn> columns;
private RowReader<Object> rowReader;
- EntitySegment(RowReader<Object> rowReader, List<? extends SelectColumn> columns) {
+ EntitySegment(RowReader<Object> rowReader, List<EntitySelectColumn> columns) {
this.columns = columns;
this.rowReader = rowReader;
}
+
+ RowReader<Object> getRowReader() {
+ return rowReader;
+ }
- public List<? extends SelectColumn> getColumns() {
+ public List<EntitySelectColumn> getColumns() {
return columns;
}
public RowReader<Object> getRowReader(ResultSet resultSet) throws CayenneException {
- return rowReader;
+ return getRowReader();
}
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntitySegmentBuilder.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntitySegmentBuilder.java?rev=729693&r1=729692&r2=729693&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntitySegmentBuilder.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntitySegmentBuilder.java Sat Dec 27 15:18:20 2008
@@ -18,46 +18,34 @@
****************************************************************/
package org.apache.cayenne.access.select;
-import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import org.apache.cayenne.access.types.ExtendedTypeMap;
-import org.apache.cayenne.dba.TypesMapping;
import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
import org.apache.cayenne.map.DbJoin;
import org.apache.cayenne.map.DbRelationship;
import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.map.ObjEntity;
import org.apache.cayenne.map.ObjRelationship;
import org.apache.cayenne.query.QueryMetadata;
-import org.apache.cayenne.reflect.ClassDescriptor;
/**
* @since 3.0
*/
-class EntitySegmentBuilder {
+class EntitySegmentBuilder extends MappedColumnBuilder {
- private QueryMetadata metadata;
- private ExtendedTypeMap extendedTypes;
- private List<EntitySelectColumn> columns;
- private Map<DbAttribute, Integer> columnMap;
- private DbEntity dbEntity;
- private ClassDescriptor classDescriptor;
+ protected QueryMetadata metadata;
+ protected ObjEntity entity;
EntitySegmentBuilder(QueryMetadata metadata, ExtendedTypeMap extendedTypes,
- ClassDescriptor classDescriptor, DbEntity dbEntity) {
+ ObjEntity entity) {
- this.columns = new ArrayList<EntitySelectColumn>();
- this.columnMap = new HashMap<DbAttribute, Integer>();
- this.dbEntity = dbEntity;
- this.classDescriptor = classDescriptor;
+ super(extendedTypes);
+ this.entity = entity;
this.metadata = metadata;
- this.extendedTypes = extendedTypes;
}
- SelectDescriptor<Object> getDescriptor() {
+ List<EntitySelectColumn> buildColumns() {
if (metadata.getPageSize() > 0) {
appendId();
}
@@ -65,6 +53,13 @@
appendAll();
}
+ return columns;
+ }
+
+ EntitySegment buildSegment() {
+
+ buildColumns();
+
RowReader<Object> rowReader;
// read single column ID as scalar
if (metadata.getPageSize() > 0 && columns.size() == 1) {
@@ -72,15 +67,13 @@
rowReader = new ScalarRowReader(column.getConverter(), column.getJdbcType());
}
else {
- rowReader = new EntityRowReader(
- classDescriptor.getEntity().getName(),
- columns);
+ rowReader = new EntityRowReader(entity.getName(), columns);
}
return new EntitySegment(rowReader, columns);
}
- private void appendId() {
+ protected void appendId() {
// append meaningful attributes prior to any special DbAttributes; this way if
// there is an overlap between meaningful and Db attributes, the right Java
// type will be used.
@@ -88,7 +81,7 @@
appendIdDbAttributes();
}
- private void appendAll() {
+ protected void appendAll() {
// append meaningful attributes prior to any special DbAttributes; this way if
// there is an overlap between meaningful and Db attributes, the right Java
// type will be used.
@@ -99,86 +92,48 @@
appendJointPrefetches();
}
- private void appendIdObjAttributes() {
- for (ObjAttribute attribute : classDescriptor.getEntity().getDeclaredAttributes()) {
+ protected void appendIdObjAttributes() {
+ for (ObjAttribute attribute : entity.getDeclaredAttributes()) {
if (attribute.isPrimaryKey()) {
- appendObjAttribute(attribute);
+ append(attribute);
}
}
}
- private void appendObjAttributes() {
- for (ObjAttribute attribute : classDescriptor.getEntity().getDeclaredAttributes()) {
- appendObjAttribute(attribute);
+ protected void appendObjAttributes() {
+ for (ObjAttribute attribute : entity.getDeclaredAttributes()) {
+ append(attribute);
}
}
- private void appendIdDbAttributes() {
- for (DbAttribute attribute : dbEntity.getPrimaryKeys()) {
- appendDbAttrribute(attribute);
+ protected void appendIdDbAttributes() {
+
+ // if this ObjENtity inherits DbEntity from super, we will rely in super
+ // descriptor to map ID columns
+ if (entity.getDbEntityName() != null) {
+ for (DbAttribute attribute : entity.getDbEntity().getPrimaryKeys()) {
+ append(attribute);
+ }
}
}
- private void appendFK() {
- for (ObjRelationship relationship : classDescriptor
- .getEntity()
- .getDeclaredRelationships()) {
+ protected void appendFK() {
+ for (ObjRelationship relationship : entity.getDeclaredRelationships()) {
DbRelationship dbRel = relationship.getDbRelationships().get(0);
List<DbJoin> joins = dbRel.getJoins();
int len = joins.size();
for (int i = 0; i < len; i++) {
- appendDbAttrribute(joins.get(i).getSource());
+ append(joins.get(i).getSource());
}
}
}
- private void appendJointPrefetches() {
+ protected void appendJointPrefetches() {
if (metadata.getPrefetchTree() != null) {
throw new UnsupportedOperationException("TODO: joint prefetches");
}
}
-
- private void appendObjAttribute(ObjAttribute attribute) {
- EntitySelectColumn column = new EntitySelectColumn();
-
- DbAttribute dbAttribute = attribute.getDbAttribute();
-
- // void column
- if (dbAttribute == null) {
- int jdbcType = TypesMapping.getSqlTypeByJava(attribute.getType());
- column.setColumnName(TypesMapping.isNumeric(jdbcType) ? "1" : "'1'");
- column.setJdbcType(jdbcType);
- }
- else {
- column.setColumnName(dbAttribute.getName());
- column.setJdbcType(dbAttribute.getType());
- }
-
- column.setDataRowKey(attribute.getDbAttributePath());
- column.setPath(attribute);
- column.setConverter(extendedTypes.getRegisteredType(attribute.getType()));
-
- columnMap.put(dbAttribute, columns.size());
- columns.add(column);
- }
-
- private void appendDbAttrribute(DbAttribute attribute) {
- // skip if already appended via ObjAttributes
- if (!columnMap.containsKey(attribute)) {
-
- EntitySelectColumn column = new EntitySelectColumn();
- column.setColumnName(attribute.getName());
- column.setJdbcType(attribute.getType());
- column.setDataRowKey(attribute.getName());
-
- String javaType = TypesMapping.getJavaBySqlType(attribute.getType());
- column.setConverter(extendedTypes.getRegisteredType(javaType));
-
- columnMap.put(attribute, columns.size());
- columns.add(column);
- }
- }
-}
\ No newline at end of file
+}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntitySelectColumn.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntitySelectColumn.java?rev=729693&r1=729692&r2=729693&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntitySelectColumn.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntitySelectColumn.java Sat Dec 27 15:18:20 2008
@@ -18,14 +18,11 @@
****************************************************************/
package org.apache.cayenne.access.select;
-import java.util.ArrayList;
import java.util.Collections;
-import java.util.Iterator;
import java.util.List;
import org.apache.cayenne.access.types.ExtendedType;
import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.ObjAttribute;
/**
* @since 3.0
@@ -71,19 +68,7 @@
this.jdbcType = jdbcType;
}
- void setPath(ObjAttribute attribute) {
-
- List<DbRelationship> path = new ArrayList<DbRelationship>(2);
- Iterator<?> it = attribute.getDbPathIterator();
- while (it.hasNext()) {
- Object pathComponent = it.next();
- if (!(pathComponent instanceof DbRelationship)) {
- break;
- }
-
- path.add((DbRelationship) pathComponent);
- }
-
+ void setPath(List<DbRelationship> path) {
this.path = path;
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntityTreeRowReader.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntityTreeRowReader.java?rev=729693&r1=729692&r2=729693&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntityTreeRowReader.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntityTreeRowReader.java Sat Dec 27 15:18:20 2008
@@ -32,15 +32,15 @@
class EntityTreeRowReader implements RowReader<Object> {
private RowReader<?> discriminatorReader;
- private Expression[] discriminatorExpressions;
- private RowReader<Object>[] rowReaders;
+ private Expression[] entityQualifiers;
+ private RowReader<Object>[] entityReaders;
- EntityTreeRowReader(RowReader<?> discriminatorReader,
- Expression[] discriminatorExpressions, RowReader<Object>[] rowReaders) {
+ EntityTreeRowReader(RowReader<?> discriminatorReader, Expression[] entityQualifiers,
+ RowReader<Object>[] entityReaders) {
this.discriminatorReader = discriminatorReader;
- this.discriminatorExpressions = discriminatorExpressions;
- this.rowReaders = rowReaders;
+ this.entityQualifiers = entityQualifiers;
+ this.entityReaders = entityReaders;
}
public void setColumnOffset(int offset) {
@@ -52,14 +52,17 @@
Map<String, Object> discriminator = (Map<String, Object>) discriminatorReader
.readRow(resultSet);
- int len = discriminatorExpressions.length;
- for (int i = 0; i < len; i++) {
+ // read qualifiers list in reverse order to ensure that for each superclass,
+ // subclass qualifiers are run first... This way we can even support empty
+ // qualifier superclasses.
+ int len = entityQualifiers.length;
+ for (int i = len - 1; i >= 0; i--) {
// TODO: andrus, 12/25/2008 - Expression in-memory evaluation for each row in
// a ResultSet will be a very slow operation. This procedure should be
// optimized somehow...
- if (discriminatorExpressions[i].match(discriminator)) {
- return rowReaders[i].readRow(resultSet);
+ if (entityQualifiers[i].match(discriminator)) {
+ return entityReaders[i].readRow(resultSet);
}
}
Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntityTreeSegmentBuilder.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntityTreeSegmentBuilder.java?rev=729693&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntityTreeSegmentBuilder.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntityTreeSegmentBuilder.java Sat Dec 27 15:18:20 2008
@@ -0,0 +1,157 @@
+/*****************************************************************
+ * 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.select;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cayenne.access.types.ExtendedTypeMap;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.parser.ASTTrue;
+import org.apache.cayenne.map.EntityInheritanceTree;
+import org.apache.cayenne.query.QueryMetadata;
+import org.apache.cayenne.reflect.ClassDescriptor;
+
+/**
+ * @since 3.0
+ */
+class EntityTreeSegmentBuilder {
+
+ private QueryMetadata metadata;
+ protected ExtendedTypeMap extendedTypes;
+
+ private List<Expression> entityQualifiers;
+ private List<RowReader<?>> entityReaders;
+
+ protected ClassDescriptor classDescriptor;
+ protected List<EntitySelectColumn> columns;
+ protected Map<String, Integer> columnMap;
+
+ EntityTreeSegmentBuilder(QueryMetadata metadata, ExtendedTypeMap extendedTypes,
+ ClassDescriptor classDescriptor) {
+
+ this.metadata = metadata;
+ this.extendedTypes = extendedTypes;
+ this.classDescriptor = classDescriptor;
+
+ this.entityQualifiers = new ArrayList<Expression>();
+ this.entityReaders = new ArrayList<RowReader<?>>();
+ this.columns = new ArrayList<EntitySelectColumn>();
+ this.columnMap = new HashMap<String, Integer>();
+ }
+
+ SelectDescriptor<Object> getDescriptor() {
+
+ EntityInheritanceTree inheritanceTree = classDescriptor
+ .getEntityInheritanceTree();
+
+ if (inheritanceTree == null) {
+ throw new IllegalStateException(
+ "EntityNonUnionTreeSegmentBuilder should only be used when inheritance is involved.");
+ }
+
+ appendColumns(inheritanceTree, null);
+
+ RowReader<Object> discriminatorReader = mergeColumns(
+ null,
+ new DiscriminatorBuilder(extendedTypes, inheritanceTree).buildColumns());
+
+ int size = this.entityQualifiers.size();
+ Expression[] entityQualifiers = this.entityQualifiers
+ .toArray(new Expression[size]);
+ RowReader<Object>[] entityReaders = this.entityReaders
+ .toArray(new RowReader[size]);
+ RowReader<Object> rowReader = new EntityTreeRowReader(
+ discriminatorReader,
+ entityQualifiers,
+ entityReaders);
+ return new EntitySegment(rowReader, columns);
+ }
+
+ /**
+ * Merges subsegment columns into the main columns list, generating a RowReader for
+ * subsegment.
+ */
+ private EntityRowReader mergeColumns(
+ String entityName,
+ List<EntitySelectColumn> columnsToMerge) {
+
+ int[] indexes = new int[columnsToMerge.size()];
+
+ for (int i = 0; i < indexes.length; i++) {
+
+ EntitySelectColumn column = columnsToMerge.get(i);
+
+ Integer columnIndex = columnMap.get(column.getDataRowKey());
+ if (columnIndex == null) {
+ columnIndex = columns.size();
+ columnMap.put(column.getDataRowKey(), columnIndex);
+ columns.add(column);
+ }
+
+ indexes[i] = columnIndex.intValue() + 1;
+ }
+
+ return new EntityRowReader(entityName, columnsToMerge, indexes);
+ }
+
+ private void appendColumns(EntityInheritanceTree node, EntityRowReader superReader) {
+
+ EntityRowReader reader = processNode(node);
+ reader.setSuperReader(superReader);
+
+ for (EntityInheritanceTree childNode : node.getChildren()) {
+ appendColumns(childNode, reader);
+ }
+ }
+
+ private EntityRowReader processNode(EntityInheritanceTree node) {
+
+ List<EntitySelectColumn> entityColumns = new EntitySegmentBuilder(
+ metadata,
+ extendedTypes,
+ node.getEntity()).buildColumns();
+
+ // merge columns
+ EntityRowReader rowReader = mergeColumns(
+ node.getEntity().getName(),
+ entityColumns);
+
+ // record entity qualifier and row reader...
+ if (!node.getEntity().isAbstract()) {
+
+ // register DB qualifier
+ Expression qualifier = node.getDbQualifier();
+
+ if (qualifier == null) {
+ qualifier = new ASTTrue();
+ }
+
+ entityQualifiers.add(qualifier);
+
+ // TODO: this row reader has incorrect offset and doesn't take into account
+ // superclass columns
+ entityReaders.add(rowReader);
+ }
+
+ return rowReader;
+ }
+}
Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/MappedColumnBuilder.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/MappedColumnBuilder.java?rev=729693&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/MappedColumnBuilder.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/MappedColumnBuilder.java Sat Dec 27 15:18:20 2008
@@ -0,0 +1,192 @@
+/*****************************************************************
+ * 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.select;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cayenne.access.types.ExtendedTypeMap;
+import org.apache.cayenne.dba.TypesMapping;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.ObjRelationship;
+import org.apache.cayenne.map.PathComponent;
+
+/**
+ * @since 3.0
+ */
+abstract class MappedColumnBuilder {
+
+ protected List<EntitySelectColumn> columns;
+ protected Map<String, Integer> columnMap;
+ protected ExtendedTypeMap extendedTypes;
+
+ MappedColumnBuilder(ExtendedTypeMap extendedTypes) {
+ this.columns = new ArrayList<EntitySelectColumn>();
+ this.columnMap = new HashMap<String, Integer>();
+ this.extendedTypes = extendedTypes;
+ }
+
+ /**
+ * Appends an ObjAttribute belonging to a root ObjEntity.
+ */
+ protected void append(ObjAttribute attribute) {
+
+ if (!columnMap.containsKey(attribute.getDbAttributePath())) {
+
+ List<DbRelationship> path = new ArrayList<DbRelationship>(2);
+ Iterator<?> it = attribute.getDbPathIterator();
+ while (it.hasNext()) {
+ Object pathComponent = it.next();
+ if (!(pathComponent instanceof DbRelationship)) {
+ break;
+ }
+
+ path.add((DbRelationship) pathComponent);
+ }
+
+ makeColumn(attribute.getDbAttributePath(), attribute, path);
+ }
+ }
+
+ /**
+ * Appends a DbAttribute belonging to a root DbEntity.
+ */
+ protected void append(DbAttribute attribute) {
+ // skip if already appended via ObjAttributes
+ if (!columnMap.containsKey(attribute.getName())) {
+ makeColumn(attribute.getName(), attribute, null);
+ }
+ }
+
+ /**
+ * Appends a column matching a path Expression rooted in DbEntity.
+ */
+ protected void append(DbEntity root, Expression dbPath) {
+
+ String pathString = dbPath.getOperand(0).toString();
+ if (!columnMap.containsKey(pathString)) {
+
+ List<DbRelationship> relationships = null;
+
+ for (PathComponent<DbAttribute, DbRelationship> c : root.resolvePath(
+ dbPath,
+ Collections.emptyMap())) {
+
+ if (c.isLast()) {
+ makeColumn(pathString, c.getAttribute(), relationships);
+ }
+ else {
+
+ if (relationships == null) {
+ relationships = new ArrayList<DbRelationship>(2);
+ }
+
+ relationships.add(c.getRelationship());
+ }
+ }
+ }
+ }
+
+ /**
+ * Appends a column matching a path Expression rooted in ObjEntity.
+ */
+ protected void append(ObjEntity root, Expression objPath) {
+
+ Expression dbPath = root.translateToDbPath(objPath);
+ String pathString = dbPath.getOperand(0).toString();
+ if (!columnMap.containsKey(pathString)) {
+
+ List<DbRelationship> relationships = null;
+
+ for (PathComponent<ObjAttribute, ObjRelationship> c : root.resolvePath(
+ objPath,
+ Collections.emptyMap())) {
+
+ if (c.isLast()) {
+ makeColumn(pathString, c.getAttribute(), relationships);
+ }
+ else {
+
+ if (relationships == null) {
+ relationships = new ArrayList<DbRelationship>(2);
+ }
+
+ relationships.addAll(c.getRelationship().getDbRelationships());
+ }
+ }
+ }
+ }
+
+ private EntitySelectColumn makeColumn(
+ String dataRowKey,
+ ObjAttribute attribute,
+ List<DbRelationship> relationships) {
+
+ EntitySelectColumn column = new EntitySelectColumn();
+ DbAttribute dbAttribute = attribute.getDbAttribute();
+
+ // void column
+ if (dbAttribute == null) {
+ int jdbcType = TypesMapping.getSqlTypeByJava(attribute.getType());
+ column.setColumnName(TypesMapping.isNumeric(jdbcType) ? "1" : "'1'");
+ column.setJdbcType(jdbcType);
+ }
+ else {
+ column.setColumnName(dbAttribute.getName());
+ column.setJdbcType(dbAttribute.getType());
+ }
+
+ column.setDataRowKey(dataRowKey);
+ column.setConverter(extendedTypes.getRegisteredType(attribute.getType()));
+ column.setPath(relationships);
+
+ columnMap.put(dataRowKey, columns.size());
+ columns.add(column);
+
+ return column;
+ }
+
+ private EntitySelectColumn makeColumn(
+ String dataRowKey,
+ DbAttribute attribute,
+ List<DbRelationship> relationships) {
+ EntitySelectColumn column = new EntitySelectColumn();
+ column.setColumnName(attribute.getName());
+ column.setJdbcType(attribute.getType());
+ column.setDataRowKey(dataRowKey);
+
+ String javaType = TypesMapping.getJavaBySqlType(attribute.getType());
+ column.setConverter(extendedTypes.getRegisteredType(javaType));
+ column.setPath(relationships);
+
+ columnMap.put(dataRowKey, columns.size());
+ columns.add(column);
+
+ return column;
+ }
+}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/SelectDescriptorBuilder.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/SelectDescriptorBuilder.java?rev=729693&r1=729692&r2=729693&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/SelectDescriptorBuilder.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/SelectDescriptorBuilder.java Sat Dec 27 15:18:20 2008
@@ -124,14 +124,12 @@
}
if (classDescriptor.getEntityInheritanceTree() != null) {
- throw new UnsupportedOperationException("TODO: Inheritance aware queries");
+ return new EntityTreeSegmentBuilder(metadata, extendedTypes, classDescriptor)
+ .getDescriptor();
}
else {
- return new EntitySegmentBuilder(
- metadata,
- extendedTypes,
- classDescriptor,
- classDescriptor.getEntity().getDbEntity()).getDescriptor();
+ return new EntitySegmentBuilder(metadata, extendedTypes, classDescriptor
+ .getEntity()).buildSegment();
}
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityInheritanceTree.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityInheritanceTree.java?rev=729693&r1=729692&r2=729693&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityInheritanceTree.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityInheritanceTree.java Sat Dec 27 15:18:20 2008
@@ -87,19 +87,33 @@
}
}
- Expression qualifier = entity.getDeclaredQualifier();
+ Expression qualifier = getDbQualifier();
if (qualifier != null) {
- if (normalizedQualifier == null) {
- normalizedQualifier = entity.translateToDbPath(qualifier);
- }
-
- return normalizedQualifier.match(row) ? entity : null;
+ return qualifier.match(row) ? entity : null;
}
// no qualifier ... matches all rows
return entity;
}
+ /**
+ * Returns entity qualifier expressed as DB path qualifier or null if entity has no
+ * qualifier.
+ *
+ * @since 3.0
+ */
+ public Expression getDbQualifier() {
+ if (entity.getDeclaredQualifier() == null) {
+ return null;
+ }
+
+ if (normalizedQualifier == null) {
+ normalizedQualifier = entity.translateToDbPath(entity.getDeclaredQualifier());
+ }
+
+ return normalizedQualifier;
+ }
+
public void addChildNode(EntityInheritanceTree node) {
if (subentities == null) {
subentities = new ArrayList<EntityInheritanceTree>(2);
Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/select/EntityTreeSegmentBuilderTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/select/EntityTreeSegmentBuilderTest.java?rev=729693&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/select/EntityTreeSegmentBuilderTest.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/select/EntityTreeSegmentBuilderTest.java Sat Dec 27 15:18:20 2008
@@ -0,0 +1,147 @@
+/*****************************************************************
+ * 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.select;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cayenne.DataRow;
+import org.apache.cayenne.access.types.ExtendedTypeMap;
+import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.query.QueryMetadata;
+import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.reflect.ClassDescriptor;
+import org.apache.cayenne.testdo.inherit.AbstractPerson;
+import org.apache.cayenne.unit.PeopleCase;
+
+import com.mockrunner.mock.jdbc.MockResultSet;
+
+public class EntityTreeSegmentBuilderTest extends PeopleCase {
+
+ public void testGetDescriptorColumns() {
+
+ SelectQuery query = new SelectQuery(AbstractPerson.class);
+
+ EntityResolver resolver = getDomain().getEntityResolver();
+ QueryMetadata md = query.getMetaData(resolver);
+ ClassDescriptor descriptor = md.getClassDescriptor();
+ ExtendedTypeMap converters = getDomain()
+ .getDataNodes()
+ .iterator()
+ .next()
+ .getAdapter()
+ .getExtendedTypes();
+
+ SelectDescriptor<Object> select = new EntityTreeSegmentBuilder(
+ md,
+ converters,
+ descriptor).getDescriptor();
+
+ List<? extends SelectColumn> columns = select.getColumns();
+
+ Collection<String> columnNames = new ArrayList<String>(Arrays.asList(
+ "CLIENT_COMPANY_ID",
+ "CLIENT_CONTACT_TYPE",
+ "DEPARTMENT_ID",
+ "NAME",
+ "PERSON_ID",
+ "PERSON_TYPE",
+ "SALARY"));
+
+ for (SelectColumn column : columns) {
+ columnNames.remove(column.getDataRowKey());
+ }
+
+ assertTrue("Missing columns: " + columnNames, columnNames.isEmpty());
+ assertEquals("Unexpected columns present", 7, columns.size());
+ }
+
+ public void testGetDescriptorRowReader() throws Exception {
+ SelectQuery query = new SelectQuery(AbstractPerson.class);
+
+ EntityResolver resolver = getDomain().getEntityResolver();
+ QueryMetadata md = query.getMetaData(resolver);
+ ClassDescriptor descriptor = md.getClassDescriptor();
+ ExtendedTypeMap converters = getDomain()
+ .getDataNodes()
+ .iterator()
+ .next()
+ .getAdapter()
+ .getExtendedTypes();
+
+ SelectDescriptor<Object> select = new EntityTreeSegmentBuilder(
+ md,
+ converters,
+ descriptor).getDescriptor();
+
+ List<? extends SelectColumn> columns = select.getColumns();
+
+ Map<String, Object> employeeRowMap = new HashMap<String, Object>();
+ employeeRowMap.put("PERSON_ID", 1);
+ employeeRowMap.put("PERSON_TYPE", "EE");
+ employeeRowMap.put("NAME", "E1");
+ employeeRowMap.put("SALARY", new Float(1.0));
+ employeeRowMap.put("DEPARTMENT_ID", 1);
+
+ Map<String, Object> managerRowMap = new HashMap<String, Object>();
+ managerRowMap.put("PERSON_ID", 2);
+ managerRowMap.put("PERSON_TYPE", "EM");
+ managerRowMap.put("NAME", "E2");
+ managerRowMap.put("SALARY", new Float(2.0));
+ managerRowMap.put("DEPARTMENT_ID", 2);
+
+ Map<String, Object> crRowMap = new HashMap<String, Object>();
+ crRowMap.put("PERSON_ID", 3);
+ crRowMap.put("PERSON_TYPE", "C");
+ crRowMap.put("NAME", "E2");
+ crRowMap.put("CLIENT_CONTACT_TYPE", "XX");
+ crRowMap.put("CLIENT_COMPANY_ID", 3);
+
+ List<Object> employeeRow = new ArrayList<Object>();
+ List<Object> managerRow = new ArrayList<Object>();
+ List<Object> crRow = new ArrayList<Object>();
+
+ MockResultSet rs = new MockResultSet("test");
+ for (SelectColumn column : columns) {
+ rs.addColumn(column.getColumnName(0, null));
+
+ employeeRow.add(employeeRowMap.get(column.getDataRowKey()));
+ managerRow.add(managerRowMap.get(column.getDataRowKey()));
+ crRow.add(crRowMap.get(column.getDataRowKey()));
+ }
+
+ rs.addRow(employeeRow);
+ rs.addRow(managerRow);
+ rs.addRow(crRow);
+
+ RowReader<Object> reader = select.getRowReader(rs);
+
+ rs.next();
+ DataRow employeeRowRead = (DataRow) reader.readRow(rs);
+ assertEquals("Employee", employeeRowRead.getEntityName());
+ assertEquals(
+ "Invalid row read: " + employeeRowRead,
+ employeeRowMap,
+ employeeRowRead);
+ }
+}