flowquery 1.0.34 → 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.
Files changed (197) hide show
  1. package/dist/flowquery.min.js +1 -1
  2. package/dist/graph/database.d.ts +1 -0
  3. package/dist/graph/database.d.ts.map +1 -1
  4. package/dist/graph/database.js +43 -6
  5. package/dist/graph/database.js.map +1 -1
  6. package/dist/graph/relationship.d.ts +3 -1
  7. package/dist/graph/relationship.d.ts.map +1 -1
  8. package/dist/graph/relationship.js +12 -4
  9. package/dist/graph/relationship.js.map +1 -1
  10. package/dist/graph/relationship_data.js +1 -1
  11. package/dist/graph/relationship_data.js.map +1 -1
  12. package/dist/graph/relationship_match_collector.d.ts.map +1 -1
  13. package/dist/graph/relationship_match_collector.js +6 -3
  14. package/dist/graph/relationship_match_collector.js.map +1 -1
  15. package/dist/graph/relationship_reference.js +1 -1
  16. package/dist/graph/relationship_reference.js.map +1 -1
  17. package/dist/parsing/data_structures/lookup.d.ts.map +1 -1
  18. package/dist/parsing/data_structures/lookup.js +5 -1
  19. package/dist/parsing/data_structures/lookup.js.map +1 -1
  20. package/dist/parsing/functions/coalesce.d.ts +17 -0
  21. package/dist/parsing/functions/coalesce.d.ts.map +1 -0
  22. package/dist/parsing/functions/coalesce.js +61 -0
  23. package/dist/parsing/functions/coalesce.js.map +1 -0
  24. package/dist/parsing/functions/date.d.ts +22 -0
  25. package/dist/parsing/functions/date.d.ts.map +1 -0
  26. package/dist/parsing/functions/date.js +71 -0
  27. package/dist/parsing/functions/date.js.map +1 -0
  28. package/dist/parsing/functions/datetime.d.ts +22 -0
  29. package/dist/parsing/functions/datetime.d.ts.map +1 -0
  30. package/dist/parsing/functions/datetime.js +71 -0
  31. package/dist/parsing/functions/datetime.js.map +1 -0
  32. package/dist/parsing/functions/duration.d.ts +7 -0
  33. package/dist/parsing/functions/duration.d.ts.map +1 -0
  34. package/dist/parsing/functions/duration.js +145 -0
  35. package/dist/parsing/functions/duration.js.map +1 -0
  36. package/dist/parsing/functions/element_id.d.ts +7 -0
  37. package/dist/parsing/functions/element_id.d.ts.map +1 -0
  38. package/dist/parsing/functions/element_id.js +58 -0
  39. package/dist/parsing/functions/element_id.js.map +1 -0
  40. package/dist/parsing/functions/function_factory.d.ts +21 -0
  41. package/dist/parsing/functions/function_factory.d.ts.map +1 -1
  42. package/dist/parsing/functions/function_factory.js +21 -0
  43. package/dist/parsing/functions/function_factory.js.map +1 -1
  44. package/dist/parsing/functions/head.d.ts +7 -0
  45. package/dist/parsing/functions/head.d.ts.map +1 -0
  46. package/dist/parsing/functions/head.js +53 -0
  47. package/dist/parsing/functions/head.js.map +1 -0
  48. package/dist/parsing/functions/id.d.ts +7 -0
  49. package/dist/parsing/functions/id.d.ts.map +1 -0
  50. package/dist/parsing/functions/id.js +58 -0
  51. package/dist/parsing/functions/id.js.map +1 -0
  52. package/dist/parsing/functions/last.d.ts +7 -0
  53. package/dist/parsing/functions/last.d.ts.map +1 -0
  54. package/dist/parsing/functions/last.js +53 -0
  55. package/dist/parsing/functions/last.js.map +1 -0
  56. package/dist/parsing/functions/localdatetime.d.ts +21 -0
  57. package/dist/parsing/functions/localdatetime.d.ts.map +1 -0
  58. package/dist/parsing/functions/localdatetime.js +71 -0
  59. package/dist/parsing/functions/localdatetime.js.map +1 -0
  60. package/dist/parsing/functions/localtime.d.ts +20 -0
  61. package/dist/parsing/functions/localtime.d.ts.map +1 -0
  62. package/dist/parsing/functions/localtime.js +67 -0
  63. package/dist/parsing/functions/localtime.js.map +1 -0
  64. package/dist/parsing/functions/max.d.ts +14 -0
  65. package/dist/parsing/functions/max.d.ts.map +1 -0
  66. package/dist/parsing/functions/max.js +51 -0
  67. package/dist/parsing/functions/max.js.map +1 -0
  68. package/dist/parsing/functions/min.d.ts +14 -0
  69. package/dist/parsing/functions/min.d.ts.map +1 -0
  70. package/dist/parsing/functions/min.js +51 -0
  71. package/dist/parsing/functions/min.js.map +1 -0
  72. package/dist/parsing/functions/nodes.d.ts +7 -0
  73. package/dist/parsing/functions/nodes.d.ts.map +1 -0
  74. package/dist/parsing/functions/nodes.js +63 -0
  75. package/dist/parsing/functions/nodes.js.map +1 -0
  76. package/dist/parsing/functions/predicate_sum.d.ts.map +1 -1
  77. package/dist/parsing/functions/predicate_sum.js +13 -10
  78. package/dist/parsing/functions/predicate_sum.js.map +1 -1
  79. package/dist/parsing/functions/properties.d.ts +7 -0
  80. package/dist/parsing/functions/properties.d.ts.map +1 -0
  81. package/dist/parsing/functions/properties.js +74 -0
  82. package/dist/parsing/functions/properties.js.map +1 -0
  83. package/dist/parsing/functions/relationships.d.ts +7 -0
  84. package/dist/parsing/functions/relationships.d.ts.map +1 -0
  85. package/dist/parsing/functions/relationships.js +61 -0
  86. package/dist/parsing/functions/relationships.js.map +1 -0
  87. package/dist/parsing/functions/schema.d.ts +5 -2
  88. package/dist/parsing/functions/schema.d.ts.map +1 -1
  89. package/dist/parsing/functions/schema.js +7 -4
  90. package/dist/parsing/functions/schema.js.map +1 -1
  91. package/dist/parsing/functions/tail.d.ts +7 -0
  92. package/dist/parsing/functions/tail.d.ts.map +1 -0
  93. package/dist/parsing/functions/tail.js +50 -0
  94. package/dist/parsing/functions/tail.js.map +1 -0
  95. package/dist/parsing/functions/temporal_utils.d.ts +39 -0
  96. package/dist/parsing/functions/temporal_utils.d.ts.map +1 -0
  97. package/dist/parsing/functions/temporal_utils.js +168 -0
  98. package/dist/parsing/functions/temporal_utils.js.map +1 -0
  99. package/dist/parsing/functions/time.d.ts +20 -0
  100. package/dist/parsing/functions/time.d.ts.map +1 -0
  101. package/dist/parsing/functions/time.js +67 -0
  102. package/dist/parsing/functions/time.js.map +1 -0
  103. package/dist/parsing/functions/timestamp.d.ts +17 -0
  104. package/dist/parsing/functions/timestamp.d.ts.map +1 -0
  105. package/dist/parsing/functions/timestamp.js +51 -0
  106. package/dist/parsing/functions/timestamp.js.map +1 -0
  107. package/dist/parsing/functions/to_float.d.ts +7 -0
  108. package/dist/parsing/functions/to_float.d.ts.map +1 -0
  109. package/dist/parsing/functions/to_float.js +61 -0
  110. package/dist/parsing/functions/to_float.js.map +1 -0
  111. package/dist/parsing/functions/to_integer.d.ts +7 -0
  112. package/dist/parsing/functions/to_integer.d.ts.map +1 -0
  113. package/dist/parsing/functions/to_integer.js +61 -0
  114. package/dist/parsing/functions/to_integer.js.map +1 -0
  115. package/dist/parsing/functions/trim.d.ts +7 -0
  116. package/dist/parsing/functions/trim.d.ts.map +1 -0
  117. package/dist/parsing/functions/trim.js +37 -0
  118. package/dist/parsing/functions/trim.js.map +1 -0
  119. package/dist/parsing/operations/group_by.d.ts.map +1 -1
  120. package/dist/parsing/operations/group_by.js +4 -2
  121. package/dist/parsing/operations/group_by.js.map +1 -1
  122. package/dist/parsing/parser.d.ts.map +1 -1
  123. package/dist/parsing/parser.js +15 -2
  124. package/dist/parsing/parser.js.map +1 -1
  125. package/docs/flowquery.min.js +1 -1
  126. package/flowquery-py/pyproject.toml +1 -1
  127. package/flowquery-py/src/graph/database.py +44 -11
  128. package/flowquery-py/src/graph/relationship.py +11 -3
  129. package/flowquery-py/src/graph/relationship_data.py +2 -1
  130. package/flowquery-py/src/graph/relationship_match_collector.py +7 -1
  131. package/flowquery-py/src/graph/relationship_reference.py +2 -2
  132. package/flowquery-py/src/parsing/data_structures/lookup.py +2 -0
  133. package/flowquery-py/src/parsing/functions/__init__.py +42 -2
  134. package/flowquery-py/src/parsing/functions/coalesce.py +44 -0
  135. package/flowquery-py/src/parsing/functions/date_.py +63 -0
  136. package/flowquery-py/src/parsing/functions/datetime_.py +64 -0
  137. package/flowquery-py/src/parsing/functions/duration.py +159 -0
  138. package/flowquery-py/src/parsing/functions/element_id.py +50 -0
  139. package/flowquery-py/src/parsing/functions/head.py +39 -0
  140. package/flowquery-py/src/parsing/functions/id_.py +49 -0
  141. package/flowquery-py/src/parsing/functions/last.py +39 -0
  142. package/flowquery-py/src/parsing/functions/localdatetime.py +62 -0
  143. package/flowquery-py/src/parsing/functions/localtime.py +59 -0
  144. package/flowquery-py/src/parsing/functions/max_.py +49 -0
  145. package/flowquery-py/src/parsing/functions/min_.py +49 -0
  146. package/flowquery-py/src/parsing/functions/nodes.py +48 -0
  147. package/flowquery-py/src/parsing/functions/predicate_sum.py +3 -6
  148. package/flowquery-py/src/parsing/functions/properties.py +50 -0
  149. package/flowquery-py/src/parsing/functions/relationships.py +46 -0
  150. package/flowquery-py/src/parsing/functions/schema.py +9 -5
  151. package/flowquery-py/src/parsing/functions/tail.py +37 -0
  152. package/flowquery-py/src/parsing/functions/temporal_utils.py +186 -0
  153. package/flowquery-py/src/parsing/functions/time_.py +59 -0
  154. package/flowquery-py/src/parsing/functions/timestamp.py +39 -0
  155. package/flowquery-py/src/parsing/functions/to_float.py +46 -0
  156. package/flowquery-py/src/parsing/functions/to_integer.py +46 -0
  157. package/flowquery-py/src/parsing/functions/trim.py +35 -0
  158. package/flowquery-py/src/parsing/operations/group_by.py +2 -0
  159. package/flowquery-py/src/parsing/parser.py +12 -2
  160. package/flowquery-py/tests/compute/test_runner.py +1082 -4
  161. package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
  162. package/package.json +1 -1
  163. package/src/graph/database.ts +42 -4
  164. package/src/graph/relationship.ts +12 -4
  165. package/src/graph/relationship_data.ts +1 -1
  166. package/src/graph/relationship_match_collector.ts +6 -2
  167. package/src/graph/relationship_reference.ts +1 -1
  168. package/src/parsing/data_structures/lookup.ts +8 -4
  169. package/src/parsing/functions/coalesce.ts +50 -0
  170. package/src/parsing/functions/date.ts +65 -0
  171. package/src/parsing/functions/datetime.ts +65 -0
  172. package/src/parsing/functions/duration.ts +143 -0
  173. package/src/parsing/functions/element_id.ts +51 -0
  174. package/src/parsing/functions/function_factory.ts +21 -0
  175. package/src/parsing/functions/head.ts +42 -0
  176. package/src/parsing/functions/id.ts +51 -0
  177. package/src/parsing/functions/last.ts +42 -0
  178. package/src/parsing/functions/localdatetime.ts +65 -0
  179. package/src/parsing/functions/localtime.ts +60 -0
  180. package/src/parsing/functions/max.ts +37 -0
  181. package/src/parsing/functions/min.ts +37 -0
  182. package/src/parsing/functions/nodes.ts +54 -0
  183. package/src/parsing/functions/predicate_sum.ts +17 -12
  184. package/src/parsing/functions/properties.ts +56 -0
  185. package/src/parsing/functions/relationships.ts +52 -0
  186. package/src/parsing/functions/schema.ts +7 -4
  187. package/src/parsing/functions/tail.ts +39 -0
  188. package/src/parsing/functions/temporal_utils.ts +180 -0
  189. package/src/parsing/functions/time.ts +60 -0
  190. package/src/parsing/functions/timestamp.ts +41 -0
  191. package/src/parsing/functions/to_float.ts +50 -0
  192. package/src/parsing/functions/to_integer.ts +50 -0
  193. package/src/parsing/functions/trim.ts +25 -0
  194. package/src/parsing/operations/group_by.ts +4 -1
  195. package/src/parsing/parser.ts +15 -2
  196. package/tests/compute/runner.test.ts +1005 -3
  197. package/tests/parsing/parser.test.ts +37 -0
