Search in sources :

Example 1 with EntityResult

use of org.apache.cayenne.map.EntityResult in project cayenne by apache.

the class SelectQueryMetadata method buildEntityResultForColumn.

/**
 * Collect metadata for column that will be unwrapped to full entity in the final SQL
 * (possibly including joint prefetch).
 * This information will be used to correctly create Persistent object back from raw result.
 *
 * This method is actually repeating logic of
 * {@link org.apache.cayenne.access.translator.select.DefaultSelectTranslator#appendQueryColumns}.
 * Here we don't care about intermediate joins and few other things so it's shorter.
 * Logic of these methods should be unified and simplified, possibly to a single source of metadata,
 * generated only once and used everywhere.
 *
 * @param query original query
 * @param column full object column
 * @param resolver entity resolver to get ObjEntity and ClassDescriptor
 * @return Entity result
 */
private EntityResult buildEntityResultForColumn(SelectQuery<?> query, Property<?> column, EntityResolver resolver) {
    final EntityResult result = new EntityResult(column.getType());
    // Collecting visitor for ObjAttributes and toOne relationships
    PropertyVisitor visitor = new PropertyVisitor() {

        public boolean visitAttribute(AttributeProperty property) {
            ObjAttribute oa = property.getAttribute();
            Iterator<CayenneMapEntry> dbPathIterator = oa.getDbPathIterator();
            while (dbPathIterator.hasNext()) {
                CayenneMapEntry pathPart = dbPathIterator.next();
                if (pathPart instanceof DbAttribute) {
                    result.addDbField(pathPart.getName(), pathPart.getName());
                }
            }
            return true;
        }

        public boolean visitToMany(ToManyProperty property) {
            return true;
        }

        public boolean visitToOne(ToOneProperty property) {
            DbRelationship dbRel = property.getRelationship().getDbRelationships().get(0);
            List<DbJoin> joins = dbRel.getJoins();
            for (DbJoin join : joins) {
                if (!join.getSource().isPrimaryKey()) {
                    result.addDbField(join.getSource().getName(), join.getSource().getName());
                }
            }
            return true;
        }
    };
    ObjEntity oe = resolver.getObjEntity(column.getType());
    DbEntity table = oe.getDbEntity();
    // Additionally collect PKs
    for (DbAttribute dba : table.getPrimaryKeys()) {
        result.addDbField(dba.getName(), dba.getName());
    }
    ClassDescriptor descriptor = resolver.getClassDescriptor(oe.getName());
    descriptor.visitAllProperties(visitor);
    // Collection columns for joint prefetch
    if (query.getPrefetchTree() != null) {
        for (PrefetchTreeNode prefetch : query.getPrefetchTree().adjacentJointNodes()) {
            // for each prefetch add columns from the target entity
            Expression prefetchExp = ExpressionFactory.exp(prefetch.getPath());
            ASTDbPath dbPrefetch = (ASTDbPath) oe.translateToDbPath(prefetchExp);
            DbRelationship r = findRelationByPath(table, dbPrefetch);
            if (r == null) {
                throw new CayenneRuntimeException("Invalid joint prefetch '%s' for entity: %s", prefetch, oe.getName());
            }
            // go via target OE to make sure that Java types are mapped correctly...
            ObjRelationship targetRel = (ObjRelationship) prefetchExp.evaluate(oe);
            ObjEntity targetEntity = targetRel.getTargetEntity();
            prefetch.setEntityName(targetRel.getSourceEntity().getName());
            String labelPrefix = dbPrefetch.getPath();
            Set<String> seenNames = new HashSet<>();
            for (ObjAttribute oa : targetEntity.getAttributes()) {
                Iterator<CayenneMapEntry> dbPathIterator = oa.getDbPathIterator();
                while (dbPathIterator.hasNext()) {
                    Object pathPart = dbPathIterator.next();
                    if (pathPart instanceof DbAttribute) {
                        DbAttribute attribute = (DbAttribute) pathPart;
                        if (seenNames.add(attribute.getName())) {
                            result.addDbField(labelPrefix + '.' + attribute.getName(), labelPrefix + '.' + attribute.getName());
                        }
                    }
                }
            }
            // append remaining target attributes such as keys
            DbEntity targetDbEntity = r.getTargetEntity();
            for (DbAttribute attribute : targetDbEntity.getAttributes()) {
                if (seenNames.add(attribute.getName())) {
                    result.addDbField(labelPrefix + '.' + attribute.getName(), labelPrefix + '.' + attribute.getName());
                }
            }
        }
    }
    return result;
}
Also used : ObjRelationship(org.apache.cayenne.map.ObjRelationship) ObjAttribute(org.apache.cayenne.map.ObjAttribute) ClassDescriptor(org.apache.cayenne.reflect.ClassDescriptor) ASTDbPath(org.apache.cayenne.exp.parser.ASTDbPath) DbAttribute(org.apache.cayenne.map.DbAttribute) CayenneRuntimeException(org.apache.cayenne.CayenneRuntimeException) EntityResult(org.apache.cayenne.map.EntityResult) AttributeProperty(org.apache.cayenne.reflect.AttributeProperty) ToOneProperty(org.apache.cayenne.reflect.ToOneProperty) CayenneMapEntry(org.apache.cayenne.util.CayenneMapEntry) ObjEntity(org.apache.cayenne.map.ObjEntity) ToManyProperty(org.apache.cayenne.reflect.ToManyProperty) DbEntity(org.apache.cayenne.map.DbEntity) Expression(org.apache.cayenne.exp.Expression) DbRelationship(org.apache.cayenne.map.DbRelationship) DbJoin(org.apache.cayenne.map.DbJoin) PropertyVisitor(org.apache.cayenne.reflect.PropertyVisitor) HashSet(java.util.HashSet)

