flowquery 1.0.13 → 1.0.15

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 (61) hide show
  1. package/.editorconfig +21 -0
  2. package/.husky/pre-commit +1 -0
  3. package/.prettierrc +22 -0
  4. package/dist/flowquery.min.js +1 -1
  5. package/dist/parsing/expressions/expression_map.d.ts +8 -0
  6. package/dist/parsing/expressions/expression_map.d.ts.map +1 -0
  7. package/dist/parsing/expressions/expression_map.js +21 -0
  8. package/dist/parsing/expressions/expression_map.js.map +1 -0
  9. package/dist/parsing/functions/async_function.d.ts +16 -2
  10. package/dist/parsing/functions/async_function.d.ts.map +1 -1
  11. package/dist/parsing/functions/async_function.js +15 -1
  12. package/dist/parsing/functions/async_function.js.map +1 -1
  13. package/dist/parsing/operations/call.d.ts +17 -0
  14. package/dist/parsing/operations/call.d.ts.map +1 -0
  15. package/dist/parsing/operations/call.js +103 -0
  16. package/dist/parsing/operations/call.js.map +1 -0
  17. package/dist/parsing/operations/load.d.ts +7 -6
  18. package/dist/parsing/operations/load.d.ts.map +1 -1
  19. package/dist/parsing/operations/load.js +11 -7
  20. package/dist/parsing/operations/load.js.map +1 -1
  21. package/dist/parsing/operations/operation.d.ts +1 -0
  22. package/dist/parsing/operations/operation.d.ts.map +1 -1
  23. package/dist/parsing/operations/operation.js +6 -5
  24. package/dist/parsing/operations/operation.js.map +1 -1
  25. package/dist/parsing/operations/projection.d.ts +1 -1
  26. package/dist/parsing/operations/projection.d.ts.map +1 -1
  27. package/dist/parsing/operations/projection.js.map +1 -1
  28. package/dist/parsing/parser.d.ts +1 -0
  29. package/dist/parsing/parser.d.ts.map +1 -1
  30. package/dist/parsing/parser.js +148 -99
  31. package/dist/parsing/parser.js.map +1 -1
  32. package/dist/parsing/token_to_node.d.ts +2 -2
  33. package/dist/parsing/token_to_node.d.ts.map +1 -1
  34. package/dist/parsing/token_to_node.js +12 -12
  35. package/dist/parsing/token_to_node.js.map +1 -1
  36. package/dist/tokenization/token.d.ts +5 -1
  37. package/dist/tokenization/token.d.ts.map +1 -1
  38. package/dist/tokenization/token.js +17 -5
  39. package/dist/tokenization/token.js.map +1 -1
  40. package/docs/flowquery.min.js +1 -1
  41. package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
  42. package/misc/apps/RAG/package.json +1 -1
  43. package/misc/apps/RAG/src/plugins/loaders/FetchJson.ts +4 -4
  44. package/misc/apps/RAG/src/plugins/loaders/Form.ts +3 -3
  45. package/misc/apps/RAG/src/plugins/loaders/Llm.ts +4 -3
  46. package/misc/apps/RAG/src/plugins/loaders/MockData.ts +7 -5
  47. package/misc/apps/RAG/src/plugins/loaders/Table.ts +3 -3
  48. package/misc/apps/RAG/src/plugins/loaders/Weather.ts +4 -3
  49. package/package.json +12 -2
  50. package/src/parsing/expressions/expression_map.ts +19 -0
  51. package/src/parsing/functions/async_function.ts +16 -2
  52. package/src/parsing/operations/call.ts +67 -0
  53. package/src/parsing/operations/load.ts +123 -118
  54. package/src/parsing/operations/operation.ts +14 -13
  55. package/src/parsing/operations/projection.ts +3 -3
  56. package/src/parsing/parser.ts +303 -239
  57. package/src/parsing/token_to_node.ts +67 -50
  58. package/src/tokenization/token.ts +29 -14
  59. package/tests/compute/runner.test.ts +277 -165
  60. package/tests/parsing/parser.test.ts +355 -303
  61. package/vscode-settings.json.recommended +16 -0
