|
1 |
| -import { Query } from 'cypher-query-builder'; |
| 1 | +import { entries } from '@seedcompany/common'; |
| 2 | +import { Clause, Query } from 'cypher-query-builder'; |
| 3 | +import { Parameter } from 'cypher-query-builder/dist/typings/parameter-bag'; |
| 4 | +import { isExp, variable } from '../query'; |
2 | 5 |
|
3 | 6 | declare module 'cypher-query-builder/dist/typings/query' {
|
4 | 7 | interface Query {
|
5 | 8 | /**
|
6 |
| - * Apply custom query modifications while maintaining the fluent chain. |
| 9 | + * Call a procedure. |
7 | 10 | *
|
8 |
| - * @deprecated Use {@link apply}() instead. |
9 |
| - * |
10 |
| - * In the future this could be changed to utilize native neo4j call logic. |
| 11 | + * Args can be an array of positional args, or an object of named args. |
| 12 | + * Objects are still converted to positional args, so the order matters. |
| 13 | + * Objects allow the query parameters to be named for better readability. |
11 | 14 | */
|
12 |
| - call<A extends any[], R extends this | Query<any> | void>( |
13 |
| - fn: (query: this, ...args: A) => R, |
14 |
| - ...args: A |
15 |
| - ): R extends void ? this : R; |
| 15 | + call(procedure: ProcedureCall): this; |
| 16 | + call(procedureName: string, args?: ProcedureArgs): this; |
16 | 17 | }
|
17 | 18 | }
|
18 | 19 |
|
19 |
| -Query.prototype.call = function call< |
20 |
| - A extends any[], |
21 |
| - R extends Query<any> | void, |
22 |
| ->( |
| 20 | +Query.prototype.call = function call( |
23 | 21 | this: Query,
|
24 |
| - fn: (q: Query, ...args: A) => R, |
25 |
| - ...args: A |
26 |
| -): R extends void ? Query : R { |
27 |
| - return (fn(this, ...args) || this) as Exclude<R, void>; |
| 22 | + procedure: ProcedureCall | string, |
| 23 | + args?: ProcedureArgs, |
| 24 | +) { |
| 25 | + const clause = |
| 26 | + typeof procedure === 'string' |
| 27 | + ? new Procedure(procedure, args ?? []) |
| 28 | + : new Procedure(procedure.name, procedure.args); |
| 29 | + return this.continueChainClause(clause); |
28 | 30 | };
|
| 31 | + |
| 32 | +interface ProcedureCall { |
| 33 | + name: string; |
| 34 | + args: ProcedureArgs; |
| 35 | +} |
| 36 | +type ProcedureArgs = Record<string, any> | any[]; |
| 37 | + |
| 38 | +class Procedure extends Clause { |
| 39 | + private readonly params: Parameter[]; |
| 40 | + constructor(public name: string, public args: Record<string, any> | any[]) { |
| 41 | + super(); |
| 42 | + this.params = ( |
| 43 | + Array.isArray(args) |
| 44 | + ? args.map((value) => [undefined, value] as const) |
| 45 | + : entries(this.args as Record<string, any>) |
| 46 | + ).map(([key, value]) => |
| 47 | + isExp(value) ? variable(value) : this.addParam(value, key), |
| 48 | + ); |
| 49 | + } |
| 50 | + build() { |
| 51 | + return `CALL ${this.name}(${this.params.join(', ')})`; |
| 52 | + } |
| 53 | +} |
0 commit comments