UNPKG

@neo4j/graphql

Version:

A GraphQL to Cypher query execution layer for Neo4j and JavaScript GraphQL implementations

143 lines 6.88 kB
"use strict"; /* * Copyright (c) "Neo4j" * Neo4j Sweden AB [http://neo4j.com] * * This file is part of Neo4j. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CompositeConnectionReadOperation = void 0; const cypher_builder_1 = __importDefault(require("@neo4j/cypher-builder")); const operations_1 = require("../operations"); const utils_1 = require("../../../../../utils/utils"); const context_has_target_1 = require("../../../utils/context-has-target"); const QueryASTContext_1 = require("../../QueryASTContext"); class CompositeConnectionReadOperation extends operations_1.Operation { constructor(children) { super(); this.sortFields = []; this.children = children; } transpile(context) { const edgeVar = new cypher_builder_1.default.NamedVariable("edge"); const edgesVar = new cypher_builder_1.default.NamedVariable("edges"); const totalCount = new cypher_builder_1.default.NamedVariable("totalCount"); const nestedSubqueries = this.children.flatMap((c) => { const subQueryContext = new QueryASTContext_1.QueryASTContext({ ...context, returnVariable: edgeVar }); const result = c.transpile(subQueryContext); if ((0, context_has_target_1.hasTarget)(context)) { const parentNode = context.target; return result.clauses.map((sq) => cypher_builder_1.default.utils.concat(new cypher_builder_1.default.With(parentNode), sq)); } else { return result.clauses; } }); const union = new cypher_builder_1.default.Union(...nestedSubqueries); const contextTarget = context.target ? [context.target] : []; const nestedSubquery = new cypher_builder_1.default.Call(new cypher_builder_1.default.Call(union, contextTarget).return([cypher_builder_1.default.collect(edgeVar), edgesVar]), contextTarget); let orderSubquery; let returnEdgesVar = edgesVar; if (this.pagination || this.sortFields.length > 0) { const paginationField = this.pagination && this.pagination.getPagination(); const nestedContext = new QueryASTContext_1.QueryASTContext({ // NOOP context target: new cypher_builder_1.default.Node(), env: context.env, neo4jGraphQLContext: context.neo4jGraphQLContext, }); const sortFields = this.getSortFields(nestedContext, edgeVar.property("node"), edgeVar.property("properties")); const extraWithOrder = new cypher_builder_1.default.Unwind([edgesVar, edgeVar]).with(edgeVar).orderBy(...sortFields); if (paginationField && paginationField.skip) { extraWithOrder.skip(paginationField.skip); } // Missing skip if (paginationField && paginationField.limit) { extraWithOrder.limit(paginationField.limit); } const edgesVar2 = new cypher_builder_1.default.Variable(); extraWithOrder.return([cypher_builder_1.default.collect(edgeVar), edgesVar2]); returnEdgesVar = edgesVar2; orderSubquery = new cypher_builder_1.default.Call(extraWithOrder, [edgesVar]); } const { fields: aggregateFields, subqueries: aggregateSubqueries, projectionMap: aggregateReturnMap, } = this.transpileAggregation(context); const aggregateVariables = aggregateFields.map((c) => c[1]); const subqueryWith = new cypher_builder_1.default.With(edgesVar, ...aggregateFields).with(edgesVar, [cypher_builder_1.default.size(edgesVar), totalCount], ...aggregateVariables); const returnClause = new cypher_builder_1.default.Return([ new cypher_builder_1.default.Map({ edges: returnEdgesVar, totalCount: totalCount, ...aggregateReturnMap, }), context.returnVariable, ]); return { clauses: [ cypher_builder_1.default.utils.concat(nestedSubquery, ...aggregateSubqueries.map((clause) => new cypher_builder_1.default.Call(clause, (0, utils_1.filterTruthy)([context.target]))), subqueryWith, orderSubquery, returnClause), ], projectionExpr: context.returnVariable, }; } addSort(sortElement) { this.sortFields.push(sortElement); } addPagination(pagination) { this.pagination = pagination; } setAggregationField(aggregationField) { this.aggregationField = aggregationField; } getChildren() { const sortFields = this.sortFields.flatMap((s) => { return [...s.edge, ...s.node]; }); return (0, utils_1.filterTruthy)([...this.children, this.aggregationField, ...sortFields, this.pagination]); } getSortFields(context, nodeVar, edgeVar) { return this.sortFields.flatMap(({ node, edge }) => { const nodeFields = node.flatMap((s) => s.getSortFields(context, nodeVar, false)); const edgeFields = edge.flatMap((s) => s.getSortFields(context, edgeVar, false)); return [...nodeFields, ...edgeFields]; }); } // NOTE: duplicate from ConnectionReadOperation transpileAggregation(context) { if (!this.aggregationField) { return { fields: [], subqueries: [], projectionMap: {}, }; } const projectionMap = {}; const subqueries = this.aggregationField.getSubqueries(context); const aggregationProjectionField = this.aggregationField.getProjectionField(); const fields = Object.entries(aggregationProjectionField).map(([key, value]) => { const variable = new cypher_builder_1.default.Variable(); projectionMap[key] = variable; return [value, variable]; }); return { fields, subqueries, projectionMap, }; } } exports.CompositeConnectionReadOperation = CompositeConnectionReadOperation; //# sourceMappingURL=CompositeConnectionReadOperation.js.map