@type32/tauri-sqlite-orm 0.1.19 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -21,47 +21,77 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  BaseQueryBuilder: () => BaseQueryBuilder,
24
+ ColumnNotFoundError: () => ColumnNotFoundError,
24
25
  DeleteQueryBuilder: () => DeleteQueryBuilder,
25
26
  InsertQueryBuilder: () => InsertQueryBuilder,
27
+ InsertValidationError: () => InsertValidationError,
26
28
  ManyRelation: () => ManyRelation,
29
+ ManyToManyRelation: () => ManyToManyRelation,
30
+ MigrationError: () => MigrationError,
31
+ MissingWhereClauseError: () => MissingWhereClauseError,
27
32
  OneRelation: () => OneRelation,
33
+ QueryBuilderError: () => QueryBuilderError,
28
34
  Relation: () => Relation,
35
+ RelationError: () => RelationError,
29
36
  SQLiteColumn: () => SQLiteColumn,
30
37
  SelectQueryBuilder: () => SelectQueryBuilder,
31
38
  Table: () => Table,
39
+ TableNotFoundError: () => TableNotFoundError,
32
40
  TauriORM: () => TauriORM,
41
+ TauriORMError: () => TauriORMError,
33
42
  UpdateQueryBuilder: () => UpdateQueryBuilder,
43
+ UpdateValidationError: () => UpdateValidationError,
44
+ ValidationError: () => ValidationError,
34
45
  WithQueryBuilder: () => WithQueryBuilder,
35
46
  alias: () => alias,
36
47
  and: () => and,
48
+ as: () => as,
37
49
  asc: () => asc,
38
50
  avg: () => avg,
51
+ between: () => between,
39
52
  blob: () => blob,
40
53
  boolean: () => boolean,
54
+ contains: () => contains,
41
55
  count: () => count,
42
56
  countDistinct: () => countDistinct,
43
57
  desc: () => desc,
58
+ endsWith: () => endsWith,
44
59
  enumType: () => enumType,
45
60
  eq: () => eq,
61
+ eqSubquery: () => eqSubquery,
62
+ exists: () => exists,
46
63
  getTableColumns: () => getTableColumns,
64
+ groupConcat: () => groupConcat,
47
65
  gt: () => gt,
66
+ gtSubquery: () => gtSubquery,
48
67
  gte: () => gte,
68
+ gteSubquery: () => gteSubquery,
69
+ ilike: () => ilike,
49
70
  inArray: () => inArray,
50
71
  integer: () => integer,
51
72
  isNotNull: () => isNotNull,
52
73
  isNull: () => isNull,
53
74
  like: () => like,
54
75
  lt: () => lt,
76
+ ltSubquery: () => ltSubquery,
55
77
  lte: () => lte,
78
+ lteSubquery: () => lteSubquery,
56
79
  max: () => max,
57
80
  min: () => min,
81
+ ne: () => ne,
82
+ neSubquery: () => neSubquery,
58
83
  not: () => not,
84
+ notExists: () => notExists,
85
+ notIn: () => notIn,
59
86
  numeric: () => numeric,
60
87
  or: () => or,
61
88
  real: () => real,
62
89
  relations: () => relations,
90
+ scalarSubquery: () => scalarSubquery,
63
91
  sql: () => sql,
64
92
  sqliteTable: () => sqliteTable,
93
+ startsWith: () => startsWith,
94
+ subquery: () => subquery,
65
95
  sum: () => sum,
66
96
  text: () => text
67
97
  });
@@ -102,6 +132,9 @@ var BaseQueryBuilder = class {
102
132
  params: this.params
103
133
  };
104
134
  }
135
+ toSQL() {
136
+ return this.build();
137
+ }
105
138
  };
106
139
 
107
140
  // src/operators.ts
@@ -112,6 +145,13 @@ var eq = (column, value, tableAlias) => {
112
145
  params: [value]
113
146
  };
114
147
  };
