package org.vertexium.cypher.executor;
import org.vertexium.cypher.VertexiumCypherQueryContext;
import org.vertexium.cypher.VertexiumCypherScope;
import org.vertexium.cypher.ast.model.CypherMergeActionCreate;
import org.vertexium.cypher.ast.model.CypherMergeActionMatch;
import org.vertexium.cypher.ast.model.CypherMergeClause;
import org.vertexium.cypher.executor.models.match.PatternPartMatchConstraint;
import org.vertexium.cypher.executor.utils.MatchConstraintBuilder;
import org.vertexium.util.VertexiumLogger;
import org.vertexium.util.VertexiumLoggerFactory;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.stream.Stream;
public class MergeClauseExecutor {
private static final VertexiumLogger LOGGER = VertexiumLoggerFactory.getLogger(MergeClauseExecutor.class);
public VertexiumCypherScope execute(VertexiumCypherQueryContext ctx, CypherMergeClause clause, VertexiumCypherScope scope) {
LOGGER.debug("execute: %s", clause);
PatternPartMatchConstraint patternPartConstraint = new MatchConstraintBuilder().patternPartToConstraints(clause.getPatternPart(), false);
Stream<VertexiumCypherScope> results = scope.stream().map(item -> {
List<VertexiumCypherScope.Item> patternPartResults = ctx.getMatchClauseExecutor().executePatternPartConstraint(ctx, patternPartConstraint, item);
if (patternPartResults.size() == 0) {
List<VertexiumCypherScope.Item> createResults = executeCreate(ctx, clause, patternPartConstraint, item);
return VertexiumCypherScope.newItemsScope(createResults, scope);
} else {
return executeMatch(ctx, clause, patternPartResults.stream(), scope);
}
});
return results.collect(VertexiumCypherScope.concatStreams(scope));
}
private VertexiumCypherScope executeMatch(
VertexiumCypherQueryContext ctx,
CypherMergeClause clause,
Stream<VertexiumCypherScope.Item> results,
VertexiumCypherScope scope
) {
results = results.map(result -> {
clause.getMergeActions().stream()
.filter(ma -> ma instanceof CypherMergeActionMatch)
.forEach(ma -> executeMatchMergeAction(ctx, (CypherMergeActionMatch) ma, result));
return result;
});
return VertexiumCypherScope.newFromItems(results, scope);
}
private void executeMatchMergeAction(
VertexiumCypherQueryContext ctx,
CypherMergeActionMatch ma,
VertexiumCypherScope.Item existingObj
) {
ctx.getSetClauseExecutor().execute(ctx, ma.getSet(), existingObj);
}
private List<VertexiumCypherScope.Item> executeCreate(
VertexiumCypherQueryContext ctx,
CypherMergeClause clause,
PatternPartMatchConstraint patternPartConstraint,
VertexiumCypherScope.Item item
) {
LinkedHashMap<String, ?> map = ctx.getCreateClauseExecutor().executePatternPart(ctx, clause.getPatternPart(), item);
VertexiumCypherScope.Item concatItem = item.concat(VertexiumCypherScope.newMapItem(map, item.getParentScope()));
clause.getMergeActions().stream()
.filter(ma -> ma instanceof CypherMergeActionCreate)
.forEach(ma -> executeCreateMergeAction(ctx, (CypherMergeActionCreate) ma, concatItem));
return ctx.getMatchClauseExecutor().executePatternPartConstraint(ctx, patternPartConstraint, item);
}
private void executeCreateMergeAction(
VertexiumCypherQueryContext ctx,
CypherMergeActionCreate ma,
VertexiumCypherScope.Item newObj
) {
ctx.getSetClauseExecutor().execute(ctx, ma.getSet(), newObj);
}
}