flowquery 1.0.35 → 1.0.37

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.
Files changed (144) hide show
  1. package/dist/flowquery.min.js +1 -1
  2. package/dist/parsing/data_structures/lookup.d.ts.map +1 -1
  3. package/dist/parsing/data_structures/lookup.js +5 -1
  4. package/dist/parsing/data_structures/lookup.js.map +1 -1
  5. package/dist/parsing/functions/coalesce.d.ts +16 -0
  6. package/dist/parsing/functions/coalesce.d.ts.map +1 -0
  7. package/dist/parsing/functions/coalesce.js +60 -0
  8. package/dist/parsing/functions/coalesce.js.map +1 -0
  9. package/dist/parsing/functions/date.d.ts +20 -0
  10. package/dist/parsing/functions/date.d.ts.map +1 -0
  11. package/dist/parsing/functions/date.js +69 -0
  12. package/dist/parsing/functions/date.js.map +1 -0
  13. package/dist/parsing/functions/datetime.d.ts +20 -0
  14. package/dist/parsing/functions/datetime.d.ts.map +1 -0
  15. package/dist/parsing/functions/datetime.js +69 -0
  16. package/dist/parsing/functions/datetime.js.map +1 -0
  17. package/dist/parsing/functions/duration.d.ts +7 -0
  18. package/dist/parsing/functions/duration.d.ts.map +1 -0
  19. package/dist/parsing/functions/duration.js +145 -0
  20. package/dist/parsing/functions/duration.js.map +1 -0
  21. package/dist/parsing/functions/element_id.d.ts +7 -0
  22. package/dist/parsing/functions/element_id.d.ts.map +1 -0
  23. package/dist/parsing/functions/element_id.js +58 -0
  24. package/dist/parsing/functions/element_id.js.map +1 -0
  25. package/dist/parsing/functions/function_factory.d.ts +20 -0
  26. package/dist/parsing/functions/function_factory.d.ts.map +1 -1
  27. package/dist/parsing/functions/function_factory.js +20 -0
  28. package/dist/parsing/functions/function_factory.js.map +1 -1
  29. package/dist/parsing/functions/head.d.ts +7 -0
  30. package/dist/parsing/functions/head.d.ts.map +1 -0
  31. package/dist/parsing/functions/head.js +53 -0
  32. package/dist/parsing/functions/head.js.map +1 -0
  33. package/dist/parsing/functions/id.d.ts +7 -0
  34. package/dist/parsing/functions/id.d.ts.map +1 -0
  35. package/dist/parsing/functions/id.js +58 -0
  36. package/dist/parsing/functions/id.js.map +1 -0
  37. package/dist/parsing/functions/last.d.ts +7 -0
  38. package/dist/parsing/functions/last.d.ts.map +1 -0
  39. package/dist/parsing/functions/last.js +53 -0
  40. package/dist/parsing/functions/last.js.map +1 -0
  41. package/dist/parsing/functions/localdatetime.d.ts +19 -0
  42. package/dist/parsing/functions/localdatetime.d.ts.map +1 -0
  43. package/dist/parsing/functions/localdatetime.js +69 -0
  44. package/dist/parsing/functions/localdatetime.js.map +1 -0
  45. package/dist/parsing/functions/localtime.d.ts +18 -0
  46. package/dist/parsing/functions/localtime.d.ts.map +1 -0
  47. package/dist/parsing/functions/localtime.js +65 -0
  48. package/dist/parsing/functions/localtime.js.map +1 -0
  49. package/dist/parsing/functions/max.d.ts +14 -0
  50. package/dist/parsing/functions/max.d.ts.map +1 -0
  51. package/dist/parsing/functions/max.js +51 -0
  52. package/dist/parsing/functions/max.js.map +1 -0
  53. package/dist/parsing/functions/min.d.ts +14 -0
  54. package/dist/parsing/functions/min.d.ts.map +1 -0
  55. package/dist/parsing/functions/min.js +51 -0
  56. package/dist/parsing/functions/min.js.map +1 -0
  57. package/dist/parsing/functions/nodes.d.ts +7 -0
  58. package/dist/parsing/functions/nodes.d.ts.map +1 -0
  59. package/dist/parsing/functions/nodes.js +63 -0
  60. package/dist/parsing/functions/nodes.js.map +1 -0
  61. package/dist/parsing/functions/properties.d.ts +7 -0
  62. package/dist/parsing/functions/properties.d.ts.map +1 -0
  63. package/dist/parsing/functions/properties.js +74 -0
  64. package/dist/parsing/functions/properties.js.map +1 -0
  65. package/dist/parsing/functions/relationships.d.ts +7 -0
  66. package/dist/parsing/functions/relationships.d.ts.map +1 -0
  67. package/dist/parsing/functions/relationships.js +61 -0
  68. package/dist/parsing/functions/relationships.js.map +1 -0
  69. package/dist/parsing/functions/tail.d.ts +7 -0
  70. package/dist/parsing/functions/tail.d.ts.map +1 -0
  71. package/dist/parsing/functions/tail.js +50 -0
  72. package/dist/parsing/functions/tail.js.map +1 -0
  73. package/dist/parsing/functions/temporal_utils.d.ts +39 -0
  74. package/dist/parsing/functions/temporal_utils.d.ts.map +1 -0
  75. package/dist/parsing/functions/temporal_utils.js +168 -0
  76. package/dist/parsing/functions/temporal_utils.js.map +1 -0
  77. package/dist/parsing/functions/time.d.ts +18 -0
  78. package/dist/parsing/functions/time.d.ts.map +1 -0
  79. package/dist/parsing/functions/time.js +65 -0
  80. package/dist/parsing/functions/time.js.map +1 -0
  81. package/dist/parsing/functions/timestamp.d.ts +15 -0
  82. package/dist/parsing/functions/timestamp.d.ts.map +1 -0
  83. package/dist/parsing/functions/timestamp.js +48 -0
  84. package/dist/parsing/functions/timestamp.js.map +1 -0
  85. package/dist/parsing/functions/to_float.d.ts +7 -0
  86. package/dist/parsing/functions/to_float.d.ts.map +1 -0
  87. package/dist/parsing/functions/to_float.js +61 -0
  88. package/dist/parsing/functions/to_float.js.map +1 -0
  89. package/dist/parsing/functions/to_integer.d.ts +7 -0
  90. package/dist/parsing/functions/to_integer.d.ts.map +1 -0
  91. package/dist/parsing/functions/to_integer.js +61 -0
  92. package/dist/parsing/functions/to_integer.js.map +1 -0
  93. package/docs/flowquery.min.js +1 -1
  94. package/flowquery-py/pyproject.toml +1 -1
  95. package/flowquery-py/src/parsing/data_structures/lookup.py +2 -0
  96. package/flowquery-py/src/parsing/functions/__init__.py +40 -2
  97. package/flowquery-py/src/parsing/functions/coalesce.py +43 -0
  98. package/flowquery-py/src/parsing/functions/date_.py +61 -0
  99. package/flowquery-py/src/parsing/functions/datetime_.py +62 -0
  100. package/flowquery-py/src/parsing/functions/duration.py +159 -0
  101. package/flowquery-py/src/parsing/functions/element_id.py +50 -0
  102. package/flowquery-py/src/parsing/functions/head.py +39 -0
  103. package/flowquery-py/src/parsing/functions/id_.py +49 -0
  104. package/flowquery-py/src/parsing/functions/last.py +39 -0
  105. package/flowquery-py/src/parsing/functions/localdatetime.py +60 -0
  106. package/flowquery-py/src/parsing/functions/localtime.py +57 -0
  107. package/flowquery-py/src/parsing/functions/max_.py +49 -0
  108. package/flowquery-py/src/parsing/functions/min_.py +49 -0
  109. package/flowquery-py/src/parsing/functions/nodes.py +48 -0
  110. package/flowquery-py/src/parsing/functions/properties.py +50 -0
  111. package/flowquery-py/src/parsing/functions/relationships.py +46 -0
  112. package/flowquery-py/src/parsing/functions/tail.py +37 -0
  113. package/flowquery-py/src/parsing/functions/temporal_utils.py +186 -0
  114. package/flowquery-py/src/parsing/functions/time_.py +57 -0
  115. package/flowquery-py/src/parsing/functions/timestamp.py +37 -0
  116. package/flowquery-py/src/parsing/functions/to_float.py +46 -0
  117. package/flowquery-py/src/parsing/functions/to_integer.py +46 -0
  118. package/flowquery-py/tests/compute/test_runner.py +834 -1
  119. package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
  120. package/package.json +1 -1
  121. package/src/parsing/data_structures/lookup.ts +8 -4
  122. package/src/parsing/functions/coalesce.ts +49 -0
  123. package/src/parsing/functions/date.ts +63 -0
  124. package/src/parsing/functions/datetime.ts +63 -0
  125. package/src/parsing/functions/duration.ts +143 -0
  126. package/src/parsing/functions/element_id.ts +51 -0
  127. package/src/parsing/functions/function_factory.ts +20 -0
  128. package/src/parsing/functions/head.ts +42 -0
  129. package/src/parsing/functions/id.ts +51 -0
  130. package/src/parsing/functions/last.ts +42 -0
  131. package/src/parsing/functions/localdatetime.ts +63 -0
  132. package/src/parsing/functions/localtime.ts +58 -0
  133. package/src/parsing/functions/max.ts +37 -0
  134. package/src/parsing/functions/min.ts +37 -0
  135. package/src/parsing/functions/nodes.ts +54 -0
  136. package/src/parsing/functions/properties.ts +56 -0
  137. package/src/parsing/functions/relationships.ts +52 -0
  138. package/src/parsing/functions/tail.ts +39 -0
  139. package/src/parsing/functions/temporal_utils.ts +180 -0
  140. package/src/parsing/functions/time.ts +58 -0
  141. package/src/parsing/functions/timestamp.ts +37 -0
  142. package/src/parsing/functions/to_float.ts +50 -0
  143. package/src/parsing/functions/to_integer.ts +50 -0
  144. package/tests/compute/runner.test.ts +726 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowquery",
