@pol-studios/db 1.0.9 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/dist/DataLayerContext-CL6alnkb.d.ts +755 -0
  2. package/dist/UserMetadataContext-B8gVWGMl.d.ts +35 -0
  3. package/dist/UserMetadataContext-DntmpK41.d.ts +33 -0
  4. package/dist/auth/context.d.ts +3 -2
  5. package/dist/auth/context.js +22 -12786
  6. package/dist/auth/context.js.map +1 -1
  7. package/dist/auth/guards.js +12 -7640
  8. package/dist/auth/guards.js.map +1 -1
  9. package/dist/auth/hooks.d.ts +3 -3
  10. package/dist/auth/hooks.js +26 -10591
  11. package/dist/auth/hooks.js.map +1 -1
  12. package/dist/auth/index.d.ts +3 -2
  13. package/dist/auth/index.js +45 -13008
  14. package/dist/auth/index.js.map +1 -1
  15. package/dist/{canvas-UVNDA54X.node → canvas-C4TBBDUL.node} +0 -0
  16. package/dist/canvas-ZQNCL7JL.js +1541 -0
  17. package/dist/canvas-ZQNCL7JL.js.map +1 -0
  18. package/dist/chunk-3PJTNH2L.js +2778 -0
  19. package/dist/chunk-3PJTNH2L.js.map +1 -0
  20. package/dist/chunk-5EFDS7SR.js +205 -0
  21. package/dist/chunk-5EFDS7SR.js.map +1 -0
  22. package/dist/chunk-7SCJNYTE.js +1459 -0
  23. package/dist/chunk-7SCJNYTE.js.map +1 -0
  24. package/dist/chunk-DJ6VLEAL.js +247 -0
  25. package/dist/chunk-DJ6VLEAL.js.map +1 -0
  26. package/dist/chunk-GC3TBUWE.js +14 -0
  27. package/dist/chunk-GC3TBUWE.js.map +1 -0
  28. package/dist/chunk-H3LNH2NT.js +611 -0
  29. package/dist/chunk-H3LNH2NT.js.map +1 -0
  30. package/dist/chunk-H6365JPC.js +1858 -0
  31. package/dist/chunk-H6365JPC.js.map +1 -0
  32. package/dist/chunk-HAWJTZCK.js +86 -0
  33. package/dist/chunk-HAWJTZCK.js.map +1 -0
  34. package/dist/chunk-J4ZVCXZ4.js +1 -0
  35. package/dist/chunk-J4ZVCXZ4.js.map +1 -0
  36. package/dist/chunk-JAATANS3.js +429 -0
  37. package/dist/chunk-JAATANS3.js.map +1 -0
  38. package/dist/chunk-LNJ3WF7V.js +470 -0
  39. package/dist/chunk-LNJ3WF7V.js.map +1 -0
  40. package/dist/chunk-N26IEHZT.js +79 -0
  41. package/dist/chunk-N26IEHZT.js.map +1 -0
  42. package/dist/chunk-NSIAAYW3.js +1 -0
  43. package/dist/chunk-NSIAAYW3.js.map +1 -0
  44. package/dist/chunk-NZON56CB.js +3864 -0
  45. package/dist/chunk-NZON56CB.js.map +1 -0
  46. package/dist/chunk-OQ7U6EQ3.js +7550 -0
  47. package/dist/chunk-OQ7U6EQ3.js.map +1 -0
  48. package/dist/chunk-P4UZ7IXC.js +42 -0
  49. package/dist/chunk-P4UZ7IXC.js.map +1 -0
  50. package/dist/chunk-SM73S2DY.js +11 -0
  51. package/dist/chunk-SM73S2DY.js.map +1 -0
  52. package/dist/chunk-TKWR5AAY.js +415 -0
  53. package/dist/chunk-TKWR5AAY.js.map +1 -0
  54. package/dist/chunk-U5UNPBKB.js +501 -0
  55. package/dist/chunk-U5UNPBKB.js.map +1 -0
  56. package/dist/chunk-WGDJ4IXR.js +921 -0
  57. package/dist/chunk-WGDJ4IXR.js.map +1 -0
  58. package/dist/chunk-WVF7RUW5.js +186 -0
  59. package/dist/chunk-WVF7RUW5.js.map +1 -0
  60. package/dist/chunk-X3HZLNBV.js +2129 -0
  61. package/dist/chunk-X3HZLNBV.js.map +1 -0
  62. package/dist/chunk-XU3SBFAG.js +5205 -0
  63. package/dist/chunk-XU3SBFAG.js.map +1 -0
  64. package/dist/chunk-ZVBHWU7O.js +1412 -0
  65. package/dist/chunk-ZVBHWU7O.js.map +1 -0
  66. package/dist/client/index.d.ts +1 -1
  67. package/dist/client/index.js +54 -163
  68. package/dist/client/index.js.map +1 -1
  69. package/dist/core/index.d.ts +19 -0
  70. package/dist/{index-BFu5_dS8.d.ts → database.types-ChFCG-4M.d.ts} +1 -177
  71. package/dist/dist-NDNRSNOG.js +521 -0
  72. package/dist/dist-NDNRSNOG.js.map +1 -0
  73. package/dist/gen/index.js +188 -1280
  74. package/dist/gen/index.js.map +1 -1
  75. package/dist/hooks/index.d.ts +10 -3
  76. package/dist/hooks/index.js +20 -8695
  77. package/dist/hooks/index.js.map +1 -1
  78. package/dist/index-CQLyNG6A.d.ts +433 -0
  79. package/dist/index.d.ts +12 -8
  80. package/dist/index.js +447 -47848
  81. package/dist/index.js.map +1 -1
  82. package/dist/index.native.d.ts +373 -33
  83. package/dist/index.native.js +432 -25048
  84. package/dist/index.native.js.map +1 -1
  85. package/dist/index.web.d.ts +10 -7
  86. package/dist/index.web.js +585 -43773
  87. package/dist/index.web.js.map +1 -1
  88. package/dist/mutation/index.d.ts +2 -2
  89. package/dist/mutation/index.js +331 -4777
  90. package/dist/mutation/index.js.map +1 -1
  91. package/dist/parser/index.js +45 -3697
  92. package/dist/parser/index.js.map +1 -1
  93. package/dist/pdf-PHXP7RHD.js +20336 -0
  94. package/dist/pdf-PHXP7RHD.js.map +1 -0
  95. package/dist/powersync-bridge/index.d.ts +284 -0
  96. package/dist/powersync-bridge/index.js +22 -0
  97. package/dist/powersync-bridge/index.js.map +1 -0
  98. package/dist/query/index.js +31 -13175
  99. package/dist/query/index.js.map +1 -1
  100. package/dist/realtime/index.js +279 -12541
  101. package/dist/realtime/index.js.map +1 -1
  102. package/dist/{UserMetadataContext-BYYqA6LI.d.ts → setupAuthContext-Kv-THH-h.d.ts} +1 -29
  103. package/dist/types/index.d.ts +5 -1
  104. package/dist/types/index.js +14 -0
  105. package/dist/{useBatchUpsert-CSQVX7w8.d.ts → useBatchUpsert-9OYjibLh.d.ts} +1 -1
  106. package/dist/{useDbCount-RGCuHmHp.d.ts → useDbCount-BG356T9i.d.ts} +3 -719
  107. package/dist/{useReceiptAI-Bn0czE7C.d.ts → useReceiptAI-6HkRpRml.d.ts} +1 -1
  108. package/dist/{useResolveFeedback-CpZPP8Pw.d.ts → useResolveFeedback-BWmatBlE.d.ts} +26 -45
  109. package/dist/{useSupabase-pPhUZHcl.d.ts → useSupabase-DvWVuHHE.d.ts} +2 -1
  110. package/dist/with-auth/index.d.ts +704 -0
  111. package/dist/with-auth/index.js +1221 -0
  112. package/dist/with-auth/index.js.map +1 -0
  113. package/package.json +25 -10
