flowquery 1.0.35 → 1.0.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/flowquery.min.js +1 -1
- package/dist/parsing/data_structures/lookup.d.ts.map +1 -1
- package/dist/parsing/data_structures/lookup.js +5 -1
- package/dist/parsing/data_structures/lookup.js.map +1 -1
- package/dist/parsing/functions/coalesce.d.ts +17 -0
- package/dist/parsing/functions/coalesce.d.ts.map +1 -0
- package/dist/parsing/functions/coalesce.js +61 -0
- package/dist/parsing/functions/coalesce.js.map +1 -0
- package/dist/parsing/functions/date.d.ts +22 -0
- package/dist/parsing/functions/date.d.ts.map +1 -0
- package/dist/parsing/functions/date.js +71 -0
- package/dist/parsing/functions/date.js.map +1 -0
- package/dist/parsing/functions/datetime.d.ts +22 -0
- package/dist/parsing/functions/datetime.d.ts.map +1 -0
- package/dist/parsing/functions/datetime.js +71 -0
- package/dist/parsing/functions/datetime.js.map +1 -0
- package/dist/parsing/functions/duration.d.ts +7 -0
- package/dist/parsing/functions/duration.d.ts.map +1 -0
- package/dist/parsing/functions/duration.js +145 -0
- package/dist/parsing/functions/duration.js.map +1 -0
- package/dist/parsing/functions/element_id.d.ts +7 -0
- package/dist/parsing/functions/element_id.d.ts.map +1 -0
- package/dist/parsing/functions/element_id.js +58 -0
- package/dist/parsing/functions/element_id.js.map +1 -0
- package/dist/parsing/functions/function_factory.d.ts +20 -0
- package/dist/parsing/functions/function_factory.d.ts.map +1 -1
- package/dist/parsing/functions/function_factory.js +20 -0
- package/dist/parsing/functions/function_factory.js.map +1 -1
- package/dist/parsing/functions/head.d.ts +7 -0
- package/dist/parsing/functions/head.d.ts.map +1 -0
- package/dist/parsing/functions/head.js +53 -0
- package/dist/parsing/functions/head.js.map +1 -0
- package/dist/parsing/functions/id.d.ts +7 -0
- package/dist/parsing/functions/id.d.ts.map +1 -0
- package/dist/parsing/functions/id.js +58 -0
- package/dist/parsing/functions/id.js.map +1 -0
- package/dist/parsing/functions/last.d.ts +7 -0
- package/dist/parsing/functions/last.d.ts.map +1 -0
- package/dist/parsing/functions/last.js +53 -0
- package/dist/parsing/functions/last.js.map +1 -0
- package/dist/parsing/functions/localdatetime.d.ts +21 -0
- package/dist/parsing/functions/localdatetime.d.ts.map +1 -0
- package/dist/parsing/functions/localdatetime.js +71 -0
- package/dist/parsing/functions/localdatetime.js.map +1 -0
- package/dist/parsing/functions/localtime.d.ts +20 -0
- package/dist/parsing/functions/localtime.d.ts.map +1 -0
- package/dist/parsing/functions/localtime.js +67 -0
- package/dist/parsing/functions/localtime.js.map +1 -0
- package/dist/parsing/functions/max.d.ts +14 -0
- package/dist/parsing/functions/max.d.ts.map +1 -0
- package/dist/parsing/functions/max.js +51 -0
- package/dist/parsing/functions/max.js.map +1 -0
- package/dist/parsing/functions/min.d.ts +14 -0
- package/dist/parsing/functions/min.d.ts.map +1 -0
- package/dist/parsing/functions/min.js +51 -0
- package/dist/parsing/functions/min.js.map +1 -0
- package/dist/parsing/functions/nodes.d.ts +7 -0
- package/dist/parsing/functions/nodes.d.ts.map +1 -0
- package/dist/parsing/functions/nodes.js +63 -0
- package/dist/parsing/functions/nodes.js.map +1 -0
- package/dist/parsing/functions/properties.d.ts +7 -0
- package/dist/parsing/functions/properties.d.ts.map +1 -0
- package/dist/parsing/functions/properties.js +74 -0
- package/dist/parsing/functions/properties.js.map +1 -0
- package/dist/parsing/functions/relationships.d.ts +7 -0
- package/dist/parsing/functions/relationships.d.ts.map +1 -0
- package/dist/parsing/functions/relationships.js +61 -0
- package/dist/parsing/functions/relationships.js.map +1 -0
- package/dist/parsing/functions/tail.d.ts +7 -0
- package/dist/parsing/functions/tail.d.ts.map +1 -0
- package/dist/parsing/functions/tail.js +50 -0
- package/dist/parsing/functions/tail.js.map +1 -0
- package/dist/parsing/functions/temporal_utils.d.ts +39 -0
- package/dist/parsing/functions/temporal_utils.d.ts.map +1 -0
- package/dist/parsing/functions/temporal_utils.js +168 -0
- package/dist/parsing/functions/temporal_utils.js.map +1 -0
- package/dist/parsing/functions/time.d.ts +20 -0
- package/dist/parsing/functions/time.d.ts.map +1 -0
- package/dist/parsing/functions/time.js +67 -0
- package/dist/parsing/functions/time.js.map +1 -0
- package/dist/parsing/functions/timestamp.d.ts +17 -0
- package/dist/parsing/functions/timestamp.d.ts.map +1 -0
- package/dist/parsing/functions/timestamp.js +51 -0
- package/dist/parsing/functions/timestamp.js.map +1 -0
- package/dist/parsing/functions/to_float.d.ts +7 -0
- package/dist/parsing/functions/to_float.d.ts.map +1 -0
- package/dist/parsing/functions/to_float.js +61 -0
- package/dist/parsing/functions/to_float.js.map +1 -0
- package/dist/parsing/functions/to_integer.d.ts +7 -0
- package/dist/parsing/functions/to_integer.d.ts.map +1 -0
- package/dist/parsing/functions/to_integer.js +61 -0
- package/dist/parsing/functions/to_integer.js.map +1 -0
- package/docs/flowquery.min.js +1 -1
- package/flowquery-py/pyproject.toml +1 -1
- package/flowquery-py/src/parsing/data_structures/lookup.py +2 -0
- package/flowquery-py/src/parsing/functions/__init__.py +40 -2
- package/flowquery-py/src/parsing/functions/coalesce.py +44 -0
- package/flowquery-py/src/parsing/functions/date_.py +63 -0
- package/flowquery-py/src/parsing/functions/datetime_.py +64 -0
- package/flowquery-py/src/parsing/functions/duration.py +159 -0
- package/flowquery-py/src/parsing/functions/element_id.py +50 -0
- package/flowquery-py/src/parsing/functions/head.py +39 -0
- package/flowquery-py/src/parsing/functions/id_.py +49 -0
- package/flowquery-py/src/parsing/functions/last.py +39 -0
- package/flowquery-py/src/parsing/functions/localdatetime.py +62 -0
- package/flowquery-py/src/parsing/functions/localtime.py +59 -0
- package/flowquery-py/src/parsing/functions/max_.py +49 -0
- package/flowquery-py/src/parsing/functions/min_.py +49 -0
- package/flowquery-py/src/parsing/functions/nodes.py +48 -0
- package/flowquery-py/src/parsing/functions/properties.py +50 -0
- package/flowquery-py/src/parsing/functions/relationships.py +46 -0
- package/flowquery-py/src/parsing/functions/tail.py +37 -0
- package/flowquery-py/src/parsing/functions/temporal_utils.py +186 -0
- package/flowquery-py/src/parsing/functions/time_.py +59 -0
- package/flowquery-py/src/parsing/functions/timestamp.py +39 -0
- package/flowquery-py/src/parsing/functions/to_float.py +46 -0
- package/flowquery-py/src/parsing/functions/to_integer.py +46 -0
- package/flowquery-py/tests/compute/test_runner.py +834 -1
- package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
- package/package.json +1 -1
- package/src/parsing/data_structures/lookup.ts +8 -4
- package/src/parsing/functions/coalesce.ts +50 -0
- package/src/parsing/functions/date.ts +65 -0
- package/src/parsing/functions/datetime.ts +65 -0
- package/src/parsing/functions/duration.ts +143 -0
- package/src/parsing/functions/element_id.ts +51 -0
- package/src/parsing/functions/function_factory.ts +20 -0
- package/src/parsing/functions/head.ts +42 -0
- package/src/parsing/functions/id.ts +51 -0
- package/src/parsing/functions/last.ts +42 -0
- package/src/parsing/functions/localdatetime.ts +65 -0
- package/src/parsing/functions/localtime.ts +60 -0
- package/src/parsing/functions/max.ts +37 -0
- package/src/parsing/functions/min.ts +37 -0
- package/src/parsing/functions/nodes.ts +54 -0
- package/src/parsing/functions/properties.ts +56 -0
- package/src/parsing/functions/relationships.ts +52 -0
- package/src/parsing/functions/tail.ts +39 -0
- package/src/parsing/functions/temporal_utils.ts +180 -0
- package/src/parsing/functions/time.ts +60 -0
- package/src/parsing/functions/timestamp.ts +41 -0
- package/src/parsing/functions/to_float.ts +50 -0
- package/src/parsing/functions/to_integer.ts +50 -0
- package/tests/compute/runner.test.ts +726 -0
package/package.json
CHANGED
|
@@ -2,9 +2,9 @@ import ASTNode from "../ast_node";
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Represents a lookup operation (array/object indexing) in the AST.
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
6
|
* Lookups access elements from arrays or properties from objects using an index or key.
|
|
7
|
-
*
|
|
7
|
+
*
|
|
8
8
|
* @example
|
|
9
9
|
* ```typescript
|
|
10
10
|
* // For array[0] or obj.property or obj["key"]
|
|
@@ -33,8 +33,12 @@ class Lookup extends ASTNode {
|
|
|
33
33
|
return true;
|
|
34
34
|
}
|
|
35
35
|
public value(): any {
|
|
36
|
-
|
|
36
|
+
const obj = this.variable.value();
|
|
37
|
+
if (obj === null || obj === undefined) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
return obj[this.index.value()];
|
|
37
41
|
}
|
|
38
42
|
}
|
|
39
43
|
|
|
40
|
-
export default Lookup;
|
|
44
|
+
export default Lookup;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import Function from "./function";
|
|
2
|
+
import { FunctionDef } from "./function_metadata";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns the first non-null value from a list of expressions.
|
|
6
|
+
* Equivalent to Neo4j's coalesce() function.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```
|
|
10
|
+
* RETURN coalesce(null, null, 'hello', 'world') // returns 'hello'
|
|
11
|
+
* MATCH (n) RETURN coalesce(n.nickname, n.name) AS displayName
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
@FunctionDef({
|
|
15
|
+
description: "Returns the first non-null value from a list of expressions",
|
|
16
|
+
category: "scalar",
|
|
17
|
+
parameters: [
|
|
18
|
+
{ name: "expressions", description: "Two or more expressions to evaluate", type: "any" },
|
|
19
|
+
],
|
|
20
|
+
output: {
|
|
21
|
+
description: "The first non-null value, or null if all values are null",
|
|
22
|
+
type: "any",
|
|
23
|
+
},
|
|
24
|
+
examples: [
|
|
25
|
+
"RETURN coalesce(null, 'hello', 'world')",
|
|
26
|
+
"MATCH (n) RETURN coalesce(n.nickname, n.name) AS displayName",
|
|
27
|
+
],
|
|
28
|
+
})
|
|
29
|
+
class Coalesce extends Function {
|
|
30
|
+
constructor() {
|
|
31
|
+
super("coalesce");
|
|
32
|
+
this._expectedParameterCount = null; // variable number of parameters
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public value(): any {
|
|
36
|
+
const children = this.getChildren();
|
|
37
|
+
if (children.length === 0) {
|
|
38
|
+
throw new Error("coalesce() requires at least one argument");
|
|
39
|
+
}
|
|
40
|
+
for (const child of children) {
|
|
41
|
+
const val = child.value();
|
|
42
|
+
if (val !== null && val !== undefined) {
|
|
43
|
+
return val;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export default Coalesce;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import Function from "./function";
|
|
2
|
+
import { FunctionDef } from "./function_metadata";
|
|
3
|
+
import { buildDateObject, parseTemporalArg } from "./temporal_utils";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Returns a date value (no time component).
|
|
7
|
+
* When called with no arguments, returns the current date.
|
|
8
|
+
* When called with a string argument, parses it as an ISO 8601 date.
|
|
9
|
+
* When called with a map argument, constructs a date from components.
|
|
10
|
+
*
|
|
11
|
+
* Equivalent to Neo4j's date() function.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```
|
|
15
|
+
* RETURN date() AS today
|
|
16
|
+
* RETURN date('2025-06-15') AS d
|
|
17
|
+
* RETURN date({year: 2025, month: 6, day: 15}) AS d
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
@FunctionDef({
|
|
21
|
+
description:
|
|
22
|
+
"Returns a date value. With no arguments returns the current date. " +
|
|
23
|
+
"Accepts an ISO 8601 date string or a map of components (year, month, day).",
|
|
24
|
+
category: "scalar",
|
|
25
|
+
parameters: [
|
|
26
|
+
{
|
|
27
|
+
name: "input",
|
|
28
|
+
description: "Optional. An ISO 8601 date string (YYYY-MM-DD) or a map of components.",
|
|
29
|
+
type: "string",
|
|
30
|
+
required: false,
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
output: {
|
|
34
|
+
description:
|
|
35
|
+
"A date object with properties: year, month, day, " +
|
|
36
|
+
"epochMillis, dayOfWeek, dayOfYear, quarter, formatted",
|
|
37
|
+
type: "object",
|
|
38
|
+
},
|
|
39
|
+
examples: [
|
|
40
|
+
"RETURN date() AS today",
|
|
41
|
+
"RETURN date('2025-06-15') AS d",
|
|
42
|
+
"RETURN date({year: 2025, month: 6, day: 15}) AS d",
|
|
43
|
+
"WITH date() AS d RETURN d.year, d.month, d.dayOfWeek",
|
|
44
|
+
],
|
|
45
|
+
})
|
|
46
|
+
class DateFunction extends Function {
|
|
47
|
+
constructor() {
|
|
48
|
+
super("date");
|
|
49
|
+
this._expectedParameterCount = null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public value(): any {
|
|
53
|
+
const children = this.getChildren();
|
|
54
|
+
if (children.length > 1) {
|
|
55
|
+
throw new Error("date() accepts at most one argument");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const d: Date =
|
|
59
|
+
children.length === 1 ? parseTemporalArg(children[0].value(), "date") : new Date();
|
|
60
|
+
|
|
61
|
+
return buildDateObject(d);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export default DateFunction;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import Function from "./function";
|
|
2
|
+
import { FunctionDef } from "./function_metadata";
|
|
3
|
+
import { buildDatetimeObject, parseTemporalArg } from "./temporal_utils";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Returns a datetime value (date + time + timezone offset).
|
|
7
|
+
* When called with no arguments, returns the current UTC datetime.
|
|
8
|
+
* When called with a string argument, parses it as an ISO 8601 datetime.
|
|
9
|
+
* When called with a map argument, constructs a datetime from components.
|
|
10
|
+
*
|
|
11
|
+
* Equivalent to Neo4j's datetime() function.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```
|
|
15
|
+
* RETURN datetime() AS now
|
|
16
|
+
* RETURN datetime('2025-06-15T12:30:00Z') AS dt
|
|
17
|
+
* RETURN datetime({year: 2025, month: 6, day: 15}) AS dt
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
@FunctionDef({
|
|
21
|
+
description:
|
|
22
|
+
"Returns a datetime value. With no arguments returns the current UTC datetime. " +
|
|
23
|
+
"Accepts an ISO 8601 string or a map of components (year, month, day, hour, minute, second, millisecond).",
|
|
24
|
+
category: "scalar",
|
|
25
|
+
parameters: [
|
|
26
|
+
{
|
|
27
|
+
name: "input",
|
|
28
|
+
description: "Optional. An ISO 8601 datetime string or a map of components.",
|
|
29
|
+
type: "string",
|
|
30
|
+
required: false,
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
output: {
|
|
34
|
+
description:
|
|
35
|
+
"A datetime object with properties: year, month, day, hour, minute, second, millisecond, " +
|
|
36
|
+
"epochMillis, epochSeconds, dayOfWeek, dayOfYear, quarter, formatted",
|
|
37
|
+
type: "object",
|
|
38
|
+
},
|
|
39
|
+
examples: [
|
|
40
|
+
"RETURN datetime() AS now",
|
|
41
|
+
"RETURN datetime('2025-06-15T12:30:00Z') AS dt",
|
|
42
|
+
"RETURN datetime({year: 2025, month: 6, day: 15, hour: 12}) AS dt",
|
|
43
|
+
"WITH datetime() AS dt RETURN dt.year, dt.month, dt.day",
|
|
44
|
+
],
|
|
45
|
+
})
|
|
46
|
+
class Datetime extends Function {
|
|
47
|
+
constructor() {
|
|
48
|
+
super("datetime");
|
|
49
|
+
this._expectedParameterCount = null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public value(): any {
|
|
53
|
+
const children = this.getChildren();
|
|
54
|
+
if (children.length > 1) {
|
|
55
|
+
throw new Error("datetime() accepts at most one argument");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const d: Date =
|
|
59
|
+
children.length === 1 ? parseTemporalArg(children[0].value(), "datetime") : new Date();
|
|
60
|
+
|
|
61
|
+
return buildDatetimeObject(d, true);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export default Datetime;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import Function from "./function";
|
|
2
|
+
import { FunctionDef } from "./function_metadata";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Regex for ISO 8601 duration strings: P[nY][nM][nW][nD][T[nH][nM][nS]]
|
|
6
|
+
*/
|
|
7
|
+
const ISO_DURATION_REGEX =
|
|
8
|
+
/^P(?:(\d+(?:\.\d+)?)Y)?(?:(\d+(?:\.\d+)?)M)?(?:(\d+(?:\.\d+)?)W)?(?:(\d+(?:\.\d+)?)D)?(?:T(?:(\d+(?:\.\d+)?)H)?(?:(\d+(?:\.\d+)?)M)?(?:(\d+(?:\.\d+)?)S)?)?$/;
|
|
9
|
+
|
|
10
|
+
function parseDurationString(s: string): Record<string, number> {
|
|
11
|
+
const match = s.match(ISO_DURATION_REGEX);
|
|
12
|
+
if (!match) {
|
|
13
|
+
throw new Error(`duration(): Invalid ISO 8601 duration string: '${s}'`);
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
years: match[1] ? parseFloat(match[1]) : 0,
|
|
17
|
+
months: match[2] ? parseFloat(match[2]) : 0,
|
|
18
|
+
weeks: match[3] ? parseFloat(match[3]) : 0,
|
|
19
|
+
days: match[4] ? parseFloat(match[4]) : 0,
|
|
20
|
+
hours: match[5] ? parseFloat(match[5]) : 0,
|
|
21
|
+
minutes: match[6] ? parseFloat(match[6]) : 0,
|
|
22
|
+
seconds: match[7] ? parseFloat(match[7]) : 0,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function buildDurationObject(components: Record<string, number>): Record<string, any> {
|
|
27
|
+
const years = components.years || 0;
|
|
28
|
+
const months = components.months || 0;
|
|
29
|
+
const weeks = components.weeks || 0;
|
|
30
|
+
const days = components.days || 0;
|
|
31
|
+
const hours = components.hours || 0;
|
|
32
|
+
const minutes = components.minutes || 0;
|
|
33
|
+
const seconds = Math.floor(components.seconds || 0);
|
|
34
|
+
const fractionalSeconds = (components.seconds || 0) - seconds;
|
|
35
|
+
|
|
36
|
+
const milliseconds = components.milliseconds
|
|
37
|
+
? Math.floor(components.milliseconds)
|
|
38
|
+
: Math.round(fractionalSeconds * 1000);
|
|
39
|
+
|
|
40
|
+
const nanoseconds = components.nanoseconds
|
|
41
|
+
? Math.floor(components.nanoseconds)
|
|
42
|
+
: Math.round(fractionalSeconds * 1_000_000_000) % 1_000_000;
|
|
43
|
+
|
|
44
|
+
// Total days including weeks
|
|
45
|
+
const totalDays = days + weeks * 7;
|
|
46
|
+
|
|
47
|
+
// Total seconds for the time portion
|
|
48
|
+
const totalSeconds = hours * 3600 + minutes * 60 + seconds;
|
|
49
|
+
|
|
50
|
+
// Approximate total in various units (months approximated at 30 days)
|
|
51
|
+
const totalMonths = years * 12 + months;
|
|
52
|
+
|
|
53
|
+
// Build ISO 8601 formatted string
|
|
54
|
+
let formatted = "P";
|
|
55
|
+
if (years) formatted += `${years}Y`;
|
|
56
|
+
if (months) formatted += `${months}M`;
|
|
57
|
+
if (weeks) formatted += `${weeks}W`;
|
|
58
|
+
if (totalDays - weeks * 7) formatted += `${totalDays - weeks * 7}D`;
|
|
59
|
+
const hasTime = hours || minutes || seconds || milliseconds;
|
|
60
|
+
if (hasTime) {
|
|
61
|
+
formatted += "T";
|
|
62
|
+
if (hours) formatted += `${hours}H`;
|
|
63
|
+
if (minutes) formatted += `${minutes}M`;
|
|
64
|
+
if (seconds || milliseconds) {
|
|
65
|
+
if (milliseconds) {
|
|
66
|
+
formatted += `${seconds}.${String(milliseconds).padStart(3, "0")}S`;
|
|
67
|
+
} else {
|
|
68
|
+
formatted += `${seconds}S`;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (formatted === "P") formatted = "PT0S";
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
years,
|
|
76
|
+
months,
|
|
77
|
+
weeks,
|
|
78
|
+
days: totalDays,
|
|
79
|
+
hours,
|
|
80
|
+
minutes,
|
|
81
|
+
seconds,
|
|
82
|
+
milliseconds,
|
|
83
|
+
nanoseconds,
|
|
84
|
+
totalMonths,
|
|
85
|
+
totalDays,
|
|
86
|
+
totalSeconds,
|
|
87
|
+
formatted,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@FunctionDef({
|
|
92
|
+
description:
|
|
93
|
+
"Creates a duration value representing a span of time. " +
|
|
94
|
+
"Accepts an ISO 8601 duration string (e.g., 'P1Y2M3DT4H5M6S') or a map of components " +
|
|
95
|
+
"(years, months, weeks, days, hours, minutes, seconds, milliseconds, nanoseconds).",
|
|
96
|
+
category: "scalar",
|
|
97
|
+
parameters: [
|
|
98
|
+
{
|
|
99
|
+
name: "input",
|
|
100
|
+
description:
|
|
101
|
+
"An ISO 8601 duration string or a map of components (years, months, weeks, days, hours, minutes, seconds, milliseconds, nanoseconds)",
|
|
102
|
+
type: "any",
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
output: {
|
|
106
|
+
description:
|
|
107
|
+
"A duration object with properties: years, months, weeks, days, hours, minutes, seconds, " +
|
|
108
|
+
"milliseconds, nanoseconds, totalMonths, totalDays, totalSeconds, formatted",
|
|
109
|
+
type: "object",
|
|
110
|
+
},
|
|
111
|
+
examples: [
|
|
112
|
+
"RETURN duration('P1Y2M3D') AS d",
|
|
113
|
+
"RETURN duration('PT2H30M') AS d",
|
|
114
|
+
"RETURN duration({days: 14, hours: 16}) AS d",
|
|
115
|
+
"RETURN duration({months: 5, days: 1, hours: 12}) AS d",
|
|
116
|
+
],
|
|
117
|
+
})
|
|
118
|
+
class Duration extends Function {
|
|
119
|
+
constructor() {
|
|
120
|
+
super("duration");
|
|
121
|
+
this._expectedParameterCount = 1;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public value(): any {
|
|
125
|
+
const arg = this.getChildren()[0].value();
|
|
126
|
+
if (arg === null || arg === undefined) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (typeof arg === "string") {
|
|
131
|
+
const components = parseDurationString(arg);
|
|
132
|
+
return buildDurationObject(components);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (typeof arg === "object" && !Array.isArray(arg)) {
|
|
136
|
+
return buildDurationObject(arg);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
throw new Error("duration() expects a string or map argument");
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export default Duration;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import Function from "./function";
|
|
2
|
+
import { FunctionDef } from "./function_metadata";
|
|
3
|
+
|
|
4
|
+
@FunctionDef({
|
|
5
|
+
description:
|
|
6
|
+
"Returns the element id of a node or relationship as a string. For nodes, returns the string representation of the id property. For relationships, returns the type.",
|
|
7
|
+
category: "scalar",
|
|
8
|
+
parameters: [
|
|
9
|
+
{
|
|
10
|
+
name: "entity",
|
|
11
|
+
description: "A node or relationship to get the element id from",
|
|
12
|
+
type: "object",
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
output: {
|
|
16
|
+
description: "The element id of the entity as a string",
|
|
17
|
+
type: "string",
|
|
18
|
+
example: '"1"',
|
|
19
|
+
},
|
|
20
|
+
examples: ["MATCH (n:Person) RETURN elementId(n)", "MATCH (a)-[r]->(b) RETURN elementId(r)"],
|
|
21
|
+
})
|
|
22
|
+
class ElementId extends Function {
|
|
23
|
+
constructor() {
|
|
24
|
+
super("elementid");
|
|
25
|
+
this._expectedParameterCount = 1;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public value(): any {
|
|
29
|
+
const obj = this.getChildren()[0].value();
|
|
30
|
+
if (obj === null || obj === undefined) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
if (typeof obj !== "object" || Array.isArray(obj)) {
|
|
34
|
+
throw new Error("elementId() expects a node or relationship");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// If it's a RelationshipMatchRecord (has type, startNode, endNode, properties)
|
|
38
|
+
if ("type" in obj && "startNode" in obj && "endNode" in obj && "properties" in obj) {
|
|
39
|
+
return String(obj.type);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// If it's a node record (has id field)
|
|
43
|
+
if ("id" in obj) {
|
|
44
|
+
return String(obj.id);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
throw new Error("elementId() expects a node or relationship");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export default ElementId;
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import AsyncFunction from "./async_function";
|
|
2
2
|
import "./avg";
|
|
3
|
+
import "./coalesce";
|
|
3
4
|
import "./collect";
|
|
4
5
|
import "./count";
|
|
6
|
+
import "./date";
|
|
7
|
+
import "./datetime";
|
|
8
|
+
import "./duration";
|
|
9
|
+
import "./element_id";
|
|
5
10
|
import Function from "./function";
|
|
6
11
|
import {
|
|
7
12
|
AsyncDataProvider,
|
|
@@ -11,12 +16,22 @@ import {
|
|
|
11
16
|
getRegisteredFunctionMetadata,
|
|
12
17
|
} from "./function_metadata";
|
|
13
18
|
import "./functions";
|
|
19
|
+
import "./head";
|
|
20
|
+
import "./id";
|
|
14
21
|
import "./join";
|
|
15
22
|
import "./keys";
|
|
23
|
+
import "./last";
|
|
24
|
+
import "./localdatetime";
|
|
25
|
+
import "./localtime";
|
|
26
|
+
import "./max";
|
|
27
|
+
import "./min";
|
|
28
|
+
import "./nodes";
|
|
16
29
|
import PredicateFunction from "./predicate_function";
|
|
17
30
|
import "./predicate_sum";
|
|
31
|
+
import "./properties";
|
|
18
32
|
import "./rand";
|
|
19
33
|
import "./range";
|
|
34
|
+
import "./relationships";
|
|
20
35
|
import "./replace";
|
|
21
36
|
import "./round";
|
|
22
37
|
import "./schema";
|
|
@@ -26,6 +41,11 @@ import "./string_distance";
|
|
|
26
41
|
import "./stringify";
|
|
27
42
|
// Import built-in functions to ensure their @FunctionDef decorators run
|
|
28
43
|
import "./sum";
|
|
44
|
+
import "./tail";
|
|
45
|
+
import "./time";
|
|
46
|
+
import "./timestamp";
|
|
47
|
+
import "./to_float";
|
|
48
|
+
import "./to_integer";
|
|
29
49
|
import "./to_json";
|
|
30
50
|
import "./to_lower";
|
|
31
51
|
import "./to_string";
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import Function from "./function";
|
|
2
|
+
import { FunctionDef } from "./function_metadata";
|
|
3
|
+
|
|
4
|
+
@FunctionDef({
|
|
5
|
+
description: "Returns the first element of a list",
|
|
6
|
+
category: "scalar",
|
|
7
|
+
parameters: [
|
|
8
|
+
{
|
|
9
|
+
name: "list",
|
|
10
|
+
description: "The list to get the first element from",
|
|
11
|
+
type: "array",
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
output: {
|
|
15
|
+
description: "The first element of the list",
|
|
16
|
+
type: "any",
|
|
17
|
+
example: "1",
|
|
18
|
+
},
|
|
19
|
+
examples: ["RETURN head([1, 2, 3])", "WITH ['a', 'b', 'c'] AS items RETURN head(items)"],
|
|
20
|
+
})
|
|
21
|
+
class Head extends Function {
|
|
22
|
+
constructor() {
|
|
23
|
+
super("head");
|
|
24
|
+
this._expectedParameterCount = 1;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public value(): any {
|
|
28
|
+
const val = this.getChildren()[0].value();
|
|
29
|
+
if (val === null || val === undefined) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
if (!Array.isArray(val)) {
|
|
33
|
+
throw new Error("head() expects a list");
|
|
34
|
+
}
|
|
35
|
+
if (val.length === 0) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
return val[0];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default Head;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import Function from "./function";
|
|
2
|
+
import { FunctionDef } from "./function_metadata";
|
|
3
|
+
|
|
4
|
+
@FunctionDef({
|
|
5
|
+
description:
|
|
6
|
+
"Returns the id of a node or relationship. For nodes, returns the id property. For relationships, returns the type.",
|
|
7
|
+
category: "scalar",
|
|
8
|
+
parameters: [
|
|
9
|
+
{
|
|
10
|
+
name: "entity",
|
|
11
|
+
description: "A node or relationship to get the id from",
|
|
12
|
+
type: "object",
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
output: {
|
|
16
|
+
description: "The id of the entity",
|
|
17
|
+
type: "any",
|
|
18
|
+
example: "1",
|
|
19
|
+
},
|
|
20
|
+
examples: ["MATCH (n:Person) RETURN id(n)", "MATCH (a)-[r]->(b) RETURN id(r)"],
|
|
21
|
+
})
|
|
22
|
+
class Id extends Function {
|
|
23
|
+
constructor() {
|
|
24
|
+
super("id");
|
|
25
|
+
this._expectedParameterCount = 1;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public value(): any {
|
|
29
|
+
const obj = this.getChildren()[0].value();
|
|
30
|
+
if (obj === null || obj === undefined) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
if (typeof obj !== "object" || Array.isArray(obj)) {
|
|
34
|
+
throw new Error("id() expects a node or relationship");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// If it's a RelationshipMatchRecord (has type, startNode, endNode, properties)
|
|
38
|
+
if ("type" in obj && "startNode" in obj && "endNode" in obj && "properties" in obj) {
|
|
39
|
+
return obj.type;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// If it's a node record (has id field)
|
|
43
|
+
if ("id" in obj) {
|
|
44
|
+
return obj.id;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
throw new Error("id() expects a node or relationship");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export default Id;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import Function from "./function";
|
|
2
|
+
import { FunctionDef } from "./function_metadata";
|
|
3
|
+
|
|
4
|
+
@FunctionDef({
|
|
5
|
+
description: "Returns the last element of a list",
|
|
6
|
+
category: "scalar",
|
|
7
|
+
parameters: [
|
|
8
|
+
{
|
|
9
|
+
name: "list",
|
|
10
|
+
description: "The list to get the last element from",
|
|
11
|
+
type: "array",
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
output: {
|
|
15
|
+
description: "The last element of the list",
|
|
16
|
+
type: "any",
|
|
17
|
+
example: "3",
|
|
18
|
+
},
|
|
19
|
+
examples: ["RETURN last([1, 2, 3])", "WITH ['a', 'b', 'c'] AS items RETURN last(items)"],
|
|
20
|
+
})
|
|
21
|
+
class Last extends Function {
|
|
22
|
+
constructor() {
|
|
23
|
+
super("last");
|
|
24
|
+
this._expectedParameterCount = 1;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public value(): any {
|
|
28
|
+
const val = this.getChildren()[0].value();
|
|
29
|
+
if (val === null || val === undefined) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
if (!Array.isArray(val)) {
|
|
33
|
+
throw new Error("last() expects a list");
|
|
34
|
+
}
|
|
35
|
+
if (val.length === 0) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
return val[val.length - 1];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default Last;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import Function from "./function";
|
|
2
|
+
import { FunctionDef } from "./function_metadata";
|
|
3
|
+
import { buildDatetimeObject, parseTemporalArg } from "./temporal_utils";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Returns a local datetime value (date + time, no timezone offset).
|
|
7
|
+
* When called with no arguments, returns the current local datetime.
|
|
8
|
+
* When called with a string argument, parses it as an ISO 8601 datetime.
|
|
9
|
+
* When called with a map argument, constructs a datetime from components.
|
|
10
|
+
*
|
|
11
|
+
* Equivalent to Neo4j's localdatetime() function.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```
|
|
15
|
+
* RETURN localdatetime() AS now
|
|
16
|
+
* RETURN localdatetime('2025-06-15T12:30:00') AS dt
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
@FunctionDef({
|
|
20
|
+
description:
|
|
21
|
+
"Returns a local datetime value (no timezone). With no arguments returns the current local datetime. " +
|
|
22
|
+
"Accepts an ISO 8601 string or a map of components.",
|
|
23
|
+
category: "scalar",
|
|
24
|
+
parameters: [
|
|
25
|
+
{
|
|
26
|
+
name: "input",
|
|
27
|
+
description: "Optional. An ISO 8601 datetime string or a map of components.",
|
|
28
|
+
type: "string",
|
|
29
|
+
required: false,
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
output: {
|
|
33
|
+
description:
|
|
34
|
+
"A datetime object with properties: year, month, day, hour, minute, second, millisecond, " +
|
|
35
|
+
"epochMillis, epochSeconds, dayOfWeek, dayOfYear, quarter, formatted",
|
|
36
|
+
type: "object",
|
|
37
|
+
},
|
|
38
|
+
examples: [
|
|
39
|
+
"RETURN localdatetime() AS now",
|
|
40
|
+
"RETURN localdatetime('2025-06-15T12:30:00') AS dt",
|
|
41
|
+
"WITH localdatetime() AS dt RETURN dt.hour, dt.minute",
|
|
42
|
+
],
|
|
43
|
+
})
|
|
44
|
+
class LocalDatetime extends Function {
|
|
45
|
+
constructor() {
|
|
46
|
+
super("localdatetime");
|
|
47
|
+
this._expectedParameterCount = null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public value(): any {
|
|
51
|
+
const children = this.getChildren();
|
|
52
|
+
if (children.length > 1) {
|
|
53
|
+
throw new Error("localdatetime() accepts at most one argument");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const d: Date =
|
|
57
|
+
children.length === 1
|
|
58
|
+
? parseTemporalArg(children[0].value(), "localdatetime")
|
|
59
|
+
: new Date();
|
|
60
|
+
|
|
61
|
+
return buildDatetimeObject(d, false);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export default LocalDatetime;
|