@reifydb/react 0.9.0 → 0.9.2

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