@@ -0,0 +1,2129 @@
1
+ import {
2
+ getSupabaseUrl
3
+ } from "./chunk-GC3TBUWE.js";
4
+ import {
5
+ PostgrestParser
6
+ } from "./chunk-TKWR5AAY.js";
7
+ import {
8
+ isNullOrWhitespace,
9
+ isUsable,
10
+ omit
11
+ } from "./chunk-OQ7U6EQ3.js";
12
+ import {
13
+ encode,
14
+ useQuery
15
+ } from "./chunk-H6365JPC.js";
16
+ import {
17
+ generateUUID,
18
+ useSupabase
19
+ } from "./chunk-5EFDS7SR.js";
20
+
21
+ // src/query/select-parser.ts
22
+ function tokenizeTopLevel(input) {
23
+ const tokens = [];
24
+ let current = "";
25
+ let depth = 0;
26
+ for (const char of input) {
27
+ if (char === "(") {
28
+ depth++;
29
+ current += char;
30
+ } else if (char === ")") {
31
+ depth--;
32
+ current += char;
33
+ } else if (char === "," && depth === 0) {
34
+ const trimmed2 = current.trim();
35
+ if (trimmed2) {
36
+ tokens.push(trimmed2);
37
+ }
38
+ current = "";
39
+ } else {
40
+ current += char;
41
+ }
42
+ }
43
+ const trimmed = current.trim();
44
+ if (trimmed) {
45
+ tokens.push(trimmed);
46
+ }
47
+ return tokens;
48
+ }
49
+ function parseColumnToken(token) {
50
+ const aliasMatch = token.match(/^(\w+):(\w+)$/);
51
+ if (aliasMatch) {
52
+ return {
53
+ name: aliasMatch[2],
54
+ alias: aliasMatch[1]
55
+ };
56
+ }
57
+ return {
58
+ name: token
59
+ };
60
+ }
61
+ function parseSelect(select) {
62
+ const trimmed = select.trim();
63
+ if (trimmed === "*") {
64
+ return {
65
+ columns: "*",
66
+ relations: []
67
+ };
68
+ }
69
+ if (!trimmed) {
70
+ return {
71
+ columns: "*",
72
+ relations: []
73
+ };
74
+ }
75
+ const result = {
76
+ columns: [],
77
+ relations: []
78
+ };
79
+ const tokens = tokenizeTopLevel(trimmed);
80
+ for (const token of tokens) {
81
+ const trimmedToken = token.trim();
82
+ if (!trimmedToken) {
83
+ continue;
84
+ }
85
+ const relationMatch = trimmedToken.match(/^(?:(\w+):)?(\w+)\((.+)\)$/);
86
+ if (relationMatch) {
87
+ const alias = relationMatch[1];
88
+ const name = relationMatch[2];
89
+ const innerSelect = relationMatch[3];
90
+ const innerParsed = parseSelect(innerSelect);
91
+ result.relations.push({
92
+ name,
93
+ alias,
94
+ columns: innerParsed.columns,
95
+ relations: innerParsed.relations
96
+ });
97
+ } else if (trimmedToken === "*") {
98
+ result.columns = "*";
99
+ } else {
100
+ const column = parseColumnToken(trimmedToken);
101
+ if (result.columns !== "*") {
102
+ result.columns.push(column);
103
+ }
104
+ }
105
+ }
106
+ if (Array.isArray(result.columns) && result.columns.length === 0) {
107
+ result.columns = "*";
108
+ }
109
+ return result;
110
+ }
111
+ function stringifySelect(parsed) {
112
+ const parts = [];
113
+ if (parsed.columns === "*") {
114
+ parts.push("*");
115
+ } else {
116
+ for (const col of parsed.columns) {
117
+ if (col.alias) {
118
+ parts.push(`${col.alias}:${col.name}`);
119
+ } else {
120
+ parts.push(col.name);
121
+ }
122
+ }
123
+ }
124
+ for (const rel of parsed.relations) {
125
+ const innerStr = stringifySelect({
126
+ columns: rel.columns,
127
+ relations: rel.relations
128
+ });
129
+ if (rel.alias) {
130
+ parts.push(`${rel.alias}:${rel.name}(${innerStr})`);
131
+ } else {
132
+ parts.push(`${rel.name}(${innerStr})`);
133
+ }
134
+ }
135
+ return parts.join(", ");
136
+ }
137
+ function extractColumnNames(parsed) {
138
+ if (parsed.columns === "*") {
139
+ return "*";
140
+ }
141
+ return parsed.columns.map((col) => col.name);
142
+ }
143
+ function extractRelationNames(parsed) {
144
+ return parsed.relations.map((rel) => rel.alias ?? rel.name);
145
+ }
146
+ function hasRelation(parsed, relationName) {
147
+ return parsed.relations.some((rel) => rel.name === relationName || rel.alias === relationName);
148
+ }
149
+ function getRelationSelect(parsed, relationName) {
150
+ return parsed.relations.find((rel) => rel.name === relationName || rel.alias === relationName);
151
+ }
152
+
153
+ // src/query/relationship-resolver.ts
154
+ var RelationshipResolver = class {
155
+ constructor(schema) {
156
+ this.schema = schema;
157
+ }
158
+ /**
159
+ * Resolve a relationship from one table to another.
160
+ *
161
+ * This handles both:
162
+ * - Forward relationships: This table has a FK to the related table (many-to-one)
163
+ * - Reverse relationships: Related table has a FK to this table (one-to-many)
164
+ *
165
+ * @param fromTable - The table we're querying from
166
+ * @param relationName - The name of the related table
167
+ * @returns The resolved relationship or null if not found
168
+ *
169
+ * @example
170
+ * // Forward relationship (many-to-one)
171
+ * // EquipmentUnit.projectDatabaseId -> ProjectDatabase.id
172
+ * resolver.resolve("EquipmentUnit", "ProjectDatabase")
173
+ * // Returns: {
174
+ * // type: "many-to-one",
175
+ * // fromTable: "EquipmentUnit",
176
+ * // toTable: "ProjectDatabase",
177
+ * // foreignKey: "projectDatabaseId",
178
+ * // referencedColumn: "id"
179
+ * // }
180
+ *
181
+ * @example
182
+ * // Reverse relationship (one-to-many)
183
+ * // EquipmentUnit <- EquipmentFixture.equipmentUnitId
184
+ * resolver.resolve("EquipmentUnit", "EquipmentFixture")
185
+ * // Returns: {
186
+ * // type: "one-to-many",
187
+ * // fromTable: "EquipmentUnit",
188
+ * // toTable: "EquipmentFixture",
189
+ * // foreignKey: "equipmentUnitId",
190
+ * // referencedColumn: "id"
191
+ * // }
192
+ */
193
+ resolve(fromTable, relationName) {
194
+ const tableSchema = this.getTableSchema(fromTable);
195
+ if (!tableSchema) {
196
+ return null;
197
+ }
198
+ for (const rel of tableSchema.relationships) {
199
+ if (rel.referencedTable === relationName) {
200
+ return {
201
+ type: "many-to-one",
202
+ fromTable,
203
+ toTable: relationName,
204
+ foreignKey: rel.foreignKey,
205
+ referencedColumn: rel.referencedColumn
206
+ };
207
+ }
208
+ }
209
+ const relatedTableSchema = this.getTableSchema(relationName);
210
+ if (relatedTableSchema) {
211
+ for (const rel of relatedTableSchema.relationships) {
212
+ if (rel.referencedTable === fromTable) {
213
+ return {
214
+ type: "one-to-many",
215
+ fromTable,
216
+ toTable: relationName,
217
+ foreignKey: rel.foreignKey,
218
+ referencedColumn: rel.referencedColumn
219
+ };
220
+ }
221
+ }
222
+ }
223
+ return null;
224
+ }
225
+ /**
226
+ * Get all forward relationships for a table (many-to-one).
227
+ * These are relationships where this table has a foreign key.
228
+ */
229
+ getForwardRelationships(tableName) {
230
+ const tableSchema = this.getTableSchema(tableName);
231
+ if (!tableSchema) {
232
+ return [];
233
+ }
234
+ return tableSchema.relationships.map((rel) => ({
235
+ type: "many-to-one",
236
+ fromTable: tableName,
237
+ toTable: rel.referencedTable,
238
+ foreignKey: rel.foreignKey,
239
+ referencedColumn: rel.referencedColumn
240
+ }));
241
+ }
242
+ /**
243
+ * Get all reverse relationships for a table (one-to-many).
244
+ * These are relationships where other tables have FKs pointing to this table.
245
+ */
246
+ getReverseRelationships(tableName) {
247
+ const results = [];
248
+ for (const schemaName of Object.keys(this.schema.schemas)) {
249
+ const schemaDefinition = this.schema.schemas[schemaName];
250
+ if (!schemaDefinition) continue;
251
+ for (const [otherTableName, otherTableSchema] of Object.entries(schemaDefinition.tables)) {
252
+ if (otherTableName === tableName) continue;
253
+ for (const rel of otherTableSchema.relationships) {
254
+ if (rel.referencedTable === tableName) {
255
+ results.push({
256
+ type: "one-to-many",
257
+ fromTable: tableName,
258
+ toTable: otherTableName,
259
+ foreignKey: rel.foreignKey,
260
+ referencedColumn: rel.referencedColumn
261
+ });
262
+ }
263
+ }
264
+ }
265
+ }
266
+ return results;
267
+ }
268
+ /**
269
+ * Get all relationships for a table (both directions).
270
+ */
271
+ getAllRelationships(tableName) {
272
+ return [...this.getForwardRelationships(tableName), ...this.getReverseRelationships(tableName)];
273
+ }
274
+ /**
275
+ * Check if a relationship exists between two tables.
276
+ */
277
+ hasRelationship(fromTable, toTable) {
278
+ return this.resolve(fromTable, toTable) !== null;
279
+ }
280
+ /**
281
+ * Get the table schema from the database schema.
282
+ * Searches across all schema namespaces (public, core, etc.).
283
+ */
284
+ getTableSchema(tableName) {
285
+ for (const schemaName of Object.keys(this.schema.schemas)) {
286
+ const schemaDefinition = this.schema.schemas[schemaName];
287
+ if (!schemaDefinition) continue;
288
+ if (schemaDefinition.tables[tableName]) {
289
+ return schemaDefinition.tables[tableName];
290
+ }
291
+ if (schemaDefinition.views && schemaDefinition.views[tableName]) {
292
+ return schemaDefinition.views[tableName];
293
+ }
294
+ }
295
+ return null;
296
+ }
297
+ /**
298
+ * Get the primary key column for a table.
299
+ * Defaults to "id" if not explicitly found.
300
+ */
301
+ getPrimaryKey(tableName) {
302
+ const tableSchema = this.getTableSchema(tableName);
303
+ if (!tableSchema) {
304
+ return "id";
305
+ }
306
+ const idColumn = tableSchema.columns.find((col) => col.name === "id");
307
+ if (idColumn) {
308
+ return "id";
309
+ }
310
+ if (tableSchema.columns.length > 0) {
311
+ return tableSchema.columns[0].name;
312
+ }
313
+ return "id";
314
+ }
315
+ /**
316
+ * Get all column names for a table.
317
+ */
318
+ getColumnNames(tableName) {
319
+ const tableSchema = this.getTableSchema(tableName);
320
+ if (!tableSchema) {
321
+ return [];
322
+ }
323
+ return tableSchema.columns.map((col) => col.name);
324
+ }
325
+ /**
326
+ * Check if a table exists in the schema.
327
+ */
328
+ hasTable(tableName) {
329
+ return this.getTableSchema(tableName) !== null;
330
+ }
331
+ /**
332
+ * Get all table names in the schema.
333
+ */
334
+ getAllTableNames() {
335
+ const tables = [];
336
+ for (const schemaName of Object.keys(this.schema.schemas)) {
337
+ const schemaDefinition = this.schema.schemas[schemaName];
338
+ if (!schemaDefinition) continue;
339
+ tables.push(...Object.keys(schemaDefinition.tables));
340
+ }
341
+ return tables;
342
+ }
343
+ };
344
+ function createRelationshipResolver(schema) {
345
+ return new RelationshipResolver(schema);
346
+ }
347
+
348
+ // src/query/sql-builder.ts
349
+ function isWhereOperator(value) {
350
+ if (value === null || typeof value !== "object") {
351
+ return false;
352
+ }
353
+ const obj = value;
354
+ return "in" in obj || "gt" in obj || "gte" in obj || "lt" in obj || "lte" in obj || "like" in obj || "is" in obj || "neq" in obj || "notIn" in obj;
355
+ }
356
+ var SQLBuilder = class {
357
+ /**
358
+ * Build a SELECT query for a single table.
359
+ *
360
+ * @param table - Table name
361
+ * @param columns - Columns to select ("*" or array of column definitions)
362
+ * @param options - Query options (where, orderBy, limit, offset)
363
+ * @returns Built query with SQL and parameters
364
+ *
365
+ * @example
366
+ * const builder = new SQLBuilder();
367
+ * const query = builder.build("EquipmentUnit", "*", {
368
+ * where: { status: "active", projectDatabaseId: 123 },
369
+ * orderBy: [{ field: "name", direction: "asc" }],
370
+ * limit: 10
371
+ * });
372
+ * // query.sql: SELECT * FROM "EquipmentUnit" WHERE "status" = ? AND "projectDatabaseId" = ? ORDER BY "name" ASC LIMIT ?
373
+ * // query.params: ["active", 123, 10]
374
+ */
375
+ build(table, columns, options = {}) {
376
+ const params = [];
377
+ let columnList;
378
+ if (columns === "*") {
379
+ columnList = "*";
380
+ } else if (columns.length === 0) {
381
+ columnList = "*";
382
+ } else {
383
+ columnList = columns.map((c) => {
384
+ if (c.alias) {
385
+ return `"${c.name}" AS "${c.alias}"`;
386
+ }
387
+ return `"${c.name}"`;
388
+ }).join(", ");
389
+ }
390
+ let sql = `SELECT ${columnList} FROM "${table}"`;
391
+ if (options.where && Object.keys(options.where).length > 0) {
392
+ const whereClauses = [];
393
+ for (const [field, value] of Object.entries(options.where)) {
394
+ if (value === null) {
395
+ whereClauses.push(`"${field}" IS NULL`);
396
+ } else if (isWhereOperator(value)) {
397
+ const operatorClauses = this.buildOperatorClauses(field, value, params);
398
+ whereClauses.push(...operatorClauses);
399
+ } else {
400
+ whereClauses.push(`"${field}" = ?`);
401
+ params.push(value);
402
+ }
403
+ }
404
+ if (whereClauses.length > 0) {
405
+ sql += ` WHERE ${whereClauses.join(" AND ")}`;
406
+ }
407
+ }
408
+ if (options.orderBy && options.orderBy.length > 0) {
409
+ const orderClauses = options.orderBy.map((o) => `"${o.field}" ${o.direction.toUpperCase()}`);
410
+ sql += ` ORDER BY ${orderClauses.join(", ")}`;
411
+ }
412
+ if (options.limit !== void 0) {
413
+ sql += ` LIMIT ?`;
414
+ params.push(options.limit);
415
+ }
416
+ if (options.offset !== void 0) {
417
+ sql += ` OFFSET ?`;
418
+ params.push(options.offset);
419
+ }
420
+ return {
421
+ sql,
422
+ params
423
+ };
424
+ }
425
+ /**
426
+ * Build WHERE clauses from operator objects.
427
+ */
428
+ buildOperatorClauses(field, operators, params) {
429
+ const clauses = [];
430
+ if ("in" in operators && operators.in !== void 0) {
431
+ if (operators.in.length === 0) {
432
+ clauses.push("1 = 0");
433
+ } else {
434
+ const placeholders = operators.in.map(() => "?").join(", ");
435
+ clauses.push(`"${field}" IN (${placeholders})`);
436
+ params.push(...operators.in);
437
+ }
438
+ }
439
+ if ("notIn" in operators && operators.notIn !== void 0) {
440
+ if (operators.notIn.length === 0) {
441
+ } else {
442
+ const placeholders = operators.notIn.map(() => "?").join(", ");
443
+ clauses.push(`"${field}" NOT IN (${placeholders})`);
444
+ params.push(...operators.notIn);
445
+ }
446
+ }
447
+ if ("gt" in operators && operators.gt !== void 0) {
448
+ clauses.push(`"${field}" > ?`);
449
+ params.push(operators.gt);
450
+ }
451
+ if ("gte" in operators && operators.gte !== void 0) {
452
+ clauses.push(`"${field}" >= ?`);
453
+ params.push(operators.gte);
454
+ }
455
+ if ("lt" in operators && operators.lt !== void 0) {
456
+ clauses.push(`"${field}" < ?`);
457
+ params.push(operators.lt);
458
+ }
459
+ if ("lte" in operators && operators.lte !== void 0) {
460
+ clauses.push(`"${field}" <= ?`);
461
+ params.push(operators.lte);
462
+ }
463
+ if ("like" in operators && operators.like !== void 0) {
464
+ clauses.push(`"${field}" LIKE ?`);
465
+ const pattern = operators.like.includes("%") ? operators.like : `%${operators.like}%`;
466
+ params.push(pattern);
467
+ }
468
+ if ("is" in operators && operators.is === null) {
469
+ clauses.push(`"${field}" IS NULL`);
470
+ }
471
+ if ("neq" in operators && operators.neq !== void 0) {
472
+ if (operators.neq === null) {
473
+ clauses.push(`"${field}" IS NOT NULL`);
474
+ } else {
475
+ clauses.push(`"${field}" != ?`);
476
+ params.push(operators.neq);
477
+ }
478
+ }
479
+ return clauses;
480
+ }
481
+ /**
482
+ * Build a query to fetch related records by foreign key.
483
+ *
484
+ * @param table - The related table name
485
+ * @param foreignKey - The FK column to match against
486
+ * @param parentIds - Array of parent IDs to fetch related records for
487
+ * @param columns - Columns to select
488
+ * @returns Built query
489
+ *
490
+ * @example
491
+ * // Fetch all EquipmentFixtures for given EquipmentUnit IDs
492
+ * const query = builder.buildRelationQuery(
493
+ * "EquipmentFixture",
494
+ * "equipmentUnitId",
495
+ * ["uuid-1", "uuid-2"],
496
+ * "*"
497
+ * );
498
+ * // query.sql: SELECT * FROM "EquipmentFixture" WHERE "equipmentUnitId" IN (?, ?)
499
+ * // query.params: ["uuid-1", "uuid-2"]
500
+ */
501
+ buildRelationQuery(table, foreignKey, parentIds, columns) {
502
+ if (parentIds.length === 0) {
503
+ return {
504
+ sql: `SELECT ${columns === "*" ? "*" : this.buildColumnList(columns, foreignKey)} FROM "${table}" WHERE 1 = 0`,
505
+ params: []
506
+ };
507
+ }
508
+ let columnList;
509
+ if (columns === "*") {
510
+ columnList = "*";
511
+ } else {
512
+ columnList = this.buildColumnList(columns, foreignKey);
513
+ }
514
+ const placeholders = parentIds.map(() => "?").join(", ");
515
+ const sql = `SELECT ${columnList} FROM "${table}" WHERE "${foreignKey}" IN (${placeholders})`;
516
+ return {
517
+ sql,
518
+ params: [...parentIds]
519
+ };
520
+ }
521
+ /**
522
+ * Build column list ensuring the foreign key is included.
523
+ */
524
+ buildColumnList(columns, foreignKey) {
525
+ const colNames = columns.map((c) => c.name);
526
+ const columnList = columns.map((c) => {
527
+ if (c.alias) {
528
+ return `"${c.name}" AS "${c.alias}"`;
529
+ }
530
+ return `"${c.name}"`;
531
+ });
532
+ if (!colNames.includes(foreignKey)) {
533
+ columnList.unshift(`"${foreignKey}"`);
534
+ }
535
+ return columnList.join(", ");
536
+ }
537
+ /**
538
+ * Build a SELECT query for a single record by ID.
539
+ *
540
+ * @param table - Table name
541
+ * @param id - Record ID
542
+ * @param columns - Columns to select
543
+ * @param idColumn - Name of the ID column (defaults to "id")
544
+ * @returns Built query
545
+ */
546
+ buildByIdQuery(table, id, columns = "*", idColumn = "id") {
547
+ let columnList;
548
+ if (columns === "*") {
549
+ columnList = "*";
550
+ } else if (columns.length === 0) {
551
+ columnList = "*";
552
+ } else {
553
+ columnList = columns.map((c) => c.alias ? `"${c.name}" AS "${c.alias}"` : `"${c.name}"`).join(", ");
554
+ }
555
+ const sql = `SELECT ${columnList} FROM "${table}" WHERE "${idColumn}" = ? LIMIT 1`;
556
+ return {
557
+ sql,
558
+ params: [id]
559
+ };
560
+ }
561
+ /**
562
+ * Build an INSERT query.
563
+ *
564
+ * @param table - Table name
565
+ * @param data - Record data to insert
566
+ * @returns Built query
567
+ */
568
+ buildInsertQuery(table, data) {
569
+ const columns = Object.keys(data).filter((k) => data[k] !== void 0);
570
+ const values = columns.map((k) => data[k]);
571
+ if (columns.length === 0) {
572
+ throw new Error("Cannot insert empty record");
573
+ }
574
+ const columnList = columns.map((c) => `"${c}"`).join(", ");
575
+ const placeholders = columns.map(() => "?").join(", ");
576
+ const sql = `INSERT INTO "${table}" (${columnList}) VALUES (${placeholders})`;
577
+ return {
578
+ sql,
579
+ params: values
580
+ };
581
+ }
582
+ /**
583
+ * Build an UPDATE query.
584
+ *
585
+ * @param table - Table name
586
+ * @param id - Record ID
587
+ * @param data - Fields to update
588
+ * @param idColumn - Name of the ID column (defaults to "id")
589
+ * @returns Built query
590
+ */
591
+ buildUpdateQuery(table, id, data, idColumn = "id") {
592
+ const columns = Object.keys(data).filter((k) => k !== idColumn && data[k] !== void 0);
593
+ if (columns.length === 0) {
594
+ throw new Error("No fields to update");
595
+ }
596
+ const setClauses = columns.map((c) => `"${c}" = ?`).join(", ");
597
+ const values = columns.map((k) => data[k]);
598
+ const sql = `UPDATE "${table}" SET ${setClauses} WHERE "${idColumn}" = ?`;
599
+ return {
600
+ sql,
601
+ params: [...values, id]
602
+ };
603
+ }
604
+ /**
605
+ * Build a DELETE query.
606
+ *
607
+ * @param table - Table name
608
+ * @param id - Record ID
609
+ * @param idColumn - Name of the ID column (defaults to "id")
610
+ * @returns Built query
611
+ */
612
+ buildDeleteQuery(table, id, idColumn = "id") {
613
+ const sql = `DELETE FROM "${table}" WHERE "${idColumn}" = ?`;
614
+ return {
615
+ sql,
616
+ params: [id]
617
+ };
618
+ }
619
+ /**
620
+ * Build a COUNT query.
621
+ *
622
+ * @param table - Table name
623
+ * @param where - Optional where clause
624
+ * @returns Built query
625
+ */
626
+ buildCountQuery(table, where) {
627
+ const params = [];
628
+ let sql = `SELECT COUNT(*) as count FROM "${table}"`;
629
+ if (where && Object.keys(where).length > 0) {
630
+ const whereClauses = [];
631
+ for (const [field, value] of Object.entries(where)) {
632
+ if (value === null) {
633
+ whereClauses.push(`"${field}" IS NULL`);
634
+ } else if (isWhereOperator(value)) {
635
+ const operatorClauses = this.buildOperatorClauses(field, value, params);
636
+ whereClauses.push(...operatorClauses);
637
+ } else {
638
+ whereClauses.push(`"${field}" = ?`);
639
+ params.push(value);
640
+ }
641
+ }
642
+ if (whereClauses.length > 0) {
643
+ sql += ` WHERE ${whereClauses.join(" AND ")}`;
644
+ }
645
+ }
646
+ return {
647
+ sql,
648
+ params
649
+ };
650
+ }
651
+ };
652
+ function createSQLBuilder() {
653
+ return new SQLBuilder();
654
+ }
655
+
656
+ // src/query/result-joiner.ts
657
+ var ResultJoiner = class {
658
+ /**
659
+ * Join related data onto base records.
660
+ *
661
+ * @param baseRecords - The base table records
662
+ * @param relatedRecords - Records from the related table
663
+ * @param relationship - The relationship definition
664
+ * @param relationName - The property name to use for the relation
665
+ * @returns Base records with related data attached
666
+ *
667
+ * @example
668
+ * // One-to-many: EquipmentUnit -> EquipmentFixture[]
669
+ * const joiner = new ResultJoiner();
670
+ * const result = joiner.join(
671
+ * equipmentUnits,
672
+ * equipmentFixtures,
673
+ * { type: "one-to-many", foreignKey: "equipmentUnitId", referencedColumn: "id", ... },
674
+ * "EquipmentFixture"
675
+ * );
676
+ * // Each equipmentUnit now has EquipmentFixture: [...]
677
+ *
678
+ * @example
679
+ * // Many-to-one: EquipmentUnit -> ProjectDatabase
680
+ * const result = joiner.join(
681
+ * equipmentUnits,
682
+ * projectDatabases,
683
+ * { type: "many-to-one", foreignKey: "projectDatabaseId", referencedColumn: "id", ... },
684
+ * "ProjectDatabase"
685
+ * );
686
+ * // Each equipmentUnit now has ProjectDatabase: {...} or null
687
+ */
688
+ join(baseRecords, relatedRecords, relationship, relationName) {
689
+ if (baseRecords.length === 0) {
690
+ return baseRecords;
691
+ }
692
+ if (relationship.type === "one-to-many") {
693
+ return baseRecords.map((base) => {
694
+ const baseId = base[relationship.referencedColumn];
695
+ const related = relatedRecords.filter((r) => r[relationship.foreignKey] === baseId);
696
+ return {
697
+ ...base,
698
+ [relationName]: related
699
+ };
700
+ });
701
+ } else {
702
+ const relatedMap = /* @__PURE__ */ new Map();
703
+ for (const r of relatedRecords) {
704
+ const refValue = r[relationship.referencedColumn];
705
+ if (refValue !== null && refValue !== void 0) {
706
+ relatedMap.set(refValue, r);
707
+ }
708
+ }
709
+ return baseRecords.map((base) => {
710
+ const fkValue = base[relationship.foreignKey];
711
+ const related = fkValue != null ? relatedMap.get(fkValue) ?? null : null;
712
+ return {
713
+ ...base,
714
+ [relationName]: related
715
+ };
716
+ });
717
+ }
718
+ }
719
+ /**
720
+ * Recursively join nested relations onto records.
721
+ *
722
+ * @param baseRecords - The base records
723
+ * @param relationData - Map of relation names to join data
724
+ * @returns Base records with all nested relations attached
725
+ *
726
+ * @example
727
+ * // Join EquipmentFixture and ProjectDatabase onto EquipmentUnit
728
+ * // where EquipmentFixture has its own nested Organization relation
729
+ * const result = joiner.joinNested(equipmentUnits, new Map([
730
+ * ["EquipmentFixture", {
731
+ * records: fixtures,
732
+ * relationship: { type: "one-to-many", ... },
733
+ * nestedRelations: new Map()
734
+ * }],
735
+ * ["ProjectDatabase", {
736
+ * records: projects,
737
+ * relationship: { type: "many-to-one", ... },
738
+ * nestedRelations: new Map([
739
+ * ["Organization", { records: orgs, relationship: ..., nestedRelations: new Map() }]
740
+ * ])
741
+ * }]
742
+ * ]));
743
+ */
744
+ joinNested(baseRecords, relationData) {
745
+ let result = [...baseRecords];
746
+ const entries = Array.from(relationData.entries());
747
+ for (const [relationName, data] of entries) {
748
+ let relatedRecords = data.records;
749
+ if (data.nestedRelations.size > 0) {
750
+ relatedRecords = this.joinNested(relatedRecords, data.nestedRelations);
751
+ }
752
+ result = this.join(result, relatedRecords, data.relationship, relationName);
753
+ }
754
+ return result;
755
+ }
756
+ /**
757
+ * Group records by a key field.
758
+ * Useful for preparing data before joining.
759
+ *
760
+ * @param records - Records to group
761
+ * @param keyField - Field to group by
762
+ * @returns Map of key values to arrays of records
763
+ */
764
+ groupBy(records, keyField) {
765
+ const groups = /* @__PURE__ */ new Map();
766
+ for (const record of records) {
767
+ const key = record[keyField];
768
+ if (!groups.has(key)) {
769
+ groups.set(key, []);
770
+ }
771
+ groups.get(key).push(record);
772
+ }
773
+ return groups;
774
+ }
775
+ /**
776
+ * Index records by a unique key field.
777
+ * Useful for many-to-one lookups.
778
+ *
779
+ * @param records - Records to index
780
+ * @param keyField - Field to index by (should be unique)
781
+ * @returns Map of key values to single records
782
+ */
783
+ indexBy(records, keyField) {
784
+ const index = /* @__PURE__ */ new Map();
785
+ for (const record of records) {
786
+ const key = record[keyField];
787
+ if (key !== null && key !== void 0) {
788
+ index.set(key, record);
789
+ }
790
+ }
791
+ return index;
792
+ }
793
+ /**
794
+ * Extract unique values for a field from records.
795
+ * Useful for building IN clauses for related queries.
796
+ *
797
+ * @param records - Records to extract from
798
+ * @param field - Field to extract
799
+ * @returns Array of unique non-null values
800
+ */
801
+ extractUniqueValues(records, field) {
802
+ const values = /* @__PURE__ */ new Set();
803
+ for (const record of records) {
804
+ const value = record[field];
805
+ if (value !== null && value !== void 0) {
806
+ values.add(value);
807
+ }
808
+ }
809
+ return Array.from(values);
810
+ }
811
+ /**
812
+ * Remove a relation property from records (for cleanup).
813
+ *
814
+ * @param records - Records to process
815
+ * @param relationName - Relation property to remove
816
+ * @returns Records without the specified property
817
+ */
818
+ removeRelation(records, relationName) {
819
+ return records.map((record) => {
820
+ const {
821
+ [relationName]: _removed,
822
+ ...rest
823
+ } = record;
824
+ return rest;
825
+ });
826
+ }
827
+ /**
828
+ * Flatten a nested relation into the parent record.
829
+ * Useful for flattening many-to-one relations.
830
+ *
831
+ * @param records - Records with nested relation
832
+ * @param relationName - Name of the relation to flatten
833
+ * @param prefix - Prefix for flattened field names
834
+ * @returns Records with flattened relation fields
835
+ */
836
+ flattenRelation(records, relationName, prefix = "") {
837
+ return records.map((record) => {
838
+ const relation = record[relationName];
839
+ const {
840
+ [relationName]: _removed,
841
+ ...rest
842
+ } = record;
843
+ if (!relation) {
844
+ return rest;
845
+ }
846
+ const flattenedRelation = {};
847
+ for (const [key, value] of Object.entries(relation)) {
848
+ const fieldName = prefix ? `${prefix}_${key}` : `${relationName}_${key}`;
849
+ flattenedRelation[fieldName] = value;
850
+ }
851
+ return {
852
+ ...rest,
853
+ ...flattenedRelation
854
+ };
855
+ });
856
+ }
857
+ };
858
+ function createResultJoiner() {
859
+ return new ResultJoiner();
860
+ }
861
+
862
+ // src/query/executor.ts
863
+ var QueryExecutor = class {
864
+ constructor(db, schema) {
865
+ this.db = db;
866
+ this.schema = schema;
867
+ this.resolver = new RelationshipResolver(schema);
868
+ this.builder = new SQLBuilder();
869
+ this.joiner = new ResultJoiner();
870
+ }
871
+ resolver;
872
+ builder;
873
+ joiner;
874
+ /**
875
+ * Execute a query and return results.
876
+ *
877
+ * @param table - The table to query
878
+ * @param options - Query options including select, where, orderBy, limit, offset
879
+ * @returns Array of records with relations attached
880
+ */
881
+ async execute(table, options = {}) {
882
+ const parsed = parseSelect(options.select ?? "*");
883
+ const baseQuery = this.builder.build(table, parsed.columns, {
884
+ where: options.where,
885
+ orderBy: options.orderBy,
886
+ limit: options.limit,
887
+ offset: options.offset
888
+ });
889
+ const baseRecords = await this.db.getAll(baseQuery.sql, baseQuery.params);
890
+ if (baseRecords.length === 0 || parsed.relations.length === 0) {
891
+ return baseRecords;
892
+ }
893
+ const result = await this.queryAndJoinRelations(table, baseRecords, parsed.relations);
894
+ return result;
895
+ }
896
+ /**
897
+ * Execute a query for a single record by ID.
898
+ *
899
+ * @param table - The table to query
900
+ * @param id - The record ID
901
+ * @param options - Query options (only select is used)
902
+ * @returns Single record or null
903
+ */
904
+ async executeById(table, id, options = {}) {
905
+ const parsed = parseSelect(options.select ?? "*");
906
+ const idColumn = this.resolver.getPrimaryKey(table);
907
+ const baseQuery = this.builder.buildByIdQuery(table, id, parsed.columns, idColumn);
908
+ const records = await this.db.getAll(baseQuery.sql, baseQuery.params);
909
+ if (records.length === 0) {
910
+ return null;
911
+ }
912
+ if (parsed.relations.length === 0) {
913
+ return records[0];
914
+ }
915
+ const result = await this.queryAndJoinRelations(table, records, parsed.relations);
916
+ return result[0];
917
+ }
918
+ /**
919
+ * Execute a count query.
920
+ *
921
+ * @param table - The table to count
922
+ * @param options - Query options (only where is used)
923
+ * @returns Count of matching records
924
+ */
925
+ async count(table, options = {}) {
926
+ const query = this.builder.buildCountQuery(table, options.where);
927
+ const result = await this.db.getAll(query.sql, query.params);
928
+ return result[0]?.count ?? 0;
929
+ }
930
+ /**
931
+ * Insert a record.
932
+ *
933
+ * @param table - The table to insert into
934
+ * @param data - The record data
935
+ * @returns The inserted record (re-fetched to get defaults)
936
+ */
937
+ async insert(table, data) {
938
+ if (__DEV__) {
939
+ console.log(`[QueryExecutor] insert called:`, {
940
+ table,
941
+ dataKeys: Object.keys(data),
942
+ hasId: "id" in data
943
+ });
944
+ }
945
+ const idColumn = this.resolver.getPrimaryKey(table);
946
+ if (!data[idColumn]) {
947
+ const [{
948
+ id
949
+ }] = await this.db.getAll("SELECT uuid() as id");
950
+ data = {
951
+ ...data,
952
+ [idColumn]: id
953
+ };
954
+ if (__DEV__) {
955
+ console.log(`[QueryExecutor] insert generated UUID:`, {
956
+ table,
957
+ id
958
+ });
959
+ }
960
+ }
961
+ const query = this.builder.buildInsertQuery(table, data);
962
+ if (__DEV__) {
963
+ console.log(`[QueryExecutor] insert executing SQL:`, {
964
+ table,
965
+ sql: query.sql,
966
+ paramCount: query.params.length
967
+ });
968
+ }
969
+ await this.db.execute(query.sql, query.params);
970
+ if (__DEV__) {
971
+ console.log(`[QueryExecutor] insert SQL executed successfully:`, {
972
+ table,
973
+ id: data[idColumn]
974
+ });
975
+ }
976
+ const result = await this.executeById(table, data[idColumn]);
977
+ if (__DEV__) {
978
+ console.log(`[QueryExecutor] insert completed:`, {
979
+ table,
980
+ operation: "insert",
981
+ resultId: result?.[idColumn] ?? data[idColumn],
982
+ refetchSucceeded: result !== null
983
+ });
984
+ }
985
+ return result ?? data;
986
+ }
987
+ /**
988
+ * Update a record.
989
+ *
990
+ * @param table - The table to update
991
+ * @param id - The record ID
992
+ * @param data - The fields to update
993
+ * @returns The updated record
994
+ */
995
+ async update(table, id, data) {
996
+ if (__DEV__) {
997
+ console.log(`[QueryExecutor] update called:`, {
998
+ table,
999
+ id,
1000
+ dataKeys: Object.keys(data)
1001
+ });
1002
+ }
1003
+ const idColumn = this.resolver.getPrimaryKey(table);
1004
+ const query = this.builder.buildUpdateQuery(table, id, data, idColumn);
1005
+ if (__DEV__) {
1006
+ console.log(`[QueryExecutor] update executing SQL:`, {
1007
+ table,
1008
+ id,
1009
+ sql: query.sql,
1010
+ paramCount: query.params.length
1011
+ });
1012
+ }
1013
+ await this.db.execute(query.sql, query.params);
1014
+ if (__DEV__) {
1015
+ console.log(`[QueryExecutor] update SQL executed successfully:`, {
1016
+ table,
1017
+ id
1018
+ });
1019
+ }
1020
+ const result = await this.executeById(table, id);
1021
+ if (__DEV__) {
1022
+ console.log(`[QueryExecutor] update completed:`, {
1023
+ table,
1024
+ operation: "update",
1025
+ id,
1026
+ refetchSucceeded: result !== null
1027
+ });
1028
+ }
1029
+ if (result) {
1030
+ return result;
1031
+ }
1032
+ return {
1033
+ ...data,
1034
+ [idColumn]: id
1035
+ };
1036
+ }
1037
+ /**
1038
+ * Upsert a record (insert or update).
1039
+ *
1040
+ * @param table - The table to upsert into
1041
+ * @param data - The record data (must include ID for update)
1042
+ * @returns The upserted record
1043
+ */
1044
+ async upsert(table, data) {
1045
+ if (__DEV__) {
1046
+ console.log(`[QueryExecutor] upsert called:`, {
1047
+ table,
1048
+ dataKeys: Object.keys(data),
1049
+ hasId: "id" in data,
1050
+ idValue: data.id ?? "none"
1051
+ });
1052
+ }
1053
+ const idColumn = this.resolver.getPrimaryKey(table);
1054
+ let id = data[idColumn];
1055
+ if (!id) {
1056
+ const [{
1057
+ id: generatedId
1058
+ }] = await this.db.getAll("SELECT uuid() as id");
1059
+ id = generatedId;
1060
+ data = {
1061
+ ...data,
1062
+ [idColumn]: id
1063
+ };
1064
+ if (__DEV__) {
1065
+ console.log(`[QueryExecutor] upsert generated UUID:`, {
1066
+ table,
1067
+ id
1068
+ });
1069
+ }
1070
+ }
1071
+ const existing = await this.executeById(table, id);
1072
+ if (__DEV__) {
1073
+ console.log(`[QueryExecutor] upsert existence check:`, {
1074
+ table,
1075
+ id,
1076
+ exists: existing !== null,
1077
+ willPerform: existing ? "update" : "insert"
1078
+ });
1079
+ }
1080
+ if (existing) {
1081
+ return this.update(table, id, data);
1082
+ }
1083
+ return this.insert(table, data);
1084
+ }
1085
+ /**
1086
+ * Delete a record.
1087
+ *
1088
+ * @param table - The table to delete from
1089
+ * @param id - The record ID
1090
+ */
1091
+ async delete(table, id) {
1092
+ const idColumn = this.resolver.getPrimaryKey(table);
1093
+ const query = this.builder.buildDeleteQuery(table, id, idColumn);
1094
+ await this.db.execute(query.sql, query.params);
1095
+ }
1096
+ /**
1097
+ * Query and join relations onto parent records.
1098
+ *
1099
+ * @param parentTable - The parent table name
1100
+ * @param parentRecords - Parent records to add relations to
1101
+ * @param relations - Relations to query and join
1102
+ * @returns Parent records with relations attached
1103
+ */
1104
+ async queryAndJoinRelations(parentTable, parentRecords, relations) {
1105
+ let result = [...parentRecords];
1106
+ for (const relation of relations) {
1107
+ const resolved = this.resolver.resolve(parentTable, relation.name);
1108
+ if (!resolved) {
1109
+ console.warn(`Could not resolve relationship: ${parentTable} -> ${relation.name}`);
1110
+ continue;
1111
+ }
1112
+ const parentIds = this.getParentIdsForRelation(parentRecords, resolved);
1113
+ if (parentIds.length === 0) {
1114
+ result = result.map((r) => ({
1115
+ ...r,
1116
+ [relation.alias ?? relation.name]: resolved.type === "one-to-many" ? [] : null
1117
+ }));
1118
+ continue;
1119
+ }
1120
+ const relQuery = this.buildRelatedQuery(relation, resolved, parentIds);
1121
+ let relatedRecords = await this.db.getAll(relQuery.sql, relQuery.params);
1122
+ if (relation.relations.length > 0 && relatedRecords.length > 0) {
1123
+ relatedRecords = await this.queryAndJoinRelations(relation.name, relatedRecords, relation.relations);
1124
+ }
1125
+ result = this.joiner.join(result, relatedRecords, resolved, relation.alias ?? relation.name);
1126
+ }
1127
+ return result;
1128
+ }
1129
+ /**
1130
+ * Get parent IDs needed for a relation query.
1131
+ */
1132
+ getParentIdsForRelation(parentRecords, resolved) {
1133
+ let parentIds;
1134
+ if (resolved.type === "one-to-many") {
1135
+ parentIds = this.joiner.extractUniqueValues(parentRecords, resolved.referencedColumn);
1136
+ } else {
1137
+ parentIds = this.joiner.extractUniqueValues(parentRecords, resolved.foreignKey);
1138
+ }
1139
+ return parentIds;
1140
+ }
1141
+ /**
1142
+ * Build a query for related records.
1143
+ */
1144
+ buildRelatedQuery(relation, resolved, parentIds) {
1145
+ const filterColumn = resolved.type === "one-to-many" ? resolved.foreignKey : resolved.referencedColumn;
1146
+ const uniqueIds = Array.from(new Set(parentIds));
1147
+ return this.builder.buildRelationQuery(relation.name, filterColumn, uniqueIds, relation.columns);
1148
+ }
1149
+ /**
1150
+ * Get the relationship resolver (for advanced use).
1151
+ */
1152
+ getResolver() {
1153
+ return this.resolver;
1154
+ }
1155
+ /**
1156
+ * Get the SQL builder (for advanced use).
1157
+ */
1158
+ getBuilder() {
1159
+ return this.builder;
1160
+ }
1161
+ /**
1162
+ * Get the result joiner (for advanced use).
1163
+ */
1164
+ getJoiner() {
1165
+ return this.joiner;
1166
+ }
1167
+ };
1168
+ function createQueryExecutor(db, schema) {
1169
+ return new QueryExecutor(db, schema);
1170
+ }
1171
+
1172
+ // src/query/useQuery.ts
1173
+ import { c as _c } from "react/compiler-runtime";
1174
+ import { useDelayedValue } from "@pol-studios/hooks/state";
1175
+ function useQuery2(query, config) {
1176
+ const $ = _c(5);
1177
+ let t0;
1178
+ if ($[0] !== query) {
1179
+ const queryKey = encode(query, false);
1180
+ t0 = queryKey.join("-");
1181
+ $[0] = query;
1182
+ $[1] = t0;
1183
+ } else {
1184
+ t0 = $[1];
1185
+ }
1186
+ const queryKeyString = t0;
1187
+ const debouncedKeyString = useDelayedValue(queryKeyString, 50);
1188
+ const isKeyStable = queryKeyString === debouncedKeyString;
1189
+ const effectiveEnabled = config?.enabled !== false && isKeyStable;
1190
+ let t1;
1191
+ if ($[2] !== config || $[3] !== effectiveEnabled) {
1192
+ t1 = omit({
1193
+ retry: 1,
1194
+ ...config,
1195
+ enabled: effectiveEnabled
1196
+ }, ["queryKey"]);
1197
+ $[2] = config;
1198
+ $[3] = effectiveEnabled;
1199
+ $[4] = t1;
1200
+ } else {
1201
+ t1 = $[4];
1202
+ }
1203
+ const request = useQuery(query, t1);
1204
+ return request;
1205
+ }
1206
+
1207
+ // src/query/usePartialQuery.ts
1208
+ import { c as _c2 } from "react/compiler-runtime";
1209
+ import { useSessionStorageState } from "@pol-studios/hooks/storage";
1210
+ function usePartialQuery(query, itemCountPerPage, config) {
1211
+ const $ = _c2(28);
1212
+ let t0;
1213
+ if ($[0] !== query) {
1214
+ t0 = encode(query, false);
1215
+ $[0] = query;
1216
+ $[1] = t0;
1217
+ } else {
1218
+ t0 = $[1];
1219
+ }
1220
+ const initialQuery = t0;
1221
+ let t1;
1222
+ if ($[2] !== initialQuery[7] || $[3] !== initialQuery[8]) {
1223
+ t1 = [initialQuery[7], initialQuery[8]];
1224
+ $[2] = initialQuery[7];
1225
+ $[3] = initialQuery[8];
1226
+ $[4] = t1;
1227
+ } else {
1228
+ t1 = $[4];
1229
+ }
1230
+ const id = t1.join("-");
1231
+ const [currentPage, setCurrentPage] = useSessionStorageState(id, 1);
1232
+ const page = currentPage ?? 1;
1233
+ const t2 = query;
1234
+ let t3;
1235
+ if ($[5] !== itemCountPerPage || $[6] !== page || $[7] !== t2) {
1236
+ t3 = t2.range((page - 1) * itemCountPerPage, page * itemCountPerPage - 1);
1237
+ $[5] = itemCountPerPage;
1238
+ $[6] = page;
1239
+ $[7] = t2;
1240
+ $[8] = t3;
1241
+ } else {
1242
+ t3 = $[8];
1243
+ }
1244
+ const rangedQuery = t3;
1245
+ const baseQuery = useQuery2(rangedQuery, config);
1246
+ let t4;
1247
+ if ($[9] !== setCurrentPage) {
1248
+ t4 = () => {
1249
+ setCurrentPage(_temp);
1250
+ };
1251
+ $[9] = setCurrentPage;
1252
+ $[10] = t4;
1253
+ } else {
1254
+ t4 = $[10];
1255
+ }
1256
+ const safeFetchNextPage = t4;
1257
+ let t5;
1258
+ if ($[11] !== setCurrentPage) {
1259
+ t5 = () => {
1260
+ setCurrentPage(_temp2);
1261
+ };
1262
+ $[11] = setCurrentPage;
1263
+ $[12] = t5;
1264
+ } else {
1265
+ t5 = $[12];
1266
+ }
1267
+ const fetchPreviousPage = t5;
1268
+ const pageCount = Math.max(Math.ceil((baseQuery.count ?? 0) / itemCountPerPage), 1);
1269
+ let t6;
1270
+ if ($[13] !== baseQuery.count || $[14] !== baseQuery.data || $[15] !== currentPage || $[16] !== itemCountPerPage) {
1271
+ t6 = baseQuery.data ? toPagedResponse(baseQuery.data, currentPage, baseQuery.count ?? baseQuery.data.length, itemCountPerPage) : null;
1272
+ $[13] = baseQuery.count;
1273
+ $[14] = baseQuery.data;
1274
+ $[15] = currentPage;
1275
+ $[16] = itemCountPerPage;
1276
+ $[17] = t6;
1277
+ } else {
1278
+ t6 = $[17];
1279
+ }
1280
+ const t7 = currentPage < pageCount;
1281
+ const t8 = currentPage > 1;
1282
+ let t9;
1283
+ if ($[18] !== baseQuery || $[19] !== currentPage || $[20] !== fetchPreviousPage || $[21] !== pageCount || $[22] !== safeFetchNextPage || $[23] !== setCurrentPage || $[24] !== t6 || $[25] !== t7 || $[26] !== t8) {
1284
+ t9 = {
1285
+ ...baseQuery,
1286
+ fetchPreviousPage,
1287
+ fetchNextPage: safeFetchNextPage,
1288
+ currentPage,
1289
+ setCurrentPage,
1290
+ data: t6,
1291
+ pageCount,
1292
+ hasNextPage: t7,
1293
+ hasPreviousPage: t8
1294
+ };
1295
+ $[18] = baseQuery;
1296
+ $[19] = currentPage;
1297
+ $[20] = fetchPreviousPage;
1298
+ $[21] = pageCount;
1299
+ $[22] = safeFetchNextPage;
1300
+ $[23] = setCurrentPage;
1301
+ $[24] = t6;
1302
+ $[25] = t7;
1303
+ $[26] = t8;
1304
+ $[27] = t9;
1305
+ } else {
1306
+ t9 = $[27];
1307
+ }
1308
+ return t9;
1309
+ }
1310
+ function _temp2(currentPage_1) {
1311
+ return currentPage_1 - 1;
1312
+ }
1313
+ function _temp(currentPage_0) {
1314
+ return currentPage_0 + 1;
1315
+ }
1316
+ function toPagedResponse(results, currentPage, totalCount, itemPerPage) {
1317
+ const newPage = {
1318
+ Items: results,
1319
+ CurrentPage: currentPage,
1320
+ ItemCount: totalCount,
1321
+ MaxCountPerPage: itemPerPage,
1322
+ PageCount: Math.max(Math.ceil(totalCount / itemPerPage), 1)
1323
+ };
1324
+ return newPage;
1325
+ }
1326
+
1327
+ // src/query/useAdvancedQuery.ts
1328
+ import { useEffect, useMemo, useRef, useState } from "react";
1329
+ import { useQuery as useQuery3 } from "@tanstack/react-query";
1330
+ import { useSessionStorageState as useSessionStorageState2 } from "@pol-studios/hooks/storage";
1331
+ var normalizeFilter = (filter) => {
1332
+ const groupOp = filter.op || filter.operator;
1333
+ if (groupOp && (groupOp === "AND" || groupOp === "OR") && filter.filters) {
1334
+ return {
1335
+ id: filter.id || generateUUID(),
1336
+ op: groupOp,
1337
+ not: filter.not || filter.inverted,
1338
+ // Support both 'not' and legacy 'inverted' for groups
1339
+ filters: filter.filters.map(normalizeFilter).filter(Boolean)
1340
+ };
1341
+ }
1342
+ let operator = filter.op || filter.condition;
1343
+ let shouldNegate = filter.not || filter.inverted || false;
1344
+ if (operator === "\u220B") operator = "in";
1345
+ if (operator === "\u2260" || operator === "!=") {
1346
+ operator = "=";
1347
+ shouldNegate = true;
1348
+ }
1349
+ if (operator === "like") operator = "contains";
1350
+ if (operator === "regex" || operator === "regex_i" || operator === "similar_to") {
1351
+ operator = "contains";
1352
+ }
1353
+ if (!operator) {
1354
+ console.error("Filter has undefined operator:", JSON.stringify(filter, null, 2));
1355
+ return null;
1356
+ }
1357
+ if (filter.propertyName) {
1358
+ return {
1359
+ id: filter.id || generateUUID(),
1360
+ field: filter.propertyName,
1361
+ op: operator,
1362
+ value: filter.value,
1363
+ not: shouldNegate,
1364
+ display: filter.display || filter.propertyName
1365
+ };
1366
+ }
1367
+ return {
1368
+ id: filter.id || generateUUID(),
1369
+ field: filter.field || "",
1370
+ op: operator,
1371
+ value: filter.value,
1372
+ not: shouldNegate,
1373
+ similarity: filter.similarity,
1374
+ where: filter.where,
1375
+ display: filter.display || filter.field || ""
1376
+ };
1377
+ };
1378
+ function useAdvancedFilterQuery(query, config) {
1379
+ const filterKey = useMemo(() => config?.filterKey ?? window.location?.pathname, [config?.filterKey]);
1380
+ const [filterLayer, setFilterLayer] = useSessionStorageState2(filterKey, {
1381
+ id: "root",
1382
+ op: "AND",
1383
+ filters: [],
1384
+ pagination: void 0,
1385
+ sort: [],
1386
+ isReady: isUsable(config?.searchByDefault) ? config.searchByDefault ? false : true : true
1387
+ });
1388
+ const parser = useMemo(() => new PostgrestParser(query), [query, config?.key]);
1389
+ useEffect(() => {
1390
+ const searchParam = parser.searchParams.get("order");
1391
+ if (searchParam) {
1392
+ const orderColumns = searchParam.split(",");
1393
+ const orders = [];
1394
+ orderColumns.forEach((x) => {
1395
+ const values = x.split(".");
1396
+ orders.push({
1397
+ field: values[0],
1398
+ direction: values[1] === "asc" ? "asc" : "desc"
1399
+ });
1400
+ });
1401
+ setFilterLayer((pre) => {
1402
+ if (!pre) {
1403
+ return {
1404
+ id: "root",
1405
+ op: "AND",
1406
+ filters: [],
1407
+ isReady: true,
1408
+ sort: orders
1409
+ };
1410
+ }
1411
+ return {
1412
+ ...pre,
1413
+ id: pre.id || "root",
1414
+ op: pre.op || "AND",
1415
+ filters: pre.filters || [],
1416
+ isReady: pre.isReady ?? true,
1417
+ sort: [...(pre.sort || []).filter((old) => orders.some((o) => o.field === old.field) === false), ...orders]
1418
+ };
1419
+ });
1420
+ }
1421
+ }, [JSON.stringify(parser.searchParams), config?.key]);
1422
+ const encodedQueryKeyRef = useRef([]);
1423
+ const encodedQueryKey = useMemo(() => {
1424
+ const newEncoded = encode(query, false);
1425
+ const newEncodedString = JSON.stringify(newEncoded);
1426
+ const oldEncodedString = JSON.stringify(encodedQueryKeyRef.current);
1427
+ if (newEncodedString !== oldEncodedString) {
1428
+ encodedQueryKeyRef.current = newEncoded;
1429
+ }
1430
+ return encodedQueryKeyRef.current;
1431
+ }, [query, parser.offset, parser.limit]);
1432
+ const filterLayerStringRef = useRef("");
1433
+ const currentFilterString = JSON.stringify(filterLayer, (key, value) => key === "id" ? "redacted" : value);
1434
+ if (filterLayerStringRef.current !== currentFilterString) {
1435
+ filterLayerStringRef.current = currentFilterString;
1436
+ }
1437
+ const queryKeyRef = useRef([]);
1438
+ const newKey = [encodedQueryKey[0], encodedQueryKey[1], encodedQueryKey[2], encodedQueryKey[3], encodedQueryKey[4], encodedQueryKey[5], "count=" + (config?.count ?? ""), encodedQueryKey[7], encodedQueryKey[8], filterLayerStringRef.current];
1439
+ const newKeyString = JSON.stringify(newKey);
1440
+ const oldKeyString = JSON.stringify(queryKeyRef.current);
1441
+ if (oldKeyString !== newKeyString) {
1442
+ queryKeyRef.current = newKey;
1443
+ }
1444
+ const queryKey = queryKeyRef.current;
1445
+ const [previousKey, setPreviousKey] = useState(queryKey);
1446
+ useEffect(() => {
1447
+ if (filterLayer?.isReady) {
1448
+ setPreviousKey(queryKey);
1449
+ }
1450
+ }, [...queryKey]);
1451
+ const loadingKey = filterLayer?.isReady ? queryKey : previousKey ?? queryKey;
1452
+ const supabase = useSupabase();
1453
+ const isEnabled = config?.enabled == null || config?.enabled === void 0 ? true : config.enabled;
1454
+ const [extraData, setExtraData] = useState({});
1455
+ const queryResponse = useQuery3({
1456
+ ...omit({
1457
+ retry: 0,
1458
+ // Changed from 1 to 0 to prevent retries
1459
+ ...config ?? {},
1460
+ // Override any config settings to prevent multiple executions
1461
+ refetchOnMount: false,
1462
+ refetchOnWindowFocus: false,
1463
+ refetchOnReconnect: false,
1464
+ structuralSharing: false,
1465
+ enabled: filterLayer?.isReady && isEnabled
1466
+ }, ["queryKey", "persister", "initialData"]),
1467
+ queryKey: loadingKey,
1468
+ queryFn: async (props) => {
1469
+ if (!filterLayer) {
1470
+ throw new Error("Filter layer is not initialized");
1471
+ }
1472
+ try {
1473
+ const searchParams = Array.from(parser.searchParams.entries());
1474
+ const body = {
1475
+ ...filterLayer,
1476
+ filters: [...filterLayer.filters],
1477
+ pagination: {
1478
+ ...filterLayer.pagination
1479
+ },
1480
+ sort: [...filterLayer.sort || []]
1481
+ };
1482
+ const currentKey = `${parser.schema}${parser.table}${parser.select}${JSON.stringify(omit(body, "pagination"))}`;
1483
+ const requiresEdgeForOrdering = false;
1484
+ const hasNaturalLanguageQuery = !!filterLayer.naturalLanguageQuery;
1485
+ if (filterLayer.filters.length == 0 && requiresEdgeForOrdering === false && !hasNaturalLanguageQuery) {
1486
+ const result = await executeSupabaseQuery(supabase, body, parser, extraData, props.signal, config?.count);
1487
+ setExtraData((pre_0) => ({
1488
+ ...omit(result, "data"),
1489
+ count: result.count ? result.count : pre_0.count,
1490
+ key: currentKey
1491
+ }));
1492
+ return result;
1493
+ }
1494
+ searchParams.forEach(([k, v]) => {
1495
+ if (k.includes("offset")) {
1496
+ body.pagination.offset = Number(v);
1497
+ return;
1498
+ }
1499
+ if (k.includes("limit")) {
1500
+ body.pagination.limit = Number(v);
1501
+ return;
1502
+ }
1503
+ if (k.includes("order")) {
1504
+ return;
1505
+ }
1506
+ if (k === "or") {
1507
+ return;
1508
+ }
1509
+ if (v.includes(".") === false) return;
1510
+ const values_0 = v.split(".");
1511
+ const column = k;
1512
+ let rawCondition = values_0[0];
1513
+ let condition = "";
1514
+ let value_0 = values_0[1];
1515
+ const inverted = values_0[0] === "not";
1516
+ if (column == "select") return;
1517
+ if (rawCondition === "not") {
1518
+ rawCondition = values_0[1];
1519
+ value_0 = values_0[2];
1520
+ }
1521
+ switch (rawCondition) {
1522
+ case "eq":
1523
+ condition = "=";
1524
+ break;
1525
+ case "in":
1526
+ condition = "in";
1527
+ value_0 = value_0.slice(1, value_0.length - 1).split(",").filter((x_0) => isNullOrWhitespace(x_0) === false);
1528
+ break;
1529
+ case "lt":
1530
+ condition = "<";
1531
+ break;
1532
+ case "gt":
1533
+ condition = ">";
1534
+ break;
1535
+ case "lte":
1536
+ condition = "<=";
1537
+ break;
1538
+ case "gte":
1539
+ condition = ">=";
1540
+ break;
1541
+ case "is":
1542
+ condition = "is";
1543
+ if (value_0 == "null") {
1544
+ value_0 = null;
1545
+ }
1546
+ break;
1547
+ }
1548
+ body.filters = [{
1549
+ id: `filter_${column}_${Date.now()}`,
1550
+ field: column,
1551
+ op: condition,
1552
+ value: value_0,
1553
+ not: inverted,
1554
+ display: column
1555
+ }, {
1556
+ filters: [...body.filters],
1557
+ op: body.op ?? "AND",
1558
+ id: "filterstate"
1559
+ }];
1560
+ body.op = "AND";
1561
+ const bodyCopy = JSON.parse(JSON.stringify(body));
1562
+ bodyCopy.pagination = {
1563
+ page: 0,
1564
+ pageSize: 50
1565
+ };
1566
+ bodyCopy.isReady = true;
1567
+ });
1568
+ const {
1569
+ data: {
1570
+ session
1571
+ }
1572
+ } = await supabase.auth.getSession();
1573
+ if (!session?.access_token) {
1574
+ throw new Error("No active session");
1575
+ }
1576
+ const controller = new AbortController();
1577
+ props.signal.addEventListener("abort", () => {
1578
+ controller.abort();
1579
+ });
1580
+ const timeout = setTimeout(() => controller.abort(), config?.timeout ?? 15e3);
1581
+ let result_0 = null;
1582
+ let response = {
1583
+ error: null,
1584
+ data: null
1585
+ };
1586
+ try {
1587
+ const UI_ONLY_KEYS = /* @__PURE__ */ new Set(["info", "options", "display"]);
1588
+ const filteredBody = JSON.parse(JSON.stringify(body, (key_0, value_1) => {
1589
+ if (UI_ONLY_KEYS.has(key_0)) {
1590
+ return void 0;
1591
+ }
1592
+ return value_1;
1593
+ }));
1594
+ filteredBody.filters = filteredBody.filters.map(normalizeFilter).filter(Boolean);
1595
+ const orParam = parser.searchParams.get("or");
1596
+ if (orParam) {
1597
+ const cleanedOrParam = orParam.replace(/^\(|\)$/g, "");
1598
+ const orConditions = cleanedOrParam.split(",");
1599
+ const orFilters = orConditions.map((condition_0, idx) => {
1600
+ const match = condition_0.match(/^(.+?)\.([^.]+)\.(.+)$/);
1601
+ if (match) {
1602
+ const [_, field, rawOp, value_2] = match;
1603
+ let op = rawOp.trim();
1604
+ switch (op) {
1605
+ case "eq":
1606
+ op = "=";
1607
+ break;
1608
+ case "neq":
1609
+ op = "!=";
1610
+ break;
1611
+ case "gt":
1612
+ op = ">";
1613
+ break;
1614
+ case "gte":
1615
+ op = ">=";
1616
+ break;
1617
+ case "lt":
1618
+ op = "<";
1619
+ break;
1620
+ case "lte":
1621
+ op = "<=";
1622
+ break;
1623
+ case "like":
1624
+ op = "contains";
1625
+ break;
1626
+ case "ilike":
1627
+ op = "contains";
1628
+ break;
1629
+ case "in":
1630
+ op = "in";
1631
+ break;
1632
+ }
1633
+ return {
1634
+ id: `or-${idx}`,
1635
+ field: field.trim(),
1636
+ op,
1637
+ value: value_2.trim()
1638
+ };
1639
+ }
1640
+ return null;
1641
+ }).filter(Boolean);
1642
+ if (orFilters.length > 0) {
1643
+ filteredBody.filters = [...filteredBody.filters, {
1644
+ id: "base-or-group",
1645
+ op: "OR",
1646
+ filters: orFilters,
1647
+ pagination: void 0,
1648
+ sort: void 0,
1649
+ isReady: true
1650
+ }];
1651
+ }
1652
+ }
1653
+ const res = await fetch(`${getSupabaseUrl()}/functions/v1/query?forceDenoVersion=2`, {
1654
+ method: "POST",
1655
+ headers: {
1656
+ "Content-Type": "application/json",
1657
+ "Authorization": `Bearer ${session.access_token}`
1658
+ },
1659
+ body: JSON.stringify({
1660
+ table: parser.table,
1661
+ schema: parser.schema,
1662
+ select: parser.select,
1663
+ filters: {
1664
+ id: filteredBody.id || "root",
1665
+ op: filteredBody.op || filteredBody.operator || "AND",
1666
+ not: filteredBody.not || filteredBody.inverted,
1667
+ // Support both 'not' and legacy 'inverted'
1668
+ filters: filteredBody.filters || []
1669
+ },
1670
+ pagination: filteredBody.pagination,
1671
+ sort: filteredBody.sort,
1672
+ distinctOn: filteredBody.distinctOn,
1673
+ naturalLanguageQuery: filteredBody.naturalLanguageQuery,
1674
+ count: currentKey === extraData.key ? "" : config?.count ?? "",
1675
+ debug: true
1676
+ }),
1677
+ signal: controller.signal
1678
+ });
1679
+ if (!res.ok) {
1680
+ const errorData = await res.json();
1681
+ const errorMessage_0 = typeof errorData?.error === "string" ? errorData.error : errorData?.error?.message || errorData?.message || "An error occurred while processing your request";
1682
+ throw new Error(errorMessage_0);
1683
+ }
1684
+ const data = await res.json();
1685
+ if (data.clarification) {
1686
+ return {
1687
+ data: [],
1688
+ // Empty data array
1689
+ count: 0,
1690
+ clarification: data.clarification,
1691
+ error: void 0
1692
+ };
1693
+ }
1694
+ result_0 = data;
1695
+ response = {
1696
+ error: null,
1697
+ data
1698
+ };
1699
+ } catch (err) {
1700
+ if (err.name === "AbortError") {
1701
+ console.error("Fetch aborted/time-out");
1702
+ response = {
1703
+ error: new Error("This query timed out"),
1704
+ data: null
1705
+ };
1706
+ } else if (err instanceof Error) {
1707
+ response = {
1708
+ error: err,
1709
+ data: null
1710
+ };
1711
+ } else {
1712
+ const errorMessage = err?.error || err?.message || String(err);
1713
+ response = {
1714
+ error: new Error(errorMessage),
1715
+ data: null
1716
+ };
1717
+ }
1718
+ } finally {
1719
+ clearTimeout(timeout);
1720
+ }
1721
+ if (response.error) {
1722
+ throw response.error;
1723
+ } else if (response.data?.error) {
1724
+ throw new Error(response.data.error);
1725
+ }
1726
+ if (result_0.clarification) {
1727
+ return {
1728
+ data: [],
1729
+ count: 0,
1730
+ clarification: result_0.clarification,
1731
+ error: void 0
1732
+ };
1733
+ }
1734
+ setExtraData((pre_1) => ({
1735
+ ...omit(result_0, "data"),
1736
+ count: pre_1.key === currentKey ? pre_1.count : result_0.count,
1737
+ key: currentKey
1738
+ }));
1739
+ return {
1740
+ ...result_0,
1741
+ statusText: "",
1742
+ status: result_0.data?.length > result_0.count ? 206 : 200,
1743
+ error: response.data?.error ?? null,
1744
+ hasMore: result_0.data?.length < result_0.count ? true : false
1745
+ };
1746
+ } catch (error) {
1747
+ if (error instanceof Error && error.name === "AbortError") {
1748
+ console.log("Fetch aborted");
1749
+ } else {
1750
+ console.error("Error fetching data:", error);
1751
+ }
1752
+ if (error instanceof Error && error.message === "Failed to send a request to the Edge Function") {
1753
+ throw new Error("Could not contact query server");
1754
+ }
1755
+ throw error;
1756
+ }
1757
+ }
1758
+ });
1759
+ const response_0 = {
1760
+ ...queryResponse,
1761
+ data: queryResponse.data?.data,
1762
+ count: extraData.count,
1763
+ clarification: queryResponse.data?.clarification
1764
+ };
1765
+ useEffect(() => {
1766
+ if (queryResponse.isFetched && response_0.count == null) {
1767
+ queryResponse.refetch();
1768
+ }
1769
+ }, [response_0.count]);
1770
+ useEffect(() => {
1771
+ if (queryResponse.data?.error == null) return;
1772
+ if (queryResponse.data?.error?.message?.includes(" does not exist")) {
1773
+ setFilterLayer({
1774
+ id: "root",
1775
+ op: "AND",
1776
+ filters: [],
1777
+ pagination: void 0,
1778
+ sort: [],
1779
+ isReady: isUsable(config?.searchByDefault) ? config.searchByDefault ? false : true : true
1780
+ });
1781
+ }
1782
+ }, [queryResponse.data?.error]);
1783
+ return [response_0, filterLayer, setFilterLayer];
1784
+ }
1785
+ function isSearchableColumn(columnName) {
1786
+ return true;
1787
+ }
1788
+ async function executeSupabaseQuery(supabase, body, parser, extraData, signal, count) {
1789
+ const searchParams = Array.from(parser.searchParams.entries());
1790
+ const currentKey = `${parser.schema}${parser.table}${parser.select}${JSON.stringify(omit(body, "pagination"))}`;
1791
+ const query = supabase.schema(parser.schema).from(parser.table).select(parser.select, {
1792
+ count: currentKey === extraData.key ? void 0 : count || void 0
1793
+ });
1794
+ if (body.sort && Array.isArray(body.sort)) {
1795
+ body.sort.forEach((s) => {
1796
+ query.order(s.field, {
1797
+ ascending: s.direction === "asc"
1798
+ });
1799
+ });
1800
+ }
1801
+ const from = searchParams.find((x) => x[0].includes("offset"))?.[1];
1802
+ const to = searchParams.find((x) => x[0].includes("limit"))?.[1];
1803
+ searchParams.forEach(([k, v]) => {
1804
+ if (k.includes("offset") && isUsable(v)) {
1805
+ body.pagination.from = Number(v);
1806
+ return;
1807
+ }
1808
+ if (k.includes("limit") && isUsable(v)) {
1809
+ body.pagination.to = Number(from) + Number(v) - 1;
1810
+ return;
1811
+ }
1812
+ if (k === "or") {
1813
+ query.or(v.slice(1, v.length - 1));
1814
+ return;
1815
+ }
1816
+ const values = v.split(".");
1817
+ const column = k;
1818
+ let rawCondition = values[0];
1819
+ let value = values[1];
1820
+ if (column == "select") return;
1821
+ if (column == "order") return;
1822
+ if (v.includes(".") === false) return;
1823
+ if (rawCondition === "ilike" && !isSearchableColumn(column)) {
1824
+ return;
1825
+ }
1826
+ if (rawCondition === "not") {
1827
+ rawCondition = values[1];
1828
+ value = values[2];
1829
+ query.not(column, rawCondition, value);
1830
+ } else {
1831
+ query.filter(column, rawCondition, value);
1832
+ }
1833
+ });
1834
+ if (body.pagination.from !== null && body.pagination.from !== void 0 && body.pagination.to !== null && body.pagination.to !== void 0 && isNaN(body.pagination.from) === false && isNaN(body.pagination.to) === false) {
1835
+ query.range(body.pagination.from, body.pagination.to);
1836
+ }
1837
+ const result = await query.abortSignal(signal);
1838
+ const dataLength = result.data?.length ?? 0;
1839
+ const totalCount = result.count ?? 0;
1840
+ return {
1841
+ ...result,
1842
+ statusText: "",
1843
+ status: dataLength > totalCount ? 206 : 200,
1844
+ error: result.error,
1845
+ hasMore: dataLength < totalCount
1846
+ };
1847
+ }
1848
+ var useAdvancedQuery = useAdvancedFilterQuery;
1849
+
1850
+ // src/query/useInfiniteQuery.ts
1851
+ import { useInfiniteQuery as useTanstackInfiniteQuery } from "@tanstack/react-query";
1852
+ import { useMemo as useMemo2, useRef as useRef2 } from "react";
1853
+ function useInfiniteQuery(query, countPerLoad, config) {
1854
+ const initialQueryKey = encode(query, false).join("-");
1855
+ const lastKnownQuery = useRef2(initialQueryKey);
1856
+ const currentPageNumber = useRef2(1);
1857
+ if (lastKnownQuery.current != initialQueryKey) {
1858
+ lastKnownQuery.current = initialQueryKey;
1859
+ currentPageNumber.current = 1;
1860
+ }
1861
+ const isFetching = useRef2(false);
1862
+ const queryKey = useMemo2(() => encode(query, false), [initialQueryKey, config?.crossOrganization]);
1863
+ const getQuery = useTanstackInfiniteQuery({
1864
+ ...config,
1865
+ queryKey,
1866
+ queryFn: async ({
1867
+ pageParam,
1868
+ signal
1869
+ }) => {
1870
+ let adjustableQuery = query;
1871
+ const pageNumber = pageParam;
1872
+ if (config?.onQuery && config?.enableOnQuery) {
1873
+ config?.onQuery({
1874
+ query: adjustableQuery,
1875
+ pageParam: pageNumber
1876
+ });
1877
+ } else {
1878
+ adjustableQuery = adjustableQuery.range((pageNumber - 1) * countPerLoad, pageNumber * countPerLoad - 1);
1879
+ }
1880
+ adjustableQuery = adjustableQuery.abortSignal(signal);
1881
+ updatedCache.current = false;
1882
+ const response = await adjustableQuery;
1883
+ currentPageNumber.current = pageNumber;
1884
+ if (response.error) {
1885
+ throw response.error;
1886
+ } else {
1887
+ return response;
1888
+ }
1889
+ },
1890
+ initialPageParam: 1,
1891
+ getNextPageParam: (response_0, allResponses, lastParam) => {
1892
+ const pageParam_0 = lastParam;
1893
+ const resp = response_0;
1894
+ if (allResponses.length * countPerLoad >= (resp?.count ?? 0)) {
1895
+ return void 0;
1896
+ }
1897
+ return pageParam_0 + 1;
1898
+ }
1899
+ });
1900
+ const updatedCache = useRef2(true);
1901
+ return useMemo2(() => {
1902
+ const pages = getQuery.data?.pages;
1903
+ return {
1904
+ ...getQuery,
1905
+ count: pages?.[pages.length - 1]?.count,
1906
+ data: pages?.flatMap((x) => x.data ?? [])
1907
+ };
1908
+ }, [getQuery.data, currentPageNumber.current]);
1909
+ }
1910
+
1911
+ // src/query/usePartialAdvancedQuery.ts
1912
+ import { c as _c3 } from "react/compiler-runtime";
1913
+ import { useLayoutEffect, useState as useState2 } from "react";
1914
+ import { useSessionStorageState as useSessionStorageState3 } from "@pol-studios/hooks/storage";
1915
+ function usePartialAdvancedQuery(query, itemCountPerPage, config) {
1916
+ const $ = _c3(54);
1917
+ const initialQuery = encode(query, false);
1918
+ const [id, setId] = useState2(window.location.pathname);
1919
+ const [currentPage, setCurrentPage] = useSessionStorageState3(`${id}-currentPage`, 1);
1920
+ const page = currentPage ?? 1;
1921
+ const t0 = query;
1922
+ let t1;
1923
+ if ($[0] !== itemCountPerPage || $[1] !== page || $[2] !== t0) {
1924
+ t1 = t0.range((page - 1) * itemCountPerPage, page * itemCountPerPage - 1);
1925
+ $[0] = itemCountPerPage;
1926
+ $[1] = page;
1927
+ $[2] = t0;
1928
+ $[3] = t1;
1929
+ } else {
1930
+ t1 = $[3];
1931
+ }
1932
+ const rangedQuery = t1;
1933
+ const t2 = config?.filterKey;
1934
+ const t3 = currentPage ?? 1;
1935
+ let t4;
1936
+ if ($[4] !== t3) {
1937
+ t4 = t3.toString();
1938
+ $[4] = t3;
1939
+ $[5] = t4;
1940
+ } else {
1941
+ t4 = $[5];
1942
+ }
1943
+ let t5;
1944
+ if ($[6] !== config || $[7] !== t2 || $[8] !== t4) {
1945
+ t5 = {
1946
+ ...config,
1947
+ filterKey: t2,
1948
+ count: "exact",
1949
+ key: t4
1950
+ };
1951
+ $[6] = config;
1952
+ $[7] = t2;
1953
+ $[8] = t4;
1954
+ $[9] = t5;
1955
+ } else {
1956
+ t5 = $[9];
1957
+ }
1958
+ const [baseQuery, filter, setFilters] = useAdvancedFilterQuery(rangedQuery, t5);
1959
+ let t6;
1960
+ if ($[10] !== filter) {
1961
+ t6 = JSON.stringify(omit(filter, ["pagination"]));
1962
+ $[10] = filter;
1963
+ $[11] = t6;
1964
+ } else {
1965
+ t6 = $[11];
1966
+ }
1967
+ const filterKey = t6;
1968
+ const select = initialQuery[4].split("&").find(_temp4);
1969
+ let t7;
1970
+ if ($[12] !== filterKey || $[13] !== id || $[14] !== initialQuery[3] || $[15] !== initialQuery[5] || $[16] !== initialQuery[6] || $[17] !== initialQuery[7] || $[18] !== initialQuery[8] || $[19] !== select || $[20] !== setId) {
1971
+ t7 = () => {
1972
+ const newId = [initialQuery[3], select, initialQuery[5], initialQuery[6], initialQuery[7], initialQuery[8], filterKey].join("-");
1973
+ console.log({
1974
+ newId,
1975
+ id
1976
+ });
1977
+ setId(newId);
1978
+ };
1979
+ $[12] = filterKey;
1980
+ $[13] = id;
1981
+ $[14] = initialQuery[3];
1982
+ $[15] = initialQuery[5];
1983
+ $[16] = initialQuery[6];
1984
+ $[17] = initialQuery[7];
1985
+ $[18] = initialQuery[8];
1986
+ $[19] = select;
1987
+ $[20] = setId;
1988
+ $[21] = t7;
1989
+ } else {
1990
+ t7 = $[21];
1991
+ }
1992
+ let t8;
1993
+ if ($[22] !== filterKey || $[23] !== initialQuery[3] || $[24] !== initialQuery[5] || $[25] !== initialQuery[6] || $[26] !== initialQuery[7] || $[27] !== initialQuery[8] || $[28] !== select) {
1994
+ t8 = [initialQuery[3], select, initialQuery[5], initialQuery[6], initialQuery[7], initialQuery[8], filterKey];
1995
+ $[22] = filterKey;
1996
+ $[23] = initialQuery[3];
1997
+ $[24] = initialQuery[5];
1998
+ $[25] = initialQuery[6];
1999
+ $[26] = initialQuery[7];
2000
+ $[27] = initialQuery[8];
2001
+ $[28] = select;
2002
+ $[29] = t8;
2003
+ } else {
2004
+ t8 = $[29];
2005
+ }
2006
+ useLayoutEffect(t7, t8);
2007
+ let t9;
2008
+ if ($[30] !== setCurrentPage) {
2009
+ t9 = () => {
2010
+ setCurrentPage(_temp22);
2011
+ };
2012
+ $[30] = setCurrentPage;
2013
+ $[31] = t9;
2014
+ } else {
2015
+ t9 = $[31];
2016
+ }
2017
+ const safeFetchNextPage = t9;
2018
+ let t10;
2019
+ if ($[32] !== setCurrentPage) {
2020
+ t10 = () => {
2021
+ setCurrentPage(_temp3);
2022
+ };
2023
+ $[32] = setCurrentPage;
2024
+ $[33] = t10;
2025
+ } else {
2026
+ t10 = $[33];
2027
+ }
2028
+ const fetchPreviousPage = t10;
2029
+ const pageCount = Math.max(Math.ceil((baseQuery.count ?? 0) / itemCountPerPage), 1);
2030
+ let t11;
2031
+ if ($[34] !== baseQuery.count || $[35] !== baseQuery.data || $[36] !== currentPage || $[37] !== itemCountPerPage) {
2032
+ t11 = baseQuery.data ? toPagedResponse2(baseQuery.data, currentPage ?? 1, baseQuery.count ?? baseQuery.data.length, itemCountPerPage) : null;
2033
+ $[34] = baseQuery.count;
2034
+ $[35] = baseQuery.data;
2035
+ $[36] = currentPage;
2036
+ $[37] = itemCountPerPage;
2037
+ $[38] = t11;
2038
+ } else {
2039
+ t11 = $[38];
2040
+ }
2041
+ const t12 = (currentPage ?? 1) < pageCount;
2042
+ const t13 = (currentPage ?? 1) > 1;
2043
+ const t14 = baseQuery.count ?? baseQuery.data?.length;
2044
+ let t15;
2045
+ if ($[39] !== baseQuery || $[40] !== currentPage || $[41] !== fetchPreviousPage || $[42] !== pageCount || $[43] !== safeFetchNextPage || $[44] !== setCurrentPage || $[45] !== t11 || $[46] !== t12 || $[47] !== t13 || $[48] !== t14) {
2046
+ t15 = {
2047
+ ...baseQuery,
2048
+ clarification: baseQuery.clarification,
2049
+ fetchPreviousPage,
2050
+ fetchNextPage: safeFetchNextPage,
2051
+ currentPage,
2052
+ setCurrentPage,
2053
+ data: t11,
2054
+ pageCount,
2055
+ hasNextPage: t12,
2056
+ hasPreviousPage: t13,
2057
+ count: t14
2058
+ };
2059
+ $[39] = baseQuery;
2060
+ $[40] = currentPage;
2061
+ $[41] = fetchPreviousPage;
2062
+ $[42] = pageCount;
2063
+ $[43] = safeFetchNextPage;
2064
+ $[44] = setCurrentPage;
2065
+ $[45] = t11;
2066
+ $[46] = t12;
2067
+ $[47] = t13;
2068
+ $[48] = t14;
2069
+ $[49] = t15;
2070
+ } else {
2071
+ t15 = $[49];
2072
+ }
2073
+ const request = t15;
2074
+ let t16;
2075
+ if ($[50] !== filter || $[51] !== request || $[52] !== setFilters) {
2076
+ t16 = [request, filter, setFilters];
2077
+ $[50] = filter;
2078
+ $[51] = request;
2079
+ $[52] = setFilters;
2080
+ $[53] = t16;
2081
+ } else {
2082
+ t16 = $[53];
2083
+ }
2084
+ return t16;
2085
+ }
2086
+ function _temp3(currentPage_1) {
2087
+ return (currentPage_1 ?? 1) - 1;
2088
+ }
2089
+ function _temp22(currentPage_0) {
2090
+ return (currentPage_0 ?? 1) + 1;
2091
+ }
2092
+ function _temp4(x) {
2093
+ return x.startsWith("select=");
2094
+ }
2095
+ function toPagedResponse2(results, currentPage, totalCount, itemPerPage) {
2096
+ const newPage = {
2097
+ Items: results,
2098
+ CurrentPage: currentPage,
2099
+ ItemCount: totalCount,
2100
+ MaxCountPerPage: itemPerPage,
2101
+ PageCount: Math.max(Math.ceil(totalCount / itemPerPage), 1)
2102
+ };
2103
+ return newPage;
2104
+ }
2105
+
2106
+ export {
2107
+ tokenizeTopLevel,
2108
+ parseSelect,
2109
+ stringifySelect,
2110
+ extractColumnNames,
2111
+ extractRelationNames,
2112
+ hasRelation,
2113
+ getRelationSelect,
2114
+ RelationshipResolver,
2115
+ createRelationshipResolver,
2116
+ SQLBuilder,
2117
+ createSQLBuilder,
2118
+ ResultJoiner,
2119
+ createResultJoiner,
2120
+ QueryExecutor,
2121
+ createQueryExecutor,
2122
+ useQuery2 as useQuery,
2123
+ usePartialQuery,
2124
+ useAdvancedFilterQuery,
2125
+ useAdvancedQuery,
2126
+ useInfiniteQuery,
2127
+ usePartialAdvancedQuery
2128
+ };
2129
+ //# sourceMappingURL=chunk-X3HZLNBV.js.map