@neo4j/graphql
Version:
A GraphQL to Cypher query execution layer for Neo4j and JavaScript GraphQL implementations
115 lines • 5.12 kB
JavaScript
;
/*
* 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.QueryAST = void 0;
const cypher_builder_1 = __importDefault(require("@neo4j/cypher-builder"));
const create_node_from_entity_1 = require("../utils/create-node-from-entity");
const QueryASTContext_1 = require("./QueryASTContext");
const AggregationOperation_1 = require("./operations/AggregationOperation");
const ConnectionReadOperation_1 = require("./operations/ConnectionReadOperation");
const DeleteOperation_1 = require("./operations/DeleteOperation");
const ReadOperation_1 = require("./operations/ReadOperation");
const TopLevelCreateMutationOperation_1 = require("./operations/TopLevelCreateMutationOperation");
const UnwindCreateOperation_1 = require("./operations/UnwindCreateOperation");
class QueryAST {
constructor(operation) {
this.operation = operation;
}
build(neo4jGraphQLContext, varName) {
const context = this.buildQueryASTContext(neo4jGraphQLContext, varName);
return cypher_builder_1.default.utils.concat(...this.transpile(context).clauses);
}
// TODO: refactor other top level operations to use this method instead of build
buildNew(neo4jGraphQLContext, varName) {
const context = this.buildQueryASTContext(neo4jGraphQLContext, varName);
const { clauses, projectionExpr, extraProjectionColumns } = this.transpile(context);
const returnClause = varName ? new cypher_builder_1.default.Return([projectionExpr, varName]) : new cypher_builder_1.default.Return(projectionExpr);
if (extraProjectionColumns) {
for (const projectionColumn of extraProjectionColumns) {
returnClause.addColumns(projectionColumn);
}
}
return cypher_builder_1.default.utils.concat(...clauses, returnClause);
}
/**
* Transpile the QueryAST to a Cypher builder tree, this is used temporary to transpile incomplete trees, helpful to migrate the legacy code
**/
transpile(context) {
return this.operation.transpile(context);
}
buildQueryASTContext(neo4jGraphQLContext, varName) {
const queryASTEnv = new QueryASTContext_1.QueryASTEnv();
const node = this.getTargetFromOperation(varName);
const returnVariable = new cypher_builder_1.default.NamedVariable(varName ?? "this");
return new QueryASTContext_1.QueryASTContext({
target: node,
env: queryASTEnv,
neo4jGraphQLContext,
returnVariable,
});
}
getTargetFromOperation(varName) {
if (this.operation instanceof ReadOperation_1.ReadOperation ||
this.operation instanceof ConnectionReadOperation_1.ConnectionReadOperation ||
this.operation instanceof DeleteOperation_1.DeleteOperation ||
this.operation instanceof AggregationOperation_1.AggregationOperation ||
this.operation instanceof UnwindCreateOperation_1.UnwindCreateOperation ||
this.operation instanceof TopLevelCreateMutationOperation_1.TopLevelCreateMutationOperation) {
return (0, create_node_from_entity_1.createNode)(varName);
}
}
print() {
const resultLines = getTreeLines(this.operation);
return resultLines.join("\n");
}
}
exports.QueryAST = QueryAST;
function getTreeLines(treeNode, depth = 0) {
const nodeName = treeNode.print();
const resultLines = [];
const line = "────";
if (depth === 0) {
resultLines.push(`${nodeName}`);
}
else if (depth === 1) {
resultLines.push(`|${line} ${nodeName}`);
}
else {
// fillerLength is the line length repeated by the depth (minus 1 for the first line),
// in case of depth > 2 there are two pipes rather than one.
let fillerLength = (line.length + 1) * (depth - 1);
if (depth > 2) {
fillerLength += depth - 2;
}
resultLines.push(`|${" ".repeat(fillerLength)}|${line} ${nodeName}`);
}
const children = treeNode.getChildren();
if (children.length > 0) {
children.forEach((curr) => {
const childLines = getTreeLines(curr, depth + 1);
resultLines.push(...childLines);
});
}
return resultLines;
}
//# sourceMappingURL=QueryAST.js.map