Example 2 with EntityResult

use of org.apache.cayenne.map.EntityResult in project cayenne by apache.

the class SelectQueryMetadata method buildEntityIdResultForColumn.

/**
 * Collect metadata for result with ObjectId (used for paginated queries with FullObject columns)
 *
 * @param column full object column
 * @param resolver entity resolver
 * @return Entity result
 */
private EntityResult buildEntityIdResultForColumn(Property<?> column, EntityResolver resolver) {
    EntityResult result = new EntityResult(column.getType());
    DbEntity entity = resolver.getObjEntity(column.getType()).getDbEntity();
    for (DbAttribute attribute : entity.getPrimaryKeys()) {
        result.addDbField(attribute.getName(), attribute.getName());
    }
    return result;
}
Also used : DbEntity(org.apache.cayenne.map.DbEntity) DbAttribute(org.apache.cayenne.map.DbAttribute) EntityResult(org.apache.cayenne.map.EntityResult)

Example 3 with EntityResult

use of org.apache.cayenne.map.EntityResult in project cayenne by apache.

the class DescriptorColumnExtractor method extract.

public void extract(String prefix) {
    this.prefix = prefix;
    boolean newEntityResult = false;
    this.labelPrefix = null;
    TranslatorContext.DescriptorType type = TranslatorContext.DescriptorType.OTHER;
    if (prefix != null && prefix.startsWith(PREFETCH_PREFIX)) {
        type = TranslatorContext.DescriptorType.PREFETCH;
        labelPrefix = prefix.substring(2);
        if (context.getQuery().needsResultSetMapping()) {
            entityResult = context.getRootEntityResult();
            if (entityResult == null) {
                throw new CayenneRuntimeException("Can't process prefetch descriptor without root.");
            }
            newEntityResult = false;
        }
    } else {
        if (context.getQuery().needsResultSetMapping()) {
            entityResult = new EntityResult(descriptor.getObjectClass());
            newEntityResult = true;
        }
        if (descriptor.getEntity().getDbEntity() == context.getRootDbEntity()) {
            type = TranslatorContext.DescriptorType.ROOT;
            context.setRootEntityResult(entityResult);
        }
    }
    context.markDescriptorStart(type);
    descriptor.visitAllProperties(this);
    // add remaining needed attrs from DbEntity
    DbEntity table = descriptor.getEntity().getDbEntity();
    String alias = context.getTableTree().aliasForPath(prefix);
    for (DbAttribute dba : table.getPrimaryKeys()) {
        String columnUniqueName = alias + '.' + dba.getName();
        if (columnTracker.add(columnUniqueName)) {
            addDbAttribute(prefix, labelPrefix, dba);
            addEntityResultField(dba);
        }
    }
    if (newEntityResult) {
        context.getSqlResult().addEntityResult(entityResult);
    }
    context.markDescriptorEnd(type);
}
Also used : DbEntity(org.apache.cayenne.map.DbEntity) CayenneRuntimeException(org.apache.cayenne.CayenneRuntimeException) DbAttribute(org.apache.cayenne.map.DbAttribute) EntityResult(org.apache.cayenne.map.EntityResult)

Example 4 with EntityResult

use of org.apache.cayenne.map.EntityResult in project cayenne by apache.

the class DataContextSQLTemplateIT method testSQLResultSetMappingMixed.

