Skip to content

Commit

Permalink
Merge pull request #5597 from neo4j/update-cypher-builder
Browse files Browse the repository at this point in the history
Update cypher builder
  • Loading branch information
angrykoala authored Sep 26, 2024
2 parents 89b26fd + 013dd2e commit a067e31
Show file tree
Hide file tree
Showing 37 changed files with 115 additions and 104 deletions.
2 changes: 1 addition & 1 deletion packages/graphql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
"@graphql-tools/resolvers-composition": "^7.0.0",
"@graphql-tools/schema": "10.0.4",
"@graphql-tools/utils": "^10.0.0",
"@neo4j/cypher-builder": "^1.17.1",
"@neo4j/cypher-builder": "^1.20.1",
"camelcase": "^6.3.0",
"debug": "^4.3.4",
"dot-prop": "^6.0.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export function createAuthorizationAfterPredicate({

const preComputedSubqueries = [...asArray(extraSelections), ...asArray(nodeSubqueries)];
if (preComputedSubqueries) {
subqueries = Cypher.concat(subqueries, ...preComputedSubqueries);
subqueries = Cypher.utils.concat(subqueries, ...preComputedSubqueries);
}
}
if (!predicates.length) {
Expand Down Expand Up @@ -138,7 +138,7 @@ export function createAuthorizationAfterPredicateField({
const fieldSubqueries = attributesFilters.getSubqueries(queryASTContext);
const preComputedSubqueries = [...asArray(fieldSelection), ...asArray(fieldSubqueries)];
if (preComputedSubqueries) {
subqueries = Cypher.concat(subqueries, ...preComputedSubqueries);
subqueries = Cypher.utils.concat(subqueries, ...preComputedSubqueries);
}
if (fieldPredicate) {
predicates.push(fieldPredicate);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export function createAuthorizationBeforePredicate({

const preComputedSubqueries = [...extraSelections, ...nodeSubqueries];
if (preComputedSubqueries) {
subqueries = Cypher.concat(subqueries, ...preComputedSubqueries);
subqueries = Cypher.utils.concat(subqueries, ...preComputedSubqueries);
}
});
}
Expand Down Expand Up @@ -141,7 +141,7 @@ export function createAuthorizationBeforePredicateField({

const preComputedSubqueries = [...fieldSelection, ...fieldSubqueries];
if (preComputedSubqueries) {
subqueries = Cypher.concat(subqueries, ...preComputedSubqueries);
subqueries = Cypher.utils.concat(subqueries, ...preComputedSubqueries);
}
if (fieldPredicate) predicates.push(fieldPredicate);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,22 +106,17 @@ export function createConnectOrCreateAndParams({
? new Cypher.Return([new Cypher.NamedVariable("meta"), "update_meta"])
: new Cypher.Return([Cypher.count(new Cypher.Raw("*")), "_"]);

const withStatement = new Cypher.With(...withVarsVariables);
const subqueryClause = new Cypher.With(...withVarsVariables)
.call(Cypher.utils.concat(statement, returnStatement))
.importWith(...withVarsVariables);

const callStatement = new Cypher.Call(Cypher.concat(statement, returnStatement)).importWith(
...withVarsVariables
);
const subqueryClause = Cypher.concat(withStatement, callStatement);
if (context.subscriptionsEnabled) {
const afterCallWithStatement = new Cypher.With("*", [new Cypher.NamedVariable("update_meta"), "meta"]);
Cypher.concat(subqueryClause, afterCallWithStatement);
subqueryClause.with("*", [new Cypher.NamedVariable("update_meta"), "meta"]);
}

return subqueryClause;
});

const query = Cypher.concat(...wrappedQueries);

const query = Cypher.utils.concat(...wrappedQueries);
return query.build(`${varName}_`);
}

Expand Down Expand Up @@ -159,14 +154,14 @@ function createConnectOrCreatePartialStatement({

if (authorizationBeforePredicateReturn.predicate) {
if (authorizationBeforePredicateReturn.preComputedSubqueries) {
mergeQuery = Cypher.concat(
mergeQuery = Cypher.utils.concat(
mergeQuery,
new Cypher.With("*"),
authorizationBeforePredicateReturn.preComputedSubqueries
);
}

mergeQuery = Cypher.concat(
mergeQuery = Cypher.utils.concat(
mergeQuery,
new Cypher.With("*").where(authorizationBeforePredicateReturn.predicate)
);
Expand All @@ -184,7 +179,7 @@ function createConnectOrCreatePartialStatement({
withVars,
});

mergeQuery = Cypher.concat(mergeQuery, mergeCypher);
mergeQuery = Cypher.utils.concat(mergeQuery, mergeCypher);

const authorizationAfterPredicateReturn = createAuthorizationAfterConnectOrCreate({
context,
Expand All @@ -199,14 +194,14 @@ function createConnectOrCreatePartialStatement({
authorizationAfterPredicateReturn.preComputedSubqueries &&
!authorizationAfterPredicateReturn.preComputedSubqueries.empty
) {
mergeQuery = Cypher.concat(
mergeQuery = Cypher.utils.concat(
mergeQuery,
new Cypher.With(new Cypher.NamedVariable("*")),
authorizationAfterPredicateReturn.preComputedSubqueries,
new Cypher.With(new Cypher.NamedVariable("*")).where(authorizationAfterPredicateReturn.predicate)
);
} else {
mergeQuery = Cypher.concat(
mergeQuery = Cypher.utils.concat(
mergeQuery,
new Cypher.With("*").where(authorizationAfterPredicateReturn.predicate)
);
Expand Down Expand Up @@ -273,7 +268,7 @@ function mergeStatement({
return [node.property(key), param];
});

const merge = new Cypher.Merge(nodePattern).onCreate(...onCreateParams, ...callbackParams);
const merge = new Cypher.Merge(nodePattern).onCreateSet(...onCreateParams, ...callbackParams);

const relationshipFields = context.relationships.find((x) => x.properties === relationField.properties);
const autogeneratedRelationshipParams = relationshipFields ? getAutogeneratedParams(relationshipFields) : {};
Expand Down Expand Up @@ -317,7 +312,7 @@ function mergeStatement({
});
}

return Cypher.concat(merge, relationshipMerge, withClause);
return Cypher.utils.concat(merge, relationshipMerge, withClause);
}

function createAuthorizationBeforeConnectOrCreate({
Expand Down Expand Up @@ -353,7 +348,7 @@ function createAuthorizationBeforeConnectOrCreate({
}

if (preComputedSubqueries) {
subqueries = Cypher.concat(subqueries, preComputedSubqueries);
subqueries = Cypher.utils.concat(subqueries, preComputedSubqueries);
}
}

Expand Down Expand Up @@ -409,7 +404,7 @@ function createAuthorizationAfterConnectOrCreate({
}

if (preComputedSubqueries) {
subqueries = Cypher.concat(subqueries, preComputedSubqueries);
subqueries = Cypher.utils.concat(subqueries, preComputedSubqueries);
}
}

Expand All @@ -421,7 +416,7 @@ function createAuthorizationAfterConnectOrCreate({
}

if (preComputedSubqueries) {
subqueries = Cypher.concat(subqueries, preComputedSubqueries);
subqueries = Cypher.utils.concat(subqueries, preComputedSubqueries);
}
}

Expand Down
4 changes: 2 additions & 2 deletions packages/graphql/src/translate/queryAST/ast/QueryAST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class QueryAST {

public build(neo4jGraphQLContext: Neo4jGraphQLTranslationContext, varName?: string): Cypher.Clause {
const context = this.buildQueryASTContext(neo4jGraphQLContext, varName);
return Cypher.concat(...this.transpile(context).clauses);
return Cypher.utils.concat(...this.transpile(context).clauses);
}

// TODO: refactor other top level operations to use this method instead of build
Expand All @@ -54,7 +54,7 @@ export class QueryAST {
}
}

return Cypher.concat(...clauses, returnClause);
return Cypher.utils.concat(...clauses, returnClause);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,10 @@ export class AggregationAttributeField extends AggregationField {

const projection = new Cypher.Return([this.createAggregationExpr(listVar), returnVar]);

return Cypher.concat(
new Cypher.With(target)
.orderBy([Cypher.size(aggrProp), "DESC"])
.with([Cypher.collect(aggrProp), listVar]),
projection
);
return new Cypher.With(target)
.orderBy([Cypher.size(aggrProp), "DESC"])
.with([Cypher.collect(aggrProp), listVar])
.return(projection);
}

return new Cypher.Return([this.getAggregationExpr(target), returnVar]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ export class ConnectionFilter extends Filter {
const withPredicateReturn = new Cypher.With("*")
.where(Cypher.and(...innerFiltersPredicates))
.return([countComparisonPredicate, returnVar]);
return [Cypher.concat(match, ...subqueries, withPredicateReturn)];
return [Cypher.utils.concat(match, ...subqueries, withPredicateReturn)];
}

// This method has a big deal of complexity due to a couple of factors:
Expand Down Expand Up @@ -278,7 +278,7 @@ export class ConnectionFilter extends Filter {
const truthyPredicates = truthyFilters.map((v) => Cypher.eq(v, Cypher.true));
this.subqueryPredicate = Cypher.and(...falsyPredicates, ...truthyPredicates);

return [Cypher.concat(match, ...subqueries), Cypher.concat(match2, ...subqueries2)];
return [Cypher.utils.concat(match, ...subqueries), Cypher.utils.concat(match2, ...subqueries2)];
}

private wrapInNotIfNeeded(predicate: Cypher.Predicate): Cypher.Predicate {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export class RelationshipFilter extends Filter {
}

withClause.return([returnCondition, countVar]);
return Cypher.concat(relationshipMatch, ...selection, withClause);
return Cypher.utils.concat(relationshipMatch, ...selection, withClause);
})
);

Expand Down Expand Up @@ -202,7 +202,7 @@ export class RelationshipFilter extends Filter {

withAfterSubqueries.return([returnPredicate, returnVar]);

return [Cypher.concat(match, ...nestedSubqueries, withAfterSubqueries)];
return [Cypher.utils.concat(match, ...nestedSubqueries, withAfterSubqueries)];
}

case "ALL": {
Expand Down Expand Up @@ -257,9 +257,9 @@ export class RelationshipFilter extends Filter {
}
withClause.return([Cypher.gt(Cypher.count(context.target), new Cypher.Literal(0)), returnVar]); // THis variable needs to be used in predicate

return Cypher.concat(...nestedSubqueries, withClause);
return Cypher.utils.concat(...nestedSubqueries, withClause);
});
return { clause: Cypher.concat(match, ...subqueries), returnVariables };
return { clause: Cypher.utils.concat(match, ...subqueries), returnVariables };
}

private getNestedSubqueryFilter(target: Cypher.Expr): Cypher.Predicate {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,7 @@ export class CypherFilter extends Filter {
public getSubqueries(context: QueryASTContext): Cypher.Clause[] {
const { selection: cypherSubquery, nestedContext } = this.selection.apply(context);

const clause = Cypher.concat(
cypherSubquery,
new Cypher.Return([nestedContext.returnVariable, this.returnVariable])
);
const clause = cypherSubquery.return([nestedContext.returnVariable, this.returnVariable]);

return [clause];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ export class AggregationOperation extends Operation {
this.addSortToClause(nestedContext, targetVar, sortClause);
}

return Cypher.concat(
return Cypher.utils.concat(
matchClause,
...selectionClauses,
...nestedSubqueries,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ export class ConnectionReadOperation extends Operation {

return {
clauses: [
Cypher.concat(
Cypher.utils.concat(
...extraMatches,
selectionClause,
...filtersSubqueries,
Expand Down Expand Up @@ -239,7 +239,7 @@ export class ConnectionReadOperation extends Operation {
const paginationWith = this.generateSortAndPaginationClause(context);

return new Cypher.Call(
Cypher.concat(
Cypher.utils.concat(
unwindClause,
...prePaginationSubqueries,
paginationWith,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export class CreateOperation extends MutationOperation {

private getProjectionClause(context: QueryASTContext): Cypher.Clause[] {
return this.projectionOperations.map((operationField) => {
return Cypher.concat(...operationField.transpile(context).clauses);
return Cypher.utils.concat(...operationField.transpile(context).clauses);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export class CypherOperation extends ReadOperation {
public transpile(context: QueryASTContext<Cypher.Node | undefined>): OperationTranspileResult {
// eslint-disable-next-line prefer-const
let { selection: matchClause, nestedContext } = this.selection.apply(context);
const fieldSubqueries = Cypher.concat(
const fieldSubqueries = Cypher.utils.concat(
...this.getFieldsSubqueries(nestedContext),
...this.getCypherFieldsSubqueries(nestedContext)
);
Expand All @@ -64,7 +64,7 @@ export class CypherOperation extends ReadOperation {

const ret = this.getReturnClause(nestedContext, context.returnVariable);
const extraMatches: SelectionClause[] = this.getChildren().flatMap((f) => f.getSelection(nestedContext));
const clause = Cypher.concat(matchClause, ...extraMatches, fieldSubqueries, ...authClauses, ret);
const clause = Cypher.utils.concat(matchClause, ...extraMatches, fieldSubqueries, ...authClauses, ret);
return {
clauses: [clause],
projectionExpr: context.returnVariable,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,10 @@ export class CypherScalarOperation extends Operation {
} else {
retProj = [nestedContext.returnVariable, context.returnVariable];
}
const ret = new Cypher.Return(retProj);
const scope = context.getTargetScope();
// by setting the return variable of this operation in the attribute scope, we can avoid duplicate the same cypher resolution for sorting and projection purposes
scope.set(this.cypherAttributeField.name, context.returnVariable);
const clause = Cypher.concat(matchClause, ret);
const clause = matchClause.return(retProj);

return {
clauses: [clause],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export class DeleteOperation extends MutationOperation {
statements.push(new Cypher.With("*"), ...nestedOperations);
}
statements = this.appendDeleteClause(statements, context);
const ret = Cypher.concat(...statements);
const ret = Cypher.utils.concat(...statements);

return { clauses: [ret], projectionExpr: context.target };
}
Expand Down Expand Up @@ -131,7 +131,7 @@ export class DeleteOperation extends MutationOperation {
statements.push(new Cypher.With("*"), ...nestedOperations);
}
statements.push(withBeforeDeleteBlock, deleteBlock);
const ret = Cypher.concat(...statements);
const ret = Cypher.utils.concat(...statements);
return { clauses: [ret], projectionExpr: Cypher.Null };
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ export class ReadOperation extends Operation {
// This weird condition is just for cypher compatibility
const shouldAddWithForAuth = authFilterSubqueries.length || authFiltersPredicate.length;
if (filterSubqueries.length || shouldAddWithForAuth) {
filterSubqueriesClause = Cypher.concat(...filterSubqueries);
filterSubqueriesClause = Cypher.utils.concat(...filterSubqueries);
if (!isCreateSelection || authFilterSubqueries.length) {
filterSubqueryWith = new Cypher.With("*");
}
Expand All @@ -168,26 +168,32 @@ export class ReadOperation extends Operation {
let sortAndLimitBlock: Cypher.Clause | undefined;
let subqueries: Cypher.Clause;
if (this.relationship) {
subqueries = Cypher.concat(...fieldSubqueries, ...cypherFieldSubqueries, ...sortSubqueries);
subqueries = Cypher.utils.concat(...fieldSubqueries, ...cypherFieldSubqueries, ...sortSubqueries);
} else {
subqueries = Cypher.concat(...fieldSubqueries);
subqueries = Cypher.utils.concat(...fieldSubqueries);

let sortClause: Cypher.With | undefined;
if (this.sortFields.length || this.pagination) {
sortClause = new Cypher.With("*");
this.addSortToClause(nestedContext, nestedContext.target, sortClause);
}
const sortBlock = Cypher.concat(...sortSubqueries, sortClause);
const sortBlock = Cypher.utils.concat(...sortSubqueries, sortClause);

sortAndLimitBlock = this.hasCypherSort()
? Cypher.concat(...cypherFieldSubqueries, sortBlock)
: Cypher.concat(sortBlock, ...cypherFieldSubqueries);
? Cypher.utils.concat(...cypherFieldSubqueries, sortBlock)
: Cypher.utils.concat(sortBlock, ...cypherFieldSubqueries);
}

let clause: Cypher.Clause;
if (isCreateSelection && !this.relationship) {
// Top-level read part of a mutation does not contain the MATCH clause as it's implicit in the mutation.
clause = Cypher.concat(filterSubqueriesClause, filterSubqueryWith, sortAndLimitBlock, subqueries, ret);
clause = Cypher.utils.concat(
filterSubqueriesClause,
filterSubqueryWith,
sortAndLimitBlock,
subqueries,
ret
);
} else {
const extraMatches: SelectionClause[] = this.getChildren().flatMap((f) => f.getSelection(nestedContext));
let extraMatchesWith: Cypher.With | undefined;
Expand All @@ -209,7 +215,7 @@ export class ReadOperation extends Operation {
}
matchBlock.push(...extraMatches, extraMatchesWith);

clause = Cypher.concat(
clause = Cypher.utils.concat(
...matchBlock,
...authFilterSubqueries,
filterSubqueriesClause,
Expand Down
Loading

0 comments on commit a067e31

Please sign in to comment.