dzql 0.6.0 → 0.6.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/src/client/ws.ts CHANGED
@@ -1,4 +1,4 @@
1
- // Core WebSocket Manager for TZQL Client
1
+ // Core WebSocket Manager for DZQL Client
2
2
  // Handles connection, auth, reconnects, and message dispatching.
3
3
  // This is a pure transport layer - it does not manage or cache data.
4
4
 
@@ -10,17 +10,17 @@ export interface WebSocketOptions {
10
10
 
11
11
  // Get default token name from environment (build-time injection)
12
12
  function getDefaultTokenName(): string {
13
- // Vite: import.meta.env.VITE_TZQL_TOKEN_NAME
13
+ // Vite: import.meta.env.VITE_DZQL_TOKEN_NAME
14
14
  // @ts-ignore
15
- if (typeof import.meta !== 'undefined' && import.meta.env?.VITE_TZQL_TOKEN_NAME) {
15
+ if (typeof import.meta !== 'undefined' && import.meta.env?.VITE_DZQL_TOKEN_NAME) {
16
16
  // @ts-ignore
17
- return import.meta.env.VITE_TZQL_TOKEN_NAME;
17
+ return import.meta.env.VITE_DZQL_TOKEN_NAME;
18
18
  }
19
- // Node/bundlers: process.env.TZQL_TOKEN_NAME
20
- if (typeof process !== 'undefined' && process.env?.TZQL_TOKEN_NAME) {
21
- return process.env.TZQL_TOKEN_NAME;
19
+ // Node/bundlers: process.env.DZQL_TOKEN_NAME
20
+ if (typeof process !== 'undefined' && process.env?.DZQL_TOKEN_NAME) {
21
+ return process.env.DZQL_TOKEN_NAME;
22
22
  }
23
- return 'tzql_token';
23
+ return 'dzql_token';
24
24
  }
25
25
 
26
26
  export class WebSocketManager {
@@ -32,7 +32,7 @@ export class WebSocketManager {
32
32
  protected readyCallbacks = new Set<(user: any) => void>();
33
33
  protected reconnectAttempts = 0;
34
34
  protected maxReconnectAttempts = 5;
35
- protected tokenName = 'tzql_token';
35
+ protected tokenName = 'dzql_token';
36
36
  protected isShuttingDown = false;
37
37
 
38
38
  // Connection state
@@ -123,7 +123,7 @@ export class WebSocketManager {
123
123
 
124
124
  this.ws.onopen = () => {
125
125
  clearTimeout(connectionTimeout);
126
- console.log('[TZQL] Connected to ' + wsUrl);
126
+ console.log('[DZQL] Connected to ' + wsUrl);
127
127
  this.reconnectAttempts = 0;
128
128
  resolve();
129
129
  };
@@ -133,12 +133,12 @@ export class WebSocketManager {
133
133
  const message = JSON.parse(event.data);
134
134
  this.handleMessage(message);
135
135
  } catch (error) {
136
- console.error("[TZQL] Failed to parse message:", error);
136
+ console.error("[DZQL] Failed to parse message:", error);
137
137
  }
138
138
  };
139
139
 
140
140
  this.ws.onclose = () => {
141
- console.log("[TZQL] Disconnected");
141
+ console.log("[DZQL] Disconnected");
142
142
  if (!this.isShuttingDown) {
143
143
  this.attemptReconnect();
144
144
  }
@@ -146,7 +146,7 @@ export class WebSocketManager {
146
146
 
147
147
  this.ws.onerror = (error) => {
148
148
  clearTimeout(connectionTimeout);
149
- console.error("[TZQL] Connection error:", error);
149
+ console.error("[DZQL] Connection error:", error);
150
150
  reject(error);
151
151
  };
152
152
  });
@@ -157,7 +157,7 @@ export class WebSocketManager {
157
157
  this.reconnectAttempts++;
158
158
  const delay = 1000 * this.reconnectAttempts;
159
159
  setTimeout(() => {
160
- console.log('[TZQL] Reconnecting (' + this.reconnectAttempts + ')...');
160
+ console.log('[DZQL] Reconnecting (' + this.reconnectAttempts + ')...');
161
161
  this.connect();
162
162
  }, delay);
163
163
  }
@@ -90,7 +90,7 @@ const server = serve({
90
90
  if (server.upgrade(req, { data: { token } })) {
91
91
  return;
92
92
  }
93
- return new Response("TZQL Runtime Active", { status: 200 });
93
+ return new Response("DZQL Runtime Active", { status: 200 });
94
94
  },
95
95
  websocket: wsServer.handlers
96
96
  });
@@ -1,16 +1,16 @@
1
1
  /**
2
- * TZQL Namespace for invokej integration
2
+ * DZQL Namespace for invokej integration
3
3
  *
4
- * Provides CLI-style access to TZQL operations via the compiled manifest.
4
+ * Provides CLI-style access to DZQL operations via the compiled manifest.
5
5
  * Each method outputs JSON to console and closes the connection before returning.
6
6
  *
7
7
  * Setup - add to your tasks.js:
8
8
  * ```js
9
- * import { TzqlNamespace } from 'tzql/namespace';
9
+ * import { DzqlNamespace } from 'dzql/namespace';
10
10
  *
11
11
  * export class Tasks {
12
12
  * constructor() {
13
- * this.tzql = new TzqlNamespace();
13
+ * this.dzql = new DzqlNamespace();
14
14
  * }
15
15
  * }
16
16
  * ```
@@ -18,32 +18,32 @@
18
18
  * Available Commands:
19
19
  *
20
20
  * Discovery:
21
- * invj tzql:entities # List all entities
22
- * invj tzql:subscribables # List all subscribables
23
- * invj tzql:functions # List all manifest functions
21
+ * invj dzql:entities # List all entities
22
+ * invj dzql:subscribables # List all subscribables
23
+ * invj dzql:functions # List all manifest functions
24
24
  *
25
25
  * Entity CRUD:
26
- * invj tzql:search venues '{"query": "test"}' # Search with filters
27
- * invj tzql:get venues '{"id": 1}' # Get by primary key
28
- * invj tzql:save venues '{"name": "New", "org_id": 1}' # Create (no id)
29
- * invj tzql:save venues '{"id": 1, "name": "Updated"}' # Update (with id)
30
- * invj tzql:delete venues '{"id": 1}' # Delete by primary key
31
- * invj tzql:lookup venues '{"query": "test"}' # Lookup for dropdowns
26
+ * invj dzql:search venues '{"query": "test"}' # Search with filters
27
+ * invj dzql:get venues '{"id": 1}' # Get by primary key
28
+ * invj dzql:save venues '{"name": "New", "org_id": 1}' # Create (no id)
29
+ * invj dzql:save venues '{"id": 1, "name": "Updated"}' # Update (with id)
30
+ * invj dzql:delete venues '{"id": 1}' # Delete by primary key
31
+ * invj dzql:lookup venues '{"query": "test"}' # Lookup for dropdowns
32
32
  *
33
33
  * Subscribables:
34
- * invj tzql:subscribe venue_detail '{"venue_id": 1}' # Get snapshot
34
+ * invj dzql:subscribe venue_detail '{"venue_id": 1}' # Get snapshot
35
35
  *
36
36
  * Ad-hoc Function Calls:
37
- * invj tzql:call login_user '{"email": "x", "password": "y"}'
38
- * invj tzql:call register_user '{"email": "x", "password": "y"}'
39
- * invj tzql:call get_venue_detail '{"venue_id": 1}'
40
- * invj tzql:call save_venues '{"name": "Test", "org_id": 1}'
37
+ * invj dzql:call login_user '{"email": "x", "password": "y"}'
38
+ * invj dzql:call register_user '{"email": "x", "password": "y"}'
39
+ * invj dzql:call get_venue_detail '{"venue_id": 1}'
40
+ * invj dzql:call save_venues '{"name": "Test", "org_id": 1}'
41
41
  *
42
42
  * Environment:
43
43
  * DATABASE_URL - PostgreSQL connection string (default: postgres://localhost:5432/dzql)
44
44
  *
45
45
  * Requirements:
46
- * - Run 'tzql compile' first to generate dist/runtime/manifest.json
46
+ * - Run 'dzql compile' first to generate dist/runtime/manifest.json
47
47
  */
48
48
 
49
49
  import postgres from "postgres";
@@ -74,7 +74,7 @@ function loadManifestFromDisk(): Manifest {
74
74
  // Fall back to default paths
75
75
  const paths = [
76
76
  join(process.cwd(), "dist/runtime/manifest.json"),
77
- join(process.cwd(), "packages/tzql/dist/runtime/manifest.json"),
77
+ join(process.cwd(), "generated/runtime/manifest.json"),
78
78
  ];
79
79
 
80
80
  for (const path of paths) {
@@ -85,7 +85,7 @@ function loadManifestFromDisk(): Manifest {
85
85
  }
86
86
 
87
87
  throw new Error(
88
- "Manifest not found. Set MANIFEST_PATH env var or run 'tzql compile' to generate dist/runtime/manifest.json"
88
+ "Manifest not found. Set MANIFEST_PATH env var or run 'dzql compile' to generate dist/runtime/manifest.json"
89
89
  );
90
90
  }
91
91
 
@@ -122,9 +122,9 @@ function discoverSubscribables(manifest: Manifest): Record<string, { params: Rec
122
122
  }
123
123
 
124
124
  /**
125
- * TZQL operations namespace for invokej
125
+ * DZQL operations namespace for invokej
126
126
  */
127
- export class TzqlNamespace {
127
+ export class DzqlNamespace {
128
128
  private userId: number;
129
129
  private sql: postgres.Sql | null = null;
130
130
  private manifest: Manifest | null = null;
@@ -225,13 +225,13 @@ export class TzqlNamespace {
225
225
 
226
226
  /**
227
227
  * Search an entity
228
- * @example invj tzql:search venues '{"query": "test"}'
228
+ * @example invj dzql:search venues '{"query": "test"}'
229
229
  */
230
230
  async search(_context: any, entity?: string, argsJson: string = "{}"): Promise<void> {
231
231
  if (!entity) {
232
232
  console.error("Error: entity name required");
233
- console.error("Usage: invj tzql:search <entity> '<json_args>'");
234
- console.error('Example: invj tzql:search venues \'{"query": "test"}\'');
233
+ console.error("Usage: invj dzql:search <entity> '<json_args>'");
234
+ console.error('Example: invj dzql:search venues \'{"query": "test"}\'');
235
235
  await this.cleanup();
236
236
  process.exit(1);
237
237
  }
@@ -258,13 +258,13 @@ export class TzqlNamespace {
258
258
 
259
259
  /**
260
260
  * Get entity by ID
261
- * @example invj tzql:get venues '{"id": 1}'
261
+ * @example invj dzql:get venues '{"id": 1}'
262
262
  */
263
263
  async get(_context: any, entity?: string, argsJson: string = "{}"): Promise<void> {
264
264
  if (!entity) {
265
265
  console.error("Error: entity name required");
266
- console.error("Usage: invj tzql:get <entity> '<json_args>'");
267
- console.error('Example: invj tzql:get venues \'{"id": 1}\'');
266
+ console.error("Usage: invj dzql:get <entity> '<json_args>'");
267
+ console.error('Example: invj dzql:get venues \'{"id": 1}\'');
268
268
  await this.cleanup();
269
269
  process.exit(1);
270
270
  }
@@ -291,13 +291,13 @@ export class TzqlNamespace {
291
291
 
292
292
  /**
293
293
  * Save (create or update) entity
294
- * @example invj tzql:save venues '{"name": "New Venue", "org_id": 1}'
294
+ * @example invj dzql:save venues '{"name": "New Venue", "org_id": 1}'
295
295
  */
296
296
  async save(_context: any, entity?: string, argsJson: string = "{}"): Promise<void> {
297
297
  if (!entity) {
298
298
  console.error("Error: entity name required");
299
- console.error("Usage: invj tzql:save <entity> '<json_args>'");
300
- console.error('Example: invj tzql:save venues \'{"name": "Test Venue", "org_id": 1}\'');
299
+ console.error("Usage: invj dzql:save <entity> '<json_args>'");
300
+ console.error('Example: invj dzql:save venues \'{"name": "Test Venue", "org_id": 1}\'');
301
301
  await this.cleanup();
302
302
  process.exit(1);
303
303
  }
@@ -324,13 +324,13 @@ export class TzqlNamespace {
324
324
 
325
325
  /**
326
326
  * Delete entity by ID
327
- * @example invj tzql:delete venues '{"id": 1}'
327
+ * @example invj dzql:delete venues '{"id": 1}'
328
328
  */
329
329
  async delete(_context: any, entity?: string, argsJson: string = "{}"): Promise<void> {
330
330
  if (!entity) {
331
331
  console.error("Error: entity name required");
332
- console.error("Usage: invj tzql:delete <entity> '<json_args>'");
333
- console.error('Example: invj tzql:delete venues \'{"id": 1}\'');
332
+ console.error("Usage: invj dzql:delete <entity> '<json_args>'");
333
+ console.error('Example: invj dzql:delete venues \'{"id": 1}\'');
334
334
  await this.cleanup();
335
335
  process.exit(1);
336
336
  }
@@ -357,13 +357,13 @@ export class TzqlNamespace {
357
357
 
358
358
  /**
359
359
  * Lookup entity (for dropdowns/autocomplete)
360
- * @example invj tzql:lookup organisations '{"query": "acme"}'
360
+ * @example invj dzql:lookup organisations '{"query": "acme"}'
361
361
  */
362
362
  async lookup(_context: any, entity?: string, argsJson: string = "{}"): Promise<void> {
363
363
  if (!entity) {
364
364
  console.error("Error: entity name required");
365
- console.error("Usage: invj tzql:lookup <entity> '<json_args>'");
366
- console.error('Example: invj tzql:lookup organisations \'{"query": "acme"}\'');
365
+ console.error("Usage: invj dzql:lookup <entity> '<json_args>'");
366
+ console.error('Example: invj dzql:lookup organisations \'{"query": "acme"}\'');
367
367
  await this.cleanup();
368
368
  process.exit(1);
369
369
  }
@@ -390,13 +390,13 @@ export class TzqlNamespace {
390
390
 
391
391
  /**
392
392
  * Get subscribable snapshot
393
- * @example invj tzql:subscribe venue_detail '{"venue_id": 1}'
393
+ * @example invj dzql:subscribe venue_detail '{"venue_id": 1}'
394
394
  */
395
395
  async subscribe(_context: any, name?: string, argsJson: string = "{}"): Promise<void> {
396
396
  if (!name) {
397
397
  console.error("Error: subscribable name required");
398
- console.error("Usage: invj tzql:subscribe <name> '<json_args>'");
399
- console.error('Example: invj tzql:subscribe venue_detail \'{"venue_id": 1}\'');
398
+ console.error("Usage: invj dzql:subscribe <name> '<json_args>'");
399
+ console.error('Example: invj dzql:subscribe venue_detail \'{"venue_id": 1}\'');
400
400
  await this.cleanup();
401
401
  process.exit(1);
402
402
  }
@@ -423,15 +423,15 @@ export class TzqlNamespace {
423
423
 
424
424
  /**
425
425
  * Call any function in the manifest by name
426
- * @example invj tzql:call login_user '{"email": "test@example.com", "password": "secret"}'
427
- * @example invj tzql:call get_venue_detail '{"venue_id": 1}'
426
+ * @example invj dzql:call login_user '{"email": "test@example.com", "password": "secret"}'
427
+ * @example invj dzql:call get_venue_detail '{"venue_id": 1}'
428
428
  */
429
429
  async call(_context: any, funcName?: string, argsJson: string = "{}"): Promise<void> {
430
430
  if (!funcName) {
431
431
  console.error("Error: function name required");
432
- console.error("Usage: invj tzql:call <function_name> '<json_args>'");
433
- console.error('Example: invj tzql:call login_user \'{"email": "test@example.com", "password": "secret"}\'');
434
- console.error('Example: invj tzql:call get_venue_detail \'{"venue_id": 1}\'');
432
+ console.error("Usage: invj dzql:call <function_name> '<json_args>'");
433
+ console.error('Example: invj dzql:call login_user \'{"email": "test@example.com", "password": "secret"}\'');
434
+ console.error('Example: invj dzql:call get_venue_detail \'{"venue_id": 1}\'');
435
435
  await this.cleanup();
436
436
  process.exit(1);
437
437
  }
@@ -458,7 +458,7 @@ export class TzqlNamespace {
458
458
 
459
459
  /**
460
460
  * List all available functions in the manifest
461
- * @example invj tzql:functions
461
+ * @example invj dzql:functions
462
462
  */
463
463
  async functions(_context?: any): Promise<void> {
464
464
  try {
@@ -1 +0,0 @@
1
- export * from './ws.js';
@@ -1,114 +0,0 @@
1
- // Generated by TZQL Compiler v2.0.0
2
- // Do not edit this file directly.
3
-
4
- import { defineStore } from 'pinia';
5
- import { ref, type Ref } from 'vue';
6
- import { ws } from '../index.js';
7
-
8
- /** Parameters for my_profile subscription */
9
- export interface MyProfileParams {
10
- [key: string]: unknown;
11
- }
12
-
13
- /** Event from server for patching */
14
- export interface PatchEvent {
15
- table: string;
16
- op: 'insert' | 'update' | 'delete';
17
- pk: { id: number };
18
- data: Record<string, unknown> | null;
19
- }
20
-
21
- /** Document wrapper with loading state */
22
- export interface DocumentWrapper<T> {
23
- data: T;
24
- loading: boolean;
25
- ready: Promise<void>;
26
- }
27
-
28
- export const useMyProfileStore = defineStore('sub-my_profile', () => {
29
- const documents: Ref<Record<string, DocumentWrapper<Record<string, unknown>>>> = ref({});
30
- const unsubscribers = new Map<string, () => void>();
31
-
32
- async function bind(params: MyProfileParams): Promise<DocumentWrapper<Record<string, unknown>>> {
33
- const key = JSON.stringify(params);
34
-
35
- if (documents.value[key]) {
36
- const existing = documents.value[key];
37
- if (existing.loading) {
38
- await existing.ready;
39
- }
40
- return existing;
41
- }
42
-
43
- let resolveReady!: () => void;
44
- const ready = new Promise<void>((resolve) => { resolveReady = resolve; });
45
-
46
- documents.value[key] = { data: {}, loading: true, ready };
47
- let isFirst = true;
48
-
49
- const unsubscribe = await ws.api.subscribe_my_profile(params, (eventData: unknown) => {
50
- if (isFirst) {
51
- // Initial data - merge into existing object to preserve reactivity
52
- Object.assign(documents.value[key].data, eventData as Record<string, unknown>);
53
- documents.value[key].loading = false;
54
- isFirst = false;
55
- resolveReady();
56
- } else {
57
- // Patch event
58
- applyPatch(documents.value[key].data, eventData as PatchEvent);
59
- }
60
- });
61
-
62
- unsubscribers.set(key, unsubscribe as () => void);
63
- await ready;
64
- return documents.value[key];
65
- }
66
-
67
- function unbind(params: MyProfileParams): void {
68
- const key = JSON.stringify(params);
69
- const unsubscribe = unsubscribers.get(key);
70
- if (unsubscribe) {
71
- unsubscribe();
72
- unsubscribers.delete(key);
73
- delete documents.value[key];
74
- }
75
- }
76
-
77
- function applyPatch(doc: Record<string, unknown>, event: PatchEvent): void {
78
- if (!doc) return;
79
- switch (event.table) {
80
- case 'users':
81
- if (event.op === 'update' && doc.users) {
82
- Object.assign(doc.users, event.data);
83
- }
84
- break;
85
- case 'acts_for':
86
- handleArrayPatch(doc.memberships, event);
87
- break;
88
- case 'organisations':
89
- if (event.data && event.data.membership_id) {
90
- const parent = doc.memberships?.find((p: { id: number }) => p.id === event.data.membership_id);
91
- if (parent && parent.org) {
92
- handleArrayPatch(parent.org, event);
93
- }
94
- }
95
- break;
96
- }
97
- }
98
-
99
- function handleArrayPatch(arr: unknown[] | undefined, event: PatchEvent): void {
100
- if (!arr || !Array.isArray(arr)) return;
101
- const pkValue = event.pk?.id;
102
- const idx = arr.findIndex((i: unknown) => (i as { id: number }).id === pkValue);
103
-
104
- if (event.op === 'insert') {
105
- if (idx === -1 && event.data) arr.push(event.data);
106
- } else if (event.op === 'update') {
107
- if (idx !== -1 && event.data) Object.assign(arr[idx] as object, event.data);
108
- } else if (event.op === 'delete') {
109
- if (idx !== -1) arr.splice(idx, 1);
110
- }
111
- }
112
-
113
- return { bind, unbind, documents };
114
- });
@@ -1,131 +0,0 @@
1
- // Generated by TZQL Compiler v2.0.0
2
- // Do not edit this file directly.
3
-
4
- import { defineStore } from 'pinia';
5
- import { ref, type Ref } from 'vue';
6
- import { ws } from '../index.js';
7
-
8
- /** Parameters for org_dashboard subscription */
9
- export interface OrgDashboardParams {
10
- org_id: number;
11
- }
12
-
13
- /** Event from server for patching */
14
- export interface PatchEvent {
15
- table: string;
16
- op: 'insert' | 'update' | 'delete';
17
- pk: { id: number };
18
- data: Record<string, unknown> | null;
19
- }
20
-
21
- /** Document wrapper with loading state */
22
- export interface DocumentWrapper<T> {
23
- data: T;
24
- loading: boolean;
25
- ready: Promise<void>;
26
- }
27
-
28
- export const useOrgDashboardStore = defineStore('sub-org_dashboard', () => {
29
- const documents: Ref<Record<string, DocumentWrapper<Record<string, unknown>>>> = ref({});
30
- const unsubscribers = new Map<string, () => void>();
31
-
32
- async function bind(params: OrgDashboardParams): Promise<DocumentWrapper<Record<string, unknown>>> {
33
- const key = JSON.stringify(params);
34
-
35
- if (documents.value[key]) {
36
- const existing = documents.value[key];
37
- if (existing.loading) {
38
- await existing.ready;
39
- }
40
- return existing;
41
- }
42
-
43
- let resolveReady!: () => void;
44
- const ready = new Promise<void>((resolve) => { resolveReady = resolve; });
45
-
46
- documents.value[key] = { data: {}, loading: true, ready };
47
- let isFirst = true;
48
-
49
- const unsubscribe = await ws.api.subscribe_org_dashboard(params, (eventData: unknown) => {
50
- if (isFirst) {
51
- // Initial data - merge into existing object to preserve reactivity
52
- Object.assign(documents.value[key].data, eventData as Record<string, unknown>);
53
- documents.value[key].loading = false;
54
- isFirst = false;
55
- resolveReady();
56
- } else {
57
- // Patch event
58
- applyPatch(documents.value[key].data, eventData as PatchEvent);
59
- }
60
- });
61
-
62
- unsubscribers.set(key, unsubscribe as () => void);
63
- await ready;
64
- return documents.value[key];
65
- }
66
-
67
- function unbind(params: OrgDashboardParams): void {
68
- const key = JSON.stringify(params);
69
- const unsubscribe = unsubscribers.get(key);
70
- if (unsubscribe) {
71
- unsubscribe();
72
- unsubscribers.delete(key);
73
- delete documents.value[key];
74
- }
75
- }
76
-
77
- function applyPatch(doc: Record<string, unknown>, event: PatchEvent): void {
78
- if (!doc) return;
79
- switch (event.table) {
80
- case 'organisations':
81
- if (event.op === 'update' && doc.organisations) {
82
- Object.assign(doc.organisations, event.data);
83
- }
84
- break;
85
- case 'venues':
86
- handleArrayPatch(doc.venues, event);
87
- break;
88
- case 'sites':
89
- if (event.data && event.data.venue_id) {
90
- const parent = doc.venues?.find((p: { id: number }) => p.id === event.data.venue_id);
91
- if (parent && parent.sites) {
92
- handleArrayPatch(parent.sites, event);
93
- }
94
- }
95
- break;
96
- case 'products':
97
- handleArrayPatch(doc.products, event);
98
- break;
99
- case 'packages':
100
- handleArrayPatch(doc.packages, event);
101
- break;
102
- case 'brands':
103
- handleArrayPatch(doc.brands, event);
104
- break;
105
- case 'artwork':
106
- if (event.data && event.data.brand_id) {
107
- const parent = doc.brands?.find((p: { id: number }) => p.id === event.data.brand_id);
108
- if (parent && parent.artwork) {
109
- handleArrayPatch(parent.artwork, event);
110
- }
111
- }
112
- break;
113
- }
114
- }
115
-
116
- function handleArrayPatch(arr: unknown[] | undefined, event: PatchEvent): void {
117
- if (!arr || !Array.isArray(arr)) return;
118
- const pkValue = event.pk?.id;
119
- const idx = arr.findIndex((i: unknown) => (i as { id: number }).id === pkValue);
120
-
121
- if (event.op === 'insert') {
122
- if (idx === -1 && event.data) arr.push(event.data);
123
- } else if (event.op === 'update') {
124
- if (idx !== -1 && event.data) Object.assign(arr[idx] as object, event.data);
125
- } else if (event.op === 'delete') {
126
- if (idx !== -1) arr.splice(idx, 1);
127
- }
128
- }
129
-
130
- return { bind, unbind, documents };
131
- });
@@ -1,117 +0,0 @@
1
- // Generated by TZQL Compiler v2.0.0
2
- // Do not edit this file directly.
3
-
4
- import { defineStore } from 'pinia';
5
- import { ref, type Ref } from 'vue';
6
- import { ws } from '../index.js';
7
-
8
- /** Parameters for venue_detail subscription */
9
- export interface VenueDetailParams {
10
- venue_id: number;
11
- }
12
-
13
- /** Event from server for patching */
14
- export interface PatchEvent {
15
- table: string;
16
- op: 'insert' | 'update' | 'delete';
17
- pk: { id: number };
18
- data: Record<string, unknown> | null;
19
- }
20
-
21
- /** Document wrapper with loading state */
22
- export interface DocumentWrapper<T> {
23
- data: T;
24
- loading: boolean;
25
- ready: Promise<void>;
26
- }
27
-
28
- export const useVenueDetailStore = defineStore('sub-venue_detail', () => {
29
- const documents: Ref<Record<string, DocumentWrapper<Record<string, unknown>>>> = ref({});
30
- const unsubscribers = new Map<string, () => void>();
31
-
32
- async function bind(params: VenueDetailParams): Promise<DocumentWrapper<Record<string, unknown>>> {
33
- const key = JSON.stringify(params);
34
-
35
- if (documents.value[key]) {
36
- const existing = documents.value[key];
37
- if (existing.loading) {
38
- await existing.ready;
39
- }
40
- return existing;
41
- }
42
-
43
- let resolveReady!: () => void;
44
- const ready = new Promise<void>((resolve) => { resolveReady = resolve; });
45
-
46
- documents.value[key] = { data: {}, loading: true, ready };
47
- let isFirst = true;
48
-
49
- const unsubscribe = await ws.api.subscribe_venue_detail(params, (eventData: unknown) => {
50
- if (isFirst) {
51
- // Initial data - merge into existing object to preserve reactivity
52
- Object.assign(documents.value[key].data, eventData as Record<string, unknown>);
53
- documents.value[key].loading = false;
54
- isFirst = false;
55
- resolveReady();
56
- } else {
57
- // Patch event
58
- applyPatch(documents.value[key].data, eventData as PatchEvent);
59
- }
60
- });
61
-
62
- unsubscribers.set(key, unsubscribe as () => void);
63
- await ready;
64
- return documents.value[key];
65
- }
66
-
67
- function unbind(params: VenueDetailParams): void {
68
- const key = JSON.stringify(params);
69
- const unsubscribe = unsubscribers.get(key);
70
- if (unsubscribe) {
71
- unsubscribe();
72
- unsubscribers.delete(key);
73
- delete documents.value[key];
74
- }
75
- }
76
-
77
- function applyPatch(doc: Record<string, unknown>, event: PatchEvent): void {
78
- if (!doc) return;
79
- switch (event.table) {
80
- case 'venues':
81
- if (event.op === 'update' && doc.venues) {
82
- Object.assign(doc.venues, event.data);
83
- }
84
- break;
85
- case 'organisations':
86
- handleArrayPatch(doc.org, event);
87
- break;
88
- case 'sites':
89
- handleArrayPatch(doc.sites, event);
90
- break;
91
- case 'allocations':
92
- if (event.data && event.data.site_id) {
93
- const parent = doc.sites?.find((p: { id: number }) => p.id === event.data.site_id);
94
- if (parent && parent.allocations) {
95
- handleArrayPatch(parent.allocations, event);
96
- }
97
- }
98
- break;
99
- }
100
- }
101
-
102
- function handleArrayPatch(arr: unknown[] | undefined, event: PatchEvent): void {
103
- if (!arr || !Array.isArray(arr)) return;
104
- const pkValue = event.pk?.id;
105
- const idx = arr.findIndex((i: unknown) => (i as { id: number }).id === pkValue);
106
-
107
- if (event.op === 'insert') {
108
- if (idx === -1 && event.data) arr.push(event.data);
109
- } else if (event.op === 'update') {
110
- if (idx !== -1 && event.data) Object.assign(arr[idx] as object, event.data);
111
- } else if (event.op === 'delete') {
112
- if (idx !== -1) arr.splice(idx, 1);
113
- }
114
- }
115
-
116
- return { bind, unbind, documents };
117
- });