@@ -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;
@@ -0,0 +1,60 @@
1
+ import Function from "./function";
2
+ import { FunctionDef } from "./function_metadata";
3
+ import { buildTimeObject, parseTemporalArg } from "./temporal_utils";
4
+
5
+ /**
6
+ * Returns a local time value (no timezone offset).
7
+ * When called with no arguments, returns the current local time.
8
+ * When called with a string argument, parses it.
9
+ *
10
+ * Equivalent to Neo4j's localtime() function.
11
+ *
12
+ * @example
13
+ * ```
14
+ * RETURN localtime() AS now
15
+ * RETURN localtime('14:30:00') AS t
16
+ * ```
17
+ */
18
+ @FunctionDef({
19
+ description:
20
+ "Returns a local time value (no timezone). With no arguments returns the current local time. " +
21
+ "Accepts an ISO 8601 time string or a map of components.",
22
+ category: "scalar",
23
+ parameters: [
24
+ {
25
+ name: "input",
26
+ description: "Optional. An ISO 8601 time string (HH:MM:SS) or a map of components.",
27
+ type: "string",
28
+ required: false,
29
+ },
30
+ ],
31
+ output: {
32
+ description: "A time object with properties: hour, minute, second, millisecond, formatted",
33
+ type: "object",
34
+ },
35
+ examples: [
36
+ "RETURN localtime() AS now",
37
+ "RETURN localtime('14:30:00') AS t",
38
+ "WITH localtime() AS t RETURN t.hour, t.minute",
39
+ ],
40
+ })
41
+ class LocalTime extends Function {
42
+ constructor() {
43
+ super("localtime");
44
+ this._expectedParameterCount = null;
45
+ }
46
+
47
+ public value(): any {
48
+ const children = this.getChildren();
49
+ if (children.length > 1) {
50
+ throw new Error("localtime() accepts at most one argument");
51
+ }
52
+
53
+ const d: Date =
54
+ children.length === 1 ? parseTemporalArg(children[0].value(), "localtime") : new Date();
55
+
56
+ return buildTimeObject(d, false);
57
+ }
58
+ }
59
+
60
+ export default LocalTime;
@@ -0,0 +1,37 @@
1
+ import AggregateFunction from "./aggregate_function";
2
+ import { FunctionDef } from "./function_metadata";
3
+ import ReducerElement from "./reducer_element";
4
+
5
+ class MaxReducerElement extends ReducerElement {
6
+ private _value: any = null;
7
+ public get value(): any {
8
+ return this._value;
9
+ }
10
+ public set value(value: any) {
11
+ if (this._value === null || value > this._value) {
12
+ this._value = value;
13
+ }
14
+ }
15
+ }
16
+
17
+ @FunctionDef({
18
+ description: "Returns the maximum value across grouped rows",
19
+ category: "aggregate",
20
+ parameters: [{ name: "value", description: "Value to compare", type: "number" }],
21
+ output: { description: "Maximum value", type: "number", example: 10 },
22
+ examples: ["WITH [3, 1, 2] AS nums UNWIND nums AS n RETURN max(n)"],
23
+ })
24
+ class Max extends AggregateFunction {
25
+ constructor() {
26
+ super("max");
27
+ this._expectedParameterCount = 1;
28
+ }
29
+ public reduce(element: MaxReducerElement): void {
30
+ element.value = this.firstChild().value();
31
+ }
32
+ public element(): MaxReducerElement {
33
+ return new MaxReducerElement();
34
+ }
35
+ }
36
+
37
+ export default Max;
@@ -0,0 +1,37 @@
1
+ import AggregateFunction from "./aggregate_function";
2
+ import { FunctionDef } from "./function_metadata";
3
+ import ReducerElement from "./reducer_element";
4
+
5
+ class MinReducerElement extends ReducerElement {
6
+ private _value: any = null;
7
+ public get value(): any {
8
+ return this._value;
9
+ }
10
+ public set value(value: any) {
11
+ if (this._value === null || value < this._value) {
12
+ this._value = value;
13
+ }
14
+ }
15
+ }
16
+
17
+ @FunctionDef({
18
+ description: "Returns the minimum value across grouped rows",
19
+ category: "aggregate",
20
+ parameters: [{ name: "value", description: "Value to compare", type: "number" }],
21
+ output: { description: "Minimum value", type: "number", example: 1 },
22
+ examples: ["WITH [3, 1, 2] AS nums UNWIND nums AS n RETURN min(n)"],
23
+ })
24
+ class Min extends AggregateFunction {
25
+ constructor() {
26
+ super("min");
27
+ this._expectedParameterCount = 1;
28
+ }
29
+ public reduce(element: MinReducerElement): void {
30
+ element.value = this.firstChild().value();
31
+ }
32
+ public element(): MinReducerElement {
33
+ return new MinReducerElement();
34
+ }
35
+ }
36
+
37
+ export default Min;
@@ -0,0 +1,54 @@
1
+ import Function from "./function";
2
+ import { FunctionDef } from "./function_metadata";
3
+
4
+ @FunctionDef({
5
+ description: "Returns all nodes in a path as an array",
6
+ category: "scalar",
7
+ parameters: [
8
+ {
9
+ name: "path",
10
+ description: "A path value returned from a graph pattern match",
11
+ type: "array",
12
+ },
13
+ ],
14
+ output: {
15
+ description: "Array of node records",
16
+ type: "array",
17
+ example: "[{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]",
18
+ },
19
+ examples: ["MATCH p=(:Person)-[:KNOWS]-(:Person) RETURN nodes(p)"],
20
+ })
21
+ class Nodes extends Function {
22
+ constructor() {
23
+ super("nodes");
24
+ this._expectedParameterCount = 1;
25
+ }
26
+
27
+ public value(): any {
28
+ const path = this.getChildren()[0].value();
29
+ if (path === null || path === undefined) {
30
+ return [];
31
+ }
32
+ if (!Array.isArray(path)) {
33
+ throw new Error("nodes() expects a path (array)");
34
+ }
35
+ // A path is an array of alternating node and relationship objects:
36
+ // [node, rel, node, rel, node, ...]
37
+ // Nodes are plain NodeRecords (have 'id' but not 'type'/'startNode'/'endNode')
38
+ // Relationships are RelationshipMatchRecords (have 'type', 'startNode', 'endNode', 'properties')
39
+ return path.filter((element: any) => {
40
+ if (element === null || element === undefined || typeof element !== "object") {
41
+ return false;
42
+ }
43
+ // A RelationshipMatchRecord has type, startNode, endNode, properties
44
+ return !(
45
+ "type" in element &&
46
+ "startNode" in element &&
47
+ "endNode" in element &&
48
+ "properties" in element
49
+ );
50
+ });
51
+ }
52
+ }
53
+
54
+ export default Nodes;
@@ -1,17 +1,26 @@
1
- import PredicateFunction from "./predicate_function";
2
1
  import { FunctionDef } from "./function_metadata";
