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/26 12:50:31 UTC
svn commit: r729484 - in
/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select:
EntitySegmentBuilder.java EntityTreeRowReader.java
SelectDescriptorBuilder.java
Author: aadamchik
Date: Fri Dec 26 03:50:31 2008
New Revision: 729484
URL: http://svn.apache.org/viewvc?rev=729484&view=rev
Log:
CAY-1162 SelectDescriptor concept
support for inheritance
Added:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntityTreeRowReader.java
Modified:
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/SelectDescriptorBuilder.java
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=729484&r1=729483&r2=729484&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 Fri Dec 26 03:50:31 2008
@@ -19,12 +19,10 @@
package org.apache.cayenne.access.select;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import org.apache.cayenne.CayenneRuntimeException;
import org.apache.cayenne.access.types.ExtendedTypeMap;
import org.apache.cayenne.dba.TypesMapping;
import org.apache.cayenne.map.DbAttribute;
@@ -33,7 +31,6 @@
import org.apache.cayenne.map.DbRelationship;
import org.apache.cayenne.map.ObjAttribute;
import org.apache.cayenne.map.ObjRelationship;
-import org.apache.cayenne.query.EntityResultSegment;
import org.apache.cayenne.query.QueryMetadata;
import org.apache.cayenne.reflect.ClassDescriptor;
@@ -44,220 +41,144 @@
private QueryMetadata metadata;
private ExtendedTypeMap extendedTypes;
-
- EntitySegmentBuilder(ExtendedTypeMap extendedTypes, QueryMetadata metadata) {
- this.extendedTypes = extendedTypes;
+ private List<EntitySelectColumn> columns;
+ private Map<DbAttribute, Integer> columnMap;
+ private DbEntity dbEntity;
+ private ClassDescriptor classDescriptor;
+
+ EntitySegmentBuilder(QueryMetadata metadata, ExtendedTypeMap extendedTypes,
+ ClassDescriptor classDescriptor, DbEntity dbEntity) {
+
+ this.columns = new ArrayList<EntitySelectColumn>();
+ this.columnMap = new HashMap<DbAttribute, Integer>();
+ this.dbEntity = dbEntity;
+ this.classDescriptor = classDescriptor;
this.metadata = metadata;
+ this.extendedTypes = extendedTypes;
}
- SelectDescriptor<Object> getSegment(int position) {
-
- ClassDescriptor rootDescriptor;
- EntityResultSegment segmentMetadata;
-
- List<Object> segmentDesriptors = metadata.getResultSetMapping();
- if (segmentDesriptors != null) {
- segmentMetadata = (EntityResultSegment) segmentDesriptors.get(position);
- rootDescriptor = segmentMetadata.getClassDescriptor();
- }
- else {
- segmentMetadata = null;
- rootDescriptor = metadata.getClassDescriptor();
- }
-
- // no ObjEntity and Java class at the root of the query...
- if (rootDescriptor == null) {
- DbEntity dbEntity = metadata.getDbEntity();
- if (dbEntity == null) {
- throw new CayenneRuntimeException("Invalid entity segment in position "
- + position
- + ", no root DbEntity specified");
- }
-
- return forDbEntity(dbEntity, segmentMetadata);
- }
-
- return forEntity(rootDescriptor, segmentMetadata);
- }
-
- private SelectDescriptor<Object> forEntity(
- ClassDescriptor rootDescriptor,
- EntityResultSegment segmentMetadata) {
-
- Collection<DbEntity> unionRoots = rootDescriptor.getRootDbEntities();
- if (unionRoots.size() == 1) {
- return forSingleSelectEntity(rootDescriptor, segmentMetadata, unionRoots
- .iterator()
- .next());
- }
- else {
- return forUnionSelectEntity(rootDescriptor, segmentMetadata, unionRoots);
- }
-
- }
-
- private SelectDescriptor<Object> forSingleSelectEntity(
- ClassDescriptor rootDescriptor,
- EntityResultSegment segmentMetadata,
- DbEntity root) {
-
- EntityColumnAppender appender = new EntityColumnAppender(rootDescriptor, root);
-
+ SelectDescriptor<Object> getDescriptor() {
if (metadata.getPageSize() > 0) {
- appender.appendId();
+ appendId();
}
else {
- appender.appendAll();
+ appendAll();
}
RowReader<Object> rowReader;
// read single column ID as scalar
- if (metadata.getPageSize() > 0 && appender.columns.size() == 1) {
- EntitySelectColumn column = appender.columns.get(0);
+ if (metadata.getPageSize() > 0 && columns.size() == 1) {
+ EntitySelectColumn column = columns.get(0);
rowReader = new ScalarRowReader(column.getConverter(), column.getJdbcType());
}
else {
rowReader = new EntityRowReader(
- rootDescriptor.getEntity().getName(),
- appender.columns);
+ classDescriptor.getEntity().getName(),
+ columns);
}
- return new EntitySegment(rowReader, appender.columns);
+ return new EntitySegment(rowReader, columns);
}
- private SelectDescriptor<Object> forUnionSelectEntity(
- ClassDescriptor rootDescriptor,
- EntityResultSegment segmentMetadata,
- Collection<DbEntity> unionRoots) {
- // TODO: union query
- throw new UnsupportedOperationException("TODO: union query");
+ private 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.
+ appendIdObjAttributes();
+ appendIdDbAttributes();
}
- private SelectDescriptor<Object> forDbEntity(
- DbEntity dbEntity,
- EntityResultSegment segmentMetadata) {
- // TODO - queries with DbEntity root
- throw new UnsupportedOperationException("TODO");
- }
+ private 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.
+ appendObjAttributes();
- class EntityColumnAppender {
+ appendIdDbAttributes();
+ appendFK();
+ appendJointPrefetches();
+ }
- List<EntitySelectColumn> columns;
- Map<DbAttribute, Integer> columnMap;
- DbEntity dbEntity;
- ClassDescriptor classDescriptor;
+ private void appendIdObjAttributes() {
+ for (ObjAttribute attribute : classDescriptor.getEntity().getDeclaredAttributes()) {
- EntityColumnAppender(ClassDescriptor classDescriptor, DbEntity dbEntity) {
- this.columns = new ArrayList<EntitySelectColumn>();
- this.columnMap = new HashMap<DbAttribute, Integer>();
- this.dbEntity = dbEntity;
- this.classDescriptor = classDescriptor;
+ if (attribute.isPrimaryKey()) {
+ appendObjAttribute(attribute);
+ }
}
+ }
- 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.
- appendIdObjAttributes();
- appendIdDbAttributes();
+ private void appendObjAttributes() {
+ for (ObjAttribute attribute : classDescriptor.getEntity().getDeclaredAttributes()) {
+ appendObjAttribute(attribute);
}
+ }
- 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.
- appendObjAttributes();
-
- appendIdDbAttributes();
- appendFK();
- appendJointPrefetches();
+ private void appendIdDbAttributes() {
+ for (DbAttribute attribute : dbEntity.getPrimaryKeys()) {
+ appendDbAttrribute(attribute);
}
+ }
- private void appendIdObjAttributes() {
- for (ObjAttribute attribute : classDescriptor
- .getEntity()
- .getDeclaredAttributes()) {
+ private void appendFK() {
+ for (ObjRelationship relationship : classDescriptor
+ .getEntity()
+ .getDeclaredRelationships()) {
- if (attribute.isPrimaryKey()) {
- appendObjAttribute(attribute);
- }
- }
- }
+ DbRelationship dbRel = relationship.getDbRelationships().get(0);
- private void appendObjAttributes() {
- for (ObjAttribute attribute : classDescriptor
- .getEntity()
- .getDeclaredAttributes()) {
- appendObjAttribute(attribute);
+ List<DbJoin> joins = dbRel.getJoins();
+ int len = joins.size();
+ for (int i = 0; i < len; i++) {
+ appendDbAttrribute(joins.get(i).getSource());
}
}
+ }
- private void appendIdDbAttributes() {
- for (DbAttribute attribute : dbEntity.getPrimaryKeys()) {
- appendDbAttrribute(attribute);
- }
+ private void appendJointPrefetches() {
+ if (metadata.getPrefetchTree() != null) {
+ throw new UnsupportedOperationException("TODO: joint prefetches");
}
+ }
- private void appendFK() {
- for (ObjRelationship relationship : classDescriptor
- .getEntity()
- .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());
- }
- }
- }
+ private void appendObjAttribute(ObjAttribute attribute) {
+ EntitySelectColumn column = new EntitySelectColumn();
- private void appendJointPrefetches() {
- if (metadata.getPrefetchTree() != null) {
- throw new UnsupportedOperationException("TODO: joint prefetches");
- }
- }
+ DbAttribute dbAttribute = attribute.getDbAttribute();
- 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());
+ }
- // 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()));
- column.setDataRowKey(attribute.getDbAttributePath());
- column.setPath(attribute);
- column.setConverter(extendedTypes.getRegisteredType(attribute.getType()));
+ columnMap.put(dbAttribute, columns.size());
+ columns.add(column);
+ }
- columnMap.put(dbAttribute, columns.size());
- columns.add(column);
- }
+ private void appendDbAttrribute(DbAttribute attribute) {
+ // skip if already appended via ObjAttributes
+ if (!columnMap.containsKey(attribute)) {
- 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());
+ 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));
+ String javaType = TypesMapping.getJavaBySqlType(attribute.getType());
+ column.setConverter(extendedTypes.getRegisteredType(javaType));
- columnMap.put(attribute, columns.size());
- columns.add(column);
- }
+ columnMap.put(attribute, columns.size());
+ columns.add(column);
}
}
-}
+}
\ No newline at end of file
Added: 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=729484&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntityTreeRowReader.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/select/EntityTreeRowReader.java Fri Dec 26 03:50:31 2008
@@ -0,0 +1,70 @@
+/*****************************************************************
+ * 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.sql.ResultSet;
+import java.util.Map;
+
+import org.apache.cayenne.CayenneException;
+import org.apache.cayenne.exp.Expression;
+
+/**
+ * Inheritance-aware entity RowReader.
+ *
+ * @since 3.0
+ */
+class EntityTreeRowReader implements RowReader<Object> {
+
+ private RowReader<?> discriminatorReader;
+ private Expression[] discriminatorExpressions;
+ private RowReader<Object>[] rowReaders;
+
+ EntityTreeRowReader(RowReader<?> discriminatorReader,
+ Expression[] discriminatorExpressions, RowReader<Object>[] rowReaders) {
+
+ this.discriminatorReader = discriminatorReader;
+ this.discriminatorExpressions = discriminatorExpressions;
+ this.rowReaders = rowReaders;
+ }
+
+ public void setColumnOffset(int offset) {
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ public Object readRow(ResultSet resultSet) throws CayenneException {
+
+ Map<String, Object> discriminator = (Map<String, Object>) discriminatorReader
+ .readRow(resultSet);
+
+ int len = discriminatorExpressions.length;
+ for (int i = 0; i < len; 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);
+ }
+ }
+
+ throw new CayenneException(
+ "Row discriminator did not match any entities in the inheritance hierarchy: "
+ + discriminator);
+ }
+}
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=729484&r1=729483&r2=729484&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 Fri Dec 26 03:50:31 2008
@@ -22,8 +22,10 @@
import org.apache.cayenne.CayenneRuntimeException;
import org.apache.cayenne.access.types.ExtendedTypeMap;
+import org.apache.cayenne.map.DbEntity;
import org.apache.cayenne.query.EntityResultSegment;
import org.apache.cayenne.query.QueryMetadata;
+import org.apache.cayenne.reflect.ClassDescriptor;
/**
* A class used as a builder of SelectDescriptors of any complexity.
@@ -33,42 +35,42 @@
public class SelectDescriptorBuilder {
private ExtendedTypeMap extendedTypes;
-
private transient ScalarSegmentBuilder scalarSegmentBuilder;
- private transient EntitySegmentBuilder entitySegmentBuilder;
public SelectDescriptorBuilder(ExtendedTypeMap extendedTypes) {
this.extendedTypes = extendedTypes;
}
- public SelectDescriptor<?> fromQueryMetadata(QueryMetadata queryMetadata) {
+ public SelectDescriptor<?> fromQueryMetadata(QueryMetadata metadata) {
- List<Object> segmentDescriptors = queryMetadata.getResultSetMapping();
- int resultWidth = segmentDescriptors != null ? segmentDescriptors.size() : 1;
+ List<Object> segmentMap = metadata.getResultSetMapping();
+ int segmentsCount = segmentMap != null ? segmentMap.size() : 1;
- if (resultWidth == 0) {
+ if (segmentsCount == 0) {
throw new CayenneRuntimeException("Empty result descriptor");
}
int entitySegments = 0, scalarSegments = 0;
- SelectDescriptor<Object>[] segments = new SelectDescriptor[resultWidth];
+ SelectDescriptor<Object>[] segments = new SelectDescriptor[segmentsCount];
- if (segmentDescriptors == null) {
- segments[0] = getEntitySegmentBuilder(queryMetadata).getSegment(0);
+ if (segmentMap == null) {
+ segments[0] = getEntitySegment(metadata, null, 0);
entitySegments++;
}
else {
- for (int i = 0; i < resultWidth; i++) {
+ for (int i = 0; i < segmentsCount; i++) {
- Object segmentDescriptor = segmentDescriptors.get(i);
+ Object segmentDescriptor = segmentMap.get(i);
if (segmentDescriptor instanceof EntityResultSegment) {
- segments[i] = getEntitySegmentBuilder(queryMetadata).getSegment(i);
+ segments[i] = getEntitySegment(
+ metadata,
+ (EntityResultSegment) segmentDescriptor,
+ i);
entitySegments++;
}
else {
- segments[i] = getScalarSegmentBuilder(segmentDescriptors).getSegment(
- i);
+ segments[i] = getScalarSegment(segmentMap, i);
scalarSegments++;
}
}
@@ -76,7 +78,7 @@
// sanity check - paginated queries are only possible if there is an "id" of each
// row. for now this means single entity queries...
- if (queryMetadata.getPageSize() > 0) {
+ if (metadata.getPageSize() > 0) {
if (entitySegments != 1 || scalarSegments != 0) {
throw new CayenneRuntimeException(
"Paginated queries are only supported for a single entity result");
@@ -84,26 +86,63 @@
}
// do some small optimizations for the common 1 segment results...
- if (resultWidth == 1) {
+ if (segmentsCount == 1) {
return segments[0];
}
return new CompoundSelectDescriptor(segments);
}
- protected EntitySegmentBuilder getEntitySegmentBuilder(QueryMetadata queryMetadata) {
- if (entitySegmentBuilder == null) {
- entitySegmentBuilder = new EntitySegmentBuilder(extendedTypes, queryMetadata);
+ protected SelectDescriptor<Object> getEntitySegment(
+ QueryMetadata metadata,
+ EntityResultSegment segmentDescriptor,
+ int position) {
+
+ ClassDescriptor classDescriptor;
+ EntityResultSegment segmentMetadata;
+
+ List<Object> segmentDesriptors = metadata.getResultSetMapping();
+ if (segmentDesriptors != null) {
+ segmentMetadata = (EntityResultSegment) segmentDesriptors.get(position);
+ classDescriptor = segmentMetadata.getClassDescriptor();
+ }
+ else {
+ segmentMetadata = null;
+ classDescriptor = metadata.getClassDescriptor();
+ }
+
+ // no ObjEntity and Java class at the root of the query...
+ if (classDescriptor == null) {
+ DbEntity dbEntity = metadata.getDbEntity();
+ if (dbEntity == null) {
+ throw new CayenneRuntimeException("Invalid entity segment in position "
+ + position
+ + ", no root DbEntity specified");
+ }
+
+ throw new UnsupportedOperationException("TODO: DbEntity based queries");
+ }
+
+ if (classDescriptor.getEntityInheritanceTree() != null) {
+ throw new UnsupportedOperationException("TODO: Inheritance aware queries");
+ }
+ else {
+ return new EntitySegmentBuilder(
+ metadata,
+ extendedTypes,
+ classDescriptor,
+ classDescriptor.getEntity().getDbEntity()).getDescriptor();
}
- return entitySegmentBuilder;
}
- protected ScalarSegmentBuilder getScalarSegmentBuilder(List<Object> segmentDescriptors) {
+ protected SelectDescriptor<Object> getScalarSegment(
+ List<Object> segmentDescriptors,
+ int position) {
if (scalarSegmentBuilder == null) {
scalarSegmentBuilder = new ScalarSegmentBuilder(
extendedTypes,
segmentDescriptors);
}
- return scalarSegmentBuilder;
+ return scalarSegmentBuilder.getSegment(position);
}
}