@@ -6,7 +6,7 @@
6
6
  * RETURN user.name, user.email
7
7
  */
8
8
 
9
- import { FunctionDef } from 'flowquery/extensibility';
9
+ import { FunctionDef, AsyncFunction } from 'flowquery/extensibility';
10
10
 
11
11
  /**
12
12
  * MockUsers class - generates mock user data for testing.
@@ -39,7 +39,7 @@ import { FunctionDef } from 'flowquery/extensibility';
39
39
  "LOAD JSON FROM mockUsers(20) AS user RETURN user WHERE user.active = true"
40
40
  ]
41
41
  })
42
- export class MockUsers {
42
+ export class MockUsers extends AsyncFunction {
43
43
  private readonly firstNames: string[];
44
44
  private readonly lastNames: string[];
45
45
  private readonly domains: string[];
@@ -49,6 +49,7 @@ export class MockUsers {
49
49
  lastNames: string[] = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', 'Rodriguez', 'Martinez'],
50
50
  domains: string[] = ['example.com', 'test.org', 'demo.net']
51
51
  ) {
52
+ super();
52
53
  this.firstNames = firstNames;
53
54
  this.lastNames = lastNames;
54
55
  this.domains = domains;
@@ -59,7 +60,7 @@ export class MockUsers {
59
60
  *
60
61
  * @param count - Number of mock users to generate
61
62
  */