148
+ var ne = (column, value, tableAlias) => {
149
+ const columnName = tableAlias ? `${tableAlias}.${column._.name}` : column._.name;
150
+ return {
151
+ sql: `${columnName} != ?`,
152
+ params: [value]
153
+ };
154
+ };
115
155
  var and = (...conditions) => ({
116
156
  sql: conditions.map((c) => `(${c.sql})`).join(" AND "),
117
157
  params: conditions.flatMap((c) => c.params)
@@ -144,6 +184,22 @@ var like = (column, pattern) => ({
144
184
  sql: `${column._.name} LIKE ?`,
145
185
  params: [pattern]
146
186
  });
187
+ var ilike = (column, pattern) => ({
188
+ sql: `${column._.name} LIKE ? COLLATE NOCASE`,
189
+ params: [pattern]
190
+ });
191
+ var startsWith = (column, value) => ({
192
+ sql: `${column._.name} LIKE ?`,
193
+ params: [`${value}%`]
194
+ });
195
+ var endsWith = (column, value) => ({
196
+ sql: `${column._.name} LIKE ?`,
197
+ params: [`%${value}`]
198
+ });
199
+ var contains = (column, value) => ({
200
+ sql: `${column._.name} LIKE ?`,
201
+ params: [`%${value}%`]
202
+ });
147
203
  var isNull = (column) => ({
148
204
  sql: `${column._.name} IS NULL`,
149
205
  params: []
@@ -152,33 +208,65 @@ var isNotNull = (column) => ({
152
208
  sql: `${column._.name} IS NOT NULL`,
153
209
  params: []
154
210
  });
155
- var inArray = (column, values) => ({
156
- sql: `${column._.name} IN (${values.map(() => "?").join(",")})`,
157
- params: values
211
+ var exists = (subquery2) => ({
212
+ sql: `EXISTS (${subquery2.sql})`,
213
+ params: subquery2.params
158
214
  });
159
- var count = (column) => ({
160
- sql: `COUNT(${column ? column._.name : "*"})`,
161
- params: []
215
+ var notExists = (subquery2) => ({
216
+ sql: `NOT EXISTS (${subquery2.sql})`,
217
+ params: subquery2.params
162
218
  });
163
- var countDistinct = (column) => ({
164
- sql: `COUNT(DISTINCT ${column._.name})`,
165
- params: []
219
+ var eqSubquery = (column, subquery2) => ({
220
+ sql: `${column._.name} = ${subquery2.sql}`,
221
+ params: subquery2.params
166
222
  });
167
- var sum = (column) => ({
168
- sql: `SUM(${column._.name})`,
169
- params: []
223
+ var neSubquery = (column, subquery2) => ({
224
+ sql: `${column._.name} != ${subquery2.sql}`,
225
+ params: subquery2.params
170
226
  });
171
- var avg = (column) => ({
172
- sql: `AVG(${column._.name})`,
173
- params: []
227
+ var gtSubquery = (column, subquery2) => ({
228
+ sql: `${column._.name} > ${subquery2.sql}`,
229
+ params: subquery2.params
174
230
  });
175
- var max = (column) => ({
176
- sql: `MAX(${column._.name})`,
177
- params: []
231
+ var gteSubquery = (column, subquery2) => ({
232
+ sql: `${column._.name} >= ${subquery2.sql}`,
233
+ params: subquery2.params
178
234
  });
179
- var min = (column) => ({
180
- sql: `MIN(${column._.name})`,
181
- params: []
235
+ var ltSubquery = (column, subquery2) => ({
236
+ sql: `${column._.name} < ${subquery2.sql}`,
237
+ params: subquery2.params
238
+ });
239
+ var lteSubquery = (column, subquery2) => ({
240
+ sql: `${column._.name} <= ${subquery2.sql}`,
241
+ params: subquery2.params
242
+ });
243
+ var inArray = (column, values) => {
244
+ if ("_isSubquery" in values && values._isSubquery) {
245
+ return {
246
+ sql: `${column._.name} IN ${values.sql}`,
247
+ params: values.params
248
+ };
249
+ }
250
+ return {
251
+ sql: `${column._.name} IN (${values.map(() => "?").join(",")})`,
252
+ params: values
253
+ };
254
+ };
255
+ var notIn = (column, values) => {
256
+ if ("_isSubquery" in values && values._isSubquery) {
257
+ return {
258
+ sql: `${column._.name} NOT IN ${values.sql}`,
259
+ params: values.params
260
+ };
261
+ }
262
+ return {
263
+ sql: `${column._.name} NOT IN (${values.map(() => "?").join(",")})`,
264
+ params: values
265
+ };
266
+ };
267
+ var between = (column, min2, max2) => ({
268
+ sql: `${column._.name} BETWEEN ? AND ?`,
269
+ params: [min2, max2]
182
270
  });
183
271
 
184
272
  // src/builders/select.ts
@@ -244,42 +332,30 @@ var SelectQueryBuilder = class extends BaseQueryBuilder {
244
332
  sql2 += ` ${join.type} JOIN ${join.table._.name} ${join.alias} ON ${join.condition.sql}`;
245
333
  params.push(...join.condition.params);
246
334
  }
247
- for (const [relationName, include] of Object.entries(this.includeRelations)) {
248
- if (!include) continue;
249
- const relation = this.table.relations[relationName];
250
- if (!relation) {
251
- console.warn(
252
- `[Tauri-ORM] Relation "${relationName}" not found on table "${this.table._.name}". Skipping include.`
253
- );
254
- continue;
335
+ const processRelations = (parentTable, parentAlias, relations2, depth = 0) => {
336
+ if (depth > 10) {
337
+ console.warn("[Tauri-ORM] Maximum relation depth (10) exceeded. Skipping deeper relations.");
338
+ return;
255
339
  }
256
- const foreignTable = relation.foreignTable;
257
- const foreignAlias = `${this.selectedTableAlias}_${relationName}`;
258
- const aliasedColumns = Object.values(foreignTable._.columns).map(
259
- (col) => `${foreignAlias}.${col._.name} AS "${foreignAlias}.${col._.name}"`
260
- );
261
- this.selectedColumns.push(...aliasedColumns);
262
- if (relation.type === "one" && relation.fields && relation.references) {
263
- const conditions = relation.fields.map((field, i) => {
264
- const localColumn = `${this.selectedTableAlias}.${field._.name}`;
265
- const foreignColumn = `${foreignAlias}.${relation.references[i]._.name}`;
266
- return {
267
- sql: `${localColumn} = ${foreignColumn}`,
268
- params: []
269
- };
270
- });
271
- const condition = conditions.length > 1 ? and(...conditions) : conditions[0];
272
- sql2 += ` LEFT JOIN ${foreignTable._.name} ${foreignAlias} ON ${condition.sql}`;
273
- params.push(...condition.params);
274
- } else if (relation.type === "many") {
275
- const refRelation = Object.entries(foreignTable.relations).find(
276
- ([_, r]) => r.foreignTable === this.table
340
+ for (const [relationName, include] of Object.entries(relations2)) {
341
+ if (!include) continue;
342
+ const relation = parentTable.relations[relationName];
343
+ if (!relation) {
344
+ console.warn(
345
+ `[Tauri-ORM] Relation "${relationName}" not found on table "${parentTable._.name}". Skipping include.`
346
+ );
347
+ continue;
348
+ }
349
+ const foreignTable = relation.foreignTable;
350
+ const foreignAlias = `${parentAlias}_${relationName}`;
351
+ const aliasedColumns = Object.values(foreignTable._.columns).map(
352
+ (col) => `${foreignAlias}.${col._.name} AS "${foreignAlias}.${col._.name}"`
277
353
  );
278
- if (refRelation && refRelation[1].fields && refRelation[1].references) {
279
- const [_, relationConfig] = refRelation;
280
- const conditions = relationConfig.fields.map((field, i) => {
281
- const localColumn = `${foreignAlias}.${field._.name}`;
282
- const foreignColumn = `${this.selectedTableAlias}.${relationConfig.references[i]._.name}`;
354
+ this.selectedColumns.push(...aliasedColumns);
355
+ if (relation.type === "one" && relation.fields && relation.references) {
356
+ const conditions = relation.fields.map((field, i) => {
357
+ const localColumn = `${parentAlias}.${field._.name}`;
358
+ const foreignColumn = `${foreignAlias}.${relation.references[i]._.name}`;
283
359
  return {
284
360
  sql: `${localColumn} = ${foreignColumn}`,
285
361
  params: []
@@ -288,9 +364,64 @@ var SelectQueryBuilder = class extends BaseQueryBuilder {
288
364
  const condition = conditions.length > 1 ? and(...conditions) : conditions[0];
289
365
  sql2 += ` LEFT JOIN ${foreignTable._.name} ${foreignAlias} ON ${condition.sql}`;
290
366
  params.push(...condition.params);
367
+ } else if (relation.type === "many") {
368
+ const refRelation = Object.entries(foreignTable.relations).find(
369
+ ([_, r]) => r.foreignTable === parentTable
370
+ );
371
+ if (refRelation && refRelation[1].fields && refRelation[1].references) {
372
+ const [_, relationConfig] = refRelation;
373
+ const conditions = relationConfig.fields.map((field, i) => {
374
+ const localColumn = `${foreignAlias}.${field._.name}`;
375
+ const foreignColumn = `${parentAlias}.${relationConfig.references[i]._.name}`;
376
+ return {
377
+ sql: `${localColumn} = ${foreignColumn}`,
378
+ params: []
379
+ };
380
+ });
381
+ const condition = conditions.length > 1 ? and(...conditions) : conditions[0];
382
+ sql2 += ` LEFT JOIN ${foreignTable._.name} ${foreignAlias} ON ${condition.sql}`;
383
+ params.push(...condition.params);
384
+ }
385
+ } else if (relation.type === "manyToMany" && relation.junctionTable && relation.junctionFields && relation.junctionReferences) {
386
+ const junctionTable = relation.junctionTable;
387
+ const junctionAlias = `${foreignAlias}_junction`;
388
+ const parentTablePks = Object.values(parentTable._.columns).filter((c) => c.options.primaryKey).map((c) => c._.name);
389
+ if (parentTablePks.length > 0 && relation.junctionFields.length > 0) {
390
+ const junctionConditions = relation.junctionFields.map((field, i) => {
391
+ const parentPk = parentTablePks[i] || parentTablePks[0];
392
+ const localColumn = `${parentAlias}.${parentPk}`;
393
+ const junctionColumn = `${junctionAlias}.${field._.name}`;
394
+ return {
395
+ sql: `${localColumn} = ${junctionColumn}`,
396
+ params: []
397
+ };
398
+ });
399
+ const junctionCondition = junctionConditions.length > 1 ? and(...junctionConditions) : junctionConditions[0];
400
+ sql2 += ` LEFT JOIN ${junctionTable._.name} ${junctionAlias} ON ${junctionCondition.sql}`;
401
+ params.push(...junctionCondition.params);
402
+ const foreignTablePks = Object.values(foreignTable._.columns).filter((c) => c.options.primaryKey).map((c) => c._.name);
403
+ if (foreignTablePks.length > 0 && relation.junctionReferences.length > 0) {
404
+ const foreignConditions = relation.junctionReferences.map((field, i) => {
405
+ const foreignPk = foreignTablePks[i] || foreignTablePks[0];
406
+ const junctionColumn = `${junctionAlias}.${field._.name}`;
407
+ const foreignColumn = `${foreignAlias}.${foreignPk}`;
408
+ return {
409
+ sql: `${junctionColumn} = ${foreignColumn}`,
410
+ params: []
411
+ };
412
+ });
413
+ const foreignCondition = foreignConditions.length > 1 ? and(...foreignConditions) : foreignConditions[0];
414
+ sql2 += ` LEFT JOIN ${foreignTable._.name} ${foreignAlias} ON ${foreignCondition.sql}`;
415
+ params.push(...foreignCondition.params);
416
+ }
417
+ }
418
+ }
419
+ if (typeof include === "object" && include.with) {
420
+ processRelations(foreignTable, foreignAlias, include.with, depth + 1);
291
421
  }
292
422
  }
293
- }
423
+ };
424
+ processRelations(this.table, this.selectedTableAlias, this.includeRelations, 0);
294
425
  return { sql: sql2, params };
295
426
  }
296
427
  // Enhanced execute method that handles relation data mapping
@@ -301,7 +432,6 @@ var SelectQueryBuilder = class extends BaseQueryBuilder {
301
432
  this.query += joinSql;
302
433
  this.params.push(...joinParams);
303
434
  const { sql: sql2, params } = this.build();
304
- console.log("Executing SQL:", sql2, "with params:", params);
305
435
  const rawResults = await this.db.select(sql2, params);
306
436
  const hasIncludes = Object.values(this.includeRelations).some((i) => i);
307
437
  if (hasIncludes) {
@@ -331,6 +461,36 @@ var SelectQueryBuilder = class extends BaseQueryBuilder {
331
461
  return rawResults;
332
462
  }
333
463
  const groupedResults = /* @__PURE__ */ new Map();
464
+ const parseRelationPath = (tableAlias, baseAlias) => {
465
+ if (!tableAlias.startsWith(baseAlias + "_")) {
466
+ return [];
467
+ }
468
+ const path = tableAlias.substring(baseAlias.length + 1);
469
+ return path.split("_");
470
+ };
471
+ const setNestedValue = (obj, path, value, columnName) => {
472
+ let current = obj;
473
+ for (let i = 0; i < path.length; i++) {
474
+ const key = path[i];
475
+ if (i === path.length - 1) {
476
+ if (!current[key]) current[key] = {};
477
+ current[key][columnName] = value;
478
+ } else {
479
+ if (!current[key]) current[key] = {};
480
+ current = current[key];
481
+ }
482
+ }
483
+ };
484
+ const getNestedRelation = (table, path) => {
485
+ let currentTable = table;
486
+ let currentRelation = null;
487
+ for (const relationName of path) {
488
+ currentRelation = currentTable.relations[relationName];
489
+ if (!currentRelation) return null;
490
+ currentTable = currentRelation.foreignTable;
491
+ }
492
+ return currentRelation;
493
+ };
334
494
  for (const row of rawResults) {
335
495
  const mainTableKey = mainTablePks.map((pk) => row[`${this.selectedTableAlias}.${pk}`] ?? row[pk]).join("_");
336
496
  if (!groupedResults.has(mainTableKey)) {
@@ -344,11 +504,9 @@ var SelectQueryBuilder = class extends BaseQueryBuilder {
344
504
  if (tableAlias === this.selectedTableAlias) {
345
505
  result[columnName] = value;
346
506
  } else {
347
- const parts = tableAlias.split("_");
348
- if (parts.length >= 2 && parts[0] === this.selectedTableAlias) {
349
- const relationName = parts.slice(1).join("_");
350
- if (!relations2[relationName]) relations2[relationName] = {};
351
- relations2[relationName][columnName] = value;
507
+ const relationPath = parseRelationPath(tableAlias, this.selectedTableAlias);
508
+ if (relationPath.length > 0) {
509
+ setNestedValue(relations2, relationPath, value, columnName);
352
510
  } else {
353
511
  if (!result[tableAlias]) result[tableAlias] = {};
354
512
  result[tableAlias][columnName] = value;
@@ -358,24 +516,72 @@ var SelectQueryBuilder = class extends BaseQueryBuilder {
358
516
  result[key] = value;
359
517
  }
360
518
  }
361
- for (const [relName, relData] of Object.entries(relations2)) {
362
- const relationConfig = this.table.relations[relName];
363
- if (!relationConfig) continue;
364
- const hasData = Object.values(relData).some(
365
- (v) => v !== null && v !== void 0 && v !== ""
366
- );
367
- if (!hasData) continue;
368
- if (relationConfig.type === "many") {
369
- if (!result[relName]) result[relName] = [];
370
- const relatedPks = Object.values(relationConfig.foreignTable._.columns).filter((c) => c.options.primaryKey).map((c) => c._.name);
371
- const relDataKey = relatedPks.map((pk) => relData[pk]).join("_");
372
- if (relatedPks.length === 0 || !result[relName].some((r) => relatedPks.map((pk) => r[pk]).join("_") === relDataKey)) {
373
- result[relName].push(relData);
519
+ const attachRelations = (target, relationsData, table, pathPrefix = []) => {
520
+ for (const [relName, relData] of Object.entries(relationsData)) {
521
+ const currentPath = [...pathPrefix, relName];
522
+ const relationConfig = getNestedRelation(table, currentPath);
523
+ if (!relationConfig) continue;
524
+ const hasDirectData = typeof relData === "object" && relData !== null && Object.entries(relData).some(([k, v]) => {
525
+ return typeof v !== "object" && v !== null && v !== void 0 && v !== "";
526
+ });
527
+ if (!hasDirectData && typeof relData === "object" && relData !== null) {
528
+ const hasNestedData = Object.values(relData).some(
529
+ (v) => typeof v === "object" && v !== null && Object.keys(v).length > 0
530
+ );
531
+ if (!hasNestedData) continue;
532
+ }
533
+ if (relationConfig.type === "many" || relationConfig.type === "manyToMany") {
534
+ if (!target[relName]) target[relName] = [];
535
+ const directData = {};
536
+ const nestedData = {};
537
+ if (typeof relData === "object" && relData !== null) {
538
+ for (const [k, v] of Object.entries(relData)) {
539
+ if (typeof v === "object" && v !== null) {
540
+ nestedData[k] = v;
541
+ } else {
542
+ directData[k] = v;
543
+ }
544
+ }
545
+ }
546
+ const hasData = Object.values(directData).some(
547
+ (v) => v !== null && v !== void 0 && v !== ""
548
+ );
549
+ if (hasData) {
550
+ const relatedPks = Object.values(relationConfig.foreignTable._.columns).filter((c) => c.options.primaryKey).map((c) => c._.name);
551
+ const relDataKey = relatedPks.map((pk) => directData[pk]).join("_");
552
+ if (relatedPks.length === 0 || !target[relName].some((r) => relatedPks.map((pk) => r[pk]).join("_") === relDataKey)) {
553
+ const newItem = { ...directData };
554
+ if (Object.keys(nestedData).length > 0) {
555
+ attachRelations(newItem, nestedData, relationConfig.foreignTable, []);
556
+ }
557
+ target[relName].push(newItem);
558
+ }
559
+ }
560
+ } else {
561
+ const directData = {};
562
+ const nestedData = {};
563
+ if (typeof relData === "object" && relData !== null) {
564
+ for (const [k, v] of Object.entries(relData)) {
565
+ if (typeof v === "object" && v !== null) {
566
+ nestedData[k] = v;
567
+ } else {
568
+ directData[k] = v;
569
+ }
570
+ }
571
+ }
572
+ const hasData = Object.values(directData).some(
573
+ (v) => v !== null && v !== void 0 && v !== ""
574
+ );
575
+ if (hasData || Object.keys(nestedData).length > 0) {
576
+ target[relName] = { ...directData };
577
+ if (Object.keys(nestedData).length > 0) {
578
+ attachRelations(target[relName], nestedData, relationConfig.foreignTable, []);
579
+ }
580
+ }
374
581
  }
375
- } else {
376
- result[relName] = relData;
377
582
  }
378
- }
583
+ };
584
+ attachRelations(result, relations2, this.table);
379
585
  }
380
586
  return Array.from(groupedResults.values());
381
587
  }
@@ -388,6 +594,82 @@ var SelectQueryBuilder = class extends BaseQueryBuilder {
388
594
  const result = await this.execute();
389
595
  return result[0];
390
596
  }
597
+ toSQL() {
598
+ const { sql: joinSql, params: joinParams } = this.buildJoins();
599
+ const distinct = this.isDistinct ? "DISTINCT " : "";
600
+ const finalQuery = `SELECT ${distinct}${this.selectedColumns.join(", ")} ${this.query}${joinSql}`;
601
+ return {
602
+ sql: finalQuery,
603
+ params: [...this.params, ...joinParams]
604
+ };
605
+ }
606
+ };
607
+
608
+ // src/errors.ts
609
+ var TauriORMError = class extends Error {
610
+ constructor(message) {
611
+ super(message);
612
+ this.name = "TauriORMError";
613
+ if (Error.captureStackTrace) {
614
+ Error.captureStackTrace(this, this.constructor);
615
+ }
616
+ }
617
+ };
618
+ var QueryBuilderError = class extends TauriORMError {
619
+ constructor(message) {
620
+ super(message);
621
+ this.name = "QueryBuilderError";
622
+ }
623
+ };
624
+ var MissingWhereClauseError = class extends QueryBuilderError {
625
+ constructor(operation, tableName) {
626
+ super(
627
+ `${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.`
628
+ );
629
+ this.name = "MissingWhereClauseError";
630
+ }
631
+ };
632
+ var ValidationError = class extends TauriORMError {
633
+ constructor(message) {
634
+ super(message);
635
+ this.name = "ValidationError";
636
+ }
637
+ };
638
+ var InsertValidationError = class extends ValidationError {
639
+ constructor(message) {
640
+ super(message);
641
+ this.name = "InsertValidationError";
642
+ }
643
+ };
644
+ var UpdateValidationError = class extends ValidationError {
645
+ constructor(message) {
646
+ super(message);
647
+ this.name = "UpdateValidationError";
648
+ }
649
+ };
650
+ var MigrationError = class extends TauriORMError {
651
+ constructor(message) {
652
+ super(message);
653
+ this.name = "MigrationError";
654
+ }
655
+ };
656
+ var RelationError = class extends TauriORMError {
657
+ constructor(message) {
658
+ super(message);
659
+ this.name = "RelationError";
660
+ }
661
+ };
662
+ var ColumnNotFoundError = class extends TauriORMError {
663
+ constructor(columnName, tableName) {
664
+ super(`Column "${columnName}" does not exist on table "${tableName}"`);
665
+ this.name = "ColumnNotFoundError";
666
+ }
667
+ };
668
+ var TableNotFoundError = class extends TauriORMError {
669
+ constructor(tableName) {
670
+ super(`Table "${tableName}" not found in schema`);
671
+ this.name = "TableNotFoundError";
672
+ }
391
673
  };
392
674
 
393
675
  // src/builders/update.ts
@@ -399,10 +681,37 @@ var UpdateQueryBuilder = class extends BaseQueryBuilder {
399
681
  }
400
682
  updateData = {};
401
683
  returningColumns = [];
684
+ hasWhereClause = false;
685
+ allowGlobal = false;
686
+ incrementDecrementOps = [];
402
687
  set(data) {
403
688
  this.updateData = { ...this.updateData, ...data };
404
689
  return this;
405
690
  }
691
+ where(condition) {
692
+ this.hasWhereClause = true;
693
+ return super.where(condition);
694
+ }
695
+ increment(column, value = 1) {
696
+ const col = this.table._.columns[column];
697
+ if (!col) {
698
+ throw new ColumnNotFoundError(String(column), this.table._.name);
699
+ }
700
+ this.incrementDecrementOps.push({ column: col._.name, op: "increment", value });
701
+ return this;
702
+ }
703
+ decrement(column, value = 1) {
704
+ const col = this.table._.columns[column];
705
+ if (!col) {
706
+ throw new ColumnNotFoundError(String(column), this.table._.name);
707
+ }
708
+ this.incrementDecrementOps.push({ column: col._.name, op: "decrement", value });
709
+ return this;
710
+ }
711
+ allowGlobalOperation() {
712
+ this.allowGlobal = true;
713
+ return this;
714
+ }
406
715
  returning(...columns) {
407
716
  this.returningColumns.push(...columns);
408
717
  return this;
@@ -425,24 +734,37 @@ var UpdateQueryBuilder = class extends BaseQueryBuilder {
425
734
  whereClause = baseQuery.substring(whereIndex);
426
735
  }
427
736
  const entries = Object.entries(finalUpdateData);
428
- if (entries.length === 0) {
429
- throw new Error("Cannot execute an update query without a .set() call.");
737
+ const hasSetData = entries.length > 0;
738
+ const hasIncrementDecrement = this.incrementDecrementOps.length > 0;
739
+ if (!hasSetData && !hasIncrementDecrement) {
740
+ throw new UpdateValidationError("Cannot execute an update query without a .set(), .increment(), or .decrement() call.");
430
741
  }
431
- const setClause = entries.map(([key]) => {
432
- const column = this.table._.columns[key];
433
- if (!column) {
434
- throw new Error(
435
- `Column ${key} does not exist on table ${this.table._.name}`
436
- );
742
+ const setClauses = [];
743
+ const setParams = [];
744
+ if (hasSetData) {
745
+ for (const [key, value] of entries) {
746
+ const column = this.table._.columns[key];
747
+ if (!column) {
748
+ throw new ColumnNotFoundError(key, this.table._.name);
749
+ }
750
+ setClauses.push(`${column._.name} = ?`);
751
+ setParams.push(value);
437
752
  }
438
- return `${column._.name} = ?`;
439
- }).join(", ");
440
- const setParams = entries.map(([, value]) => value);
753
+ }
754
+ for (const op of this.incrementDecrementOps) {
755
+ const sign = op.op === "increment" ? "+" : "-";
756
+ setClauses.push(`${op.column} = ${op.column} ${sign} ?`);
757
+ setParams.push(op.value);
758
+ }
759
+ const setClause = setClauses.join(", ");
441
760
  const sql2 = `${tablePart} SET ${setClause}${whereClause}`;
442
761
  const params = [...setParams, ...whereParams];
443
762
  return { sql: sql2, params };
444
763
  }
445
764
  async execute() {
765
+ if (!this.hasWhereClause && !this.allowGlobal) {
766
+ throw new MissingWhereClauseError("UPDATE", this.table._.name);
767
+ }
446
768
  const { sql: updateSql, params } = this.buildUpdateClause();
447
769
  if (this.returningColumns.length > 0) {
448
770
  const returningNames = this.returningColumns.map((col) => this.table._.columns[col]._.name).join(", ");
@@ -459,6 +781,17 @@ var UpdateQueryBuilder = class extends BaseQueryBuilder {
459
781
  );
460
782
  return this.returning(...allColumns).execute();
461
783
  }
784
+ toSQL() {
785
+ const { sql: updateSql, params } = this.buildUpdateClause();
786
+ if (this.returningColumns.length > 0) {
787
+ const returningNames = this.returningColumns.map((col) => this.table._.columns[col]._.name).join(", ");
788
+ return {
789
+ sql: `${updateSql} RETURNING ${returningNames}`,
790
+ params
791
+ };
792
+ }
793
+ return { sql: updateSql, params };
794
+ }
462
795
  };
463
796
 
464
797
  // src/builders/insert.ts
@@ -527,7 +860,7 @@ var InsertQueryBuilder = class extends BaseQueryBuilder {
527
860
  }
528
861
  async execute() {
529
862
  if (this.dataSets.length === 0) {
530
- throw new Error("No data provided for insert");
863
+ throw new InsertValidationError("No data provided for insert. Use .values() to provide data.");
531
864
  }
532
865
  const processedDataSets = this.dataSets.map(
533
866
  (data) => this.processDefaultValues(data)
@@ -585,6 +918,42 @@ var InsertQueryBuilder = class extends BaseQueryBuilder {
585
918
  );
586
919
  return this.returning(...allColumns).execute();
587
920
  }
921
+ toSQL() {
922
+ if (this.dataSets.length === 0) {
923
+ throw new InsertValidationError("No data provided for insert. Use .values() to provide data.");
924
+ }
925
+ const processedDataSets = this.dataSets.map(
926
+ (data) => this.processDefaultValues(data)
927
+ );
928
+ const dataSet = processedDataSets[0];
929
+ const columns = Object.keys(dataSet);
930
+ const columnNames = columns.map(
931
+ (key) => this.table._.columns[key]._.name
932
+ );
933
+ const placeholders = `(${columns.map(() => "?").join(", ")})`;
934
+ const valuesSql = processedDataSets.map(() => placeholders).join(", ");
935
+ const conflictClause = this.buildConflictClause();
936
+ const finalQuery = `${this.query} (${columnNames.join(
937
+ ", "
938
+ )}) VALUES ${valuesSql}${conflictClause}`;
939
+ const params = processedDataSets.flatMap(
940
+ (data) => columns.map((col) => data[col] ?? null)
941
+ );
942
+ if (this.onConflictAction === "update") {
943
+ const setValues = Object.entries(this.updateSet).map(
944
+ ([, value]) => value
945
+ );
946
+ params.push(...setValues);
947
+ }
948
+ if (this.returningColumns.length > 0) {
949
+ const returningNames = this.returningColumns.map((col) => this.table._.columns[col]._.name).join(", ");
950
+ return {
951
+ sql: `${finalQuery} RETURNING ${returningNames}`,
952
+ params
953
+ };
954
+ }
955
+ return { sql: finalQuery, params };
956
+ }
588
957
  };
589
958
 
590
959
  // src/builders/delete.ts
@@ -595,11 +964,24 @@ var DeleteQueryBuilder = class extends BaseQueryBuilder {
595
964
  this.query = `DELETE FROM ${table._.name}`;
596
965
  }
597
966
  returningColumns = [];
967
+ hasWhereClause = false;
968
+ allowGlobal = false;
969
+ where(condition) {
970
+ this.hasWhereClause = true;
971
+ return super.where(condition);
972
+ }
973
+ allowGlobalOperation() {
974
+ this.allowGlobal = true;
975
+ return this;
976
+ }
598
977
  returning(...columns) {
599
978
  this.returningColumns.push(...columns);
600
979
  return this;
601
980
  }
602
981
  async execute() {
982
+ if (!this.hasWhereClause && !this.allowGlobal) {
983
+ throw new MissingWhereClauseError("DELETE", this.table._.name);
984
+ }
603
985
  const { sql: sql2, params } = this.build();
604
986
  if (this.returningColumns.length > 0) {
605
987
  const returningNames = this.returningColumns.map((col) => this.table._.columns[col]._.name).join(", ");
@@ -614,6 +996,17 @@ var DeleteQueryBuilder = class extends BaseQueryBuilder {
614
996
  const allColumns = Object.keys(this.table._.columns);
615
997
  return this.returning(...allColumns).execute();
616
998
  }
999
+ toSQL() {
1000
+ const { sql: sql2, params } = this.build();
1001
+ if (this.returningColumns.length > 0) {
1002
+ const returningNames = this.returningColumns.map((col) => this.table._.columns[col]._.name).join(", ");
1003
+ return {
1004
+ sql: `${sql2} RETURNING ${returningNames}`,
1005
+ params
1006
+ };
1007
+ }
1008
+ return { sql: sql2, params };
1009
+ }
617
1010
  };
618
1011
 
619
1012
  // src/builders/with.ts
@@ -995,6 +1388,12 @@ var ManyRelation = class extends Relation {
995
1388
  super(foreignTable);
996
1389
  }
997
1390
  };
1391
+ var ManyToManyRelation = class extends Relation {
1392
+ constructor(foreignTable, config) {
1393
+ super(foreignTable);
1394
+ this.config = config;
1395
+ }
1396
+ };
998
1397
  var relations = (table, relationsCallback) => {
999
1398
  const builtRelations = relationsCallback({
1000
1399
  one: (foreignTable, config) => {
@@ -1002,6 +1401,9 @@ var relations = (table, relationsCallback) => {
1002
1401
  },
1003
1402
  many: (foreignTable) => {
1004
1403
  return new ManyRelation(foreignTable);
1404
+ },
1405
+ manyToMany: (foreignTable, config) => {
1406
+ return new ManyToManyRelation(foreignTable, config);
1005
1407
  }
1006
1408
  });
1007
1409
  for (const [name, relation] of Object.entries(builtRelations)) {
@@ -1017,6 +1419,14 @@ var relations = (table, relationsCallback) => {
1017
1419
  type: "many",
1018
1420
  foreignTable: relation.foreignTable
1019
1421
  };
1422
+ } else if (relation instanceof ManyToManyRelation) {
1423
+ table.relations[name] = {
1424
+ type: "manyToMany",
1425
+ foreignTable: relation.foreignTable,
1426
+ junctionTable: relation.config.junctionTable,
1427
+ junctionFields: relation.config.junctionFields,
1428
+ junctionReferences: relation.config.junctionReferences
1429
+ };
1020
1430
  }
1021
1431
  }
1022
1432
  return builtRelations;
@@ -1028,6 +1438,53 @@ var alias = (table, alias2) => {
1028
1438
  return table;
1029
1439
  };
1030
1440
 
1441
+ // src/aggregates.ts
1442
+ var count = (column) => ({
1443
+ sql: `COUNT(${column ? column._.name : "*"})`,
1444
+ params: []
1445
+ });
1446
+ var countDistinct = (column) => ({
1447
+ sql: `COUNT(DISTINCT ${column._.name})`,
1448
+ params: []
1449
+ });
1450
+ var sum = (column) => ({
1451
+ sql: `SUM(${column._.name})`,
1452
+ params: []
1453
+ });
1454
+ var avg = (column) => ({
1455
+ sql: `AVG(${column._.name})`,
1456
+ params: []
1457
+ });
1458
+ var max = (column) => ({
1459
+ sql: `MAX(${column._.name})`,
1460
+ params: []
1461
+ });
1462
+ var min = (column) => ({
1463
+ sql: `MIN(${column._.name})`,
1464
+ params: []
1465
+ });
1466
+ var groupConcat = (column, separator = ",") => ({
1467
+ sql: `GROUP_CONCAT(${column._.name}, ?)`,
1468
+ params: [separator]
1469
+ });
1470
+ var as = (aggregate, alias2) => ({
1471
+ ...aggregate,
1472
+ alias: alias2
1473
+ });
1474
+
1475
+ // src/subquery.ts
1476
+ var subquery = (query) => {
1477
+ const { sql: sql2, params } = query.toSQL();
1478
+ return {
1479
+ sql: `(${sql2})`,
1480
+ params,
1481
+ _isSubquery: true
1482
+ };
1483
+ };
1484
+ var scalarSubquery = (query) => {
1485
+ return subquery(query);
1486
+ };
1487
+
1031
1488
  // src/column-helpers.ts
1032
1489
  var text = (name, config) => new SQLiteColumn(name, "TEXT", config, config?.mode);
1033
1490
  var integer = (name, config) => new SQLiteColumn(name, "INTEGER", {}, config?.mode || "default");
@@ -1039,47 +1496,77 @@ var enumType = (name, values) => text(name, { enum: values });
1039
1496
  // Annotate the CommonJS export names for ESM import in node:
1040
1497
  0 && (module.exports = {
1041
1498
  BaseQueryBuilder,
1499
+ ColumnNotFoundError,
1042
1500
  DeleteQueryBuilder,
1043
1501
  InsertQueryBuilder,
1502
+ InsertValidationError,
1044
1503
  ManyRelation,
1504
+ ManyToManyRelation,
1505
+ MigrationError,
1506
+ MissingWhereClauseError,
1045
1507
  OneRelation,
1508
+ QueryBuilderError,
1046
1509
  Relation,
1510
+ RelationError,
1047
1511
  SQLiteColumn,
1048
1512
  SelectQueryBuilder,
1049
1513
  Table,
1514
+ TableNotFoundError,
1050
1515
  TauriORM,
1516
+ TauriORMError,
1051
1517
  UpdateQueryBuilder,
1518
+ UpdateValidationError,
1519
+ ValidationError,
1052
1520
  WithQueryBuilder,
1053
1521
  alias,
1054
1522
  and,
1523
+ as,
1055
1524
  asc,
1056
1525
  avg,
1526
+ between,
1057
1527
  blob,
1058
1528
  boolean,
1529
+ contains,
1059
1530
  count,
1060
1531
  countDistinct,
1061
1532
  desc,
1533
+ endsWith,
1062
1534
  enumType,
1063
1535
  eq,
1536
+ eqSubquery,
1537
+ exists,
1064
1538
  getTableColumns,
1539
+ groupConcat,
1065
1540
  gt,
1541
+ gtSubquery,
1066
1542
  gte,
1543
+ gteSubquery,
1544
+ ilike,
1067
1545
  inArray,
1068
1546
  integer,
1069
1547
  isNotNull,
1070
1548
  isNull,
1071
1549
  like,
1072
1550
  lt,
1551
+ ltSubquery,
1073
1552
  lte,
1553
+ lteSubquery,
1074
1554
  max,
1075
1555
  min,
1556
+ ne,
1557
+ neSubquery,
1076
1558
  not,
1559
+ notExists,
1560
+ notIn,
1077
1561
  numeric,
1078
1562
  or,
1079
1563
  real,
1080
1564
  relations,
1565
+ scalarSubquery,
1081
1566
  sql,
1082
1567
  sqliteTable,
1568
+ startsWith,
1569
+ subquery,
1083
1570
  sum,
1084
1571
  text
1085
1572
  });