@reifydb/react 0.4.8 → 0.4.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +63 -63
- package/dist/index.js +379 -379
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -6,74 +6,74 @@ export * from "@reifydb/client";
|
|
|
6
6
|
import { Client } from "@reifydb/client";
|
|
7
7
|
var DEFAULT_CONFIG = {
|
|
8
8
|
url: "ws://127.0.0.1:8090",
|
|
9
|
-
options: {
|
|
9
|
+
options: { timeout_ms: 3e4 }
|
|
10
10
|
};
|
|
11
11
|
var DEFAULT_URL = "ws://127.0.0.1:8090";
|
|
12
12
|
var Connection = class {
|
|
13
13
|
constructor(config = DEFAULT_CONFIG) {
|
|
14
14
|
this.state = {
|
|
15
15
|
client: null,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
is_connected: false,
|
|
17
|
+
is_connecting: false,
|
|
18
|
+
connection_error: null,
|
|
19
19
|
listeners: /* @__PURE__ */ new Set()
|
|
20
20
|
};
|
|
21
|
-
this.
|
|
21
|
+
this.connect_promise = null;
|
|
22
22
|
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
23
23
|
}
|
|
24
|
-
|
|
24
|
+
set_config(config) {
|
|
25
25
|
this.config = config;
|
|
26
26
|
}
|
|
27
|
-
|
|
27
|
+
get_config() {
|
|
28
28
|
return this.config;
|
|
29
29
|
}
|
|
30
30
|
async connect(url, options) {
|
|
31
|
-
if (this.state.
|
|
31
|
+
if (this.state.is_connected) {
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
|
-
if (this.
|
|
35
|
-
return this.
|
|
34
|
+
if (this.connect_promise) {
|
|
35
|
+
return this.connect_promise;
|
|
36
36
|
}
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
this.
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
const connect_url = url || this.config.url || DEFAULT_CONFIG.url;
|
|
38
|
+
const connect_options = { token: this.config.token, ...this.config.options, ...options };
|
|
39
|
+
this.update_state({
|
|
40
|
+
is_connecting: true,
|
|
41
|
+
connection_error: null
|
|
42
42
|
});
|
|
43
|
-
this.
|
|
43
|
+
this.connect_promise = (async () => {
|
|
44
44
|
try {
|
|
45
|
-
const isHttp =
|
|
45
|
+
const isHttp = connect_url.startsWith("http://") || connect_url.startsWith("https://");
|
|
46
46
|
const isJson = this.config.format === "json";
|
|
47
47
|
let client;
|
|
48
48
|
if (isHttp) {
|
|
49
|
-
client = isJson ? Client.connect_json_http(
|
|
49
|
+
client = isJson ? Client.connect_json_http(connect_url, connect_options) : Client.connect_http(connect_url, connect_options);
|
|
50
50
|
} else {
|
|
51
|
-
client = isJson ? await Client.connect_json_ws(
|
|
51
|
+
client = isJson ? await Client.connect_json_ws(connect_url, connect_options) : await Client.connect_ws(connect_url, connect_options);
|
|
52
52
|
}
|
|
53
|
-
this.
|
|
53
|
+
this.update_state({
|
|
54
54
|
client,
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
is_connected: true,
|
|
56
|
+
is_connecting: false,
|
|
57
|
+
connection_error: null
|
|
58
58
|
});
|
|
59
59
|
} catch (err) {
|
|
60
|
-
const
|
|
61
|
-
console.error("[Connection] Connection failed:",
|
|
62
|
-
this.
|
|
60
|
+
const error_message = err instanceof Error ? err.message : "Failed to connect to ReifyDB";
|
|
61
|
+
console.error("[Connection] Connection failed:", error_message, err);
|
|
62
|
+
this.update_state({
|
|
63
63
|
client: null,
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
is_connected: false,
|
|
65
|
+
is_connecting: false,
|
|
66
|
+
connection_error: error_message
|
|
67
67
|
});
|
|
68
68
|
throw err;
|
|
69
69
|
} finally {
|
|
70
|
-
this.
|
|
70
|
+
this.connect_promise = null;
|
|
71
71
|
}
|
|
72
72
|
})();
|
|
73
|
-
return this.
|
|
73
|
+
return this.connect_promise;
|
|
74
74
|
}
|
|
75
75
|
async disconnect() {
|
|
76
|
-
this.
|
|
76
|
+
this.connect_promise = null;
|
|
77
77
|
if (this.state.client) {
|
|
78
78
|
try {
|
|
79
79
|
if ("disconnect" in this.state.client) {
|
|
@@ -84,30 +84,30 @@ var Connection = class {
|
|
|
84
84
|
console.error("Error disconnecting:", err);
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
|
-
this.
|
|
87
|
+
this.update_state({
|
|
88
88
|
client: null,
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
is_connected: false,
|
|
90
|
+
is_connecting: false,
|
|
91
|
+
connection_error: null
|
|
92
92
|
});
|
|
93
93
|
}
|
|
94
94
|
async reconnect(url, options) {
|
|
95
95
|
await this.disconnect();
|
|
96
96
|
await this.connect(url, options);
|
|
97
97
|
}
|
|
98
|
-
|
|
98
|
+
get_client() {
|
|
99
99
|
return this.state.client;
|
|
100
100
|
}
|
|
101
|
-
|
|
102
|
-
return this.state.
|
|
101
|
+
is_connected() {
|
|
102
|
+
return this.state.is_connected;
|
|
103
103
|
}
|
|
104
|
-
|
|
105
|
-
return this.state.
|
|
104
|
+
is_connecting() {
|
|
105
|
+
return this.state.is_connecting;
|
|
106
106
|
}
|
|
107
|
-
|
|
108
|
-
return this.state.
|
|
107
|
+
get_connection_error() {
|
|
108
|
+
return this.state.connection_error;
|
|
109
109
|
}
|
|
110
|
-
|
|
110
|
+
get_state() {
|
|
111
111
|
const { listeners, ...state } = this.state;
|
|
112
112
|
return state;
|
|
113
113
|
}
|
|
@@ -118,7 +118,7 @@ var Connection = class {
|
|
|
118
118
|
this.state.listeners.delete(listener);
|
|
119
119
|
};
|
|
120
120
|
}
|
|
121
|
-
|
|
121
|
+
update_state(updates) {
|
|
122
122
|
this.state = {
|
|
123
123
|
...this.state,
|
|
124
124
|
...updates
|
|
@@ -130,23 +130,23 @@ var Connection = class {
|
|
|
130
130
|
};
|
|
131
131
|
|
|
132
132
|
// src/connection/connection-pool.ts
|
|
133
|
-
var
|
|
134
|
-
function
|
|
135
|
-
if (!
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
133
|
+
var default_connection = null;
|
|
134
|
+
function get_connection(config) {
|
|
135
|
+
if (!default_connection) {
|
|
136
|
+
const merged_config = { ...DEFAULT_CONFIG, ...config };
|
|
137
|
+
default_connection = new Connection(merged_config);
|
|
138
|
+
default_connection.connect().catch((err) => {
|
|
139
139
|
console.error("[ConnectionPool] Eager connect failed:", err);
|
|
140
140
|
});
|
|
141
141
|
} else if (config) {
|
|
142
|
-
|
|
142
|
+
default_connection.set_config({ ...DEFAULT_CONFIG, ...config });
|
|
143
143
|
}
|
|
144
|
-
return
|
|
144
|
+
return default_connection;
|
|
145
145
|
}
|
|
146
|
-
async function
|
|
147
|
-
if (
|
|
148
|
-
await
|
|
149
|
-
|
|
146
|
+
async function clear_connection() {
|
|
147
|
+
if (default_connection) {
|
|
148
|
+
await default_connection.disconnect();
|
|
149
|
+
default_connection = null;
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
|
|
@@ -154,48 +154,48 @@ async function clearConnection() {
|
|
|
154
154
|
import React, { createContext, useEffect, useRef } from "react";
|
|
155
155
|
var ConnectionContext = createContext(null);
|
|
156
156
|
function ConnectionProvider({ config, children }) {
|
|
157
|
-
const connection =
|
|
158
|
-
const
|
|
159
|
-
const
|
|
157
|
+
const connection = get_connection(config);
|
|
158
|
+
const prev_config_ref = useRef(void 0);
|
|
159
|
+
const current_config_str = JSON.stringify(config);
|
|
160
160
|
useEffect(() => {
|
|
161
|
-
const
|
|
162
|
-
if (
|
|
161
|
+
const config_changed = prev_config_ref.current !== void 0 && prev_config_ref.current !== current_config_str;
|
|
162
|
+
if (config_changed && connection.is_connected()) {
|
|
163
163
|
connection.reconnect().catch((err) => {
|
|
164
164
|
console.error("[ConnectionProvider] Failed to reconnect:", err);
|
|
165
165
|
});
|
|
166
|
-
} else if (!connection.
|
|
166
|
+
} else if (!connection.is_connected() && !connection.is_connecting()) {
|
|
167
167
|
connection.connect().catch((err) => {
|
|
168
168
|
console.error("[ConnectionProvider] Failed to connect:", err);
|
|
169
169
|
});
|
|
170
170
|
}
|
|
171
|
-
|
|
172
|
-
}, [
|
|
171
|
+
prev_config_ref.current = current_config_str;
|
|
172
|
+
}, [current_config_str, connection]);
|
|
173
173
|
return /* @__PURE__ */ React.createElement(ConnectionContext.Provider, { value: connection }, children);
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
// src/hooks/use-connection.ts
|
|
177
177
|
import { useContext, useEffect as useEffect2, useState } from "react";
|
|
178
|
-
function useConnection(
|
|
179
|
-
const
|
|
178
|
+
function useConnection(override_config) {
|
|
179
|
+
const context_connection = useContext(ConnectionContext);
|
|
180
180
|
const [connection] = useState(() => {
|
|
181
|
-
if (
|
|
182
|
-
return
|
|
181
|
+
if (override_config) {
|
|
182
|
+
return get_connection(override_config);
|
|
183
183
|
}
|
|
184
|
-
if (
|
|
185
|
-
return
|
|
184
|
+
if (context_connection) {
|
|
185
|
+
return context_connection;
|
|
186
186
|
}
|
|
187
|
-
return
|
|
187
|
+
return get_connection();
|
|
188
188
|
});
|
|
189
|
-
const [state, setState] = useState(() => connection.
|
|
189
|
+
const [state, setState] = useState(() => connection.get_state());
|
|
190
190
|
useEffect2(() => {
|
|
191
|
-
const
|
|
192
|
-
setState(
|
|
193
|
-
const unsubscribe = connection.subscribe((
|
|
191
|
+
const current_state = connection.get_state();
|
|
192
|
+
setState(current_state);
|
|
193
|
+
const unsubscribe = connection.subscribe((new_state) => {
|
|
194
194
|
setState({
|
|
195
|
-
client:
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
195
|
+
client: new_state.client,
|
|
196
|
+
is_connected: new_state.is_connected,
|
|
197
|
+
is_connecting: new_state.is_connecting,
|
|
198
|
+
connection_error: new_state.connection_error
|
|
199
199
|
});
|
|
200
200
|
});
|
|
201
201
|
return unsubscribe;
|
|
@@ -211,57 +211,57 @@ function useConnection(overrideConfig) {
|
|
|
211
211
|
// src/hooks/use-query-executor.ts
|
|
212
212
|
import { useState as useState2, useCallback, useRef as useRef2, useEffect as useEffect3 } from "react";
|
|
213
213
|
function useQueryExecutor(options) {
|
|
214
|
-
const { client } = useConnection(options?.
|
|
214
|
+
const { client } = useConnection(options?.connection_config);
|
|
215
215
|
const [state, setState] = useState2({
|
|
216
|
-
|
|
216
|
+
is_executing: false,
|
|
217
217
|
results: void 0,
|
|
218
218
|
error: void 0,
|
|
219
|
-
|
|
219
|
+
execution_time: void 0
|
|
220
220
|
});
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
const
|
|
221
|
+
const client_ref = useRef2(client);
|
|
222
|
+
client_ref.current = client;
|
|
223
|
+
const is_mounted_ref = useRef2(true);
|
|
224
224
|
useEffect3(() => {
|
|
225
225
|
return () => {
|
|
226
|
-
|
|
226
|
+
is_mounted_ref.current = false;
|
|
227
227
|
};
|
|
228
228
|
}, []);
|
|
229
|
-
const
|
|
230
|
-
const
|
|
229
|
+
const execution_id_ref = useRef2(0);
|
|
230
|
+
const pending_ref = useRef2(null);
|
|
231
231
|
const query = useCallback(
|
|
232
232
|
(statements, params, shapes) => {
|
|
233
|
-
const
|
|
234
|
-
if (!
|
|
235
|
-
|
|
236
|
-
setState((prev) => ({ ...prev,
|
|
233
|
+
const current_client = client_ref.current;
|
|
234
|
+
if (!current_client) {
|
|
235
|
+
pending_ref.current = { statements, params, shapes };
|
|
236
|
+
setState((prev) => ({ ...prev, is_executing: true, error: void 0 }));
|
|
237
237
|
return Promise.resolve();
|
|
238
238
|
}
|
|
239
|
-
|
|
240
|
-
const
|
|
241
|
-
setState((prev) => ({ ...prev,
|
|
242
|
-
const
|
|
239
|
+
pending_ref.current = null;
|
|
240
|
+
const this_execution = ++execution_id_ref.current;
|
|
241
|
+
setState((prev) => ({ ...prev, is_executing: true, error: void 0 }));
|
|
242
|
+
const start_time = Date.now();
|
|
243
243
|
return (async () => {
|
|
244
244
|
try {
|
|
245
|
-
const
|
|
246
|
-
if (
|
|
247
|
-
const
|
|
248
|
-
const results =
|
|
245
|
+
const frame_results = await current_client.query(statements, params || null, shapes || []) || [];
|
|
246
|
+
if (execution_id_ref.current !== this_execution) return;
|
|
247
|
+
const execution_time = Date.now() - start_time;
|
|
248
|
+
const results = frame_results.map((frame) => {
|
|
249
249
|
if (Array.isArray(frame) && frame.length > 0) {
|
|
250
|
-
const
|
|
250
|
+
const first_row = frame[0];
|
|
251
251
|
let columns = [];
|
|
252
|
-
const
|
|
253
|
-
if (
|
|
254
|
-
columns = Object.keys(
|
|
255
|
-
const value =
|
|
256
|
-
const
|
|
252
|
+
const has_value_objects = first_row && typeof first_row === "object" && Object.values(first_row).some((v) => v && typeof v === "object" && "type" in v);
|
|
253
|
+
if (has_value_objects) {
|
|
254
|
+
columns = Object.keys(first_row).map((key) => {
|
|
255
|
+
const value = first_row[key];
|
|
256
|
+
const data_type = value?.type || "Utf8";
|
|
257
257
|
return {
|
|
258
258
|
name: key,
|
|
259
|
-
type:
|
|
259
|
+
type: data_type,
|
|
260
260
|
payload: []
|
|
261
261
|
};
|
|
262
262
|
});
|
|
263
263
|
} else {
|
|
264
|
-
columns = Object.keys(
|
|
264
|
+
columns = Object.keys(first_row).map((key) => ({
|
|
265
265
|
name: key,
|
|
266
266
|
type: "Utf8",
|
|
267
267
|
payload: []
|
|
@@ -270,41 +270,41 @@ function useQueryExecutor(options) {
|
|
|
270
270
|
return {
|
|
271
271
|
columns,
|
|
272
272
|
rows: frame,
|
|
273
|
-
|
|
273
|
+
execution_time_ms: execution_time
|
|
274
274
|
};
|
|
275
275
|
} else {
|
|
276
276
|
return {
|
|
277
277
|
columns: [],
|
|
278
278
|
rows: [],
|
|
279
|
-
|
|
279
|
+
execution_time_ms: execution_time
|
|
280
280
|
};
|
|
281
281
|
}
|
|
282
282
|
});
|
|
283
|
-
if (!
|
|
283
|
+
if (!is_mounted_ref.current) return;
|
|
284
284
|
setState({
|
|
285
|
-
|
|
285
|
+
is_executing: false,
|
|
286
286
|
results,
|
|
287
287
|
error: void 0,
|
|
288
|
-
|
|
288
|
+
execution_time
|
|
289
289
|
});
|
|
290
290
|
} catch (err) {
|
|
291
|
-
if (
|
|
292
|
-
const
|
|
293
|
-
let
|
|
291
|
+
if (execution_id_ref.current !== this_execution) return;
|
|
292
|
+
const execution_time = Date.now() - start_time;
|
|
293
|
+
let error_message = "Query execution failed";
|
|
294
294
|
if (err instanceof Error) {
|
|
295
|
-
|
|
295
|
+
error_message = err.message;
|
|
296
296
|
} else if (typeof err === "string") {
|
|
297
|
-
|
|
297
|
+
error_message = err;
|
|
298
298
|
} else if (err && typeof err === "object" && "message" in err) {
|
|
299
|
-
|
|
299
|
+
error_message = err.message;
|
|
300
300
|
}
|
|
301
|
-
console.error("Query execution failed:",
|
|
302
|
-
if (!
|
|
301
|
+
console.error("Query execution failed:", error_message);
|
|
302
|
+
if (!is_mounted_ref.current) return;
|
|
303
303
|
setState((prev) => ({
|
|
304
304
|
...prev,
|
|
305
|
-
|
|
306
|
-
error:
|
|
307
|
-
|
|
305
|
+
is_executing: false,
|
|
306
|
+
error: error_message,
|
|
307
|
+
execution_time
|
|
308
308
|
}));
|
|
309
309
|
}
|
|
310
310
|
})();
|
|
@@ -312,26 +312,26 @@ function useQueryExecutor(options) {
|
|
|
312
312
|
[]
|
|
313
313
|
);
|
|
314
314
|
useEffect3(() => {
|
|
315
|
-
if (client &&
|
|
316
|
-
const { statements, params, shapes } =
|
|
315
|
+
if (client && pending_ref.current) {
|
|
316
|
+
const { statements, params, shapes } = pending_ref.current;
|
|
317
317
|
query(statements, params, shapes);
|
|
318
318
|
}
|
|
319
319
|
}, [client, query]);
|
|
320
|
-
const
|
|
321
|
-
|
|
320
|
+
const cancel_query = useCallback(() => {
|
|
321
|
+
execution_id_ref.current++;
|
|
322
322
|
setState((prev) => ({
|
|
323
323
|
...prev,
|
|
324
|
-
|
|
324
|
+
is_executing: false,
|
|
325
325
|
error: "Query cancelled"
|
|
326
326
|
}));
|
|
327
327
|
}, []);
|
|
328
328
|
return {
|
|
329
|
-
|
|
329
|
+
is_executing: state.is_executing,
|
|
330
330
|
results: state.results,
|
|
331
331
|
error: state.error,
|
|
332
|
-
|
|
332
|
+
execution_time: state.execution_time,
|
|
333
333
|
query,
|
|
334
|
-
|
|
334
|
+
cancel_query
|
|
335
335
|
};
|
|
336
336
|
}
|
|
337
337
|
|
|
@@ -339,7 +339,7 @@ function useQueryExecutor(options) {
|
|
|
339
339
|
import { useEffect as useEffect4, useMemo } from "react";
|
|
340
340
|
function useQueryOne(rql, params, shape, options) {
|
|
341
341
|
const {
|
|
342
|
-
|
|
342
|
+
is_executing,
|
|
343
343
|
results,
|
|
344
344
|
error,
|
|
345
345
|
query
|
|
@@ -351,11 +351,11 @@ function useQueryOne(rql, params, shape, options) {
|
|
|
351
351
|
const result = useMemo(() => {
|
|
352
352
|
return results && results.length > 0 ? results[0] : void 0;
|
|
353
353
|
}, [results]);
|
|
354
|
-
return {
|
|
354
|
+
return { is_executing, result, error };
|
|
355
355
|
}
|
|
356
356
|
function useQueryMany(statements, params, shapes, options) {
|
|
357
357
|
const {
|
|
358
|
-
|
|
358
|
+
is_executing,
|
|
359
359
|
results,
|
|
360
360
|
error,
|
|
361
361
|
query
|
|
@@ -363,64 +363,64 @@ function useQueryMany(statements, params, shapes, options) {
|
|
|
363
363
|
useEffect4(() => {
|
|
364
364
|
query(statements, params, shapes);
|
|
365
365
|
}, [statements, params, query]);
|
|
366
|
-
return {
|
|
366
|
+
return { is_executing, results, error };
|
|
367
367
|
}
|
|
368
368
|
|
|
369
369
|
// src/hooks/use-command-executor.ts
|
|
370
370
|
import { useState as useState3, useCallback as useCallback2, useRef as useRef3, useEffect as useEffect5 } from "react";
|
|
371
371
|
function useCommandExecutor(options) {
|
|
372
|
-
const { client } = useConnection(options?.
|
|
372
|
+
const { client } = useConnection(options?.connection_config);
|
|
373
373
|
const [state, setState] = useState3({
|
|
374
|
-
|
|
374
|
+
is_executing: false,
|
|
375
375
|
results: void 0,
|
|
376
376
|
error: void 0,
|
|
377
|
-
|
|
377
|
+
execution_time: void 0
|
|
378
378
|
});
|
|
379
|
-
const
|
|
380
|
-
|
|
381
|
-
const
|
|
379
|
+
const client_ref = useRef3(client);
|
|
380
|
+
client_ref.current = client;
|
|
381
|
+
const is_mounted_ref = useRef3(false);
|
|
382
382
|
useEffect5(() => {
|
|
383
|
-
|
|
383
|
+
is_mounted_ref.current = true;
|
|
384
384
|
return () => {
|
|
385
|
-
|
|
385
|
+
is_mounted_ref.current = false;
|
|
386
386
|
};
|
|
387
387
|
}, []);
|
|
388
|
-
const
|
|
389
|
-
const
|
|
388
|
+
const execution_id_ref = useRef3(0);
|
|
389
|
+
const pending_ref = useRef3(null);
|
|
390
390
|
const command = useCallback2(
|
|
391
391
|
(statements, params, shapes) => {
|
|
392
|
-
const
|
|
393
|
-
if (!
|
|
394
|
-
|
|
395
|
-
setState((prev) => ({ ...prev,
|
|
392
|
+
const current_client = client_ref.current;
|
|
393
|
+
if (!current_client) {
|
|
394
|
+
pending_ref.current = { statements, params, shapes };
|
|
395
|
+
setState((prev) => ({ ...prev, is_executing: true, error: void 0 }));
|
|
396
396
|
return Promise.resolve();
|
|
397
397
|
}
|
|
398
|
-
|
|
399
|
-
const
|
|
400
|
-
setState((prev) => ({ ...prev,
|
|
401
|
-
const
|
|
398
|
+
pending_ref.current = null;
|
|
399
|
+
const this_execution = ++execution_id_ref.current;
|
|
400
|
+
setState((prev) => ({ ...prev, is_executing: true, error: void 0 }));
|
|
401
|
+
const start_time = Date.now();
|
|
402
402
|
return (async () => {
|
|
403
403
|
try {
|
|
404
|
-
const
|
|
405
|
-
if (
|
|
406
|
-
const
|
|
407
|
-
const results =
|
|
404
|
+
const frame_results = await current_client.command(statements, params || null, shapes || []) || [];
|
|
405
|
+
if (execution_id_ref.current !== this_execution) return;
|
|
406
|
+
const execution_time = Date.now() - start_time;
|
|
407
|
+
const results = frame_results.map((frame) => {
|
|
408
408
|
if (Array.isArray(frame) && frame.length > 0) {
|
|
409
|
-
const
|
|
409
|
+
const first_row = frame[0];
|
|
410
410
|
let columns = [];
|
|
411
|
-
const
|
|
412
|
-
if (
|
|
413
|
-
columns = Object.keys(
|
|
414
|
-
const value =
|
|
415
|
-
const
|
|
411
|
+
const has_value_objects = first_row && typeof first_row === "object" && Object.values(first_row).some((v) => v && typeof v === "object" && "type" in v);
|
|
412
|
+
if (has_value_objects) {
|
|
413
|
+
columns = Object.keys(first_row).map((key) => {
|
|
414
|
+
const value = first_row[key];
|
|
415
|
+
const data_type = value?.type || "Utf8";
|
|
416
416
|
return {
|
|
417
417
|
name: key,
|
|
418
|
-
type:
|
|
418
|
+
type: data_type,
|
|
419
419
|
payload: []
|
|
420
420
|
};
|
|
421
421
|
});
|
|
422
422
|
} else {
|
|
423
|
-
columns = Object.keys(
|
|
423
|
+
columns = Object.keys(first_row).map((key) => ({
|
|
424
424
|
name: key,
|
|
425
425
|
type: "Utf8",
|
|
426
426
|
payload: []
|
|
@@ -429,42 +429,42 @@ function useCommandExecutor(options) {
|
|
|
429
429
|
return {
|
|
430
430
|
columns,
|
|
431
431
|
rows: frame,
|
|
432
|
-
|
|
432
|
+
execution_time_ms: execution_time
|
|
433
433
|
};
|
|
434
434
|
} else {
|
|
435
435
|
return {
|
|
436
436
|
columns: [],
|
|
437
437
|
rows: [],
|
|
438
|
-
|
|
439
|
-
|
|
438
|
+
execution_time_ms: execution_time,
|
|
439
|
+
rows_affected: typeof frame === "number" ? frame : void 0
|
|
440
440
|
};
|
|
441
441
|
}
|
|
442
442
|
});
|
|
443
|
-
if (!
|
|
443
|
+
if (!is_mounted_ref.current) return;
|
|
444
444
|
setState({
|
|
445
|
-
|
|
445
|
+
is_executing: false,
|
|
446
446
|
results,
|
|
447
447
|
error: void 0,
|
|
448
|
-
|
|
448
|
+
execution_time
|
|
449
449
|
});
|
|
450
450
|
} catch (err) {
|
|
451
|
-
if (
|
|
452
|
-
const
|
|
453
|
-
let
|
|
451
|
+
if (execution_id_ref.current !== this_execution) return;
|
|
452
|
+
const execution_time = Date.now() - start_time;
|
|
453
|
+
let error_message = "Command execution failed";
|
|
454
454
|
if (err instanceof Error) {
|
|
455
|
-
|
|
455
|
+
error_message = err.message;
|
|
456
456
|
} else if (typeof err === "string") {
|
|
457
|
-
|
|
457
|
+
error_message = err;
|
|
458
458
|
} else if (err && typeof err === "object" && "message" in err) {
|
|
459
|
-
|
|
459
|
+
error_message = err.message;
|
|
460
460
|
}
|
|
461
|
-
console.error("Command execution failed:",
|
|
462
|
-
if (!
|
|
461
|
+
console.error("Command execution failed:", error_message);
|
|
462
|
+
if (!is_mounted_ref.current) return;
|
|
463
463
|
setState((prev) => ({
|
|
464
464
|
...prev,
|
|
465
|
-
|
|
466
|
-
error:
|
|
467
|
-
|
|
465
|
+
is_executing: false,
|
|
466
|
+
error: error_message,
|
|
467
|
+
execution_time
|
|
468
468
|
}));
|
|
469
469
|
}
|
|
470
470
|
})();
|
|
@@ -472,26 +472,26 @@ function useCommandExecutor(options) {
|
|
|
472
472
|
[]
|
|
473
473
|
);
|
|
474
474
|
useEffect5(() => {
|
|
475
|
-
if (client &&
|
|
476
|
-
const { statements, params, shapes } =
|
|
475
|
+
if (client && pending_ref.current) {
|
|
476
|
+
const { statements, params, shapes } = pending_ref.current;
|
|
477
477
|
command(statements, params, shapes);
|
|
478
478
|
}
|
|
479
479
|
}, [client, command]);
|
|
480
|
-
const
|
|
481
|
-
|
|
480
|
+
const cancel_command = useCallback2(() => {
|
|
481
|
+
execution_id_ref.current++;
|
|
482
482
|
setState((prev) => ({
|
|
483
483
|
...prev,
|
|
484
|
-
|
|
484
|
+
is_executing: false,
|
|
485
485
|
error: "Command cancelled"
|
|
486
486
|
}));
|
|
487
487
|
}, []);
|
|
488
488
|
return {
|
|
489
|
-
|
|
489
|
+
is_executing: state.is_executing,
|
|
490
490
|
results: state.results,
|
|
491
491
|
error: state.error,
|
|
492
|
-
|
|
492
|
+
execution_time: state.execution_time,
|
|
493
493
|
command,
|
|
494
|
-
|
|
494
|
+
cancel_command
|
|
495
495
|
};
|
|
496
496
|
}
|
|
497
497
|
|
|
@@ -499,7 +499,7 @@ function useCommandExecutor(options) {
|
|
|
499
499
|
import { useEffect as useEffect6, useMemo as useMemo2 } from "react";
|
|
500
500
|
function useCommandOne(statement, params, shape, options) {
|
|
501
501
|
const {
|
|
502
|
-
|
|
502
|
+
is_executing,
|
|
503
503
|
results,
|
|
504
504
|
error,
|
|
505
505
|
command
|
|
@@ -511,11 +511,11 @@ function useCommandOne(statement, params, shape, options) {
|
|
|
511
511
|
const result = useMemo2(() => {
|
|
512
512
|
return results && results.length > 0 ? results[0] : void 0;
|
|
513
513
|
}, [results]);
|
|
514
|
-
return {
|
|
514
|
+
return { is_executing, result, error };
|
|
515
515
|
}
|
|
516
516
|
function useCommandMany(statements, params, shapes, options) {
|
|
517
517
|
const {
|
|
518
|
-
|
|
518
|
+
is_executing,
|
|
519
519
|
results,
|
|
520
520
|
error,
|
|
521
521
|
command
|
|
@@ -523,64 +523,64 @@ function useCommandMany(statements, params, shapes, options) {
|
|
|
523
523
|
useEffect6(() => {
|
|
524
524
|
command(statements, params, shapes);
|
|
525
525
|
}, [statements, params, command]);
|
|
526
|
-
return {
|
|
526
|
+
return { is_executing, results, error };
|
|
527
527
|
}
|
|
528
528
|
|
|
529
529
|
// src/hooks/use-admin-executor.ts
|
|
530
530
|
import { useState as useState4, useCallback as useCallback3, useRef as useRef4, useEffect as useEffect7 } from "react";
|
|
531
531
|
function useAdminExecutor(options) {
|
|
532
|
-
const { client } = useConnection(options?.
|
|
532
|
+
const { client } = useConnection(options?.connection_config);
|
|
533
533
|
const [state, setState] = useState4({
|
|
534
|
-
|
|
534
|
+
is_executing: false,
|
|
535
535
|
results: void 0,
|
|
536
536
|
error: void 0,
|
|
537
|
-
|
|
537
|
+
execution_time: void 0
|
|
538
538
|
});
|
|
539
|
-
const
|
|
540
|
-
|
|
541
|
-
const
|
|
539
|
+
const client_ref = useRef4(client);
|
|
540
|
+
client_ref.current = client;
|
|
541
|
+
const is_mounted_ref = useRef4(false);
|
|
542
542
|
useEffect7(() => {
|
|
543
|
-
|
|
543
|
+
is_mounted_ref.current = true;
|
|
544
544
|
return () => {
|
|
545
|
-
|
|
545
|
+
is_mounted_ref.current = false;
|
|
546
546
|
};
|
|
547
547
|
}, []);
|
|
548
|
-
const
|
|
549
|
-
const
|
|
548
|
+
const execution_id_ref = useRef4(0);
|
|
549
|
+
const pending_ref = useRef4(null);
|
|
550
550
|
const admin = useCallback3(
|
|
551
551
|
(statements, params, shapes) => {
|
|
552
|
-
const
|
|
553
|
-
if (!
|
|
554
|
-
|
|
555
|
-
setState((prev) => ({ ...prev,
|
|
552
|
+
const current_client = client_ref.current;
|
|
553
|
+
if (!current_client) {
|
|
554
|
+
pending_ref.current = { statements, params, shapes };
|
|
555
|
+
setState((prev) => ({ ...prev, is_executing: true, error: void 0 }));
|
|
556
556
|
return Promise.resolve();
|
|
557
557
|
}
|
|
558
|
-
|
|
559
|
-
const
|
|
560
|
-
setState((prev) => ({ ...prev,
|
|
561
|
-
const
|
|
558
|
+
pending_ref.current = null;
|
|
559
|
+
const this_execution = ++execution_id_ref.current;
|
|
560
|
+
setState((prev) => ({ ...prev, is_executing: true, error: void 0 }));
|
|
561
|
+
const start_time = Date.now();
|
|
562
562
|
return (async () => {
|
|
563
563
|
try {
|
|
564
|
-
const
|
|
565
|
-
if (
|
|
566
|
-
const
|
|
567
|
-
const results =
|
|
564
|
+
const frame_results = await current_client.admin(statements, params || null, shapes || []) || [];
|
|
565
|
+
if (execution_id_ref.current !== this_execution) return;
|
|
566
|
+
const execution_time = Date.now() - start_time;
|
|
567
|
+
const results = frame_results.map((frame) => {
|
|
568
568
|
if (Array.isArray(frame) && frame.length > 0) {
|
|
569
|
-
const
|
|
569
|
+
const first_row = frame[0];
|
|
570
570
|
let columns = [];
|
|
571
|
-
const
|
|
572
|
-
if (
|
|
573
|
-
columns = Object.keys(
|
|
574
|
-
const value =
|
|
575
|
-
const
|
|
571
|
+
const has_value_objects = first_row && typeof first_row === "object" && Object.values(first_row).some((v) => v && typeof v === "object" && "type" in v);
|
|
572
|
+
if (has_value_objects) {
|
|
573
|
+
columns = Object.keys(first_row).map((key) => {
|
|
574
|
+
const value = first_row[key];
|
|
575
|
+
const data_type = value?.type || "Utf8";
|
|
576
576
|
return {
|
|
577
577
|
name: key,
|
|
578
|
-
type:
|
|
578
|
+
type: data_type,
|
|
579
579
|
payload: []
|
|
580
580
|
};
|
|
581
581
|
});
|
|
582
582
|
} else {
|
|
583
|
-
columns = Object.keys(
|
|
583
|
+
columns = Object.keys(first_row).map((key) => ({
|
|
584
584
|
name: key,
|
|
585
585
|
type: "Utf8",
|
|
586
586
|
payload: []
|
|
@@ -589,42 +589,42 @@ function useAdminExecutor(options) {
|
|
|
589
589
|
return {
|
|
590
590
|
columns,
|
|
591
591
|
rows: frame,
|
|
592
|
-
|
|
592
|
+
execution_time_ms: execution_time
|
|
593
593
|
};
|
|
594
594
|
} else {
|
|
595
595
|
return {
|
|
596
596
|
columns: [],
|
|
597
597
|
rows: [],
|
|
598
|
-
|
|
599
|
-
|
|
598
|
+
execution_time_ms: execution_time,
|
|
599
|
+
rows_affected: typeof frame === "number" ? frame : void 0
|
|
600
600
|
};
|
|
601
601
|
}
|
|
602
602
|
});
|
|
603
|
-
if (!
|
|
603
|
+
if (!is_mounted_ref.current) return;
|
|
604
604
|
setState({
|
|
605
|
-
|
|
605
|
+
is_executing: false,
|
|
606
606
|
results,
|
|
607
607
|
error: void 0,
|
|
608
|
-
|
|
608
|
+
execution_time
|
|
609
609
|
});
|
|
610
610
|
} catch (err) {
|
|
611
|
-
if (
|
|
612
|
-
const
|
|
613
|
-
let
|
|
611
|
+
if (execution_id_ref.current !== this_execution) return;
|
|
612
|
+
const execution_time = Date.now() - start_time;
|
|
613
|
+
let error_message = "Admin execution failed";
|
|
614
614
|
if (err instanceof Error) {
|
|
615
|
-
|
|
615
|
+
error_message = err.message;
|
|
616
616
|
} else if (typeof err === "string") {
|
|
617
|
-
|
|
617
|
+
error_message = err;
|
|
618
618
|
} else if (err && typeof err === "object" && "message" in err) {
|
|
619
|
-
|
|
619
|
+
error_message = err.message;
|
|
620
620
|
}
|
|
621
|
-
console.error("Admin execution failed:",
|
|
622
|
-
if (!
|
|
621
|
+
console.error("Admin execution failed:", error_message);
|
|
622
|
+
if (!is_mounted_ref.current) return;
|
|
623
623
|
setState((prev) => ({
|
|
624
624
|
...prev,
|
|
625
|
-
|
|
626
|
-
error:
|
|
627
|
-
|
|
625
|
+
is_executing: false,
|
|
626
|
+
error: error_message,
|
|
627
|
+
execution_time
|
|
628
628
|
}));
|
|
629
629
|
}
|
|
630
630
|
})();
|
|
@@ -633,26 +633,26 @@ function useAdminExecutor(options) {
|
|
|
633
633
|
// stable — never recreates
|
|
634
634
|
);
|
|
635
635
|
useEffect7(() => {
|
|
636
|
-
if (client &&
|
|
637
|
-
const { statements, params, shapes } =
|
|
636
|
+
if (client && pending_ref.current) {
|
|
637
|
+
const { statements, params, shapes } = pending_ref.current;
|
|
638
638
|
admin(statements, params, shapes);
|
|
639
639
|
}
|
|
640
640
|
}, [client, admin]);
|
|
641
|
-
const
|
|
642
|
-
|
|
641
|
+
const cancel_admin = useCallback3(() => {
|
|
642
|
+
execution_id_ref.current++;
|
|
643
643
|
setState((prev) => ({
|
|
644
644
|
...prev,
|
|
645
|
-
|
|
645
|
+
is_executing: false,
|
|
646
646
|
error: "Admin cancelled"
|
|
647
647
|
}));
|
|
648
648
|
}, []);
|
|
649
649
|
return {
|
|
650
|
-
|
|
650
|
+
is_executing: state.is_executing,
|
|
651
651
|
results: state.results,
|
|
652
652
|
error: state.error,
|
|
653
|
-
|
|
653
|
+
execution_time: state.execution_time,
|
|
654
654
|
admin,
|
|
655
|
-
|
|
655
|
+
cancel_admin
|
|
656
656
|
};
|
|
657
657
|
}
|
|
658
658
|
|
|
@@ -660,7 +660,7 @@ function useAdminExecutor(options) {
|
|
|
660
660
|
import { useEffect as useEffect8, useMemo as useMemo3 } from "react";
|
|
661
661
|
function useAdminOne(statement, params, shape, options) {
|
|
662
662
|
const {
|
|
663
|
-
|
|
663
|
+
is_executing,
|
|
664
664
|
results,
|
|
665
665
|
error,
|
|
666
666
|
admin
|
|
@@ -672,11 +672,11 @@ function useAdminOne(statement, params, shape, options) {
|
|
|
672
672
|
const result = useMemo3(() => {
|
|
673
673
|
return results && results.length > 0 ? results[0] : void 0;
|
|
674
674
|
}, [results]);
|
|
675
|
-
return {
|
|
675
|
+
return { is_executing, result, error };
|
|
676
676
|
}
|
|
677
677
|
function useAdminMany(statements, params, shapes, options) {
|
|
678
678
|
const {
|
|
679
|
-
|
|
679
|
+
is_executing,
|
|
680
680
|
results,
|
|
681
681
|
error,
|
|
682
682
|
admin
|
|
@@ -684,106 +684,106 @@ function useAdminMany(statements, params, shapes, options) {
|
|
|
684
684
|
useEffect8(() => {
|
|
685
685
|
admin(statements, params, shapes);
|
|
686
686
|
}, [statements, params, admin]);
|
|
687
|
-
return {
|
|
687
|
+
return { is_executing, results, error };
|
|
688
688
|
}
|
|
689
689
|
|
|
690
690
|
// src/hooks/use-subscription-executor.ts
|
|
691
691
|
import { useState as useState5, useCallback as useCallback4, useRef as useRef5, useEffect as useEffect9 } from "react";
|
|
692
692
|
function useSubscriptionExecutor(options) {
|
|
693
|
-
const { client } = useConnection(options?.
|
|
693
|
+
const { client } = useConnection(options?.connection_config);
|
|
694
694
|
const [state, setState] = useState5({
|
|
695
695
|
data: [],
|
|
696
696
|
changes: [],
|
|
697
|
-
|
|
698
|
-
|
|
697
|
+
is_subscribed: false,
|
|
698
|
+
is_subscribing: false,
|
|
699
699
|
error: void 0,
|
|
700
|
-
|
|
700
|
+
subscription_id: void 0
|
|
701
701
|
});
|
|
702
|
-
const
|
|
702
|
+
const client_ref = useRef5(client);
|
|
703
703
|
const subscriptionIdRef = useRef5(void 0);
|
|
704
|
-
const
|
|
705
|
-
const
|
|
706
|
-
const
|
|
704
|
+
const query_ref = useRef5(void 0);
|
|
705
|
+
const params_ref = useRef5(void 0);
|
|
706
|
+
const shape_ref = useRef5(void 0);
|
|
707
707
|
useEffect9(() => {
|
|
708
|
-
|
|
708
|
+
client_ref.current = client;
|
|
709
709
|
}, [client]);
|
|
710
|
-
const
|
|
710
|
+
const add_change_event = useCallback4((operation, rows) => {
|
|
711
711
|
setState((prev) => {
|
|
712
|
-
const
|
|
712
|
+
const new_change = {
|
|
713
713
|
operation,
|
|
714
714
|
rows,
|
|
715
715
|
timestamp: Date.now()
|
|
716
716
|
};
|
|
717
|
-
const
|
|
717
|
+
const new_changes = [...prev.changes, new_change];
|
|
718
718
|
return {
|
|
719
719
|
...prev,
|
|
720
720
|
data: prev.data,
|
|
721
|
-
changes:
|
|
721
|
+
changes: new_changes
|
|
722
722
|
};
|
|
723
723
|
});
|
|
724
724
|
}, []);
|
|
725
|
-
const
|
|
726
|
-
|
|
727
|
-
}, [
|
|
728
|
-
const
|
|
729
|
-
|
|
730
|
-
}, [
|
|
731
|
-
const
|
|
732
|
-
|
|
733
|
-
}, [
|
|
725
|
+
const handle_insert = useCallback4((rows) => {
|
|
726
|
+
add_change_event("INSERT", rows);
|
|
727
|
+
}, [add_change_event]);
|
|
728
|
+
const handle_update = useCallback4((rows) => {
|
|
729
|
+
add_change_event("UPDATE", rows);
|
|
730
|
+
}, [add_change_event]);
|
|
731
|
+
const handle_remove = useCallback4((rows) => {
|
|
732
|
+
add_change_event("REMOVE", rows);
|
|
733
|
+
}, [add_change_event]);
|
|
734
734
|
const subscribe = useCallback4(async (query, params, shape) => {
|
|
735
|
-
const
|
|
736
|
-
if (!
|
|
735
|
+
const current_client = client_ref.current;
|
|
736
|
+
if (!current_client) {
|
|
737
737
|
setState((prev) => ({ ...prev, error: "Client not connected" }));
|
|
738
738
|
return;
|
|
739
739
|
}
|
|
740
|
-
if (!("subscribe" in
|
|
740
|
+
if (!("subscribe" in current_client)) {
|
|
741
741
|
setState((prev) => ({ ...prev, error: "Subscriptions require a WebSocket connection" }));
|
|
742
742
|
return;
|
|
743
743
|
}
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
744
|
+
query_ref.current = query;
|
|
745
|
+
params_ref.current = params;
|
|
746
|
+
shape_ref.current = shape;
|
|
747
747
|
setState((prev) => ({
|
|
748
748
|
...prev,
|
|
749
|
-
|
|
749
|
+
is_subscribing: true,
|
|
750
750
|
error: void 0
|
|
751
751
|
}));
|
|
752
752
|
try {
|
|
753
|
-
const
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
753
|
+
const sub_id = await current_client.subscribe(query, params, shape, {
|
|
754
|
+
on_insert: handle_insert,
|
|
755
|
+
on_update: handle_update,
|
|
756
|
+
on_remove: handle_remove
|
|
757
757
|
});
|
|
758
|
-
subscriptionIdRef.current =
|
|
758
|
+
subscriptionIdRef.current = sub_id;
|
|
759
759
|
setState((prev) => ({
|
|
760
760
|
...prev,
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
761
|
+
is_subscribing: false,
|
|
762
|
+
is_subscribed: true,
|
|
763
|
+
subscription_id: sub_id
|
|
764
764
|
}));
|
|
765
765
|
} catch (err) {
|
|
766
766
|
setState((prev) => ({
|
|
767
767
|
...prev,
|
|
768
|
-
|
|
768
|
+
is_subscribing: false,
|
|
769
769
|
error: err.message || "Subscription failed"
|
|
770
770
|
}));
|
|
771
771
|
}
|
|
772
|
-
}, [
|
|
772
|
+
}, [handle_insert, handle_update, handle_remove]);
|
|
773
773
|
const unsubscribe = useCallback4(async () => {
|
|
774
|
-
const
|
|
775
|
-
if (!
|
|
776
|
-
if (!("unsubscribe" in
|
|
774
|
+
const current_client = client_ref.current;
|
|
775
|
+
if (!current_client || !subscriptionIdRef.current) return;
|
|
776
|
+
if (!("unsubscribe" in current_client)) return;
|
|
777
777
|
try {
|
|
778
|
-
await
|
|
778
|
+
await current_client.unsubscribe(subscriptionIdRef.current);
|
|
779
779
|
subscriptionIdRef.current = void 0;
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
780
|
+
query_ref.current = void 0;
|
|
781
|
+
params_ref.current = void 0;
|
|
782
|
+
shape_ref.current = void 0;
|
|
783
783
|
setState((prev) => ({
|
|
784
784
|
...prev,
|
|
785
|
-
|
|
786
|
-
|
|
785
|
+
is_subscribed: false,
|
|
786
|
+
subscription_id: void 0
|
|
787
787
|
}));
|
|
788
788
|
} catch (err) {
|
|
789
789
|
setState((prev) => ({
|
|
@@ -792,16 +792,16 @@ function useSubscriptionExecutor(options) {
|
|
|
792
792
|
}));
|
|
793
793
|
}
|
|
794
794
|
}, []);
|
|
795
|
-
const
|
|
795
|
+
const clear_changes = useCallback4(() => {
|
|
796
796
|
setState((prev) => ({ ...prev, changes: [] }));
|
|
797
797
|
}, []);
|
|
798
|
-
const
|
|
798
|
+
const clear_data = useCallback4(() => {
|
|
799
799
|
setState((prev) => ({ ...prev, data: [] }));
|
|
800
800
|
}, []);
|
|
801
801
|
useEffect9(() => {
|
|
802
802
|
return () => {
|
|
803
|
-
if (subscriptionIdRef.current &&
|
|
804
|
-
|
|
803
|
+
if (subscriptionIdRef.current && client_ref.current && "unsubscribe" in client_ref.current) {
|
|
804
|
+
client_ref.current.unsubscribe(subscriptionIdRef.current).catch(console.error);
|
|
805
805
|
}
|
|
806
806
|
};
|
|
807
807
|
}, []);
|
|
@@ -809,8 +809,8 @@ function useSubscriptionExecutor(options) {
|
|
|
809
809
|
state,
|
|
810
810
|
subscribe,
|
|
811
811
|
unsubscribe,
|
|
812
|
-
|
|
813
|
-
|
|
812
|
+
clear_changes,
|
|
813
|
+
clear_data
|
|
814
814
|
};
|
|
815
815
|
}
|
|
816
816
|
|
|
@@ -822,43 +822,43 @@ function useSubscription(query, params, shape, options) {
|
|
|
822
822
|
subscribe,
|
|
823
823
|
unsubscribe
|
|
824
824
|
} = useSubscriptionExecutor(options);
|
|
825
|
-
const
|
|
825
|
+
const params_key = useMemo4(() => JSON.stringify(params), [params]);
|
|
826
826
|
useEffect10(() => {
|
|
827
827
|
if (options?.enabled === false) return;
|
|
828
828
|
subscribe(query, params, shape);
|
|
829
829
|
return () => {
|
|
830
830
|
unsubscribe();
|
|
831
831
|
};
|
|
832
|
-
}, [query,
|
|
832
|
+
}, [query, params_key, shape, options?.enabled, subscribe, unsubscribe]);
|
|
833
833
|
return {
|
|
834
834
|
data: state.data,
|
|
835
835
|
changes: state.changes,
|
|
836
|
-
|
|
837
|
-
|
|
836
|
+
is_subscribed: state.is_subscribed,
|
|
837
|
+
is_subscribing: state.is_subscribing,
|
|
838
838
|
error: state.error,
|
|
839
|
-
|
|
839
|
+
subscription_id: state.subscription_id
|
|
840
840
|
};
|
|
841
841
|
}
|
|
842
842
|
|
|
843
843
|
// src/hooks/use-shape.ts
|
|
844
844
|
import { useEffect as useEffect11, useState as useState6 } from "react";
|
|
845
845
|
import { Shape } from "@reifydb/core";
|
|
846
|
-
var
|
|
846
|
+
var namespace_shape = Shape.object({
|
|
847
847
|
id: Shape.number(),
|
|
848
848
|
name: Shape.string()
|
|
849
849
|
});
|
|
850
|
-
var
|
|
850
|
+
var table_shape = Shape.object({
|
|
851
851
|
id: Shape.number(),
|
|
852
852
|
namespace_id: Shape.number(),
|
|
853
853
|
name: Shape.string(),
|
|
854
854
|
primary_key_id: Shape.number()
|
|
855
855
|
});
|
|
856
|
-
var
|
|
856
|
+
var view_shape = Shape.object({
|
|
857
857
|
id: Shape.number(),
|
|
858
858
|
namespace_id: Shape.number(),
|
|
859
859
|
name: Shape.string()
|
|
860
860
|
});
|
|
861
|
-
var
|
|
861
|
+
var column_shape = Shape.object({
|
|
862
862
|
id: Shape.number(),
|
|
863
863
|
shape_id: Shape.number(),
|
|
864
864
|
shape_type: Shape.number(),
|
|
@@ -868,78 +868,78 @@ var columnShape = Shape.object({
|
|
|
868
868
|
auto_increment: Shape.boolean()
|
|
869
869
|
});
|
|
870
870
|
function useShape() {
|
|
871
|
-
const {
|
|
872
|
-
const [shape,
|
|
873
|
-
const [
|
|
871
|
+
const { is_executing, results, error, query } = useQueryExecutor();
|
|
872
|
+
const [shape, set_shape] = useState6([]);
|
|
873
|
+
const [is_loading, set_is_loading] = useState6(true);
|
|
874
874
|
useEffect11(() => {
|
|
875
875
|
if (!query) return;
|
|
876
|
-
const
|
|
877
|
-
|
|
876
|
+
const fetch_shape = async () => {
|
|
877
|
+
set_is_loading(true);
|
|
878
878
|
try {
|
|
879
879
|
await query(
|
|
880
880
|
`OUTPUT FROM system::namespaces; OUTPUT FROM system::tables; OUTPUT FROM system::views; OUTPUT FROM system::columns;`,
|
|
881
881
|
void 0,
|
|
882
|
-
[
|
|
882
|
+
[namespace_shape, table_shape, view_shape, column_shape]
|
|
883
883
|
);
|
|
884
884
|
} catch (err) {
|
|
885
885
|
console.error("Failed to fetch shape:", err);
|
|
886
886
|
}
|
|
887
887
|
};
|
|
888
|
-
|
|
888
|
+
fetch_shape();
|
|
889
889
|
}, [query]);
|
|
890
890
|
useEffect11(() => {
|
|
891
891
|
if (!results || results.length < 4) {
|
|
892
|
-
|
|
892
|
+
set_is_loading(is_executing);
|
|
893
893
|
return;
|
|
894
894
|
}
|
|
895
|
-
const
|
|
896
|
-
const
|
|
897
|
-
const
|
|
898
|
-
if (!
|
|
899
|
-
|
|
895
|
+
const tables_result = results[1];
|
|
896
|
+
const views_result = results[2];
|
|
897
|
+
const columns_result = results[3];
|
|
898
|
+
if (!tables_result?.rows || !views_result?.rows || !columns_result?.rows) {
|
|
899
|
+
set_is_loading(false);
|
|
900
900
|
return;
|
|
901
901
|
}
|
|
902
|
-
const
|
|
903
|
-
const namespaces =
|
|
904
|
-
const tables =
|
|
905
|
-
const views =
|
|
906
|
-
const columns =
|
|
907
|
-
const
|
|
902
|
+
const namespaces_result = results[0];
|
|
903
|
+
const namespaces = namespaces_result.rows;
|
|
904
|
+
const tables = tables_result.rows;
|
|
905
|
+
const views = views_result.rows;
|
|
906
|
+
const columns = columns_result.rows;
|
|
907
|
+
const namespace_map = /* @__PURE__ */ new Map();
|
|
908
908
|
namespaces.forEach((ns) => {
|
|
909
909
|
const id = ns.id?.valueOf();
|
|
910
910
|
const name = ns.name?.valueOf();
|
|
911
911
|
if (id !== void 0 && name) {
|
|
912
|
-
|
|
912
|
+
namespace_map.set(id, name);
|
|
913
913
|
}
|
|
914
914
|
});
|
|
915
|
-
const
|
|
915
|
+
const table_info_map = /* @__PURE__ */ new Map();
|
|
916
916
|
tables.forEach((table) => {
|
|
917
|
-
const
|
|
918
|
-
const
|
|
919
|
-
const
|
|
920
|
-
if (
|
|
921
|
-
const namespace =
|
|
917
|
+
const table_id = table.id?.valueOf();
|
|
918
|
+
const namespace_id = table.namespace_id?.valueOf();
|
|
919
|
+
const table_name = table.name?.valueOf();
|
|
920
|
+
if (table_id === void 0 || !table_name || namespace_id === void 0) return;
|
|
921
|
+
const namespace = namespace_map.get(namespace_id);
|
|
922
922
|
if (!namespace) return;
|
|
923
|
-
const
|
|
924
|
-
|
|
925
|
-
name:
|
|
923
|
+
const full_table_name = `${namespace}::${table_name}`;
|
|
924
|
+
table_info_map.set(table_id, {
|
|
925
|
+
name: full_table_name,
|
|
926
926
|
columns: []
|
|
927
927
|
});
|
|
928
928
|
});
|
|
929
929
|
views.forEach((view) => {
|
|
930
|
-
const
|
|
931
|
-
const
|
|
932
|
-
const
|
|
933
|
-
if (
|
|
934
|
-
const namespace =
|
|
930
|
+
const view_id = view.id?.valueOf();
|
|
931
|
+
const namespace_id = view.namespace_id?.valueOf();
|
|
932
|
+
const view_name = view.name?.valueOf();
|
|
933
|
+
if (view_id === void 0 || !view_name || namespace_id === void 0) return;
|
|
934
|
+
const namespace = namespace_map.get(namespace_id);
|
|
935
935
|
if (!namespace) return;
|
|
936
|
-
const
|
|
937
|
-
|
|
938
|
-
name:
|
|
936
|
+
const full_view_name = `${namespace}::${view_name}`;
|
|
937
|
+
table_info_map.set(view_id, {
|
|
938
|
+
name: full_view_name,
|
|
939
939
|
columns: []
|
|
940
940
|
});
|
|
941
941
|
});
|
|
942
|
-
const
|
|
942
|
+
const type_map = {
|
|
943
943
|
0: "None",
|
|
944
944
|
1: "Float4",
|
|
945
945
|
2: "Float8",
|
|
@@ -968,36 +968,36 @@ function useShape() {
|
|
|
968
968
|
25: "Uint",
|
|
969
969
|
26: "Any"
|
|
970
970
|
};
|
|
971
|
-
const
|
|
971
|
+
const table_columns_map = /* @__PURE__ */ new Map();
|
|
972
972
|
columns.forEach((column) => {
|
|
973
|
-
const
|
|
974
|
-
const
|
|
975
|
-
const
|
|
976
|
-
const
|
|
973
|
+
const shape_id = column.shape_id?.valueOf();
|
|
974
|
+
const shape_type = column.shape_type?.valueOf();
|
|
975
|
+
const column_name = column.name?.valueOf();
|
|
976
|
+
const type_id = column.type?.valueOf();
|
|
977
977
|
const position = column.position?.valueOf();
|
|
978
|
-
if (
|
|
979
|
-
if (
|
|
980
|
-
if (!
|
|
981
|
-
|
|
978
|
+
if (shape_id === void 0 || !column_name || type_id === void 0) return;
|
|
979
|
+
if (shape_type !== 0 && shape_type !== 1) return;
|
|
980
|
+
if (!table_columns_map.has(shape_id)) {
|
|
981
|
+
table_columns_map.set(shape_id, []);
|
|
982
982
|
}
|
|
983
|
-
|
|
984
|
-
name:
|
|
985
|
-
|
|
983
|
+
table_columns_map.get(shape_id).push({
|
|
984
|
+
name: column_name,
|
|
985
|
+
data_type: type_map[type_id] || `Unknown(${type_id})`,
|
|
986
986
|
position: position ?? 0
|
|
987
987
|
});
|
|
988
988
|
});
|
|
989
|
-
|
|
990
|
-
const
|
|
991
|
-
if (
|
|
989
|
+
table_columns_map.forEach((cols, shape_id) => {
|
|
990
|
+
const table_info = table_info_map.get(shape_id);
|
|
991
|
+
if (table_info) {
|
|
992
992
|
cols.sort((a, b) => a.position - b.position);
|
|
993
|
-
|
|
993
|
+
table_info.columns = cols.map((c) => ({ name: c.name, data_type: c.data_type }));
|
|
994
994
|
}
|
|
995
995
|
});
|
|
996
|
-
const
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
}, [results,
|
|
1000
|
-
return [
|
|
996
|
+
const shape_array = Array.from(table_info_map.values()).filter((table) => table.name !== "reifydb::flows").sort((a, b) => a.name.localeCompare(b.name));
|
|
997
|
+
set_shape(shape_array);
|
|
998
|
+
set_is_loading(false);
|
|
999
|
+
}, [results, is_executing]);
|
|
1000
|
+
return [is_loading, shape, error];
|
|
1001
1001
|
}
|
|
1002
1002
|
export {
|
|
1003
1003
|
Connection,
|
|
@@ -1005,8 +1005,8 @@ export {
|
|
|
1005
1005
|
ConnectionProvider,
|
|
1006
1006
|
DEFAULT_CONFIG,
|
|
1007
1007
|
DEFAULT_URL,
|
|
1008
|
-
|
|
1009
|
-
|
|
1008
|
+
clear_connection,
|
|
1009
|
+
get_connection,
|
|
1010
1010
|
useAdminExecutor,
|
|
1011
1011
|
useAdminMany,
|
|
1012
1012
|
useAdminOne,
|