protected List executeQuery()

in grails-data-neo4j/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/engine/Neo4jQuery.groovy [408:557]


    protected List executeQuery(PersistentEntity persistentEntity, Query.Junction criteria) {

        CypherBuilder cypherBuilder = buildBaseQuery(persistentEntity, criteria)
        cypherBuilder.setOrderAndLimits(applyOrderAndLimits(cypherBuilder))
        GraphPersistentEntity graphEntity = (GraphPersistentEntity)persistentEntity
        def projectionList = projections.projectionList

        if(projectionList.isEmpty()) {
             if(isRelationshipEntity) {
                 cypherBuilder.addReturnColumn(CypherBuilder.DEFAULT_REL_RETURN_STATEMENT)
             }
             else {
                 Set<Association> associations = new TreeSet<Association>((Comparator<Association>){ Association a1, Association a2 -> a1.name <=> a2.name })
                 Collection<PersistentEntity> childEntities = persistentEntity.mappingContext.getChildEntities(persistentEntity)
                 if (!childEntities.empty) {
                     for (PersistentEntity childEntity : childEntities) {
                         associations.addAll(childEntity.associations)
                     }
                 }
                 associations.addAll(persistentEntity.associations)

                 if(associations.size() > 0) {
                     int i = 0
                     List previousAssociations = []
                     cypherBuilder.addReturnColumn(CypherBuilder.DEFAULT_RETURN_TYPES)

                     for(Association association in associations) {
                         if(association.isBasic()) continue

                         FetchType fetchType = fetchStrategy(association.name)
                         boolean isEager = fetchType.is(fetchType.EAGER)

                         String r = "r${i++}"

                         String associationName = association.name
                         GraphPersistentEntity associatedGraphEntity = (GraphPersistentEntity)association.associatedEntity
                         boolean isAssociationRelationshipEntity = associatedGraphEntity.isRelationshipEntity()
                         boolean isToMany = association instanceof ToMany
                         boolean isToOne = association instanceof ToOne

                         boolean lazy  = false
                         boolean isNullable = false
                         if(isToOne && !isEager) {
                             Property propertyMapping = association.mapping.mappedForm
                             Boolean isLazy = propertyMapping.getLazy()
                             isNullable = propertyMapping.isNullable()
                             lazy = (isLazy != null ? isLazy : (association instanceof ManyToOne ? !association.isCircular() : true))

                         }
                         else if(isToMany) {
                             lazy = ((ToMany)association).lazy
                         }

                         // if there are associations, add a join to get them
                         String withMatch = "WITH n, ${previousAssociations.size() > 0 ? previousAssociations.join(", ") + ", " : ""}"
                         String associationIdsRef = "${associationName}Ids"
                         String associationNodeRef = "${associationName}Node"
                         String associationNodesRef = "${associationName}Nodes"

                         boolean addOptionalMatch = false
                         // If it is a one-to-many and lazy=true
                         // Or it is a one-to-one where the association is nullable or not lazy
                         // then just collect the identifiers and not the nodes
                         if((isToMany && lazy) || (isToOne && !isEager && (isNullable || !lazy ) )) {
                             withMatch += "collect(DISTINCT ${associatedGraphEntity.formatId(associationNodeRef)}) as ${associationIdsRef}"
                             cypherBuilder.addReturnColumn(associationIdsRef)
                             previousAssociations << associationIdsRef
                             addOptionalMatch = true
                         }
                         else if(isEager) {
                             withMatch += "collect(DISTINCT $associationNodeRef) as $associationNodesRef"
                             cypherBuilder.addReturnColumn(associationNodesRef)
                             if(isAssociationRelationshipEntity) {
                                 withMatch += ", collect($r) as ${associationName}Rels"
                                 cypherBuilder.addReturnColumn("${associationName}Rels")
                             }
                             previousAssociations << associationNodesRef
                             addOptionalMatch = true
                         }

                         if(addOptionalMatch) {

                             String relationshipPattern = graphEntity
                                     .formatAssociationPatternFromExisting(
                                     association,
                                     r,
                                     CypherBuilder.NODE_VAR,
                                     associationNodeRef
                             )
                             cypherBuilder.addOptionalMatch(
                                     "$relationshipPattern $withMatch"
                             )
                         }

                     }
                 }
             }
        }
        else {
            for (projection in projectionList) {
                cypherBuilder.addReturnColumn(buildProjection(projection, cypherBuilder))
            }
        }


        String cypher = cypherBuilder.build()
        Map<String, Object> params = cypherBuilder.getParams()

        log.debug("QUERY Cypher [$cypher] for params [$params]")

        QueryRunner statementRunner = session.hasTransaction() ? session.getTransaction().getTransaction() : boltSession
        Result executionResult = params.isEmpty() ? statementRunner.run(cypher) : statementRunner.run(cypher, params)
        if (projectionList.empty) {
            return new Neo4jResultList(offset, executionResult, neo4jEntityPersister, lockResult)
        } else {

            List projectedResults = []
            while( executionResult.hasNext() ) {

                Record record = executionResult.next()
                def columnNames = executionResult.keys()
                projectedResults.add columnNames.collect { String columnName ->
                    Value value = record.get(columnName)
                    if(value.type() == session.boltDriver.defaultTypeSystem().NODE()) {
                        // if a Node has been project then this is an association
                        def propName = columnName.substring(0, columnName.lastIndexOf('_'))
                        def prop = persistentEntity.getPropertyByName(propName)
                        if(prop instanceof ToOne) {
                            Association association = (Association)prop
                            Node childNode = value.asNode()

                            def persister = getSession().getEntityPersister(association.type)

                            def data = Collections.<String,Object>singletonMap( CypherBuilder.NODE_DATA, childNode)
                            return persister.unmarshallOrFromCache(
                                    association.associatedEntity, data)
                        }
                    }
                    return value.asObject()
                }
            }

            if(projectionList.size() == 1 || projectedResults.size() == 1) {
                return projectedResults.flatten()
            }
            else {
                return projectedResults
            }
        }
    }