@type32/tauri-sqlite-orm 0.1.20 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -33,6 +33,9 @@ var BaseQueryBuilder = class {
33
33
  params: this.params
34
34
  };
35
35
  }
36
+ toSQL() {
37
+ return this.build();
38
+ }
36
39
  };
37
40
 
38
41
  // src/operators.ts
@@ -43,6 +46,13 @@ var eq = (column, value, tableAlias) => {
43
46
  params: [value]
44
47
  };
45
48
  };
49
+ var ne = (column, value, tableAlias) => {
50
+ const columnName = tableAlias ? `${tableAlias}.${column._.name}` : column._.name;
51
+ return {
52
+ sql: `${columnName} != ?`,
53
+ params: [value]
54
+ };
55
+ };
46
56
  var and = (...conditions) => ({
47
57
  sql: conditions.map((c) => `(${c.sql})`).join(" AND "),
48
58
  params: conditions.flatMap((c) => c.params)
@@ -75,6 +85,22 @@ var like = (column, pattern) => ({
75
85
  sql: `${column._.name} LIKE ?`,
76
86
  params: [pattern]
77
87
  });
88
+ var ilike = (column, pattern) => ({
89
+ sql: `${column._.name} LIKE ? COLLATE NOCASE`,
90
+ params: [pattern]
91
+ });
92
+ var startsWith = (column, value) => ({
93
+ sql: `${column._.name} LIKE ?`,
94
+ params: [`${value}%`]
95
+ });
96
+ var endsWith = (column, value) => ({
97
+ sql: `${column._.name} LIKE ?`,
98
+ params: [`%${value}`]
99
+ });
100
+ var contains = (column, value) => ({
101
+ sql: `${column._.name} LIKE ?`,
102
+ params: [`%${value}%`]
103
+ });
78
104
  var isNull = (column) => ({
79
105
  sql: `${column._.name} IS NULL`,
80
106
  params: []
@@ -83,33 +109,65 @@ var isNotNull = (column) => ({
83
109
  sql: `${column._.name} IS NOT NULL`,
84
110
  params: []
85
111
  });
86
- var inArray = (column, values) => ({
87
- sql: `${column._.name} IN (${values.map(() => "?").join(",")})`,
88
- params: values
112
+ var exists = (subquery2) => ({
113
+ sql: `EXISTS (${subquery2.sql})`,
114
+ params: subquery2.params
89
115
  });
90
- var count = (column) => ({
91
- sql: `COUNT(${column ? column._.name : "*"})`,
92
- params: []
116
+ var notExists = (subquery2) => ({
117
+ sql: `NOT EXISTS (${subquery2.sql})`,
118
+ params: subquery2.params
93
119
  });
94
- var countDistinct = (column) => ({
95
- sql: `COUNT(DISTINCT ${column._.name})`,
96
- params: []
120
+ var eqSubquery = (column, subquery2) => ({
121
+ sql: `${column._.name} = ${subquery2.sql}`,
122
+ params: subquery2.params
97
123
  });
98
- var sum = (column) => ({
99
- sql: `SUM(${column._.name})`,
100
- params: []
124
+ var neSubquery = (column, subquery2) => ({
125
+ sql: `${column._.name} != ${subquery2.sql}`,
126
+ params: subquery2.params
101
127
  });
102
- var avg = (column) => ({
103
- sql: `AVG(${column._.name})`,
104
- params: []
128
+ var gtSubquery = (column, subquery2) => ({
129
+ sql: `${column._.name} > ${subquery2.sql}`,
130
+ params: subquery2.params
105
131
  });
106
- var max = (column) => ({
107
- sql: `MAX(${column._.name})`,
108
- params: []
132
+ var gteSubquery = (column, subquery2) => ({
133
+ sql: `${column._.name} >= ${subquery2.sql}`,
134
+ params: subquery2.params
109
135
  });
110
- var min = (column) => ({
111
- sql: `MIN(${column._.name})`,
112
- params: []
136
+ var ltSubquery = (column, subquery2) => ({
137
+ sql: `${column._.name} < ${subquery2.sql}`,
138
+ params: subquery2.params
139
+ });
140
+ var lteSubquery = (column, subquery2) => ({
141
+ sql: `${column._.name} <= ${subquery2.sql}`,
142
+ params: subquery2.params
143
+ });
144
+ var inArray = (column, values) => {
145
+ if ("_isSubquery" in values && values._isSubquery) {
146
+ return {
147
+ sql: `${column._.name} IN ${values.sql}`,
148
+ params: values.params
149
+ };
150
+ }
151
+ return {
152
+ sql: `${column._.name} IN (${values.map(() => "?").join(",")})`,
153
+ params: values
154
+ };
155
+ };
156
+ var notIn = (column, values) => {
157
+ if ("_isSubquery" in values && values._isSubquery) {
158
+ return {
159
+ sql: `${column._.name} NOT IN ${values.sql}`,
160
+ params: values.params
161
+ };
162
+ }
163
+ return {
164
+ sql: `${column._.name} NOT IN (${values.map(() => "?").join(",")})`,
165
+ params: values
166
+ };
167
+ };
168
+ var between = (column, min2, max2) => ({
169
+ sql: `${column._.name} BETWEEN ? AND ?`,
170
+ params: [min2, max2]
113
171
  });
114
172
 
115
173
  // src/builders/select.ts
@@ -175,42 +233,30 @@ var SelectQueryBuilder = class extends BaseQueryBuilder {
175
233
  sql2 += ` ${join.type} JOIN ${join.table._.name} ${join.alias} ON ${join.condition.sql}`;
176
234
  params.push(...join.condition.params);
177
235
  }
178
- for (const [relationName, include] of Object.entries(this.includeRelations)) {
179
- if (!include) continue;
180
- const relation = this.table.relations[relationName];
181
- if (!relation) {
182
- console.warn(
183
- `[Tauri-ORM] Relation "${relationName}" not found on table "${this.table._.name}". Skipping include.`
184
- );
185
- continue;
236
+ const processRelations = (parentTable, parentAlias, relations2, depth = 0) => {
237
+ if (depth > 10) {
238
+ console.warn("[Tauri-ORM] Maximum relation depth (10) exceeded. Skipping deeper relations.");
239
+ return;
186
240
  }
187
- const foreignTable = relation.foreignTable;
188
- const foreignAlias = `${this.selectedTableAlias}_${relationName}`;
189
- const aliasedColumns = Object.values(foreignTable._.columns).map(
190
- (col) => `${foreignAlias}.${col._.name} AS "${foreignAlias}.${col._.name}"`
191
- );
192
- this.selectedColumns.push(...aliasedColumns);
193
- if (relation.type === "one" && relation.fields && relation.references) {
194
- const conditions = relation.fields.map((field, i) => {
195
- const localColumn = `${this.selectedTableAlias}.${field._.name}`;
196
- const foreignColumn = `${foreignAlias}.${relation.references[i]._.name}`;
197
- return {
198
- sql: `${localColumn} = ${foreignColumn}`,
199
- params: []
200
- };
201
- });
202
- const condition = conditions.length > 1 ? and(...conditions) : conditions[0];
203
- sql2 += ` LEFT JOIN ${foreignTable._.name} ${foreignAlias} ON ${condition.sql}`;
204
- params.push(...condition.params);
205
- } else if (relation.type === "many") {
206
- const refRelation = Object.entries(foreignTable.relations).find(
207
- ([_, r]) => r.foreignTable === this.table
241
+ for (const [relationName, include] of Object.entries(relations2)) {
242
+ if (!include) continue;
243
+ const relation = parentTable.relations[relationName];
244
+ if (!relation) {
245
+ console.warn(
246
+ `[Tauri-ORM] Relation "${relationName}" not found on table "${parentTable._.name}". Skipping include.`
247
+ );
248
+ continue;
249
+ }
250
+ const foreignTable = relation.foreignTable;
251
+ const foreignAlias = `${parentAlias}_${relationName}`;
252
+ const aliasedColumns = Object.values(foreignTable._.columns).map(
253
+ (col) => `${foreignAlias}.${col._.name} AS "${foreignAlias}.${col._.name}"`
208
254
  );
209
- if (refRelation && refRelation[1].fields && refRelation[1].references) {
210
- const [_, relationConfig] = refRelation;
211
- const conditions = relationConfig.fields.map((field, i) => {
212
- const localColumn = `${foreignAlias}.${field._.name}`;
213
- const foreignColumn = `${this.selectedTableAlias}.${relationConfig.references[i]._.name}`;
255
+ this.selectedColumns.push(...aliasedColumns);
256
+ if (relation.type === "one" && relation.fields && relation.references) {
257
+ const conditions = relation.fields.map((field, i) => {
258
+ const localColumn = `${parentAlias}.${field._.name}`;
259
+ const foreignColumn = `${foreignAlias}.${relation.references[i]._.name}`;
214
260
  return {
215
261
  sql: `${localColumn} = ${foreignColumn}`,
216
262
  params: []
@@ -219,9 +265,64 @@ var SelectQueryBuilder = class extends BaseQueryBuilder {
219
265
  const condition = conditions.length > 1 ? and(...conditions) : conditions[0];
220
266
  sql2 += ` LEFT JOIN ${foreignTable._.name} ${foreignAlias} ON ${condition.sql}`;
221
267
  params.push(...condition.params);
268
+ } else if (relation.type === "many") {
269
+ const refRelation = Object.entries(foreignTable.relations).find(
270
+ ([_, r]) => r.foreignTable === parentTable
271
+ );
272
+ if (refRelation && refRelation[1].fields && refRelation[1].references) {
273
+ const [_, relationConfig] = refRelation;
274
+ const conditions = relationConfig.fields.map((field, i) => {
275
+ const localColumn = `${foreignAlias}.${field._.name}`;
276
+ const foreignColumn = `${parentAlias}.${relationConfig.references[i]._.name}`;
277
+ return {
278
+ sql: `${localColumn} = ${foreignColumn}`,
279
+ params: []
280
+ };
281
+ });
282
+ const condition = conditions.length > 1 ? and(...conditions) : conditions[0];
283
+ sql2 += ` LEFT JOIN ${foreignTable._.name} ${foreignAlias} ON ${condition.sql}`;
284
+ params.push(...condition.params);
285
+ }
286
+ } else if (relation.type === "manyToMany" && relation.junctionTable && relation.junctionFields && relation.junctionReferences) {
287
+ const junctionTable = relation.junctionTable;
288
+ const junctionAlias = `${foreignAlias}_junction`;
289
+ const parentTablePks = Object.values(parentTable._.columns).filter((c) => c.options.primaryKey).map((c) => c._.name);
290
+ if (parentTablePks.length > 0 && relation.junctionFields.length > 0) {
291
+ const junctionConditions = relation.junctionFields.map((field, i) => {
292
+ const parentPk = parentTablePks[i] || parentTablePks[0];
293
+ const localColumn = `${parentAlias}.${parentPk}`;
294
+ const junctionColumn = `${junctionAlias}.${field._.name}`;
295
+ return {
296
+ sql: `${localColumn} = ${junctionColumn}`,
297
+ params: []
298
+ };
299
+ });
300
+ const junctionCondition = junctionConditions.length > 1 ? and(...junctionConditions) : junctionConditions[0];
301
+ sql2 += ` LEFT JOIN ${junctionTable._.name} ${junctionAlias} ON ${junctionCondition.sql}`;
302
+ params.push(...junctionCondition.params);
303
+ const foreignTablePks = Object.values(foreignTable._.columns).filter((c) => c.options.primaryKey).map((c) => c._.name);
304
+ if (foreignTablePks.length > 0 && relation.junctionReferences.length > 0) {
305
+ const foreignConditions = relation.junctionReferences.map((field, i) => {
306
+ const foreignPk = foreignTablePks[i] || foreignTablePks[0];
307
+ const junctionColumn = `${junctionAlias}.${field._.name}`;
308
+ const foreignColumn = `${foreignAlias}.${foreignPk}`;
309
+ return {
310
+ sql: `${junctionColumn} = ${foreignColumn}`,
311
+ params: []
312
+ };
313
+ });
314
+ const foreignCondition = foreignConditions.length > 1 ? and(...foreignConditions) : foreignConditions[0];
315
+ sql2 += ` LEFT JOIN ${foreignTable._.name} ${foreignAlias} ON ${foreignCondition.sql}`;
316
+ params.push(...foreignCondition.params);
317
+ }
318
+ }
319
+ }
320
+ if (typeof include === "object" && include.with) {
321
+ processRelations(foreignTable, foreignAlias, include.with, depth + 1);
222
322
  }
223
323
  }
224
- }
324
+ };
325
+ processRelations(this.table, this.selectedTableAlias, this.includeRelations, 0);
225
326
  return { sql: sql2, params };
226
327
  }
227
328
  // Enhanced execute method that handles relation data mapping
@@ -232,7 +333,6 @@ var SelectQueryBuilder = class extends BaseQueryBuilder {
232
333
  this.query += joinSql;
233
334
  this.params.push(...joinParams);
234
335
  const { sql: sql2, params } = this.build();
235
- console.log("Executing SQL:", sql2, "with params:", params);
236
336
  const rawResults = await this.db.select(sql2, params);
237
337
  const hasIncludes = Object.values(this.includeRelations).some((i) => i);
238
338
  if (hasIncludes) {
@@ -262,6 +362,36 @@ var SelectQueryBuilder = class extends BaseQueryBuilder {
262
362
  return rawResults;
263
363
  }
264
364
  const groupedResults = /* @__PURE__ */ new Map();
365
+ const parseRelationPath = (tableAlias, baseAlias) => {
366
+ if (!tableAlias.startsWith(baseAlias + "_")) {
367
+ return [];
368
+ }
369
+ const path = tableAlias.substring(baseAlias.length + 1);
370
+ return path.split("_");
371
+ };
372
+ const setNestedValue = (obj, path, value, columnName) => {
373
+ let current = obj;
374
+ for (let i = 0; i < path.length; i++) {
375
+ const key = path[i];
376
+ if (i === path.length - 1) {
377
+ if (!current[key]) current[key] = {};
378
+ current[key][columnName] = value;
379
+ } else {
380
+ if (!current[key]) current[key] = {};
381
+ current = current[key];
382
+ }
383
+ }
384
+ };
385
+ const getNestedRelation = (table, path) => {
386
+ let currentTable = table;
387
+ let currentRelation = null;
388
+ for (const relationName of path) {
389
+ currentRelation = currentTable.relations[relationName];
390
+ if (!currentRelation) return null;
391
+ currentTable = currentRelation.foreignTable;
392
+ }
393
+ return currentRelation;
394
+ };
265
395
  for (const row of rawResults) {
266
396
  const mainTableKey = mainTablePks.map((pk) => row[`${this.selectedTableAlias}.${pk}`] ?? row[pk]).join("_");
267
397
  if (!groupedResults.has(mainTableKey)) {
@@ -275,11 +405,9 @@ var SelectQueryBuilder = class extends BaseQueryBuilder {
275
405
  if (tableAlias === this.selectedTableAlias) {
276
406
  result[columnName] = value;
277
407
  } else {
278
- const parts = tableAlias.split("_");
279
- if (parts.length >= 2 && parts[0] === this.selectedTableAlias) {
280
- const relationName = parts.slice(1).join("_");
281
- if (!relations2[relationName]) relations2[relationName] = {};
282
- relations2[relationName][columnName] = value;
408
+ const relationPath = parseRelationPath(tableAlias, this.selectedTableAlias);
409
+ if (relationPath.length > 0) {
410
+ setNestedValue(relations2, relationPath, value, columnName);
283
411
  } else {
284
412
  if (!result[tableAlias]) result[tableAlias] = {};
285
413
  result[tableAlias][columnName] = value;
@@ -289,24 +417,72 @@ var SelectQueryBuilder = class extends BaseQueryBuilder {
289
417
  result[key] = value;
290
418
  }
291
419
  }
292
- for (const [relName, relData] of Object.entries(relations2)) {
293
- const relationConfig = this.table.relations[relName];
294
- if (!relationConfig) continue;
295
- const hasData = Object.values(relData).some(
296
- (v) => v !== null && v !== void 0 && v !== ""
297
- );
298
- if (!hasData) continue;
299
- if (relationConfig.type === "many") {
300
- if (!result[relName]) result[relName] = [];
301
- const relatedPks = Object.values(relationConfig.foreignTable._.columns).filter((c) => c.options.primaryKey).map((c) => c._.name);
302
- const relDataKey = relatedPks.map((pk) => relData[pk]).join("_");
303
- if (relatedPks.length === 0 || !result[relName].some((r) => relatedPks.map((pk) => r[pk]).join("_") === relDataKey)) {
304
- result[relName].push(relData);
420
+ const attachRelations = (target, relationsData, table, pathPrefix = []) => {
421
+ for (const [relName, relData] of Object.entries(relationsData)) {
422
+ const currentPath = [...pathPrefix, relName];
423
+ const relationConfig = getNestedRelation(table, currentPath);
424
+ if (!relationConfig) continue;
425
+ const hasDirectData = typeof relData === "object" && relData !== null && Object.entries(relData).some(([k, v]) => {
426
+ return typeof v !== "object" && v !== null && v !== void 0 && v !== "";
427
+ });
428
+ if (!hasDirectData && typeof relData === "object" && relData !== null) {
429
+ const hasNestedData = Object.values(relData).some(
430
+ (v) => typeof v === "object" && v !== null && Object.keys(v).length > 0
431
+ );
432
+ if (!hasNestedData) continue;
433
+ }
434
+ if (relationConfig.type === "many" || relationConfig.type === "manyToMany") {
435
+ if (!target[relName]) target[relName] = [];
436
+ const directData = {};
437
+ const nestedData = {};
438
+ if (typeof relData === "object" && relData !== null) {
439
+ for (const [k, v] of Object.entries(relData)) {
440
+ if (typeof v === "object" && v !== null) {
441
+ nestedData[k] = v;
442
+ } else {
443
+ directData[k] = v;
444
+ }
445
+ }
446
+ }
447
+ const hasData = Object.values(directData).some(
448
+ (v) => v !== null && v !== void 0 && v !== ""
449
+ );
450
+ if (hasData) {
451
+ const relatedPks = Object.values(relationConfig.foreignTable._.columns).filter((c) => c.options.primaryKey).map((c) => c._.name);
452
+ const relDataKey = relatedPks.map((pk) => directData[pk]).join("_");
453
+ if (relatedPks.length === 0 || !target[relName].some((r) => relatedPks.map((pk) => r[pk]).join("_") === relDataKey)) {
454
+ const newItem = { ...directData };
455
+ if (Object.keys(nestedData).length > 0) {
456
+ attachRelations(newItem, nestedData, relationConfig.foreignTable, []);
457
+ }
458
+ target[relName].push(newItem);
459
+ }
460
+ }
461
+ } else {
462
+ const directData = {};
463
+ const nestedData = {};
464
+ if (typeof relData === "object" && relData !== null) {
465
+ for (const [k, v] of Object.entries(relData)) {
466
+ if (typeof v === "object" && v !== null) {
467
+ nestedData[k] = v;
468
+ } else {
469
+ directData[k] = v;
470
+ }
471
+ }
472
+ }
473
+ const hasData = Object.values(directData).some(
474
+ (v) => v !== null && v !== void 0 && v !== ""
475
+ );
476
+ if (hasData || Object.keys(nestedData).length > 0) {
477
+ target[relName] = { ...directData };
478
+ if (Object.keys(nestedData).length > 0) {
479
+ attachRelations(target[relName], nestedData, relationConfig.foreignTable, []);
480
+ }
481
+ }
305
482
  }
306
- } else {
307
- result[relName] = relData;
308
483
  }
309
- }
484
+ };
485
+ attachRelations(result, relations2, this.table);
310
486
  }
311
487
  return Array.from(groupedResults.values());
312
488
  }
@@ -319,6 +495,82 @@ var SelectQueryBuilder = class extends BaseQueryBuilder {
319
495
  const result = await this.execute();
320
496
  return result[0];
321
497
  }
498
+ toSQL() {
499
+ const { sql: joinSql, params: joinParams } = this.buildJoins();
500
+ const distinct = this.isDistinct ? "DISTINCT " : "";
501
+ const finalQuery = `SELECT ${distinct}${this.selectedColumns.join(", ")} ${this.query}${joinSql}`;
502
+ return {
503
+ sql: finalQuery,
504
+ params: [...this.params, ...joinParams]
505
+ };
506
+ }
507
+ };
508
+
509
+ // src/errors.ts
510
+ var TauriORMError = class extends Error {
511
+ constructor(message) {
512
+ super(message);
513
+ this.name = "TauriORMError";
514
+ if (Error.captureStackTrace) {
515
+ Error.captureStackTrace(this, this.constructor);
516
+ }
517
+ }
518
+ };
519
+ var QueryBuilderError = class extends TauriORMError {
520
+ constructor(message) {
521
+ super(message);
522
+ this.name = "QueryBuilderError";
523
+ }
524
+ };
525
+ var MissingWhereClauseError = class extends QueryBuilderError {
526
+ constructor(operation, tableName) {
527
+ super(
528
+ `${operation} operation on table "${tableName}" requires a WHERE clause to prevent accidental data loss. Use .where() to specify conditions, or use .allowGlobalOperation() to explicitly allow operations without WHERE.`
529
+ );
530
+ this.name = "MissingWhereClauseError";
531
+ }
532
+ };
533
+ var ValidationError = class extends TauriORMError {
534
+ constructor(message) {
535
+ super(message);
536
+ this.name = "ValidationError";
537
+ }
538
+ };
539
+ var InsertValidationError = class extends ValidationError {
540
+ constructor(message) {
541
+ super(message);
542
+ this.name = "InsertValidationError";
543
+ }
544
+ };
545
+ var UpdateValidationError = class extends ValidationError {
546
+ constructor(message) {
547
+ super(message);
548
+ this.name = "UpdateValidationError";
549
+ }
550
+ };
551
+ var MigrationError = class extends TauriORMError {
552
+ constructor(message) {
553
+ super(message);
554
+ this.name = "MigrationError";
555
+ }
556
+ };
557
+ var RelationError = class extends TauriORMError {
558
+ constructor(message) {
559
+ super(message);
560
+ this.name = "RelationError";
561
+ }
562
+ };
563
+ var ColumnNotFoundError = class extends TauriORMError {
564
+ constructor(columnName, tableName) {
565
+ super(`Column "${columnName}" does not exist on table "${tableName}"`);
566
+ this.name = "ColumnNotFoundError";
567
+ }
568
+ };
569
+ var TableNotFoundError = class extends TauriORMError {
570
+ constructor(tableName) {
571
+ super(`Table "${tableName}" not found in schema`);
572
+ this.name = "TableNotFoundError";
573
+ }
322
574
  };
323
575
 
324
576
  // src/builders/update.ts
@@ -330,10 +582,37 @@ var UpdateQueryBuilder = class extends BaseQueryBuilder {
330
582
  }
331
583
  updateData = {};
332
584
  returningColumns = [];
585
+ hasWhereClause = false;
586
+ allowGlobal = false;
587
+ incrementDecrementOps = [];
333
588
  set(data) {
334
589
  this.updateData = { ...this.updateData, ...data };
335
590
  return this;
336
591
  }
592
+ where(condition) {
593
+ this.hasWhereClause = true;
594
+ return super.where(condition);
595
+ }
596
+ increment(column, value = 1) {
597
+ const col = this.table._.columns[column];
598
+ if (!col) {
599
+ throw new ColumnNotFoundError(String(column), this.table._.name);
600
+ }
601
+ this.incrementDecrementOps.push({ column: col._.name, op: "increment", value });
602
+ return this;
603
+ }
604
+ decrement(column, value = 1) {
605
+ const col = this.table._.columns[column];
606
+ if (!col) {
607
+ throw new ColumnNotFoundError(String(column), this.table._.name);
608
+ }
609
+ this.incrementDecrementOps.push({ column: col._.name, op: "decrement", value });
610
+ return this;
611
+ }
612
+ allowGlobalOperation() {
613
+ this.allowGlobal = true;
614
+ return this;
615
+ }
337
616
  returning(...columns) {
338
617
  this.returningColumns.push(...columns);
339
618
  return this;
@@ -356,24 +635,37 @@ var UpdateQueryBuilder = class extends BaseQueryBuilder {
356
635
  whereClause = baseQuery.substring(whereIndex);
357
636
  }
358
637
  const entries = Object.entries(finalUpdateData);
359
- if (entries.length === 0) {
360
- throw new Error("Cannot execute an update query without a .set() call.");
361
- }
362
- const setClause = entries.map(([key]) => {
363
- const column = this.table._.columns[key];
364
- if (!column) {
365
- throw new Error(
366
- `Column ${key} does not exist on table ${this.table._.name}`
367
- );
638
+ const hasSetData = entries.length > 0;
639
+ const hasIncrementDecrement = this.incrementDecrementOps.length > 0;
640
+ if (!hasSetData && !hasIncrementDecrement) {
641
+ throw new UpdateValidationError("Cannot execute an update query without a .set(), .increment(), or .decrement() call.");
642
+ }
643
+ const setClauses = [];
644
+ const setParams = [];
645
+ if (hasSetData) {
646
+ for (const [key, value] of entries) {
647
+ const column = this.table._.columns[key];
648
+ if (!column) {
649
+ throw new ColumnNotFoundError(key, this.table._.name);
650
+ }
651
+ setClauses.push(`${column._.name} = ?`);
652
+ setParams.push(value);
368
653
  }
369
- return `${column._.name} = ?`;
370
- }).join(", ");
371
- const setParams = entries.map(([, value]) => value);
654
+ }
655
+ for (const op of this.incrementDecrementOps) {
656
+ const sign = op.op === "increment" ? "+" : "-";
657
+ setClauses.push(`${op.column} = ${op.column} ${sign} ?`);
658
+ setParams.push(op.value);
659
+ }
660
+ const setClause = setClauses.join(", ");
372
661
  const sql2 = `${tablePart} SET ${setClause}${whereClause}`;
373
662
  const params = [...setParams, ...whereParams];
374
663
  return { sql: sql2, params };
375
664
  }
376
665
  async execute() {
666
+ if (!this.hasWhereClause && !this.allowGlobal) {
667
+ throw new MissingWhereClauseError("UPDATE", this.table._.name);
668
+ }
377
669
  const { sql: updateSql, params } = this.buildUpdateClause();
378
670
  if (this.returningColumns.length > 0) {
379
671
  const returningNames = this.returningColumns.map((col) => this.table._.columns[col]._.name).join(", ");
@@ -390,6 +682,17 @@ var UpdateQueryBuilder = class extends BaseQueryBuilder {
390
682
  );
391
683
  return this.returning(...allColumns).execute();
392
684
  }
685
+ toSQL() {
686
+ const { sql: updateSql, params } = this.buildUpdateClause();
687
+ if (this.returningColumns.length > 0) {
688
+ const returningNames = this.returningColumns.map((col) => this.table._.columns[col]._.name).join(", ");
689
+ return {
690
+ sql: `${updateSql} RETURNING ${returningNames}`,
691
+ params
692
+ };
693
+ }
694
+ return { sql: updateSql, params };
695
+ }
393
696
  };
394
697
 
395
698
  // src/builders/insert.ts
@@ -458,7 +761,7 @@ var InsertQueryBuilder = class extends BaseQueryBuilder {
458
761
  }
459
762
  async execute() {
460
763
  if (this.dataSets.length === 0) {
461
- throw new Error("No data provided for insert");
764
+ throw new InsertValidationError("No data provided for insert. Use .values() to provide data.");
462
765
  }
463
766
  const processedDataSets = this.dataSets.map(
464
767
  (data) => this.processDefaultValues(data)
@@ -516,6 +819,42 @@ var InsertQueryBuilder = class extends BaseQueryBuilder {
516
819
  );
517
820
  return this.returning(...allColumns).execute();
518
821
  }
822
+ toSQL() {
823
+ if (this.dataSets.length === 0) {
824
+ throw new InsertValidationError("No data provided for insert. Use .values() to provide data.");
825
+ }
826
+ const processedDataSets = this.dataSets.map(
827
+ (data) => this.processDefaultValues(data)
828
+ );
829
+ const dataSet = processedDataSets[0];
830
+ const columns = Object.keys(dataSet);
831
+ const columnNames = columns.map(
832
+ (key) => this.table._.columns[key]._.name
833
+ );
834
+ const placeholders = `(${columns.map(() => "?").join(", ")})`;
835
+ const valuesSql = processedDataSets.map(() => placeholders).join(", ");
836
+ const conflictClause = this.buildConflictClause();
837
+ const finalQuery = `${this.query} (${columnNames.join(
838
+ ", "
839
+ )}) VALUES ${valuesSql}${conflictClause}`;
840
+ const params = processedDataSets.flatMap(
841
+ (data) => columns.map((col) => data[col] ?? null)
842
+ );
843
+ if (this.onConflictAction === "update") {
844
+ const setValues = Object.entries(this.updateSet).map(
845
+ ([, value]) => value
846
+ );
847
+ params.push(...setValues);
848
+ }
849
+ if (this.returningColumns.length > 0) {
850
+ const returningNames = this.returningColumns.map((col) => this.table._.columns[col]._.name).join(", ");
851
+ return {
852
+ sql: `${finalQuery} RETURNING ${returningNames}`,
853
+ params
854
+ };
855
+ }
856
+ return { sql: finalQuery, params };
857
+ }
519
858
  };
520
859
 
521
860
  // src/builders/delete.ts
@@ -526,11 +865,24 @@ var DeleteQueryBuilder = class extends BaseQueryBuilder {
526
865
  this.query = `DELETE FROM ${table._.name}`;
527
866
  }
528
867
  returningColumns = [];
868
+ hasWhereClause = false;
869
+ allowGlobal = false;
870
+ where(condition) {
871
+ this.hasWhereClause = true;
872
+ return super.where(condition);
873
+ }
874
+ allowGlobalOperation() {
875
+ this.allowGlobal = true;
876
+ return this;
877
+ }
529
878
  returning(...columns) {
530
879
  this.returningColumns.push(...columns);
531
880
  return this;
532
881
  }
533
882
  async execute() {
883
+ if (!this.hasWhereClause && !this.allowGlobal) {
884
+ throw new MissingWhereClauseError("DELETE", this.table._.name);
885
+ }
534
886
  const { sql: sql2, params } = this.build();
535
887
  if (this.returningColumns.length > 0) {
536
888
  const returningNames = this.returningColumns.map((col) => this.table._.columns[col]._.name).join(", ");
@@ -545,6 +897,17 @@ var DeleteQueryBuilder = class extends BaseQueryBuilder {
545
897
  const allColumns = Object.keys(this.table._.columns);
546
898
  return this.returning(...allColumns).execute();
547
899
  }
900
+ toSQL() {
901
+ const { sql: sql2, params } = this.build();
902
+ if (this.returningColumns.length > 0) {
903
+ const returningNames = this.returningColumns.map((col) => this.table._.columns[col]._.name).join(", ");
904
+ return {
905
+ sql: `${sql2} RETURNING ${returningNames}`,
906
+ params
907
+ };
908
+ }
909
+ return { sql: sql2, params };
910
+ }
548
911
  };
549
912
 
550
913
  // src/builders/with.ts
@@ -630,6 +993,8 @@ var SQLiteColumn = class _SQLiteColumn {
630
993
  return new _SQLiteColumn(this._.name, this.type, { ...this.options, unique: true }, this._.mode);
631
994
  }
632
995
  references(ref, column) {
996
+ const columnKey = typeof column === "string" ? column : column._.name;
997
+ const columnObj = typeof column === "string" ? ref._.columns[column] : column;
633
998
  return new _SQLiteColumn(
634
999
  this._.name,
635
1000
  this.type,
@@ -637,7 +1002,7 @@ var SQLiteColumn = class _SQLiteColumn {
637
1002
  ...this.options,
638
1003
  references: {
639
1004
  table: ref,
640
- column: ref._.columns[column]
1005
+ column: columnObj
641
1006
  }
642
1007
  },
643
1008
  this._.mode
@@ -926,6 +1291,12 @@ var ManyRelation = class extends Relation {
926
1291
  super(foreignTable);
927
1292
  }
928
1293
  };
1294
+ var ManyToManyRelation = class extends Relation {
1295
+ constructor(foreignTable, config) {
1296
+ super(foreignTable);
1297
+ this.config = config;
1298
+ }
1299
+ };
929
1300
  var relations = (table, relationsCallback) => {
930
1301
  const builtRelations = relationsCallback({
931
1302
  one: (foreignTable, config) => {
@@ -933,6 +1304,9 @@ var relations = (table, relationsCallback) => {
933
1304
  },
934
1305
  many: (foreignTable) => {
935
1306
  return new ManyRelation(foreignTable);
1307
+ },
1308
+ manyToMany: (foreignTable, config) => {
1309
+ return new ManyToManyRelation(foreignTable, config);
936
1310
  }
937
1311
  });
938
1312
  for (const [name, relation] of Object.entries(builtRelations)) {
@@ -948,6 +1322,14 @@ var relations = (table, relationsCallback) => {
948
1322
  type: "many",
949
1323
  foreignTable: relation.foreignTable
950
1324
  };
1325
+ } else if (relation instanceof ManyToManyRelation) {
1326
+ table.relations[name] = {
1327
+ type: "manyToMany",
1328
+ foreignTable: relation.foreignTable,
1329
+ junctionTable: relation.config.junctionTable,
1330
+ junctionFields: relation.config.junctionFields,
1331
+ junctionReferences: relation.config.junctionReferences
1332
+ };
951
1333
  }
952
1334
  }
953
1335
  return builtRelations;
@@ -959,6 +1341,53 @@ var alias = (table, alias2) => {
959
1341
  return table;
960
1342
  };
961
1343
 
1344
+ // src/aggregates.ts
1345
+ var count = (column) => ({
1346
+ sql: `COUNT(${column ? column._.name : "*"})`,
1347
+ params: []
1348
+ });
1349
+ var countDistinct = (column) => ({
1350
+ sql: `COUNT(DISTINCT ${column._.name})`,
1351
+ params: []
1352
+ });
1353
+ var sum = (column) => ({
1354
+ sql: `SUM(${column._.name})`,
1355
+ params: []
1356
+ });
1357
+ var avg = (column) => ({
1358
+ sql: `AVG(${column._.name})`,
1359
+ params: []
1360
+ });
1361
+ var max = (column) => ({
1362
+ sql: `MAX(${column._.name})`,
1363
+ params: []
1364
+ });
1365
+ var min = (column) => ({
1366
+ sql: `MIN(${column._.name})`,
1367
+ params: []
1368
+ });
1369
+ var groupConcat = (column, separator = ",") => ({
1370
+ sql: `GROUP_CONCAT(${column._.name}, ?)`,
1371
+ params: [separator]
1372
+ });
1373
+ var as = (aggregate, alias2) => ({
1374
+ ...aggregate,
1375
+ alias: alias2
1376
+ });
1377
+
1378
+ // src/subquery.ts
1379
+ var subquery = (query) => {
1380
+ const { sql: sql2, params } = query.toSQL();
1381
+ return {
1382
+ sql: `(${sql2})`,
1383
+ params,
1384
+ _isSubquery: true
1385
+ };
1386
+ };
1387
+ var scalarSubquery = (query) => {
1388
+ return subquery(query);
1389
+ };
1390
+
962
1391
  // src/column-helpers.ts
963
1392
  var text = (name, config) => new SQLiteColumn(name, "TEXT", config, config?.mode);
964
1393
  var integer = (name, config) => new SQLiteColumn(name, "INTEGER", {}, config?.mode || "default");
@@ -969,47 +1398,77 @@ var numeric = (name, config) => new SQLiteColumn(name, "NUMERIC", {}, config?.mo
969
1398
  var enumType = (name, values) => text(name, { enum: values });
970
1399
  export {
971
1400
  BaseQueryBuilder,
1401
+ ColumnNotFoundError,
972
1402
  DeleteQueryBuilder,
973
1403
  InsertQueryBuilder,
1404
+ InsertValidationError,
974
1405
  ManyRelation,
1406
+ ManyToManyRelation,
1407
+ MigrationError,
1408
+ MissingWhereClauseError,
975
1409
  OneRelation,
1410
+ QueryBuilderError,
976
1411
  Relation,
1412
+ RelationError,
977
1413
  SQLiteColumn,
978
1414
  SelectQueryBuilder,
979
1415
  Table,
1416
+ TableNotFoundError,
980
1417
  TauriORM,
1418
+ TauriORMError,
981
1419
  UpdateQueryBuilder,
1420
+ UpdateValidationError,
1421
+ ValidationError,
982
1422
  WithQueryBuilder,
983
1423
  alias,
984
1424
  and,
1425
+ as,
985
1426
  asc,
986
1427
  avg,
1428
+ between,
987
1429
  blob,
988
1430
  boolean,
1431
+ contains,
989
1432
  count,
990
1433
  countDistinct,
991
1434
  desc,
1435
+ endsWith,
992
1436
  enumType,
993
1437
  eq,
1438
+ eqSubquery,
1439
+ exists,
994
1440
  getTableColumns,
1441
+ groupConcat,
995
1442
  gt,
1443
+ gtSubquery,
996
1444
  gte,
1445
+ gteSubquery,
1446
+ ilike,
997
1447
  inArray,
998
1448
  integer,
999
1449
  isNotNull,
1000
1450
  isNull,
1001
1451
  like,
1002
1452
  lt,
1453
+ ltSubquery,
1003
1454
  lte,
1455
+ lteSubquery,
1004
1456
  max,
1005
1457
  min,
1458
+ ne,
1459
+ neSubquery,
1006
1460
  not,
1461
+ notExists,
1462
+ notIn,
1007
1463
  numeric,
1008
1464
  or,
1009
1465
  real,
1010
1466
  relations,
1467
+ scalarSubquery,
1011
1468
  sql,
1012
1469
  sqliteTable,
1470
+ startsWith,
1471
+ subquery,
1013
1472
  sum,
1014
1473
  text
1015
1474
  };