3
- "version": "1.0.35",
3
+ "version": "1.0.37",
4
4
  "description": "A declarative query language for data processing pipelines.",
5
5
  "main": "dist/index.node.js",
6
6
  "types": "dist/index.node.d.ts",
@@ -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
- return this.variable.value()[this.index.value()];
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,49 @@
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
+ *
7
+ * @example
8
+ * ```
9
+ * RETURN coalesce(null, null, 'hello', 'world') // returns 'hello'
10
+ * MATCH (n) RETURN coalesce(n.nickname, n.name) AS displayName
11
+ * ```
12
+ */
13
+ @FunctionDef({
14
+ description: "Returns the first non-null value from a list of expressions",
15
+ category: "scalar",
16
+ parameters: [
17
+ { name: "expressions", description: "Two or more expressions to evaluate", type: "any" },
18
+ ],
19
+ output: {
20
+ description: "The first non-null value, or null if all values are null",
21
+ type: "any",
22
+ },
23
+ examples: [
24
+ "RETURN coalesce(null, 'hello', 'world')",
25
+ "MATCH (n) RETURN coalesce(n.nickname, n.name) AS displayName",
26
+ ],
27
+ })
28
+ class Coalesce extends Function {
29
+ constructor() {
30
+ super("coalesce");
31
+ this._expectedParameterCount = null; // variable number of parameters
32
+ }
33
+
34
+ public value(): any {
35
+ const children = this.getChildren();
36
+ if (children.length === 0) {
37
+ throw new Error("coalesce() requires at least one argument");
38
+ }
39
+ for (const child of children) {
40
+ const val = child.value();
41
+ if (val !== null && val !== undefined) {
42
+ return val;
43
+ }
44
+ }
45
+ return null;
46
+ }
47
+ }
48
+
49
+ export default Coalesce;
@@ -0,0 +1,63 @@
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
+ * @example
12
+ * ```
13
+ * RETURN date() AS today
14
+ * RETURN date('2025-06-15') AS d
15
+ * RETURN date({year: 2025, month: 6, day: 15}) AS d
16
+ * ```
17
+ */
18
+ @FunctionDef({
19
+ description:
20
+ "Returns a date value. With no arguments returns the current date. " +
21
+ "Accepts an ISO 8601 date string or a map of components (year, month, day).",
22
+ category: "scalar",
23
+ parameters: [
24
+ {
25
+ name: "input",
26
+ description: "Optional. An ISO 8601 date string (YYYY-MM-DD) or a map of components.",
27
+ type: "string",
28
+ required: false,
29
+ },
30
+ ],
31
+ output: {
32
+ description:
33
+ "A date object with properties: year, month, day, " +
34
+ "epochMillis, dayOfWeek, dayOfYear, quarter, formatted",
35
+ type: "object",
36
+ },
37
+ examples: [
38
+ "RETURN date() AS today",
39
+ "RETURN date('2025-06-15') AS d",
40
+ "RETURN date({year: 2025, month: 6, day: 15}) AS d",
41
+ "WITH date() AS d RETURN d.year, d.month, d.dayOfWeek",
42
+ ],
43
+ })
44
+ class DateFunction extends Function {
45
+ constructor() {
46
+ super("date");
47
+ this._expectedParameterCount = null;
48
+ }
49
+
50
+ public value(): any {
51
+ const children = this.getChildren();
52
+ if (children.length > 1) {
53
+ throw new Error("date() accepts at most one argument");
54
+ }
55
+
56
+ const d: Date =
57
+ children.length === 1 ? parseTemporalArg(children[0].value(), "date") : new Date();
58
+
59
+ return buildDateObject(d);
60
+ }
61
+ }
62
+
63
+ export default DateFunction;
@@ -0,0 +1,63 @@
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
+ * @example
12
+ * ```
13
+ * RETURN datetime() AS now
14
+ * RETURN datetime('2025-06-15T12:30:00Z') AS dt
15
+ * RETURN datetime({year: 2025, month: 6, day: 15}) AS dt
16
+ * ```
17
+ */
18
+ @FunctionDef({
19
+ description:
20
+ "Returns a datetime value. With no arguments returns the current UTC datetime. " +
21
+ "Accepts an ISO 8601 string or a map of components (year, month, day, hour, minute, second, millisecond).",
22
+ category: "scalar",
23
+ parameters: [
24
+ {
25
+ name: "input",
26
+ description: "Optional. An ISO 8601 datetime string or a map of components.",
27
+ type: "string",
28
+ required: false,
29
+ },
30
+ ],
31
+ output: {
32
+ description:
33
+ "A datetime object with properties: year, month, day, hour, minute, second, millisecond, " +
34
+ "epochMillis, epochSeconds, dayOfWeek, dayOfYear, quarter, formatted",
35
+ type: "object",
36
+ },
37
+ examples: [
38
+ "RETURN datetime() AS now",
39
+ "RETURN datetime('2025-06-15T12:30:00Z') AS dt",
40
+ "RETURN datetime({year: 2025, month: 6, day: 15, hour: 12}) AS dt",
41
+ "WITH datetime() AS dt RETURN dt.year, dt.month, dt.day",
42
+ ],
43
+ })
44
+ class Datetime extends Function {
45
+ constructor() {
46
+ super("datetime");
47
+ this._expectedParameterCount = null;
48
+ }
49
+
50
+ public value(): any {
51
+ const children = this.getChildren();
52
+ if (children.length > 1) {
53
+ throw new Error("datetime() accepts at most one argument");
54
+ }
55
+
56
+ const d: Date =
57
+ children.length === 1 ? parseTemporalArg(children[0].value(), "datetime") : new Date();
58
+
59
+ return buildDatetimeObject(d, true);
60
+ }
61
+ }
62
+
63
+ 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,63 @@
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
+ * @example
12
+ * ```
13
+ * RETURN localdatetime() AS now
14
+ * RETURN localdatetime('2025-06-15T12:30:00') AS dt
15
+ * ```
16
+ */
17
+ @FunctionDef({
18
+ description:
19
+ "Returns a local datetime value (no timezone). With no arguments returns the current local datetime. " +
20
+ "Accepts an ISO 8601 string or a map of components.",
21
+ category: "scalar",
22
+ parameters: [
23
+ {
24
+ name: "input",
25
+ description: "Optional. An ISO 8601 datetime string or a map of components.",
26
+ type: "string",
27
+ required: false,
28
+ },
29
+ ],
30
+ output: {
31
+ description:
32
+ "A datetime object with properties: year, month, day, hour, minute, second, millisecond, " +
33
+ "epochMillis, epochSeconds, dayOfWeek, dayOfYear, quarter, formatted",
34
+ type: "object",
35
+ },
36
+ examples: [
37
+ "RETURN localdatetime() AS now",
38
+ "RETURN localdatetime('2025-06-15T12:30:00') AS dt",
39
+ "WITH localdatetime() AS dt RETURN dt.hour, dt.minute",
40
+ ],
41
+ })
42
+ class LocalDatetime extends Function {
43
+ constructor() {
44
+ super("localdatetime");
45
+ this._expectedParameterCount = null;
46
+ }
47
+
48
+ public value(): any {
49
+ const children = this.getChildren();
50
+ if (children.length > 1) {
51
+ throw new Error("localdatetime() accepts at most one argument");
52
+ }
53
+
54
+ const d: Date =
55
+ children.length === 1
56
+ ? parseTemporalArg(children[0].value(), "localdatetime")
57
+ : new Date();
58
+
59
+ return buildDatetimeObject(d, false);
60
+ }
61
+ }
62
+
63
+ export default LocalDatetime;