62
- async *fetch(count: number = 5): AsyncGenerator<any, void, unknown> {
63
+ async *generate(count: number = 5): AsyncGenerator<any, void, unknown> {
63
64
  for (let i = 0; i < count; i++) {
64
65
  const firstName = this.firstNames[Math.floor(Math.random() * this.firstNames.length)];
65
66
  const lastName = this.lastNames[Math.floor(Math.random() * this.lastNames.length)];
@@ -108,7 +109,7 @@ export class MockUsers {
108
109
  "LOAD JSON FROM mockProducts(50) AS p RETURN p WHERE p.category = 'Electronics'"
109
110
  ]
110
111
  })
111
- export class MockProducts {
112
+ export class MockProducts extends AsyncFunction {
112
113
  private readonly categories: string[];
113
114
  private readonly adjectives: string[];
114
115
  private readonly nouns: string[];
@@ -118,6 +119,7 @@ export class MockProducts {
118
119
  adjectives: string[] = ['Premium', 'Basic', 'Pro', 'Ultra', 'Classic'],
119
120
  nouns: string[] = ['Widget', 'Gadget', 'Item', 'Product', 'Thing']
120
121
  ) {
122
+ super();
121
123
  this.categories = categories;
122
124
  this.adjectives = adjectives;
123
125
  this.nouns = nouns;
@@ -128,7 +130,7 @@ export class MockProducts {
128
130
  *
129
131
  * @param count - Number of mock products to generate
130
132
  */
131
- async *fetch(count: number = 5): AsyncGenerator<any, void, unknown> {
133
+ async *generate(count: number = 5): AsyncGenerator<any, void, unknown> {
132
134
  for (let i = 0; i < count; i++) {
133
135
  const adj = this.adjectives[Math.floor(Math.random() * this.adjectives.length)];
134
136
  const noun = this.nouns[Math.floor(Math.random() * this.nouns.length)];
@@ -14,7 +14,7 @@
14
14
  * Note: Async providers cannot be nested as function arguments.
15
15
  */
16
16
 
17
- import { FunctionDef } from 'flowquery/extensibility';
17
+ import { FunctionDef, AsyncFunction } from 'flowquery/extensibility';
18
18
 
19
19
  /**
20
20
  * Interface for Adaptive Card structure
@@ -90,7 +90,7 @@ interface TableRow {
90
90
  "LOAD JSON FROM mockProducts(10) AS p WITH collect(p) AS products LOAD JSON FROM table(products, 'Products', ['name', 'price', 'category']) AS card RETURN card"
91
91
  ]
92
92
  })
93
- export class Table {
93
+ export class Table extends AsyncFunction {
94
94
  /**
95
95
  * Transforms data into an Adaptive Card with table layout.
96
96
  *
@@ -99,7 +99,7 @@ export class Table {
99
99
  * @param columns - Optional column names to include
100
100
  * @param maxRows - Maximum rows to include
101
101
  */
102
- async *fetch(
102
+ async *generate(
103
103
  data: any[] | AsyncIterable<any>,
104
104
  title: string = 'Data Table',
105
105
  columns?: string[],
@@ -6,7 +6,7 @@
6
6
  * RETURN forecast
7
7
  */
8
8
 
9
- import { FunctionDef } from 'flowquery/extensibility';
9
+ import { FunctionDef, AsyncFunction } from 'flowquery/extensibility';
10
10
 
11
11
  const GEOCODING_API = 'https://geocoding-api.open-meteo.com/v1/search';
12
12
  const WEATHER_API = 'https://api.met.no/weatherapi/locationforecast/2.0/compact';
@@ -48,11 +48,12 @@ const WEATHER_API = 'https://api.met.no/weatherapi/locationforecast/2.0/compact'
48
48
  "LOAD JSON FROM weather('London') AS forecast RETURN forecast[0]"
49
49
  ]
50
50
  })
51
- export class Weather {
51
+ export class Weather extends AsyncFunction {
52
52
  private readonly geocodingApiUrl: string;
53
53
  private readonly weatherApiUrl: string;
54
54
 
55
55
  constructor(geocodingApiUrl: string = GEOCODING_API, weatherApiUrl: string = WEATHER_API) {
56
+ super();
56
57
  this.geocodingApiUrl = geocodingApiUrl;
57
58
  this.weatherApiUrl = weatherApiUrl;
58
59
  }
@@ -62,7 +63,7 @@ export class Weather {
62
63
  *
63
64
  * @param location - The name of the location to get weather for
64
65
  */
65
- async *fetch(location: string): AsyncGenerator<any, void, unknown> {
66
+ async *generate(location: string): AsyncGenerator<any, void, unknown> {
66
67
  // Step 1: Geocode the location name to get lat/lon
67
68
  const geocodeUrl = `${this.geocodingApiUrl}?name=${encodeURIComponent(location)}`;
68
69
  const geocodeResponse = await fetch(geocodeUrl);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowquery",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
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",
@@ -31,16 +31,26 @@
31
31
  "build:node": "tsc",
32
32
  "build:browser": "webpack",
33
33
  "main": "tsc & node dist/index.js",
34
- "docs": "typedoc --out docs/api src/index.node.ts"
34
+ "docs": "typedoc --out docs/api src/index.node.ts",
35
+ "prepare": "husky",
36
+ "format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\""
37
+ },
38
+ "lint-staged": {
39
+ "*.{ts,js}": "prettier --write",
40
+ "*.{json,md}": "prettier --write"
35
41
  },
36
42
  "keywords": [],
37
43
  "author": "",
38
44
  "license": "ISC",
39
45
  "devDependencies": {
46
+ "@trivago/prettier-plugin-sort-imports": "^5.2.2",
40
47
  "@types/jest": "^29.5.14",
41
48
  "@types/node": "^25.0.3",
42
49
  "copyfiles": "^2.4.1",
50
+ "husky": "^9.1.7",
43
51
  "jest": "^29.7.0",
52
+ "lint-staged": "^15.2.11",
53
+ "prettier": "^3.4.2",
44
54
  "ts-jest": "^29.2.5",
45
55
  "ts-loader": "^9.5.1",
46
56
  "ts-node": "^10.9.2",
@@ -0,0 +1,19 @@
1
+ import Expression from "./expression";
2
+
3
+ class ExpressionMap {
4
+ private _map: Map<string, Expression> = new Map();
5
+ public get(alias: string): Expression | undefined {
6
+ return this._map.get(alias);
7
+ }
8
+ public set map(expressions: Expression[]) {
9
+ this._map.clear();
10
+ for (const expr of expressions) {
11
+ if (expr.alias == undefined) {
12
+ continue;
13
+ }
14
+ this._map.set(expr.alias, expr);
15
+ }
16
+ }
17
+ }
18
+
19
+ export default ExpressionMap;
@@ -29,20 +29,34 @@ class AsyncFunction extends Function {
29
29
 
30
30
  /**
31
31
  * Evaluates all parameters and returns their values.
32
+ * Used by the framework to pass arguments to generate().
32
33
  *
33
34
  * @returns Array of parameter values
34
35
  */
35
- private getArguments(): any[] {
36
+ public getArguments(): any[] {
36
37
  return this.children.map(child => child.value());
37
38
  }
38
39
 
39
40
  /**
40
41
  * Generates the async data provider function results.
41
42
  *
43
+ * Subclasses override this method with their own typed parameters.
44
+ * The framework automatically evaluates the AST children and spreads
45
+ * them as arguments when calling this method.
46
+ *
47
+ * @param args - Arguments passed from the query (e.g., myFunc(arg1, arg2))
42
48
  * @yields Data items from the async provider
43
49
  * @throws {Error} If the function is not registered as an async provider
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * // Subclass with typed parameters:
54
+ * async *generate(count: number = 1, filter?: string): AsyncGenerator<any> {
55
+ * // Implementation
56
+ * }
57
+ * ```
44
58
  */
45
- public async *generate(): AsyncGenerator<any, void, unknown> {
59
+ public async *generate(...args: any[]): AsyncGenerator<any, void, unknown> {
46
60
  throw new Error("Not implemented: generate method must be overridden in subclasses.");
47
61
  }
48
62
  }
@@ -0,0 +1,67 @@
1
+ import Expression from "../expressions/expression";
2
+ import ExpressionMap from "../expressions/expression_map";
3
+ import AsyncFunction from "../functions/async_function";
4
+ import Projection from "./projection";
5
+
6
+ const DEFAULT_VARIABLE_NAME: string = "value";
7
+
8
+ class Call extends Projection {
9
+ protected _function: AsyncFunction | null = null;
10
+ private _map: ExpressionMap = new ExpressionMap();
11
+ protected _results: Record<string, any>[] = [];
12
+ constructor() {
13
+ super([]);
14
+ }
15
+ public set function(asyncFunction: AsyncFunction) {
16
+ this._function = asyncFunction;
17
+ }
18
+ public get function(): AsyncFunction | null {
19
+ return this._function;
20
+ }
21
+ public set yielded(expressions: Expression[]) {
22
+ this.children = expressions;
23
+ this._map.map = expressions;
24
+ }
25
+ public get hasYield(): boolean {
26
+ return this.children.length > 0;
27
+ }
28
+ public async run(): Promise<void> {
29
+ if (this._function === null) {
30
+ throw new Error("No function set for Call operation.");
31
+ }
32
+ const args = this._function.getArguments();
33
+ for await (const item of this._function.generate(...args)) {
34
+ if (!this.isLast) {
35
+ if (typeof item == "object" && !Array.isArray(item)) {
36
+ for (const [key, value] of Object.entries(item)) {
37
+ const expression = this._map.get(key);
38
+ if (expression) {
39
+ expression.overridden = value;
40
+ }
41
+ }
42
+ } else {
43
+ const expression = this._map.get(DEFAULT_VARIABLE_NAME);
44
+ if (expression) {
45
+ expression.overridden = item;
46
+ }
47
+ }
48
+ await this.next?.run();
49
+ } else {
50
+ const record: Map<string, any> = new Map();
51
+ if (typeof item == "object" && !Array.isArray(item)) {
52
+ for (const [key, value] of Object.entries(item)) {
53
+ record.set(key, value);
54
+ }
55
+ } else {
56
+ record.set(DEFAULT_VARIABLE_NAME, item);
57
+ }
58
+ this._results.push(Object.fromEntries(record));
59
+ }
60
+ }
61
+ }
62
+ public get results(): Record<string, any>[] {
63
+ return this._results;
64
+ }
65
+ }
66
+
67
+ export default Call;
@@ -1,141 +1,146 @@
1
- import Operation from "./operation";
2
1
  import CSV from "../components/csv";
3
- import {default as _JSON} from "../components/json";
4
- import Text from "../components/text";
5
- import Function from "../functions/function";
6
- import AsyncFunction from "../functions/async_function";
7
- import AssociativeArray from "../data_structures/associative_array";
8
- import Reference from "../expressions/reference";
9
- import Expression from "../expressions/expression";
2
+ import From from "../components/from";
10
3
  import Headers from "../components/headers";
4
+ import { default as _JSON } from "../components/json";
11
5
  import Post from "../components/post";
6
+ import Text from "../components/text";
7
+ import AssociativeArray from "../data_structures/associative_array";
12
8
  import Lookup from "../data_structures/lookup";
13
- import From from "../components/from";
9
+ import Expression from "../expressions/expression";
10
+ import Reference from "../expressions/reference";
11
+ import AsyncFunction from "../functions/async_function";
12
+ import Function from "../functions/function";
13
+ import Operation from "./operation";
14
14
 
15
15
  class Load extends Operation {
16
- private _value: any = null;
17
- constructor() {
18
- super()
19
- }
20
- public get type(): _JSON | CSV | Text {
21
- return this.children[0] as _JSON | CSV | Text;
22
- }
16
+ private _value: any = null;
17
+
18
+ constructor() {
19
+ super();
20
+ }
21
+ public get type(): _JSON | CSV | Text {
22
+ return this.children[0] as _JSON | CSV | Text;
23
+ }
23
24
 
24
- /**
25
- * Gets the From component which contains either a URL expression or an AsyncFunction.
26
- */
27
- public get fromComponent(): From {
28
- return this.children[1] as From;
29
- }
25
+ /**
26
+ * Gets the From component which contains either a URL expression or an AsyncFunction.
27
+ */
28
+ public get fromComponent(): From {
29
+ return this.children[1] as From;
30
+ }
30
31
 
31
- /**
32
- * Checks if the data source is an async function.
33
- */
34
- public get isAsyncFunction(): boolean {
35
- return this.fromComponent.firstChild() instanceof AsyncFunction;
36
- }
32
+ /**
33
+ * Checks if the data source is an async function.
34
+ */
35
+ public get isAsyncFunction(): boolean {
36
+ return this.fromComponent.firstChild() instanceof AsyncFunction;
37
+ }
37
38
 
38
- /**
39
- * Gets the async function if the source is a function, otherwise null.
40
- */
41
- public get asyncFunction(): AsyncFunction | null {
42
- const child = this.fromComponent.firstChild();
43
- return child instanceof AsyncFunction ? child : null;
44
- }
39
+ /**
40
+ * Gets the async function if the source is a function, otherwise null.
41
+ */
42
+ public get asyncFunction(): AsyncFunction | null {
43
+ const child = this.fromComponent.firstChild();
44
+ return child instanceof AsyncFunction ? child : null;
45
+ }
45
46
 
46
- public get from(): string {
47
- return this.children[1].value() as string;
48
- }
49
- public get headers(): { [key: string]: string } {
50
- if(this.childCount() > 2 && this.children[2] instanceof Headers) {
51
- return this.children[2].value() as { [key: string]: string } || {};
47
+ public get from(): string {
48
+ return this.children[1].value() as string;
52
49
  }
53
- return {};
54
- }
55
- public get payload(): Function | Reference | Expression | AssociativeArray | Lookup | null {
56
- let post: Post | null = null;
57
- if(this.childCount() > 2 && this.children[2] instanceof Post) {
58
- post = this.children[2] as Post;
59
- } else if(this.childCount() > 3 && this.children[3] instanceof Post) {
60
- post = this.children[3] as Post;
50
+ public get headers(): { [key: string]: string } {
51
+ if (this.childCount() > 2 && this.children[2] instanceof Headers) {
52
+ return (this.children[2].value() as { [key: string]: string }) || {};
53
+ }
54
+ return {};
61
55
  }
62
- return post !== null ? post.firstChild() as Function | Reference | Expression | AssociativeArray | Lookup : null;
63
- }
64
- private method(): "GET" | "POST" {
65
- if(this.payload === null) {
66
- return "GET";
67
- } else {
68
- return "POST";
56
+ public get payload(): Function | Reference | Expression | AssociativeArray | Lookup | null {
57
+ let post: Post | null = null;
58
+ if (this.childCount() > 2 && this.children[2] instanceof Post) {
59
+ post = this.children[2] as Post;
60
+ } else if (this.childCount() > 3 && this.children[3] instanceof Post) {
61
+ post = this.children[3] as Post;
62
+ }
63
+ return post !== null
64
+ ? (post.firstChild() as Function | Reference | Expression | AssociativeArray | Lookup)
65
+ : null;
69
66
  }
70
- }
71
- private options(): object {
72
- const headers = this.headers as { [key: string]: string };
73
- const payload = this.payload;
74
- const data = payload?.value();
75
- if(data !== null && typeof data === "object" && !(headers.hasOwnProperty("Content-Type"))) {
76
- headers["Content-Type"] = "application/json";
67
+ private method(): "GET" | "POST" {
68
+ if (this.payload === null) {
69
+ return "GET";
70
+ } else {
71
+ return "POST";
72
+ }
77
73
  }
78
- return {
79
- "method": this.method(),
80
- "headers": headers,
81
- ...(payload !== null ? {"body": JSON.stringify(payload.value())} : {})
82
- };
83
- }
84
-
85
- /**
86
- * Loads data from an async function source.
87
- */
88
- private async loadFromFunction(): Promise<void> {
89
- const asyncFunc = this.asyncFunction!;
90
- for await (const item of asyncFunc.generate()) {
91
- this._value = item;
92
- await this.next?.run();
74
+ private options(): object {
75
+ const headers = this.headers as { [key: string]: string };
76
+ const payload = this.payload;
77
+ const data = payload?.value();
78
+ if (data !== null && typeof data === "object" && !headers.hasOwnProperty("Content-Type")) {
79
+ headers["Content-Type"] = "application/json";
80
+ }
81
+ return {
82
+ method: this.method(),
83
+ headers: headers,
84
+ ...(payload !== null ? { body: JSON.stringify(payload.value()) } : {}),
85
+ };
93
86
  }
94
- }
95
87
 
96
- /**
97
- * Loads data from a URL source (original behavior).
98
- */
99
- private async loadFromUrl(): Promise<void> {
100
- const result = await fetch(this.from, this.options());
101
- let data: any = null;
102
- if(this.type instanceof _JSON) {
103
- data = await result.json();
104
- } else if(this.type instanceof Text) {
105
- data = await result.text();
88
+ /**
89
+ * Loads data from an async function source.
90
+ * Arguments from the query (e.g., myFunc(arg1, arg2)) are passed to generate().
91
+ */
92
+ private async loadFromFunction(): Promise<void> {
93
+ const asyncFunc = this.asyncFunction!;
94
+ const args = asyncFunc.getArguments();
95
+ for await (const item of asyncFunc.generate(...args)) {
96
+ this._value = item;
97
+ await this.next?.run();
98
+ }
106
99
  }
107
- if(Array.isArray(data)) {
108
- for(const item of data) {
109
- this._value = item;
110
- await this.next?.run();
111
- }
112
- } else if(typeof data === "object" && data !== null) {
113
- this._value = data;
114
- await this.next?.run();
115
- } else if(typeof data === "string") {
116
- this._value = data;
117
- await this.next?.run();
100
+
101
+ /**
102
+ * Loads data from a URL source (original behavior).
103
+ */
104
+ private async loadFromUrl(): Promise<void> {
105
+ const result = await fetch(this.from, this.options());
106
+ let data: any = null;
107
+ if (this.type instanceof _JSON) {
108
+ data = await result.json();
109
+ } else if (this.type instanceof Text) {
110
+ data = await result.text();
111
+ }
112
+ if (Array.isArray(data)) {
113
+ for (const item of data) {
114
+ this._value = item;
115
+ await this.next?.run();
116
+ }
117
+ } else if (typeof data === "object" && data !== null) {
118
+ this._value = data;
119
+ await this.next?.run();
120
+ } else if (typeof data === "string") {
121
+ this._value = data;
122
+ await this.next?.run();
123
+ }
118
124
  }
119
- }
120
125
 
121
- public async load(): Promise<any> {
122
- if (this.isAsyncFunction) {
123
- await this.loadFromFunction();
124
- } else {
125
- await this.loadFromUrl();
126
+ public async load(): Promise<any> {
127
+ if (this.isAsyncFunction) {
128
+ await this.loadFromFunction();
129
+ } else {
130
+ await this.loadFromUrl();
131
+ }
132
+ }
133
+ public async run(): Promise<void> {
134
+ try {
135
+ await this.load();
136
+ } catch (e) {
137
+ const source = this.isAsyncFunction ? this.asyncFunction?.name : this.from;
138
+ throw new Error(`Failed to load data from ${source}. Error: ${e}`);
139
+ }
126
140
  }
127
- }
128
- public async run(): Promise<void> {
129
- try {
130
- await this.load();
131
- } catch(e) {
132
- const source = this.isAsyncFunction ? this.asyncFunction?.name : this.from;
133
- throw new Error(`Failed to load data from ${source}. Error: ${e}`);
141
+ public value(): any {
142
+ return this._value;
134
143
  }
135
- }
136
- public value(): any {
137
- return this._value;
138
- }
139
144
  }
140
145
 
141
- export default Load;
146
+ export default Load;
@@ -2,16 +2,16 @@ import ASTNode from "../ast_node";
2
2
 
3
3
  /**
4
4
  * Base class for all FlowQuery operations.
5
- *
5
+ *
6
6
  * Operations represent the main statements in FlowQuery (WITH, UNWIND, RETURN, LOAD, WHERE).
7
7
  * They form a linked list structure and can be executed sequentially.
8
- *
8
+ *
9
9
  * @abstract
10
10
  */
11
11
  abstract class Operation extends ASTNode {
12
12
  private _previous: Operation | null = null;
13
13
  private _next: Operation | null = null;
14
-
14
+
15
15
  /**
16
16
  * Creates a new Operation instance.
17
17
  */
@@ -35,31 +35,32 @@ abstract class Operation extends ASTNode {
35
35
  operation.previous = this;
36
36
  this.next = operation;
37
37
  }
38
-
38
+ public get isLast(): boolean {
39
+ return this._next === null;
40
+ }
41
+
39
42
  /**
40
43
  * Executes this operation. Must be implemented by subclasses.
41
- *
44
+ *
42
45
  * @returns A promise that resolves when the operation completes
43
46
  * @throws {Error} If not implemented by subclass
44
47
  */
45
48
  public async run(): Promise<void> {
46
- throw new Error('Not implemented');
49
+ throw new Error("Not implemented");
47
50
  }
48
-
51
+
49
52
  /**
50
53
  * Finishes execution by calling finish on the next operation in the chain.
51
- *
54
+ *
52
55
  * @returns A promise that resolves when all operations finish
53
56
  */
54
57
  public async finish(): Promise<void> {
55
58
  await this.next?.finish();
56
59
  }
57
- public reset(): void {
58
- ;
59
- }
60
+ public reset(): void {}
60
61
  public get results(): Record<string, any>[] {
61
- throw new Error('Not implemented');
62
+ throw new Error("Not implemented");
62
63
  }
63
64
  }
64
65
 
65
- export default Operation;
66
+ export default Operation;
@@ -1,5 +1,5 @@
1
- import Operation from "./operation";
2
1
  import Expression from "../expressions/expression";
2
+ import Operation from "./operation";
3
3
 
4
4
  class Projection extends Operation {
5
5
  constructor(expressions: Expression[]) {
@@ -7,7 +7,7 @@ class Projection extends Operation {
7
7
  this.children = expressions;
8
8
  }
9
9
  protected *expressions(): Generator<[Expression, string]> {
10
- for(let i = 0; i < this.children.length; i++) {
10
+ for (let i = 0; i < this.children.length; i++) {
11
11
  const expression: Expression = this.children[i] as Expression;
12
12
  const alias = expression.alias || `expr${i}`;
13
13
  yield [expression, alias];
@@ -15,4 +15,4 @@ class Projection extends Operation {
15
15
  }
16
16
  }
17
17
 
18
- export default Projection;
18
+ export default Projection;