@type32/tauri-sqlite-orm 0.1.18-8 → 0.1.19

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
@@ -1,113 +1,48 @@
1
- // src/orm.ts
2
- var SQLiteColumn = class _SQLiteColumn {
3
- constructor(name, type, options = {}, mode) {
4
- this.type = type;
5
- this.options = options;
6
- this._ = {
7
- name,
8
- dataType: type,
9
- mode: mode || "default",
10
- notNull: options.notNull ?? false,
11
- hasDefault: options.default !== void 0 || options.$defaultFn !== void 0,
12
- autoincrement: options.autoincrement ?? false
13
- };
14
- }
15
- _;
16
- notNull() {
17
- return new _SQLiteColumn(
18
- this._.name,
19
- this.type,
20
- { ...this.options, notNull: true },
21
- this._.mode
22
- );
23
- }
24
- default(value) {
25
- return new _SQLiteColumn(
26
- this._.name,
27
- this.type,
28
- { ...this.options, default: value },
29
- this._.mode
30
- );
31
- }
32
- $defaultFn(fn) {
33
- return new _SQLiteColumn(
34
- this._.name,
35
- this.type,
36
- { ...this.options, $defaultFn: fn },
37
- this._.mode
38
- );
39
- }
40
- primaryKey() {
41
- return new _SQLiteColumn(
42
- this._.name,
43
- this.type,
44
- { ...this.options, primaryKey: true, notNull: true },
45
- this._.mode
46
- );
47
- }
48
- autoincrement() {
49
- return new _SQLiteColumn(
50
- this._.name,
51
- this.type,
52
- { ...this.options, autoincrement: true },
53
- this._.mode
54
- );
1
+ // src/builders/query-base.ts
2
+ var BaseQueryBuilder = class {
3
+ constructor(db) {
4
+ this.db = db;
55
5
  }
56
- unique() {
57
- return new _SQLiteColumn(
58
- this._.name,
59
- this.type,
60
- { ...this.options, unique: true },
61
- this._.mode
62
- );
6
+ query = "";
7
+ params = [];
8
+ where(condition) {
9
+ this.query += ` WHERE ${condition.sql}`;
10
+ this.params.push(...condition.params);
11
+ return this;
63
12
  }
64
- references(ref, column) {
65
- return new _SQLiteColumn(
66
- this._.name,
67
- this.type,
68
- {
69
- ...this.options,
70
- references: {
71
- table: ref,
72
- column: ref._.columns[column]
73
- }
74
- },
75
- this._.mode
76
- );
13
+ orderBy(column, direction = "ASC") {
14
+ if ("sql" in column) {
15
+ this.query += ` ORDER BY ${column.sql} ${direction}`;
16
+ this.params.push(...column.params);
17
+ } else {
18
+ this.query += ` ORDER BY ${column._.name} ${direction}`;
19
+ }
20
+ return this;
77
21
  }
78
- $onUpdateFn(fn) {
79
- return new _SQLiteColumn(
80
- this._.name,
81
- this.type,
82
- { ...this.options, $onUpdateFn: fn },
83
- this._.mode
84
- );
22
+ limit(count2) {
23
+ this.query += ` LIMIT ${count2}`;
24
+ return this;
85
25
  }
86
- as(alias2) {
26
+ offset(count2) {
27
+ this.query += ` OFFSET ${count2}`;
87
28
  return this;
88
29
  }
89
- };
90
- var text = (name) => new SQLiteColumn(name, "TEXT");
91
- var integer = (name, config) => new SQLiteColumn(name, "INTEGER", {}, config?.mode || "default");
92
- var real = (name) => new SQLiteColumn(name, "REAL");
93
- var blob = (name) => new SQLiteColumn(name, "BLOB");
94
- var boolean = (name) => new SQLiteColumn(name, "BOOLEAN");
95
- var Table = class {
96
- _;
97
- constructor(name, columns) {
98
- this._ = {
99
- name,
100
- columns
30
+ build() {
31
+ return {
32
+ sql: this.query,
33
+ params: this.params
101
34
  };
102
35
  }
103
36
  };
104
- var sqliteTable = (tableName, columns) => {
105
- return new Table(tableName, columns);
37
+
38
+ // src/operators.ts
39
+ var eq = (column, value, tableAlias) => {
40
+ const columnName = tableAlias ? `${tableAlias}.${column._.name}` : column._.name;
41
+ return {
42
+ sql: `${columnName} = ?`,
43
+ params: [value]
44
+ };
106
45
  };
107
- var eq = (column, value) => ({
108
- sql: `${column._.name} = ?`,
109
- params: [value]
110
- });
111
46
  var and = (...conditions) => ({
112
47
  sql: conditions.map((c) => `(${c.sql})`).join(" AND "),
113
48
  params: conditions.flatMap((c) => c.params)
@@ -152,14 +87,6 @@ var inArray = (column, values) => ({
152
87
  sql: `${column._.name} IN (${values.map(() => "?").join(",")})`,
153
88
  params: values
154
89
  });
155
- var asc = (column) => ({
156
- sql: `${column._.name} ASC`,
157
- params: []
158
- });
159
- var desc = (column) => ({
160
- sql: `${column._.name} DESC`,
161
- params: []
162
- });
163
90
  var count = (column) => ({
164
91
  sql: `COUNT(${column ? column._.name : "*"})`,
165
92
  params: []
@@ -184,80 +111,34 @@ var min = (column) => ({
184
111
  sql: `MIN(${column._.name})`,
185
112
  params: []
186
113
  });
187
- var sql = (strings, ...values) => {
188
- const queryParts = [];
189
- const params = [];
190
- strings.forEach((str, i) => {
191
- queryParts.push(str);
192
- if (values[i] !== void 0) {
193
- if (typeof values[i] === "object" && values[i].sql) {
194
- queryParts.push(values[i].sql);
195
- params.push(...values[i].params);
196
- } else {
197
- queryParts.push("?");
198
- params.push(values[i]);
199
- }
200
- }
201
- });
202
- return {
203
- sql: queryParts.join(""),
204
- params
205
- };
206
- };
207
- var BaseQueryBuilder = class {
208
- constructor(db) {
209
- this.db = db;
210
- }
211
- query = "";
212
- params = [];
213
- where(condition) {
214
- this.query += ` WHERE ${condition.sql}`;
215
- this.params.push(...condition.params);
216
- return this;
217
- }
218
- orderBy(column, direction = "ASC") {
219
- if ("sql" in column) {
220
- this.query += ` ORDER BY ${column.sql} ${direction}`;
221
- this.params.push(...column.params);
222
- } else {
223
- this.query += ` ORDER BY ${column._.name} ${direction}`;
224
- }
225
- return this;
226
- }
227
- limit(count2) {
228
- this.query += ` LIMIT ${count2}`;
229
- return this;
230
- }
231
- offset(count2) {
232
- this.query += ` OFFSET ${count2}`;
233
- return this;
234
- }
235
- build() {
236
- return {
237
- sql: this.query,
238
- params: this.params
239
- };
240
- }
241
- };
114
+
115
+ // src/builders/select.ts
242
116
  var SelectQueryBuilder = class extends BaseQueryBuilder {
243
117
  constructor(db, table, columns) {
244
118
  super(db);
245
119
  this.table = table;
246
120
  this.columns = columns;
247
- const columnNames = columns ? columns.map((c) => table._.columns[c]._.name) : ["*"];
248
- this.query = `SELECT ${columnNames.join(", ")} FROM ${table._.name}`;
121
+ this.selectedTableAlias = table._.name;
122
+ const selected = columns ? columns.map((c) => this.table._.columns[c]) : Object.values(this.table._.columns);
123
+ this.selectedColumns = selected.map(
124
+ (col) => `${this.selectedTableAlias}.${col._.name} AS "${this.selectedTableAlias}.${col._.name}"`
125
+ );
126
+ this.query = `FROM ${table._.name} ${this.selectedTableAlias}`;
249
127
  }
250
128
  isDistinct = false;
251
129
  groupByColumns = [];
252
130
  havingCondition = null;
131
+ joins = [];
132
+ includeRelations = {};
133
+ selectedTableAlias;
134
+ selectedColumns = [];
253
135
  distinct() {
254
136
  this.isDistinct = true;
255
- this.query = this.query.replace("SELECT", "SELECT DISTINCT");
256
137
  return this;
257
138
  }
258
139
  groupBy(...columns) {
259
140
  this.groupByColumns.push(...columns);
260
- const columnNames = columns.map((col) => col._.name).join(", ");
141
+ const columnNames = columns.map((col) => `${this.selectedTableAlias}.${col._.name}`).join(", ");
261
142
  this.query += ` GROUP BY ${columnNames}`;
262
143
  return this;
263
144
  }
@@ -267,10 +148,169 @@ var SelectQueryBuilder = class extends BaseQueryBuilder {
267
148
  this.params.push(...condition.params);
268
149
  return this;
269
150
  }
151
+ leftJoin(table, condition, alias2) {
152
+ this.joins.push({ type: "LEFT", table, condition, alias: alias2 });
153
+ const aliasedColumns = Object.values(table._.columns).map(
154
+ (col) => `${alias2}.${col._.name} AS "${alias2}.${col._.name}"`
155
+ );
156
+ this.selectedColumns.push(...aliasedColumns);
157
+ return this;
158
+ }
159
+ innerJoin(table, condition, alias2) {
160
+ this.joins.push({ type: "INNER", table, condition, alias: alias2 });
161
+ const aliasedColumns = Object.values(table._.columns).map(
162
+ (col) => `${alias2}.${col._.name} AS "${alias2}.${col._.name}"`
163
+ );
164
+ this.selectedColumns.push(...aliasedColumns);
165
+ return this;
166
+ }
167
+ include(relations2) {
168
+ this.includeRelations = { ...this.includeRelations, ...relations2 };
169
+ return this;
170
+ }
171
+ buildJoins() {
172
+ let sql2 = "";
173
+ const params = [];
174
+ for (const join of this.joins) {
175
+ sql2 += ` ${join.type} JOIN ${join.table._.name} ${join.alias} ON ${join.condition.sql}`;
176
+ params.push(...join.condition.params);
177
+ }
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;
186
+ }
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
208
+ );
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}`;
214
+ return {
215
+ sql: `${localColumn} = ${foreignColumn}`,
216
+ params: []
217
+ };
218
+ });
219
+ const condition = conditions.length > 1 ? and(...conditions) : conditions[0];
220
+ sql2 += ` LEFT JOIN ${foreignTable._.name} ${foreignAlias} ON ${condition.sql}`;
221
+ params.push(...condition.params);
222
+ }
223
+ }
224
+ }
225
+ return { sql: sql2, params };
226
+ }
227
+ // Enhanced execute method that handles relation data mapping
270
228
  async execute() {
229
+ const { sql: joinSql, params: joinParams } = this.buildJoins();
230
+ const distinct = this.isDistinct ? "DISTINCT " : "";
231
+ this.query = `SELECT ${distinct}${this.selectedColumns.join(", ")} ${this.query}`;
232
+ this.query += joinSql;
233
+ this.params.push(...joinParams);
271
234
  const { sql: sql2, params } = this.build();
272
- return this.db.select(sql2, params);
235
+ console.log("Executing SQL:", sql2, "with params:", params);
236
+ const rawResults = await this.db.select(sql2, params);
237
+ const hasIncludes = Object.values(this.includeRelations).some((i) => i);
238
+ if (hasIncludes) {
239
+ return this.processRelationResults(rawResults);
240
+ }
241
+ const hasJoins = this.joins.length > 0;
242
+ if (hasJoins) {
243
+ return rawResults;
244
+ }
245
+ const prefix = `${this.selectedTableAlias}.`;
246
+ return rawResults.map((row) => {
247
+ const newRow = {};
248
+ for (const key in row) {
249
+ if (key.startsWith(prefix)) {
250
+ newRow[key.substring(prefix.length)] = row[key];
251
+ } else {
252
+ newRow[key] = row[key];
253
+ }
254
+ }
255
+ return newRow;
256
+ });
273
257
  }
258
+ processRelationResults(rawResults) {
259
+ if (!rawResults.length) return [];
260
+ const mainTablePks = Object.values(this.table._.columns).filter((c) => c.options.primaryKey).map((c) => c._.name);
261
+ if (mainTablePks.length === 0) {
262
+ return rawResults;
263
+ }
264
+ const groupedResults = /* @__PURE__ */ new Map();
265
+ for (const row of rawResults) {
266
+ const mainTableKey = mainTablePks.map((pk) => row[`${this.selectedTableAlias}.${pk}`] ?? row[pk]).join("_");
267
+ if (!groupedResults.has(mainTableKey)) {
268
+ groupedResults.set(mainTableKey, {});
269
+ }
270
+ const result = groupedResults.get(mainTableKey);
271
+ const relations2 = {};
272
+ for (const [key, value] of Object.entries(row)) {
273
+ if (key.includes(".")) {
274
+ const [tableAlias, columnName] = key.split(".");
275
+ if (tableAlias === this.selectedTableAlias) {
276
+ result[columnName] = value;
277
+ } 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;
283
+ } else {
284
+ if (!result[tableAlias]) result[tableAlias] = {};
285
+ result[tableAlias][columnName] = value;
286
+ }
287
+ }
288
+ } else {
289
+ result[key] = value;
290
+ }
291
+ }
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);
305
+ }
306
+ } else {
307
+ result[relName] = relData;
308
+ }
309
+ }
310
+ }
311
+ return Array.from(groupedResults.values());
312
+ }
313
+ // Update the return type signatures
274
314
  async all() {
275
315
  return this.execute();
276
316
  }
@@ -280,6 +320,79 @@ var SelectQueryBuilder = class extends BaseQueryBuilder {
280
320
  return result[0];
281
321
  }
282
322
  };
323
+
324
+ // src/builders/update.ts
325
+ var UpdateQueryBuilder = class extends BaseQueryBuilder {
326
+ constructor(db, table) {
327
+ super(db);
328
+ this.table = table;
329
+ this.query = `UPDATE ${table._.name}`;
330
+ }
331
+ updateData = {};
332
+ returningColumns = [];
333
+ set(data) {
334
+ this.updateData = { ...this.updateData, ...data };
335
+ return this;
336
+ }
337
+ returning(...columns) {
338
+ this.returningColumns.push(...columns);
339
+ return this;
340
+ }
341
+ buildUpdateClause() {
342
+ const finalUpdateData = { ...this.updateData };
343
+ for (const [key, column] of Object.entries(this.table._.columns)) {
344
+ const typedKey = key;
345
+ if (finalUpdateData[typedKey] === void 0 && column.options.$onUpdateFn) {
346
+ finalUpdateData[typedKey] = column.options.$onUpdateFn();
347
+ }
348
+ }
349
+ const baseQuery = this.query;
350
+ const whereParams = this.params;
351
+ let tablePart = baseQuery;
352
+ let whereClause = "";
353
+ const whereIndex = baseQuery.indexOf(" WHERE ");
354
+ if (whereIndex !== -1) {
355
+ tablePart = baseQuery.substring(0, whereIndex);
356
+ whereClause = baseQuery.substring(whereIndex);
357
+ }
358
+ 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
+ );
368
+ }
369
+ return `${column._.name} = ?`;
370
+ }).join(", ");
371
+ const setParams = entries.map(([, value]) => value);
372
+ const sql2 = `${tablePart} SET ${setClause}${whereClause}`;
373
+ const params = [...setParams, ...whereParams];
374
+ return { sql: sql2, params };
375
+ }
376
+ async execute() {
377
+ const { sql: updateSql, params } = this.buildUpdateClause();
378
+ if (this.returningColumns.length > 0) {
379
+ const returningNames = this.returningColumns.map((col) => this.table._.columns[col]._.name).join(", ");
380
+ const sqlWithReturning = `${updateSql} RETURNING ${returningNames}`;
381
+ return this.db.select(sqlWithReturning, params);
382
+ } else {
383
+ const result = await this.db.execute(updateSql, params);
384
+ return [{ rowsAffected: result.rowsAffected }];
385
+ }
386
+ }
387
+ async returningAll() {
388
+ const allColumns = Object.keys(
389
+ this.table._.columns
390
+ );
391
+ return this.returning(...allColumns).execute();
392
+ }
393
+ };
394
+
395
+ // src/builders/insert.ts
283
396
  var InsertQueryBuilder = class extends BaseQueryBuilder {
284
397
  constructor(db, table) {
285
398
  super(db);
@@ -297,7 +410,7 @@ var InsertQueryBuilder = class extends BaseQueryBuilder {
297
410
  return this;
298
411
  }
299
412
  returning(...columns) {
300
- this.returningColumns = columns;
413
+ this.returningColumns.push(...columns);
301
414
  return this;
302
415
  }
303
416
  onConflictDoNothing(target) {
@@ -404,75 +517,8 @@ var InsertQueryBuilder = class extends BaseQueryBuilder {
404
517
  return this.returning(...allColumns).execute();
405
518
  }
406
519
  };
407
- var UpdateQueryBuilder = class extends BaseQueryBuilder {
408
- constructor(db, table) {
409
- super(db);
410
- this.table = table;
411
- this.query = `UPDATE ${table._.name}`;
412
- }
413
- updateData = {};
414
- returningColumns = [];
415
- set(data) {
416
- this.updateData = { ...this.updateData, ...data };
417
- return this;
418
- }
419
- returning(...columns) {
420
- this.returningColumns = columns;
421
- return this;
422
- }
423
- buildUpdateClause() {
424
- const finalUpdateData = { ...this.updateData };
425
- for (const [key, column] of Object.entries(this.table._.columns)) {
426
- const typedKey = key;
427
- if (finalUpdateData[typedKey] === void 0 && column.options.$onUpdateFn) {
428
- finalUpdateData[typedKey] = column.options.$onUpdateFn();
429
- }
430
- }
431
- const baseQuery = this.query;
432
- const whereParams = this.params;
433
- let tablePart = baseQuery;
434
- let whereClause = "";
435
- const whereIndex = baseQuery.indexOf(" WHERE ");
436
- if (whereIndex !== -1) {
437
- tablePart = baseQuery.substring(0, whereIndex);
438
- whereClause = baseQuery.substring(whereIndex);
439
- }
440
- const entries = Object.entries(finalUpdateData);
441
- if (entries.length === 0) {
442
- throw new Error("Cannot execute an update query without a .set() call.");
443
- }
444
- const setClause = entries.map(([key]) => {
445
- const column = this.table._.columns[key];
446
- if (!column) {
447
- throw new Error(
448
- `Column ${key} does not exist on table ${this.table._.name}`
449
- );
450
- }
451
- return `${column._.name} = ?`;
452
- }).join(", ");
453
- const setParams = entries.map(([, value]) => value);
454
- const sql2 = `${tablePart} SET ${setClause}${whereClause}`;
455
- const params = [...setParams, ...whereParams];
456
- return { sql: sql2, params };
457
- }
458
- async execute() {
459
- const { sql: updateSql, params } = this.buildUpdateClause();
460
- if (this.returningColumns.length > 0) {
461
- const returningNames = this.returningColumns.map((col) => this.table._.columns[col]._.name).join(", ");
462
- const sqlWithReturning = `${updateSql} RETURNING ${returningNames}`;
463
- return this.db.select(sqlWithReturning, params);
464
- } else {
465
- const result = await this.db.execute(updateSql, params);
466
- return [{ rowsAffected: result.rowsAffected }];
467
- }
468
- }
469
- async returningAll() {
470
- const allColumns = Object.keys(
471
- this.table._.columns
472
- );
473
- return this.returning(...allColumns).execute();
474
- }
475
- };
520
+
521
+ // src/builders/delete.ts
476
522
  var DeleteQueryBuilder = class extends BaseQueryBuilder {
477
523
  constructor(db, table) {
478
524
  super(db);
@@ -481,7 +527,7 @@ var DeleteQueryBuilder = class extends BaseQueryBuilder {
481
527
  }
482
528
  returningColumns = [];
483
529
  returning(...columns) {
484
- this.returningColumns = columns;
530
+ this.returningColumns.push(...columns);
485
531
  return this;
486
532
  }
487
533
  async execute() {
@@ -496,12 +542,12 @@ var DeleteQueryBuilder = class extends BaseQueryBuilder {
496
542
  }
497
543
  }
498
544
  async returningAll() {
499
- const allColumns = Object.keys(
500
- this.table._.columns
501
- );
545
+ const allColumns = Object.keys(this.table._.columns);
502
546
  return this.returning(...allColumns).execute();
503
547
  }
504
548
  };
549
+
550
+ // src/builders/with.ts
505
551
  var WithQueryBuilder = class {
506
552
  constructor(db) {
507
553
  this.db = db;
@@ -542,13 +588,119 @@ var WithQueryBuilder = class {
542
588
  }
543
589
  }
544
590
  };
591
+
592
+ // src/orm.ts
593
+ var SQLiteColumn = class _SQLiteColumn {
594
+ constructor(name, type, options = {}, mode) {
595
+ this.type = type;
596
+ this.options = options;
597
+ this._ = {
598
+ name,
599
+ dataType: type,
600
+ mode: mode || "default",
601
+ notNull: options.notNull ?? false,
602
+ hasDefault: options.default !== void 0 || options.$defaultFn !== void 0,
603
+ autoincrement: options.autoincrement ?? false,
604
+ enum: options.enum,
605
+ customType: void 0
606
+ };
607
+ }
608
+ _;
609
+ notNull() {
610
+ return new _SQLiteColumn(this._.name, this.type, { ...this.options, notNull: true }, this._.mode);
611
+ }
612
+ default(value) {
613
+ return new _SQLiteColumn(this._.name, this.type, { ...this.options, default: value }, this._.mode);
614
+ }
615
+ $defaultFn(fn) {
616
+ return new _SQLiteColumn(this._.name, this.type, { ...this.options, $defaultFn: fn }, this._.mode);
617
+ }
618
+ primaryKey() {
619
+ return new _SQLiteColumn(
620
+ this._.name,
621
+ this.type,
622
+ { ...this.options, primaryKey: true, notNull: true },
623
+ this._.mode
624
+ );
625
+ }
626
+ autoincrement() {
627
+ return new _SQLiteColumn(this._.name, this.type, { ...this.options, autoincrement: true }, this._.mode);
628
+ }
629
+ unique() {
630
+ return new _SQLiteColumn(this._.name, this.type, { ...this.options, unique: true }, this._.mode);
631
+ }
632
+ references(ref, column) {
633
+ return new _SQLiteColumn(
634
+ this._.name,
635
+ this.type,
636
+ {
637
+ ...this.options,
638
+ references: {
639
+ table: ref,
640
+ column: ref._.columns[column]
641
+ }
642
+ },
643
+ this._.mode
644
+ );
645
+ }
646
+ $onUpdateFn(fn) {
647
+ return new _SQLiteColumn(this._.name, this.type, { ...this.options, $onUpdateFn: fn }, this._.mode);
648
+ }
649
+ $type() {
650
+ return this;
651
+ }
652
+ as(alias2) {
653
+ return this;
654
+ }
655
+ };
656
+ var Table = class {
657
+ _;
658
+ relations = {};
659
+ constructor(name, columns) {
660
+ this._ = {
661
+ name,
662
+ columns
663
+ };
664
+ }
665
+ };
666
+ var sqliteTable = (tableName, columns) => {
667
+ return new Table(tableName, columns);
668
+ };
669
+ var asc = (column) => ({
670
+ sql: `${column._.name} ASC`,
671
+ params: []
672
+ });
673
+ var desc = (column) => ({
674
+ sql: `${column._.name} DESC`,
675
+ params: []
676
+ });
677
+ var sql = (strings, ...values) => {
678
+ const queryParts = [];
679
+ const params = [];
680
+ strings.forEach((str, i) => {
681
+ queryParts.push(str);
682
+ if (values[i] !== void 0) {
683
+ if (typeof values[i] === "object" && values[i].sql) {
684
+ queryParts.push(values[i].sql);
685
+ params.push(...values[i].params);
686
+ } else {
687
+ queryParts.push("?");
688
+ params.push(values[i]);
689
+ }
690
+ }
691
+ });
692
+ return {
693
+ sql: queryParts.join(""),
694
+ params
695
+ };
696
+ };
545
697
  var TauriORM = class {
546
698
  constructor(db, schema = void 0) {
547
699
  this.db = db;
548
700
  if (schema) {
549
- for (const table of Object.values(schema)) {
550
- if (table instanceof Table) {
551
- this.tables.set(table._.name, table);
701
+ for (const [key, value] of Object.entries(schema)) {
702
+ if (value instanceof Table) {
703
+ this.tables.set(value._.name, value);
552
704
  }
553
705
  }
554
706
  }
@@ -573,31 +725,60 @@ var TauriORM = class {
573
725
  }
574
726
  return sql2;
575
727
  }
576
- async migrate() {
728
+ async migrate(options) {
729
+ const dbTables = await this.db.select(
730
+ `SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'`
731
+ );
732
+ const dbTableNames = new Set(dbTables.map((t) => t.name));
733
+ const schemaTableNames = new Set(Array.from(this.tables.keys()));
577
734
  for (const table of this.tables.values()) {
578
- const existingTableInfo = await this.db.select(
579
- `PRAGMA table_info('${table._.name}')`
580
- );
581
- if (existingTableInfo.length === 0) {
735
+ const tableName = table._.name;
736
+ const tableExists = dbTableNames.has(tableName);
737
+ if (!tableExists) {
582
738
  const columnsSql = Object.values(table._.columns).map((col) => this.buildColumnDefinition(col)).join(", ");
583
- const createSql = `CREATE TABLE ${table._.name} (${columnsSql})`;
739
+ const createSql = `CREATE TABLE ${tableName}
740
+ (
741
+ ${columnsSql}
742
+ )`;
584
743
  await this.db.execute(createSql);
585
744
  } else {
586
- const existingColumnNames = new Set(
587
- existingTableInfo.map((c) => c.name)
588
- );
745
+ const existingTableInfo = await this.db.select(`PRAGMA table_info('${tableName}')`);
746
+ const existingColumnNames = new Set(existingTableInfo.map((c) => c.name));
747
+ const schemaColumnNames = new Set(Object.keys(table._.columns));
589
748
  for (const column of Object.values(table._.columns)) {
590
749
  if (!existingColumnNames.has(column._.name)) {
591
750
  const columnSql = this.buildColumnDefinition(column, true);
592
- const alterSql = `ALTER TABLE ${table._.name} ADD COLUMN ${columnSql}`;
751
+ const alterSql = `ALTER TABLE ${tableName}
752
+ ADD COLUMN ${columnSql}`;
593
753
  await this.db.execute(alterSql);
594
754
  }
595
755
  }
756
+ if (options?.performDestructiveActions) {
757
+ for (const colName of existingColumnNames) {
758
+ if (!schemaColumnNames.has(colName)) {
759
+ await this.dropColumn(tableName, colName);
760
+ }
761
+ }
762
+ }
763
+ }
764
+ }
765
+ if (options?.performDestructiveActions) {
766
+ for (const tableName of dbTableNames) {
767
+ if (!schemaTableNames.has(tableName)) {
768
+ await this.dropTable(tableName);
769
+ }
596
770
  }
597
771
  }
598
772
  }
599
773
  select(table, columns) {
600
- return new SelectQueryBuilder(this.db, table, columns);
774
+ const internalTable = this.tables.get(table._.name);
775
+ if (!internalTable) {
776
+ console.warn(
777
+ `[Tauri-ORM] Table "${table._.name}" was not passed in the schema to the ORM constructor. Relations will not be available.`
778
+ );
779
+ return new SelectQueryBuilder(this.db, table, columns);
780
+ }
781
+ return new SelectQueryBuilder(this.db, internalTable, columns);
601
782
  }
602
783
  insert(table) {
603
784
  return new InsertQueryBuilder(this.db, table);
@@ -634,13 +815,25 @@ var TauriORM = class {
634
815
  // --- Schema detection / signature ---
635
816
  async ensureSchemaMeta() {
636
817
  await this.db.execute(
637
- `CREATE TABLE IF NOT EXISTS _schema_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)`
818
+ `CREATE TABLE IF NOT EXISTS _schema_meta
819
+ (
820
+ key
821
+ TEXT
822
+ PRIMARY
823
+ KEY,
824
+ value
825
+ TEXT
826
+ NOT
827
+ NULL
828
+ )`
638
829
  );
639
830
  }
640
831
  async getSchemaMeta(key) {
641
832
  await this.ensureSchemaMeta();
642
833
  const rows = await this.db.select(
643
- `SELECT value FROM _schema_meta WHERE key = ?`,
834
+ `SELECT value
835
+ FROM _schema_meta
836
+ WHERE key = ?`,
644
837
  [key]
645
838
  );
646
839
  return rows?.[0]?.value ?? null;
@@ -648,7 +841,10 @@ var TauriORM = class {
648
841
  async setSchemaMeta(key, value) {
649
842
  await this.ensureSchemaMeta();
650
843
  await this.db.execute(
651
- `INSERT INTO _schema_meta(key, value) VALUES(?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value`,
844
+ `INSERT INTO _schema_meta(key, value)
845
+ VALUES (?, ?) ON CONFLICT(key) DO
846
+ UPDATE
847
+ SET value = excluded.value`,
652
848
  [key, value]
653
849
  );
654
850
  }
@@ -685,14 +881,34 @@ var TauriORM = class {
685
881
  const status = await this.isSchemaDirty();
686
882
  if (status.dirty) {
687
883
  await this.migrate();
688
- await this.setSchemaMeta(
689
- "schema_signature",
690
- this.computeModelSignature()
691
- );
884
+ await this.setSchemaMeta("schema_signature", this.computeModelSignature());
692
885
  return true;
693
886
  }
694
887
  return false;
695
888
  }
889
+ async doesTableExist(tableName) {
890
+ const result = await this.db.select(
891
+ `SELECT name FROM sqlite_master WHERE type='table' AND name=?`,
892
+ [tableName]
893
+ );
894
+ return result.length > 0;
895
+ }
896
+ async dropTable(tableName) {
897
+ await this.db.execute(`DROP TABLE IF EXISTS ${tableName}`);
898
+ }
899
+ async doesColumnExist(tableName, columnName) {
900
+ const result = await this.db.select(`PRAGMA table_info('${tableName}')`);
901
+ return result.some((col) => col.name === columnName);
902
+ }
903
+ async renameTable(from, to) {
904
+ await this.db.execute(`ALTER TABLE ${from} RENAME TO ${to}`);
905
+ }
906
+ async dropColumn(tableName, columnName) {
907
+ await this.db.execute(`ALTER TABLE ${tableName} DROP COLUMN ${columnName}`);
908
+ }
909
+ async renameColumn(tableName, from, to) {
910
+ await this.db.execute(`ALTER TABLE ${tableName} RENAME COLUMN ${from} TO ${to}`);
911
+ }
696
912
  };
697
913
  var Relation = class {
698
914
  constructor(foreignTable) {
@@ -710,15 +926,31 @@ var ManyRelation = class extends Relation {
710
926
  super(foreignTable);
711
927
  }
712
928
  };
713
- var relations = (_table, relationsCallback) => {
714
- return relationsCallback({
715
- one: (table, config) => {
716
- return new OneRelation(table, config);
929
+ var relations = (table, relationsCallback) => {
930
+ const builtRelations = relationsCallback({
931
+ one: (foreignTable, config) => {
932
+ return new OneRelation(foreignTable, config);
717
933
  },
718
- many: (table) => {
719
- return new ManyRelation(table);
934
+ many: (foreignTable) => {
935
+ return new ManyRelation(foreignTable);
720
936
  }
721
937
  });
938
+ for (const [name, relation] of Object.entries(builtRelations)) {
939
+ if (relation instanceof OneRelation) {
940
+ table.relations[name] = {
941
+ type: "one",
942
+ foreignTable: relation.foreignTable,
943
+ fields: relation.config?.fields,
944
+ references: relation.config?.references
945
+ };
946
+ } else if (relation instanceof ManyRelation) {
947
+ table.relations[name] = {
948
+ type: "many",
949
+ foreignTable: relation.foreignTable
950
+ };
951
+ }
952
+ }
953
+ return builtRelations;
722
954
  };
723
955
  var getTableColumns = (table) => {
724
956
  return table._.columns;
@@ -726,7 +958,17 @@ var getTableColumns = (table) => {
726
958
  var alias = (table, alias2) => {
727
959
  return table;
728
960
  };
961
+
962
+ // src/column-helpers.ts
963
+ var text = (name, config) => new SQLiteColumn(name, "TEXT", config, config?.mode);
964
+ var integer = (name, config) => new SQLiteColumn(name, "INTEGER", {}, config?.mode || "default");
965
+ var real = (name) => new SQLiteColumn(name, "REAL");
966
+ var blob = (name, config) => new SQLiteColumn(name, "BLOB", {}, config?.mode);
967
+ var boolean = (name) => new SQLiteColumn(name, "BOOLEAN");
968
+ var numeric = (name, config) => new SQLiteColumn(name, "NUMERIC", {}, config?.mode);
969
+ var enumType = (name, values) => text(name, { enum: values });
729
970
  export {
971
+ BaseQueryBuilder,
730
972
  DeleteQueryBuilder,
731
973
  InsertQueryBuilder,
732
974
  ManyRelation,
@@ -747,6 +989,7 @@ export {
747
989
  count,
748
990
  countDistinct,
749
991
  desc,
992
+ enumType,
750
993
  eq,
751
994
  getTableColumns,
752
995
  gt,
@@ -761,6 +1004,7 @@ export {
761
1004
  max,
762
1005
  min,
763
1006
  not,
1007
+ numeric,
764
1008
  or,
765
1009
  real,
766
1010
  relations,