private void processInsertsForEntity()

in grails-data-neo4j/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/Neo4jSession.java [448:603]


    private void processInsertsForEntity(org.neo4j.driver.Transaction neo4jTransaction, GraphPersistentEntity entity, Map<PersistentEntity, Collection<PendingInsert>> inserts, List<PendingOperation<Object, Serializable>> cascadingOperations) {
        final Collection<PendingInsert> entityInserts = inserts.get(entity);
        final boolean hasDynamicLabels = entity.hasDynamicLabels();
        final EntityReflector reflector = entity.getReflector();
        Neo4jMappingContext mappingContext = getMappingContext();
        if (!entityInserts.isEmpty()) {

            if (hasDynamicLabels) {
                buildAndExecuteCreateStatement(entityInserts, entity, cascadingOperations);
            } else {
                // use UNWIND and FOREACH to batch
                StringBuilder batchCypher = new StringBuilder();
                final Map<String, Object> params = new HashMap<>(inserts.size());
                Map<String, String> associationMerges = new LinkedHashMap<>();
                batchCypher.append(entity.getBatchCreateStatement());
                Collection<Map<String, Object>> rows = new ArrayList<>();
                for (PendingInsert entityInsert : entityInserts) {
                    EntityAccess entityAccess = entityInsert.getEntityAccess();
                    if (entityInsert.wasExecuted()) {
                        processPendingRelationshipUpdates(entity, entityAccess, (Serializable) entityInsert.getNativeKey(), cascadingOperations, false);
                        cascadingOperations.addAll(entityInsert.getCascadeOperations());
                    } else {
                        if (isVetoedAfterPreOperations(entityInsert)) {
                            continue;
                        }

                        if (entity.isRelationshipEntity()) {
                            RelationshipPersistentEntity relEntity = (RelationshipPersistentEntity) entity;
                            Relationship relationship = (Relationship) entityAccess.getEntity();
                            Object type = entityAccess.getProperty(RelationshipPersistentEntity.TYPE);
                            // if the type hasn't been modified we can batch
                            if(relEntity.type().equals(type)) {
                                Object from = entityAccess.getPropertyValue(RelationshipPersistentEntity.FROM);
                                Serializable id = null;
                                if (from != null) {
                                    id = relEntity.getFromEntity().getReflector().getIdentifier(from);
                                }
                                if(id != null) {
                                    RelationshipUpdateKey updateKey = new RelationshipUpdateKey(id, relEntity.getFrom());
                                    Collection<Serializable> childIds = pendingRelationshipInserts.get(updateKey);
                                    if(childIds != null) {
                                        pendingRelationshipInserts.remove(updateKey);
                                        Map<String, Object> rowData = new LinkedHashMap<>();
                                        LinkedHashMap<String, Object> nodeProperties = new LinkedHashMap<>();
                                        for (PersistentProperty pp : relEntity.getPersistentProperties()) {
                                            if(pp instanceof Simple || pp instanceof Basic || pp instanceof TenantId) {
                                                String propertyName = pp.getName();
                                                if(RelationshipPersistentEntity.TYPE.equals(propertyName)) {
                                                    continue;
                                                }

                                                Object v = reflector.getProperty(relationship, propertyName);
                                                if(v != null) {
                                                    nodeProperties.put(propertyName, mappingContext.convertToNative(v));
                                                }
                                            }
                                        }

                                        nodeProperties.putAll( relationship.attributes() );

                                        rowData.put(CypherBuilder.PROPS, nodeProperties);
                                        rowData.put(RelationshipPersistentEntity.FROM, id);
                                        rowData.put(RelationshipPersistentEntity.TO, childIds);
                                        rows.add(rowData);

                                    }
                                }
                            }
                            else {
                                // otherwise process individual inserts
                                processPendingRelationshipUpdates(entity, entityAccess, (Serializable) entityInsert.getNativeKey(), cascadingOperations, false);
                            }
                        } else {
                            Object parentId = entityAccess.getIdentifier();
                            if (parentId != null) {
                                Map<String, Object> nodeProperties = readNodePropertiesForInsert(entityInsert, entity, entity.getPersistentProperties(), entityAccess);
                                Object obj = entityInsert.getObject();
                                Map<String, List<Object>> dynamicRelProps = amendMapWithUndeclaredProperties(entity, nodeProperties, obj, getMappingContext());
                                Map<String, Object> data = new LinkedHashMap<>();
                                data.put(CypherBuilder.PROPS, nodeProperties);
                                rows.add(data);


                                for (Association association : entity.getAssociations()) {
                                    if (association.isBasic()) continue;
                                    boolean isTree = association.isCircular();
                                    if (association.isOwningSide() || isTree) {
                                        RelationshipUpdateKey key = new RelationshipUpdateKey((Serializable) parentId, association);
                                        Collection<Serializable> childIds = pendingRelationshipInserts.get(key);
                                        if (childIds != null) {
                                            GraphPersistentEntity associatedEntity = (GraphPersistentEntity) association.getAssociatedEntity();
                                            String associationName = association.getName();
                                            Collection<PendingInsert> pendingInserts = inserts.get(associatedEntity);
                                            if (pendingInserts != null) {
                                                Collection<Map<String, Object>> childRows = new ArrayList<>();
                                                for (PendingInsert pendingInsert : pendingInserts) {
                                                    Serializable childId = (Serializable) pendingInsert.getNativeKey();
                                                    if (childIds.contains(childId)) {

                                                        boolean wasExecutedBeforeHand = pendingInsert.wasExecuted();

                                                        if (wasExecutedBeforeHand || isVetoedAfterPreOperations(pendingInsert)) {
                                                            continue;
                                                        }

                                                        childIds.remove(childId);

                                                        Map<String, Object> childProperties = readNodePropertiesForInsert(pendingInsert, associatedEntity, associatedEntity.getPersistentProperties(), pendingInsert.getEntityAccess());
                                                        childRows.add(Collections.<String, Object>singletonMap(CypherBuilder.PROPS, childProperties));

                                                        cascadingOperations.addAll(pendingInsert.getCascadeOperations());
                                                    }
                                                }

                                                if (!childRows.isEmpty()) {
                                                    String parentVariable = entity.getVariableId();
                                                    associationMerges.put(associationName, associatedEntity.formatBatchCreate(parentVariable, association));
                                                    data.put(associationName, childRows);
                                                }
                                            }
                                        }
                                    }
                                }


                                processDynamicAssociationsIfNecessary(entity, entityAccess, obj, entityInsert, cascadingOperations, params, dynamicRelProps);
                                params.remove(Neo4jEntityPersister.DYNAMIC_ASSOCIATION_PARAM);
                            }


                            cascadingOperations.addAll(entityInsert.getCascadeOperations());
                        }

                    }
                }
                params.put(entity.getBatchId(), rows);
                if (!associationMerges.isEmpty()) {
                    for (String merge : associationMerges.keySet()) {
                        batchCypher.append(associationMerges.get(merge));
                    }
                }

                if (batchCypher.length() > 0 && !rows.isEmpty()) {

                    final String finalCypher = batchCypher.toString();
                    if (log.isDebugEnabled()) {
                        log.debug("CREATE Cypher [{}] for parameters [{}]", finalCypher, params);
                    }
                    neo4jTransaction.run(finalCypher, params);

                }
            }


        }
    }