@Test
public void testSQLResultSetMappingMixed() throws Exception {
    createFourArtistsAndThreePaintingsDataSet();
    String sql = "SELECT #result('t0.ARTIST_ID' 'long' 'X'), #result('t0.ARTIST_NAME' 'String' 'Y'), #result('t0.DATE_OF_BIRTH' 'Date' 'Z'), #result('count(t1.PAINTING_ID)' 'int' 'C') " + "FROM ARTIST t0 LEFT JOIN PAINTING t1 ON (t0.ARTIST_ID = t1.ARTIST_ID) " + "GROUP BY t0.ARTIST_ID, t0.ARTIST_NAME, t0.DATE_OF_BIRTH " + "ORDER BY t0.ARTIST_ID";
    DataMap map = context.getEntityResolver().getDataMap("testmap");
    SQLTemplate query = new SQLTemplate(map, sql, false);
    query.setColumnNamesCapitalization(CapsStrategy.UPPER);
    EntityResult artistResult = new EntityResult(Artist.class);
    artistResult.addDbField(Artist.ARTIST_ID_PK_COLUMN, "X");
    artistResult.addObjectField(Artist.ARTIST_NAME.getName(), "Y");
    artistResult.addObjectField(Artist.DATE_OF_BIRTH.getName(), "Z");
    SQLResult rsMap = new SQLResult();
    rsMap.addEntityResult(artistResult);
    rsMap.addColumnResult("C");
    query.setResult(rsMap);
    List<?> objects = context.performQuery(query);
    assertEquals(4, objects.size());
    Object o1 = objects.get(0);
    assertTrue("Expected Object[]: " + o1, o1 instanceof Object[]);
    Object[] array1 = (Object[]) o1;
    assertEquals(2, array1.length);
    Object[] array2 = (Object[]) objects.get(1);
    assertEquals(2, array2.length);
    Object[] array3 = (Object[]) objects.get(2);
    assertEquals(2, array3.length);
    Object[] array4 = (Object[]) objects.get(3);
    assertEquals(2, array3.length);
    assertEquals(new Integer(1), array1[1]);
    assertEquals(new Integer(1), array2[1]);
    assertEquals(new Integer(0), array3[1]);
    assertEquals(new Integer(0), array4[1]);
    assertTrue("Unexpected DataObject: " + array1[0], array1[0] instanceof Artist);
}
Also used : SQLTemplate(org.apache.cayenne.query.SQLTemplate) SQLResult(org.apache.cayenne.map.SQLResult) Artist(org.apache.cayenne.testdo.testmap.Artist) EntityResult(org.apache.cayenne.map.EntityResult) DataMap(org.apache.cayenne.map.DataMap) Test(org.junit.Test)

Example 5 with EntityResult

use of org.apache.cayenne.map.EntityResult in project cayenne by apache.

the class Compiler method compile.

