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
}
}
}