2
+ import PredicateFunction from "./predicate_function";
3
3
 
4
4
  @FunctionDef({
5
- description: "Calculates the sum of values in an array with optional filtering. Uses list comprehension syntax: sum(variable IN array [WHERE condition] | expression)",
5
+ description:
6
+ "Calculates the sum of values in an array with optional filtering. Uses list comprehension syntax: sum(variable IN array [WHERE condition] | expression)",
6
7
  category: "predicate",
7
8
  parameters: [
8
9
  { name: "variable", description: "Variable name to bind each element", type: "string" },
9
10
  { name: "array", description: "Array to iterate over", type: "array" },
10
11
  { name: "expression", description: "Expression to sum for each element", type: "any" },
11
- { name: "where", description: "Optional filter condition", type: "boolean", required: false }
12
+ {
13
+ name: "where",
14
+ description: "Optional filter condition",
15
+ type: "boolean",
16
+ required: false,
17
+ },
12
18
  ],
13
19
  output: { description: "Sum of the evaluated expressions", type: "number", example: 6 },
14
- examples: ["WITH [1, 2, 3] AS nums RETURN sum(n IN nums | n)", "WITH [1, 2, 3, 4] AS nums RETURN sum(n IN nums WHERE n > 1 | n * 2)"]
20
+ examples: [
21
+ "WITH [1, 2, 3] AS nums RETURN sum(n IN nums | n)",
22
+ "WITH [1, 2, 3, 4] AS nums RETURN sum(n IN nums WHERE n > 1 | n * 2)",
23
+ ],
15
24
  })
