@robosystems/client 0.1.15 → 0.1.16
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/package.json +48 -6
- package/sdk/client/client.gen.d.ts +2 -0
- package/sdk/client/client.gen.js +153 -0
- package/sdk/client/client.gen.ts +200 -0
- package/sdk/client/index.d.ts +7 -0
- package/sdk/client/index.js +15 -0
- package/sdk/client/index.ts +25 -0
- package/sdk/client/types.gen.d.ts +122 -0
- package/sdk/client/types.gen.js +4 -0
- package/sdk/client/types.gen.ts +233 -0
- package/sdk/client/utils.gen.d.ts +45 -0
- package/sdk/client/utils.gen.js +296 -0
- package/sdk/client/utils.gen.ts +419 -0
- package/sdk/client.gen.d.ts +12 -0
- package/sdk/client.gen.js +8 -0
- package/sdk/client.gen.ts +18 -0
- package/sdk/core/auth.gen.d.ts +18 -0
- package/sdk/core/auth.gen.js +18 -0
- package/sdk/core/auth.gen.ts +42 -0
- package/sdk/core/bodySerializer.gen.d.ts +17 -0
- package/sdk/core/bodySerializer.gen.js +57 -0
- package/sdk/core/bodySerializer.gen.ts +90 -0
- package/sdk/core/params.gen.d.ts +33 -0
- package/sdk/core/params.gen.js +92 -0
- package/sdk/core/params.gen.ts +153 -0
- package/sdk/core/pathSerializer.gen.d.ts +33 -0
- package/sdk/core/pathSerializer.gen.js +123 -0
- package/sdk/core/pathSerializer.gen.ts +181 -0
- package/sdk/core/types.gen.d.ts +78 -0
- package/sdk/core/types.gen.js +4 -0
- package/sdk/core/types.gen.ts +121 -0
- package/sdk/index.d.ts +2 -0
- package/sdk/index.js +19 -0
- package/sdk/index.ts +3 -0
- package/sdk/sdk.gen.d.ts +1269 -0
- package/sdk/sdk.gen.js +2664 -0
- package/sdk/sdk.gen.ts +2677 -0
- package/sdk/types.gen.d.ts +6265 -0
- package/sdk/types.gen.js +3 -0
- package/sdk/types.gen.ts +6784 -0
- package/sdk-extensions/OperationClient.d.ts +64 -0
- package/sdk-extensions/OperationClient.js +251 -0
- package/sdk-extensions/OperationClient.ts +322 -0
- package/sdk-extensions/QueryClient.d.ts +50 -0
- package/sdk-extensions/QueryClient.js +190 -0
- package/sdk-extensions/QueryClient.ts +283 -0
- package/sdk-extensions/README.md +672 -0
- package/sdk-extensions/SSEClient.d.ts +48 -0
- package/sdk-extensions/SSEClient.js +148 -0
- package/sdk-extensions/SSEClient.ts +189 -0
- package/sdk-extensions/config.d.ts +32 -0
- package/sdk-extensions/config.js +74 -0
- package/sdk-extensions/config.ts +91 -0
- package/sdk-extensions/hooks.d.ts +110 -0
- package/sdk-extensions/hooks.js +371 -0
- package/sdk-extensions/hooks.ts +438 -0
- package/sdk-extensions/index.d.ts +46 -0
- package/sdk-extensions/index.js +110 -0
- package/sdk-extensions/index.ts +123 -0
- package/sdk.gen.d.ts +128 -2
- package/sdk.gen.js +216 -2
- package/sdk.gen.ts +216 -2
- package/types.gen.d.ts +573 -4
- package/types.gen.ts +606 -4
- package/openapi-ts.config.js +0 -9
- package/prepare.js +0 -220
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.QueuedQueryError = exports.QueryClient = void 0;
|
|
5
|
+
/**
|
|
6
|
+
* Enhanced Query Client with SSE support
|
|
7
|
+
* Provides intelligent query execution with automatic strategy selection
|
|
8
|
+
*/
|
|
9
|
+
const sdk_gen_1 = require("../sdk/sdk.gen");
|
|
10
|
+
const SSEClient_1 = require("./SSEClient");
|
|
11
|
+
class QueryClient {
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.config = config;
|
|
14
|
+
}
|
|
15
|
+
async executeQuery(graphId, request, options = {}) {
|
|
16
|
+
const data = {
|
|
17
|
+
url: '/v1/{graph_id}/query',
|
|
18
|
+
path: { graph_id: graphId },
|
|
19
|
+
body: {
|
|
20
|
+
query: request.query,
|
|
21
|
+
parameters: request.parameters,
|
|
22
|
+
},
|
|
23
|
+
query: {
|
|
24
|
+
mode: options.mode,
|
|
25
|
+
test_mode: options.testMode,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
// Execute the query
|
|
29
|
+
const response = await (0, sdk_gen_1.executeCypherQuery)(data);
|
|
30
|
+
const responseData = response.data;
|
|
31
|
+
// Check if this is an immediate response
|
|
32
|
+
if (responseData?.data !== undefined && responseData?.columns) {
|
|
33
|
+
return {
|
|
34
|
+
data: responseData.data,
|
|
35
|
+
columns: responseData.columns,
|
|
36
|
+
row_count: responseData.row_count || responseData.data.length,
|
|
37
|
+
execution_time_ms: responseData.execution_time_ms || 0,
|
|
38
|
+
graph_id: graphId,
|
|
39
|
+
timestamp: responseData.timestamp || new Date().toISOString(),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
// Check if this is a queued response
|
|
43
|
+
if (responseData?.status === 'queued' && responseData?.operation_id) {
|
|
44
|
+
const queuedResponse = responseData;
|
|
45
|
+
// Notify about queue status
|
|
46
|
+
options.onQueueUpdate?.(queuedResponse.queue_position, queuedResponse.estimated_wait_seconds);
|
|
47
|
+
// If user doesn't want to wait, throw with queue info
|
|
48
|
+
if (options.maxWait === 0) {
|
|
49
|
+
throw new QueuedQueryError(queuedResponse);
|
|
50
|
+
}
|
|
51
|
+
// Use SSE to monitor the operation
|
|
52
|
+
if (options.mode === 'stream') {
|
|
53
|
+
return this.streamQueryResults(queuedResponse.operation_id, options);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
return this.waitForQueryCompletion(queuedResponse.operation_id, options);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Unexpected response format
|
|
60
|
+
throw new Error('Unexpected response format from query endpoint');
|
|
61
|
+
}
|
|
62
|
+
async *streamQueryResults(operationId, options) {
|
|
63
|
+
const buffer = [];
|
|
64
|
+
let completed = false;
|
|
65
|
+
let error = null;
|
|
66
|
+
// Set up SSE connection
|
|
67
|
+
this.sseClient = new SSEClient_1.SSEClient(this.config);
|
|
68
|
+
await this.sseClient.connect(operationId);
|
|
69
|
+
// Listen for data chunks
|
|
70
|
+
this.sseClient.on(SSEClient_1.EventType.DATA_CHUNK, (data) => {
|
|
71
|
+
if (Array.isArray(data.rows)) {
|
|
72
|
+
buffer.push(...data.rows);
|
|
73
|
+
}
|
|
74
|
+
else if (data.data) {
|
|
75
|
+
buffer.push(...data.data);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
// Listen for queue updates
|
|
79
|
+
this.sseClient.on(SSEClient_1.EventType.QUEUE_UPDATE, (data) => {
|
|
80
|
+
options.onQueueUpdate?.(data.position, data.estimated_wait_seconds);
|
|
81
|
+
});
|
|
82
|
+
// Listen for progress
|
|
83
|
+
this.sseClient.on(SSEClient_1.EventType.OPERATION_PROGRESS, (data) => {
|
|
84
|
+
options.onProgress?.(data.message);
|
|
85
|
+
});
|
|
86
|
+
// Listen for completion
|
|
87
|
+
this.sseClient.on(SSEClient_1.EventType.OPERATION_COMPLETED, (data) => {
|
|
88
|
+
if (data.result?.data) {
|
|
89
|
+
buffer.push(...data.result.data);
|
|
90
|
+
}
|
|
91
|
+
completed = true;
|
|
92
|
+
});
|
|
93
|
+
// Listen for errors
|
|
94
|
+
this.sseClient.on(SSEClient_1.EventType.OPERATION_ERROR, (err) => {
|
|
95
|
+
error = new Error(err.message || err.error);
|
|
96
|
+
completed = true;
|
|
97
|
+
});
|
|
98
|
+
// Yield buffered results
|
|
99
|
+
while (!completed || buffer.length > 0) {
|
|
100
|
+
if (error)
|
|
101
|
+
throw error;
|
|
102
|
+
if (buffer.length > 0) {
|
|
103
|
+
const chunk = buffer.splice(0, options.chunkSize || 100);
|
|
104
|
+
for (const item of chunk) {
|
|
105
|
+
yield item;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else if (!completed) {
|
|
109
|
+
// Wait for more data
|
|
110
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
this.sseClient.close();
|
|
114
|
+
this.sseClient = undefined;
|
|
115
|
+
}
|
|
116
|
+
async waitForQueryCompletion(operationId, options) {
|
|
117
|
+
return new Promise((resolve, reject) => {
|
|
118
|
+
const sseClient = new SSEClient_1.SSEClient(this.config);
|
|
119
|
+
sseClient
|
|
120
|
+
.connect(operationId)
|
|
121
|
+
.then(() => {
|
|
122
|
+
let result = null;
|
|
123
|
+
// Listen for queue updates
|
|
124
|
+
sseClient.on(SSEClient_1.EventType.QUEUE_UPDATE, (data) => {
|
|
125
|
+
options.onQueueUpdate?.(data.position, data.estimated_wait_seconds);
|
|
126
|
+
});
|
|
127
|
+
// Listen for progress
|
|
128
|
+
sseClient.on(SSEClient_1.EventType.OPERATION_PROGRESS, (data) => {
|
|
129
|
+
options.onProgress?.(data.message);
|
|
130
|
+
});
|
|
131
|
+
sseClient.on(SSEClient_1.EventType.OPERATION_COMPLETED, (data) => {
|
|
132
|
+
const queryResult = data.result || data;
|
|
133
|
+
result = {
|
|
134
|
+
data: queryResult.data || [],
|
|
135
|
+
columns: queryResult.columns || [],
|
|
136
|
+
row_count: queryResult.row_count || 0,
|
|
137
|
+
execution_time_ms: queryResult.execution_time_ms || 0,
|
|
138
|
+
graph_id: queryResult.graph_id,
|
|
139
|
+
timestamp: queryResult.timestamp || new Date().toISOString(),
|
|
140
|
+
};
|
|
141
|
+
sseClient.close();
|
|
142
|
+
resolve(result);
|
|
143
|
+
});
|
|
144
|
+
sseClient.on(SSEClient_1.EventType.OPERATION_ERROR, (error) => {
|
|
145
|
+
sseClient.close();
|
|
146
|
+
reject(new Error(error.message || error.error));
|
|
147
|
+
});
|
|
148
|
+
sseClient.on(SSEClient_1.EventType.OPERATION_CANCELLED, () => {
|
|
149
|
+
sseClient.close();
|
|
150
|
+
reject(new Error('Query cancelled'));
|
|
151
|
+
});
|
|
152
|
+
})
|
|
153
|
+
.catch(reject);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
// Convenience method for simple queries
|
|
157
|
+
async query(graphId, cypher, parameters) {
|
|
158
|
+
return this.executeQuery(graphId, { query: cypher, parameters }, { mode: 'auto' });
|
|
159
|
+
}
|
|
160
|
+
// Streaming query for large results
|
|
161
|
+
async *streamQuery(graphId, cypher, parameters, chunkSize = 1000) {
|
|
162
|
+
const result = await this.executeQuery(graphId, { query: cypher, parameters }, { mode: 'stream', chunkSize });
|
|
163
|
+
if (Symbol.asyncIterator in result) {
|
|
164
|
+
yield* result;
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
// If not streaming, yield all results at once
|
|
168
|
+
yield* result.data;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// Cancel any active SSE connections
|
|
172
|
+
close() {
|
|
173
|
+
if (this.sseClient) {
|
|
174
|
+
this.sseClient.close();
|
|
175
|
+
this.sseClient = undefined;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
exports.QueryClient = QueryClient;
|
|
180
|
+
/**
|
|
181
|
+
* Error thrown when query is queued and maxWait is 0
|
|
182
|
+
*/
|
|
183
|
+
class QueuedQueryError extends Error {
|
|
184
|
+
constructor(queueInfo) {
|
|
185
|
+
super('Query was queued');
|
|
186
|
+
this.queueInfo = queueInfo;
|
|
187
|
+
this.name = 'QueuedQueryError';
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
exports.QueuedQueryError = QueuedQueryError;
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Enhanced Query Client with SSE support
|
|
5
|
+
* Provides intelligent query execution with automatic strategy selection
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { executeCypherQuery } from '../sdk/sdk.gen'
|
|
9
|
+
import type { ExecuteCypherQueryData } from '../sdk/types.gen'
|
|
10
|
+
import { EventType, SSEClient } from './SSEClient'
|
|
11
|
+
|
|
12
|
+
export interface QueryRequest {
|
|
13
|
+
query: string
|
|
14
|
+
parameters?: Record<string, any>
|
|
15
|
+
timeout?: number
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface QueryOptions {
|
|
19
|
+
mode?: 'auto' | 'sync' | 'async' | 'stream'
|
|
20
|
+
chunkSize?: number
|
|
21
|
+
testMode?: boolean
|
|
22
|
+
maxWait?: number
|
|
23
|
+
onQueueUpdate?: (position: number, estimatedWait: number) => void
|
|
24
|
+
onProgress?: (message: string) => void
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface QueryResult {
|
|
28
|
+
data: any[]
|
|
29
|
+
columns: string[]
|
|
30
|
+
row_count: number
|
|
31
|
+
execution_time_ms: number
|
|
32
|
+
graph_id?: string
|
|
33
|
+
timestamp?: string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface QueuedQueryResponse {
|
|
37
|
+
status: 'queued'
|
|
38
|
+
operation_id: string
|
|
39
|
+
queue_position: number
|
|
40
|
+
estimated_wait_seconds: number
|
|
41
|
+
message: string
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class QueryClient {
|
|
45
|
+
private sseClient?: SSEClient
|
|
46
|
+
private config: {
|
|
47
|
+
baseUrl: string
|
|
48
|
+
credentials?: 'include' | 'same-origin' | 'omit'
|
|
49
|
+
headers?: Record<string, string>
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
constructor(config: {
|
|
53
|
+
baseUrl: string
|
|
54
|
+
credentials?: 'include' | 'same-origin' | 'omit'
|
|
55
|
+
headers?: Record<string, string>
|
|
56
|
+
}) {
|
|
57
|
+
this.config = config
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async executeQuery(
|
|
61
|
+
graphId: string,
|
|
62
|
+
request: QueryRequest,
|
|
63
|
+
options: QueryOptions = {}
|
|
64
|
+
): Promise<QueryResult | AsyncIterableIterator<any>> {
|
|
65
|
+
const data: ExecuteCypherQueryData = {
|
|
66
|
+
url: '/v1/{graph_id}/query' as const,
|
|
67
|
+
path: { graph_id: graphId },
|
|
68
|
+
body: {
|
|
69
|
+
query: request.query,
|
|
70
|
+
parameters: request.parameters,
|
|
71
|
+
},
|
|
72
|
+
query: {
|
|
73
|
+
mode: options.mode,
|
|
74
|
+
test_mode: options.testMode,
|
|
75
|
+
},
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Execute the query
|
|
79
|
+
const response = await executeCypherQuery(data)
|
|
80
|
+
const responseData = response.data as any
|
|
81
|
+
|
|
82
|
+
// Check if this is an immediate response
|
|
83
|
+
if (responseData?.data !== undefined && responseData?.columns) {
|
|
84
|
+
return {
|
|
85
|
+
data: responseData.data,
|
|
86
|
+
columns: responseData.columns,
|
|
87
|
+
row_count: responseData.row_count || responseData.data.length,
|
|
88
|
+
execution_time_ms: responseData.execution_time_ms || 0,
|
|
89
|
+
graph_id: graphId,
|
|
90
|
+
timestamp: responseData.timestamp || new Date().toISOString(),
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Check if this is a queued response
|
|
95
|
+
if (responseData?.status === 'queued' && responseData?.operation_id) {
|
|
96
|
+
const queuedResponse = responseData as QueuedQueryResponse
|
|
97
|
+
|
|
98
|
+
// Notify about queue status
|
|
99
|
+
options.onQueueUpdate?.(queuedResponse.queue_position, queuedResponse.estimated_wait_seconds)
|
|
100
|
+
|
|
101
|
+
// If user doesn't want to wait, throw with queue info
|
|
102
|
+
if (options.maxWait === 0) {
|
|
103
|
+
throw new QueuedQueryError(queuedResponse)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Use SSE to monitor the operation
|
|
107
|
+
if (options.mode === 'stream') {
|
|
108
|
+
return this.streamQueryResults(queuedResponse.operation_id, options)
|
|
109
|
+
} else {
|
|
110
|
+
return this.waitForQueryCompletion(queuedResponse.operation_id, options)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Unexpected response format
|
|
115
|
+
throw new Error('Unexpected response format from query endpoint')
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
private async *streamQueryResults(
|
|
119
|
+
operationId: string,
|
|
120
|
+
options: QueryOptions
|
|
121
|
+
): AsyncIterableIterator<any> {
|
|
122
|
+
const buffer: any[] = []
|
|
123
|
+
let completed = false
|
|
124
|
+
let error: Error | null = null
|
|
125
|
+
|
|
126
|
+
// Set up SSE connection
|
|
127
|
+
this.sseClient = new SSEClient(this.config)
|
|
128
|
+
await this.sseClient.connect(operationId)
|
|
129
|
+
|
|
130
|
+
// Listen for data chunks
|
|
131
|
+
this.sseClient.on(EventType.DATA_CHUNK, (data) => {
|
|
132
|
+
if (Array.isArray(data.rows)) {
|
|
133
|
+
buffer.push(...data.rows)
|
|
134
|
+
} else if (data.data) {
|
|
135
|
+
buffer.push(...data.data)
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
// Listen for queue updates
|
|
140
|
+
this.sseClient.on(EventType.QUEUE_UPDATE, (data) => {
|
|
141
|
+
options.onQueueUpdate?.(data.position, data.estimated_wait_seconds)
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
// Listen for progress
|
|
145
|
+
this.sseClient.on(EventType.OPERATION_PROGRESS, (data) => {
|
|
146
|
+
options.onProgress?.(data.message)
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
// Listen for completion
|
|
150
|
+
this.sseClient.on(EventType.OPERATION_COMPLETED, (data) => {
|
|
151
|
+
if (data.result?.data) {
|
|
152
|
+
buffer.push(...data.result.data)
|
|
153
|
+
}
|
|
154
|
+
completed = true
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
// Listen for errors
|
|
158
|
+
this.sseClient.on(EventType.OPERATION_ERROR, (err) => {
|
|
159
|
+
error = new Error(err.message || err.error)
|
|
160
|
+
completed = true
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
// Yield buffered results
|
|
164
|
+
while (!completed || buffer.length > 0) {
|
|
165
|
+
if (error) throw error
|
|
166
|
+
|
|
167
|
+
if (buffer.length > 0) {
|
|
168
|
+
const chunk = buffer.splice(0, options.chunkSize || 100)
|
|
169
|
+
for (const item of chunk) {
|
|
170
|
+
yield item
|
|
171
|
+
}
|
|
172
|
+
} else if (!completed) {
|
|
173
|
+
// Wait for more data
|
|
174
|
+
await new Promise((resolve) => setTimeout(resolve, 100))
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
this.sseClient.close()
|
|
179
|
+
this.sseClient = undefined
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
private async waitForQueryCompletion(
|
|
183
|
+
operationId: string,
|
|
184
|
+
options: QueryOptions
|
|
185
|
+
): Promise<QueryResult> {
|
|
186
|
+
return new Promise((resolve, reject) => {
|
|
187
|
+
const sseClient = new SSEClient(this.config)
|
|
188
|
+
|
|
189
|
+
sseClient
|
|
190
|
+
.connect(operationId)
|
|
191
|
+
.then(() => {
|
|
192
|
+
let result: QueryResult | null = null
|
|
193
|
+
|
|
194
|
+
// Listen for queue updates
|
|
195
|
+
sseClient.on(EventType.QUEUE_UPDATE, (data) => {
|
|
196
|
+
options.onQueueUpdate?.(data.position, data.estimated_wait_seconds)
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
// Listen for progress
|
|
200
|
+
sseClient.on(EventType.OPERATION_PROGRESS, (data) => {
|
|
201
|
+
options.onProgress?.(data.message)
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
sseClient.on(EventType.OPERATION_COMPLETED, (data) => {
|
|
205
|
+
const queryResult = data.result || data
|
|
206
|
+
result = {
|
|
207
|
+
data: queryResult.data || [],
|
|
208
|
+
columns: queryResult.columns || [],
|
|
209
|
+
row_count: queryResult.row_count || 0,
|
|
210
|
+
execution_time_ms: queryResult.execution_time_ms || 0,
|
|
211
|
+
graph_id: queryResult.graph_id,
|
|
212
|
+
timestamp: queryResult.timestamp || new Date().toISOString(),
|
|
213
|
+
}
|
|
214
|
+
sseClient.close()
|
|
215
|
+
resolve(result)
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
sseClient.on(EventType.OPERATION_ERROR, (error) => {
|
|
219
|
+
sseClient.close()
|
|
220
|
+
reject(new Error(error.message || error.error))
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
sseClient.on(EventType.OPERATION_CANCELLED, () => {
|
|
224
|
+
sseClient.close()
|
|
225
|
+
reject(new Error('Query cancelled'))
|
|
226
|
+
})
|
|
227
|
+
})
|
|
228
|
+
.catch(reject)
|
|
229
|
+
})
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Convenience method for simple queries
|
|
233
|
+
async query(
|
|
234
|
+
graphId: string,
|
|
235
|
+
cypher: string,
|
|
236
|
+
parameters?: Record<string, any>
|
|
237
|
+
): Promise<QueryResult> {
|
|
238
|
+
return this.executeQuery(
|
|
239
|
+
graphId,
|
|
240
|
+
{ query: cypher, parameters },
|
|
241
|
+
{ mode: 'auto' }
|
|
242
|
+
) as Promise<QueryResult>
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Streaming query for large results
|
|
246
|
+
async *streamQuery(
|
|
247
|
+
graphId: string,
|
|
248
|
+
cypher: string,
|
|
249
|
+
parameters?: Record<string, any>,
|
|
250
|
+
chunkSize: number = 1000
|
|
251
|
+
): AsyncIterableIterator<any> {
|
|
252
|
+
const result = await this.executeQuery(
|
|
253
|
+
graphId,
|
|
254
|
+
{ query: cypher, parameters },
|
|
255
|
+
{ mode: 'stream', chunkSize }
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
if (Symbol.asyncIterator in (result as any)) {
|
|
259
|
+
yield* result as AsyncIterableIterator<any>
|
|
260
|
+
} else {
|
|
261
|
+
// If not streaming, yield all results at once
|
|
262
|
+
yield* (result as QueryResult).data
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Cancel any active SSE connections
|
|
267
|
+
close(): void {
|
|
268
|
+
if (this.sseClient) {
|
|
269
|
+
this.sseClient.close()
|
|
270
|
+
this.sseClient = undefined
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Error thrown when query is queued and maxWait is 0
|
|
277
|
+
*/
|
|
278
|
+
export class QueuedQueryError extends Error {
|
|
279
|
+
constructor(public queueInfo: QueuedQueryResponse) {
|
|
280
|
+
super('Query was queued')
|
|
281
|
+
this.name = 'QueuedQueryError'
|
|
282
|
+
}
|
|
283
|
+
}
|