@pol-studios/db 1.0.9 → 1.0.10

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