16
25
  class PredicateSum extends PredicateFunction {
17
26
  constructor() {
@@ -24,19 +33,15 @@ class PredicateSum extends PredicateFunction {
24
33
  if (array === null || !Array.isArray(array)) {
25
34
  throw new Error("Invalid array for sum function");
26
35
  }
27
- let _sum: any | null = null;
28
- for(let i = 0; i < array.length; i++) {
36
+ let _sum: number = 0;
37
+ for (let i = 0; i < array.length; i++) {
29
38
  this._valueHolder.holder = array[i];
30
39
  if (this.where === null || this.where.value()) {
31
- if (_sum === null) {
32
- _sum = this._return.value();
33
- } else {
34
- _sum += this._return.value();
35
- }
40
+ _sum += this._return.value();
36
41
  }
37
42
  }
38
43
  return _sum;
39
44
  }
40
45
  }
41
46
 
42
- export default PredicateSum;
47
+ export default PredicateSum;
@@ -0,0 +1,56 @@
1
+ import Function from "./function";
2
+ import { FunctionDef } from "./function_metadata";
3
+
4
+ @FunctionDef({
5
+ description:
6
+ "Returns a map containing all the properties of a node, relationship, or map. For nodes and relationships, internal identifiers are excluded.",
7
+ category: "scalar",
8
+ parameters: [
9
+ {
10
+ name: "entity",
11
+ description: "A node, relationship, or map to extract properties from",
12
+ type: "object",
13
+ },
14
+ ],
15
+ output: {
16
+ description: "Map of properties",
17
+ type: "object",
18
+ example: "{ name: 'Alice', age: 30 }",
19
+ },
20
+ examples: [
21
+ "MATCH (n:Person) RETURN properties(n)",
22
+ "WITH { name: 'Alice', age: 30 } AS obj RETURN properties(obj)",
23
+ ],
24
+ })
25
+ class Properties extends Function {
26
+ constructor() {
27
+ super("properties");
28
+ this._expectedParameterCount = 1;
29
+ }
30
+
31
+ public value(): any {
32
+ const obj = this.getChildren()[0].value();
33
+ if (obj === null || obj === undefined) {
34
+ return null;
35
+ }
36
+ if (typeof obj !== "object" || Array.isArray(obj)) {
37
+ throw new Error("properties() expects a node, relationship, or map");
38
+ }
39
+
40
+ // If it's a RelationshipMatchRecord (has type, startNode, endNode, properties)
41
+ if ("type" in obj && "startNode" in obj && "endNode" in obj && "properties" in obj) {
42
+ return obj.properties;
43
+ }
44
+
45
+ // If it's a node record (has id field), exclude id
46
+ if ("id" in obj) {
47
+ const { id, ...props } = obj;
48
+ return props;
49
+ }
50
+
51
+ // Otherwise, treat as a plain map and return a copy
52
+ return { ...obj };
53
+ }
54
+ }
55
+
56
+ export default Properties;
@@ -0,0 +1,52 @@
1
+ import Function from "./function";
2
+ import { FunctionDef } from "./function_metadata";
3
+
4
+ @FunctionDef({
5
+ description: "Returns all relationships in a path as an array",
6
+ category: "scalar",
7
+ parameters: [
8
+ {
9
+ name: "path",
10
+ description: "A path value returned from a graph pattern match",
11
+ type: "array",
12
+ },
13
+ ],
14
+ output: {
15
+ description: "Array of relationship records",
16
+ type: "array",
17
+ example: "[{ type: 'KNOWS', properties: { since: '2020' } }]",
18
+ },
19
+ examples: ["MATCH p=(:Person)-[:KNOWS]-(:Person) RETURN relationships(p)"],
20
+ })
21
+ class Relationships extends Function {
22
+ constructor() {
23
+ super("relationships");
24
+ this._expectedParameterCount = 1;
25
+ }
26
+
27
+ public value(): any {
28
+ const path = this.getChildren()[0].value();
29
+ if (path === null || path === undefined) {
30
+ return [];
31
+ }
32
+ if (!Array.isArray(path)) {
33
+ throw new Error("relationships() expects a path (array)");
34
+ }
35
+ // A path is an array of alternating node and relationship objects:
36
+ // [node, rel, node, rel, node, ...]
37
+ // Relationships are RelationshipMatchRecords (have 'type', 'startNode', 'endNode', 'properties')
38
+ return path.filter((element: any) => {
39
+ if (element === null || element === undefined || typeof element !== "object") {
40
+ return false;
41
+ }
42
+ return (
43
+ "type" in element &&
44
+ "startNode" in element &&
45
+ "endNode" in element &&
46
+ "properties" in element
47
+ );
48
+ });
49
+ }
50
+ }
51
+
52
+ export default Relationships;
@@ -5,8 +5,11 @@ import { FunctionDef } from "./function_metadata";
5
5
  /**
6
6
  * Built-in function that returns the graph schema of the database.
7
7
  *
8
- * Lists all nodes and relationships with their labels/types and a sample
9
- * of their data (excluding id from nodes, left_id and right_id from relationships).
8
+ * Lists all nodes and relationships with their labels/types, properties,
9
+ * and a sample of their data (excluding id from nodes, left_id and right_id from relationships).
10
+ *
11
+ * Nodes: {label, properties, sample}
12
+ * Relationships: {type, from_label, to_label, properties, sample}
10
13
  *
11
14
  * @example
12
15
  * ```
@@ -15,11 +18,11 @@ import { FunctionDef } from "./function_metadata";
15
18
  */
16
19
  @FunctionDef({
17
20
  description:
18
- "Returns the graph schema listing all nodes and relationships with a sample of their data.",
21
+ "Returns the graph schema listing all nodes and relationships with their properties and a sample of their data.",
19
22
  category: "async",
20
23
  parameters: [],
21
24
  output: {
22
- description: "Schema entry with kind, label/type, and optional sample data",
25
+ description: "Schema entry with label/type, properties, and optional sample data",
23
26
  type: "object",
24
27
  },
25
28
  examples: ["LOAD FROM schema() AS s RETURN s"],
@@ -0,0 +1,39 @@
1
+ import Function from "./function";
2
+ import { FunctionDef } from "./function_metadata";
3
+
4
+ @FunctionDef({
5
+ description: "Returns all elements of a list except the first",
6
+ category: "scalar",
7
+ parameters: [
8
+ {
9
+ name: "list",
10
+ description: "The list to get all but the first element from",
11
+ type: "array",
12
+ },
13
+ ],
14
+ output: {
15
+ description: "All elements except the first",
16
+ type: "array",
17
+ example: "[2, 3]",
18
+ },
19
+ examples: ["RETURN tail([1, 2, 3])", "WITH ['a', 'b', 'c'] AS items RETURN tail(items)"],
20
+ })
21
+ class Tail extends Function {
22
+ constructor() {
23
+ super("tail");
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("tail() expects a list");
34
+ }
35
+ return val.slice(1);
36
+ }
37
+ }
38
+
39
+ export default Tail;