CompiledExpression compile(String source, EJBQLExpression parsed) {
    parsed.visit(new CompilationVisitor());
    Map<EJBQLPath, Integer> pathsInSelect = new HashMap<>();
    for (int i = 0; i < parsed.getChildrenCount(); i++) {
        if (parsed.getChild(i) instanceof EJBQLSelectClause) {
            EJBQLExpression parsedTemp = parsed.getChild(i);
            boolean stop = false;
            while (parsedTemp.getChildrenCount() > 0 && !stop) {
                EJBQLExpression newParsedTemp = null;
                for (int j = 0; j < parsedTemp.getChildrenCount(); j++) {
                    if (parsedTemp.getChild(j) instanceof EJBQLSelectExpression) {
                        for (int k = 0; k < parsedTemp.getChild(j).getChildrenCount(); k++) {
                            if (parsedTemp.getChild(j).getChild(k) instanceof EJBQLPath) {
                                pathsInSelect.put((EJBQLPath) parsedTemp.getChild(j).getChild(k), j);
                            }
                        }
                    } else {
                        if (parsedTemp.getChild(j).getChildrenCount() == 0) {
                            stop = true;
                        } else {
                            newParsedTemp = parsedTemp.getChild(j);
                        }
                    }
                }
                if (!stop && newParsedTemp != null) {
                    parsedTemp = newParsedTemp;
                } else {
                    stop = true;
                }
            }
        }
    }
    // postprocess paths, now that all id vars are resolved
    if (paths != null) {
        for (EJBQLPath path : paths) {
            String id = normalizeIdPath(path.getId());
            ClassDescriptor descriptor = descriptorsById.get(id);
            if (descriptor == null) {
                throw new EJBQLException("Unmapped id variable: " + id);
            }
            StringBuilder buffer = new StringBuilder(id);
            ObjRelationship incoming = null;
            String pathRelationshipString = "";
            for (int i = 1; i < path.getChildrenCount(); i++) {
                String pathChunk = path.getChild(i).getText();
                if (pathChunk.endsWith(Entity.OUTER_JOIN_INDICATOR)) {
                    pathChunk = pathChunk.substring(0, pathChunk.length() - 1);
                }
                buffer.append('.').append(pathChunk);
                PropertyDescriptor property = descriptor.getProperty(pathChunk);
                if (property instanceof ArcProperty) {
                    incoming = ((ArcProperty) property).getRelationship();
                    descriptor = ((ArcProperty) property).getTargetDescriptor();
                    pathRelationshipString = buffer.substring(0, buffer.length());
                    descriptorsById.put(pathRelationshipString, descriptor);
                    incomingById.put(pathRelationshipString, incoming);
                }
            }
            if (pathsInSelect.size() > 0 && incoming != null && pathRelationshipString.length() > 0 && pathRelationshipString.equals(buffer.toString())) {
                EJBQLIdentifier ident = new EJBQLIdentifier(0);
                ident.text = pathRelationshipString;
                Integer integer = pathsInSelect.get(path);
                if (integer != null) {
                    resultComponents.remove(integer.intValue());
                    resultComponents.add(integer, ident);
                    rootId = pathRelationshipString;
                }
            }
        }
    }
    CompiledExpression compiled = new CompiledExpression();
    compiled.setExpression(parsed);
    compiled.setSource(source);
    compiled.setRootId(rootId);
    compiled.setDescriptorsById(descriptorsById);
    compiled.setIncomingById(incomingById);
    compiled.setPrefetchTree(prefetchTree);
    if (resultComponents != null) {
        SQLResult mapping = new SQLResult();
        for (int i = 0; i < resultComponents.size(); i++) {
            Object nextMapping = resultComponents.get(i);
            if (nextMapping instanceof String) {
                mapping.addColumnResult((String) nextMapping);
            } else if (nextMapping instanceof EJBQLExpression) {
                EntityResult compileEntityResult = compileEntityResult((EJBQLExpression) nextMapping, i);
                if (prefetchTree != null) {
                    for (PrefetchTreeNode prefetch : prefetchTree.getChildren()) {
                        if (((EJBQLExpression) nextMapping).getText().equals(prefetch.getEjbqlPathEntityId())) {
                            EJBQLIdentifier ident = new EJBQLIdentifier(0);
                            ident.text = prefetch.getEjbqlPathEntityId() + "." + prefetch.getPath();
                            compileEntityResult = compileEntityResultWithPrefetch(compileEntityResult, ident);
                        }
                    }
                }
                mapping.addEntityResult(compileEntityResult);
            }
        }
        compiled.setResult(mapping);
    }
    return compiled;
}
Also used : ObjRelationship(org.apache.cayenne.map.ObjRelationship) ArcProperty(org.apache.cayenne.reflect.ArcProperty) ClassDescriptor(org.apache.cayenne.reflect.ClassDescriptor) PropertyDescriptor(org.apache.cayenne.reflect.PropertyDescriptor) HashMap(java.util.HashMap) EJBQLException(org.apache.cayenne.ejbql.EJBQLException) EntityResult(org.apache.cayenne.map.EntityResult) EJBQLCompiledExpression(org.apache.cayenne.ejbql.EJBQLCompiledExpression) SQLResult(org.apache.cayenne.map.SQLResult) PrefetchTreeNode(org.apache.cayenne.query.PrefetchTreeNode) EJBQLExpression(org.apache.cayenne.ejbql.EJBQLExpression)

Aggregations

EntityResult (org.apache.cayenne.map.EntityResult)6 DbAttribute (org.apache.cayenne.map.DbAttribute)4 DbEntity (org.apache.cayenne.map.DbEntity)3 ObjRelationship (org.apache.cayenne.map.ObjRelationship)3 ClassDescriptor (org.apache.cayenne.reflect.ClassDescriptor)3 HashSet (java.util.HashSet)2 CayenneRuntimeException (org.apache.cayenne.CayenneRuntimeException)2 EJBQLException (org.apache.cayenne.ejbql.EJBQLException)2 DbJoin (org.apache.cayenne.map.DbJoin)2 DbRelationship (org.apache.cayenne.map.DbRelationship)2 ObjAttribute (org.apache.cayenne.map.ObjAttribute)2 SQLResult (org.apache.cayenne.map.SQLResult)2 AttributeProperty (org.apache.cayenne.reflect.AttributeProperty)2 PropertyVisitor (org.apache.cayenne.reflect.PropertyVisitor)2 ToManyProperty (org.apache.cayenne.reflect.ToManyProperty)2 ToOneProperty (org.apache.cayenne.reflect.ToOneProperty)2 HashMap (java.util.HashMap)1 EJBQLCompiledExpression (org.apache.cayenne.ejbql.EJBQLCompiledExpression)1 EJBQLExpression (org.apache.cayenne.ejbql.EJBQLExpression)1 Expression (org.apache.cayenne.exp.Expression)1