UNPKG

cypher-engine

Version:

Cypher Engine to generate Cypher queries

387 lines (327 loc) 10.3 kB
import { ICypherFunction } from '../interfaces/ICypherFunction'; import { SetProperty } from '../models/SetProperty'; import { RelationshipDirection } from '../models/RelationshipDirection'; import { Property } from '../models/Property'; import { Cypher } from '../models/Cypher'; import { PathRange } from '../models/PathRange'; export class CypherEngine { private readonly _cypher: Cypher[]; private readonly _nodes: string[]; constructor() { this._cypher = []; this._nodes = []; } public get cypher(): string { let baseCypher: string = ''; for (let i = 0; i < this._cypher.length; i++) { const cypher = this._cypher[i]; baseCypher += i < this._cypher.length - 1 ? `${cypher.cypher}${cypher.seperator}` : cypher.cypher; } return baseCypher; } public match(): CypherEngine { this._cypher.push(new Cypher('MATCH', ' ')); return this; } public optionalMatch(): CypherEngine { this._cypher.push(new Cypher('OPTIONAL', ' ')); this.match(); return this; } public conditional(ifStatement: boolean | undefined, query: string, elseQuery: string): CypherEngine { if (ifStatement) { this.value(query); } else { this.value(elseQuery); } return this; } public conditionalFunc( ifStatement: boolean | undefined, query: ICypherFunction, elseQuery: ICypherFunction, ): CypherEngine { if (ifStatement) { query(this); } else { elseQuery(this); } return this; } public merge(): CypherEngine { this._cypher.push(new Cypher('MERGE', ' ')); return this; } public create(): CypherEngine { this._cypher.push(new Cypher('CREATE', ' ')); return this; } public node(labels: string[], variableName?: string, ...properties: Property[]): CypherEngine { this._cypher.push(new Cypher(this.nodeString(labels, variableName, ...properties))); if (variableName) { this._nodes.push(variableName); } return this; } public declaredNode(variableName: string, ...additionalLabels: string[]): CypherEngine { const node = this._nodes.find((x) => x === variableName); if (!node) { throw new Error(`Could not find node ${variableName}`); } this._cypher.push(new Cypher(this.nodeString(additionalLabels, variableName))); return this; } public variable(variableName: string, property?: string): CypherEngine { this._cypher.push(new Cypher(this.variableString(variableName, property), ' ')); return this; } public relates( direction: RelationshipDirection, types?: string[], variableName?: string, range?: PathRange, ...properties: Property[] ): CypherEngine { if (!types) { this._cypher.push(new Cypher('--', '')); return this; } const variableNameStatement = variableName || ''; const typesStatement = types.length ? ':' + types.join('|') : ''; const relationshipRangeStatement = range ? range!.toString() : ''; let statement = `[${variableNameStatement}${typesStatement}${relationshipRangeStatement}${this.propertyFilter( ...properties, )}]`; switch (direction) { case RelationshipDirection.left: statement = `<-${statement}-`; break; case RelationshipDirection.right: statement = `-${statement}->`; break; default: statement = `-${statement}-`; break; } this._cypher.push(new Cypher(statement, '')); return this; } public delete(variableName: string, ...furtherNames: string[]): CypherEngine { const variables: string[] = []; variables.push(variableName); variables.push(...furtherNames); const statement = `DELETE ${variables.join(',')}`; this._cypher.push(new Cypher(statement)); return this; } public where(): CypherEngine { this._cypher.push(new Cypher('WHERE', ' ')); return this; } public detach(): CypherEngine { const statement = 'DETACH'; this._cypher.push(new Cypher(statement, ' ')); return this; } public unwind(): CypherEngine { const statement = `UNWIND`; this._cypher.push(new Cypher(statement, ' ')); return this; } public with(...variableNames: string[]): CypherEngine { if (variableNames && variableNames.length) { this._nodes.length = 0; this._nodes.push(...variableNames); } const statement = `WITH ${variableNames.length ? variableNames.join(',') : '*'}`; this._cypher.push(new Cypher(statement)); return this; } public exists(variableName: string, property: string): CypherEngine { const statement = `exists(${variableName}.${property})`; this._cypher.push(new Cypher(statement)); return this; } // Uses raw data, add '' quotes for strings into the value public value(value: string | number | string[] | number[]): CypherEngine { let statement = ''; if (Array.isArray(value)) { statement = `${JSON.stringify(value)}`; } else { statement = `${value}`; } this._cypher.push(new Cypher(statement, ' ')); return this; } public set(...properties: SetProperty[]): CypherEngine { const statement = `SET${properties.length ? ' ' + this.propertySetter(...properties) : ''}`; this._cypher.push(new Cypher(statement)); return this; } public onCreate(): CypherEngine { this._cypher.push(new Cypher('ON CREATE', ' ')); return this; } public onMatch(): CypherEngine { this._cypher.push(new Cypher('ON MATCH', ' ')); return this; } public and(): CypherEngine { this._cypher.push(new Cypher('AND', ' ')); return this; } public or(): CypherEngine { this._cypher.push(new Cypher('OR', ' ')); return this; } public is(): CypherEngine { this._cypher.push(new Cypher('IS', ' ')); return this; } public call(apoc: string): CypherEngine { this._cypher.push(new Cypher(`CALL ${apoc}`)); return this; } public callQuery(engine: CypherEngine): CypherEngine { this._cypher.push(new Cypher(`CALL {${engine.cypher}}`)); return this; } public in(): CypherEngine { this._cypher.push(new Cypher('IN', ' ')); return this; } public null(): CypherEngine { this._cypher.push(new Cypher('NULL', ' ')); return this; } public not(): CypherEngine { this._cypher.push(new Cypher('NOT', ' ')); return this; } public equals(): CypherEngine { this._cypher.push(new Cypher('=', ' ')); return this; } public greaterThan(): CypherEngine { this._cypher.push(new Cypher('>', ' ')); return this; } public lessThan(): CypherEngine { this._cypher.push(new Cypher('<', ' ')); return this; } public startsWith(): CypherEngine { this._cypher.push(new Cypher('STARTS WITH', ' ')); return this; } public endsWith(): CypherEngine { this._cypher.push(new Cypher('ENDS WITH', ' ')); return this; } public contains(): CypherEngine { this._cypher.push(new Cypher('CONTAINS', ' ')); return this; } public regularExpression(): CypherEngine { this._cypher.push(new Cypher('=~', ' ')); return this; } public returns(...variableNames: string[]): CypherEngine { const statement = `RETURN ${variableNames.length ? variableNames.join(',') : '*'}`; this._cypher.push(new Cypher(statement, ' ')); return this; } public limit(limit: number | string): CypherEngine { const statement = `LIMIT ${limit}`; this._cypher.push(new Cypher(statement, ' ')); return this; } public skip(skip: number | string): CypherEngine { const statement = `SKIP ${skip}`; this._cypher.push(new Cypher(statement, ' ')); return this; } public toString(): string { return this.cypher; } private nodeString(labels: string[], variableName?: string, ...properties: Property[]): string { let statement = `(${variableName || ''}${labels.length ? ':' + labels.join(':') : ''}`; statement += this.propertyFilter(...properties); statement += ')'; return statement; } private variableString(variableName: string, property?: string): string { let statement = ''; if (property) { statement = `${variableName}${property ? '.' + property : ''}`; } else { statement = `(${variableName})`; } return statement; } private propertySetter(...properties: SetProperty[]): string { const variableArr: string[] = []; for (const prop of properties) { variableArr.push(`${prop.variableName}.${prop.property.name} = ${prop.property.value}`); } return variableArr.join(', '); } private propertyFilter(...properties: Property[]): string { let statement = ''; for (let j = 0; j < properties.length; j++) { if (j === 0) { statement += '{'; } const property = properties[j]; statement += `${property.name}:${property.value}`; if (j < properties.length - 1) { statement += ', '; } else { statement += `}`; } } return statement; } public orderBy(variableNames: string[], sorts?: { prop: string; asc: boolean }[], includePhrase: boolean = true) { if (!sorts) { return this; } let n = ''; for (let j = 0; j < variableNames.length; j++) { const variableName = variableNames[j]; for (let i = 0; i < sorts.length; i++) { const sort = sorts[i]; const asc = sort.asc ? '' : 'DESC'; n += `${variableName}.${sort.prop + ' ' + asc} `; if (i !== sorts.length - 1) { n += ', '; } } if (j !== variableNames.length - 1) { n += ', '; } } this._cypher.push(new Cypher(`${includePhrase ? 'ORDER BY' : ''} ${n.trim()}`)); return this; } public case(): CypherEngine { this._cypher.push(new Cypher('CASE', ' ')); return this; } public when(): CypherEngine { this._cypher.push(new Cypher('WHEN', ' ')); return this; } public then(): CypherEngine { this._cypher.push(new Cypher('THEN', ' ')); return this; } public remove(): CypherEngine { this._cypher.push(new Cypher('REMOVE', ' ')); return this; } public else(): CypherEngine { this._cypher.push(new Cypher('ELSE', ' ')); return this; } }