@type32/tauri-sqlite-orm 0.1.18-9 → 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,126 +1,48 @@
1
- // src/schema.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
- table: void 0
14
- };
15
- }
16
- _;
17
- notNull() {
18
- return new _SQLiteColumn(
19
- this._.name,
20
- this.type,
21
- { ...this.options, notNull: true },
22
- this._.mode
23
- );
24
- }
25
- default(value) {
26
- return new _SQLiteColumn(
27
- this._.name,
28
- this.type,
29
- { ...this.options, default: value },
30
- this._.mode
31
- );
32
- }
33
- $defaultFn(fn) {
34
- return new _SQLiteColumn(
35
- this._.name,
36
- this.type,
37
- { ...this.options, $defaultFn: fn },
38
- this._.mode
39
- );
40
- }
41
- primaryKey() {
42
- return new _SQLiteColumn(
43
- this._.name,
44
- this.type,
45
- { ...this.options, primaryKey: true, notNull: true },
46
- this._.mode
47
- );
48
- }
49
- autoincrement() {
50
- return new _SQLiteColumn(
51
- this._.name,
52
- this.type,
53
- { ...this.options, autoincrement: true },
54
- this._.mode
55
- );
1
+ // src/builders/query-base.ts
2
+ var BaseQueryBuilder = class {
3
+ constructor(db) {
4
+ this.db = db;
56
5
  }
57
- unique() {
58
- return new _SQLiteColumn(
59
- this._.name,
60
- this.type,
61
- { ...this.options, unique: true },
62
- this._.mode
63
- );
6
+ query = "";
7
+ params = [];
8
+ where(condition) {
9
+ this.query += ` WHERE ${condition.sql}`;
10
+ this.params.push(...condition.params);
11
+ return this;
64
12
  }
65
- references(ref, column) {
66
- return new _SQLiteColumn(
67
- this._.name,
68
- this.type,
69
- {
70
- ...this.options,
71
- references: {
72
- table: ref,
73
- column: ref._.columns[column]
74
- }
75
- },
76
- this._.mode
77
- );
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;
78
21
  }
79
- $onUpdateFn(fn) {
80
- return new _SQLiteColumn(
81
- this._.name,
82
- this.type,
83
- { ...this.options, $onUpdateFn: fn },
84
- this._.mode
85
- );
22
+ limit(count2) {
23
+ this.query += ` LIMIT ${count2}`;
24
+ return this;
86
25
  }
87
- as(alias2) {
26
+ offset(count2) {
27
+ this.query += ` OFFSET ${count2}`;
88
28
  return this;
89
29
  }
90
- };
91
- var text = (name) => new SQLiteColumn(name, "TEXT");
92
- var integer = (name, config) => new SQLiteColumn(name, "INTEGER", {}, config?.mode || "default");
93
- var real = (name) => new SQLiteColumn(name, "REAL");
94
- var blob = (name) => new SQLiteColumn(name, "BLOB");
95
- var boolean = (name) => new SQLiteColumn(name, "BOOLEAN");
96
- var Table = class {
97
- _;
98
- constructor(name, columns) {
99
- this._ = {
100
- name,
101
- columns
30
+ build() {
31
+ return {
32
+ sql: this.query,
33
+ params: this.params
102
34
  };
103
35
  }
104
36
  };
105
- var sqliteTable = (tableName, columns) => {
106
- const table = new Table(tableName, columns);
107
- for (const col of Object.values(columns)) {
108
- col._.table = table;
109
- }
110
- return table;
111
- };
112
- var getTableColumns = (table) => {
113
- return table._.columns;
114
- };
115
- var alias = (table, alias2) => {
116
- return table;
117
- };
118
37
 
119
- // src/query-builder.ts
120
- var eq = (column, value) => ({
121
- sql: `${column._.name} = ?`,
122
- params: [value]
123
- });
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
+ };
45
+ };
124
46
  var and = (...conditions) => ({
125
47
  sql: conditions.map((c) => `(${c.sql})`).join(" AND "),
126
48
  params: conditions.flatMap((c) => c.params)
@@ -165,14 +87,6 @@ var inArray = (column, values) => ({
165
87
  sql: `${column._.name} IN (${values.map(() => "?").join(",")})`,
166
88
  params: values
167
89
  });
168
- var asc = (column) => ({
169
- sql: `${column._.name} ASC`,
170
- params: []
171
- });
172
- var desc = (column) => ({
173
- sql: `${column._.name} DESC`,
174
- params: []
175
- });
176
90
  var count = (column) => ({
177
91
  sql: `COUNT(${column ? column._.name : "*"})`,
178
92
  params: []
@@ -197,170 +111,206 @@ var min = (column) => ({
197
111
  sql: `MIN(${column._.name})`,
198
112
  params: []
199
113
  });
200
- var sql = (strings, ...values) => {
201
- const queryParts = [];
202
- const params = [];
203
- strings.forEach((str, i) => {
204
- queryParts.push(str);
205
- if (values[i] !== void 0) {
206
- if (typeof values[i] === "object" && values[i].sql) {
207
- queryParts.push(values[i].sql);
208
- params.push(...values[i].params);
209
- } else {
210
- queryParts.push("?");
211
- params.push(values[i]);
212
- }
213
- }
214
- });
215
- return {
216
- sql: queryParts.join(""),
217
- params
218
- };
219
- };
220
- var BaseQueryBuilder = class {
221
- constructor(db) {
222
- this.db = db;
223
- }
224
- query = "";
225
- params = [];
226
- build() {
227
- return {
228
- sql: this.query,
229
- params: this.params
230
- };
231
- }
232
- };
114
+
115
+ // src/builders/select.ts
233
116
  var SelectQueryBuilder = class extends BaseQueryBuilder {
234
- constructor(db, table, selection) {
117
+ constructor(db, table, columns) {
235
118
  super(db);
236
- this.selection = selection;
237
- this.fromTable = table;
238
- this.query = "";
239
- this.params = [];
119
+ this.table = table;
120
+ this.columns = columns;
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}`;
240
127
  }
241
128
  isDistinct = false;
242
129
  groupByColumns = [];
243
- havingCondition;
244
- joinClauses = [];
245
- fromTable;
246
- orderByClauses = [];
247
- limitCount;
248
- offsetCount;
249
- whereCondition;
250
- where(condition) {
251
- this.whereCondition = condition;
252
- return this;
253
- }
254
- leftJoin(table, on) {
255
- this.joinClauses.push({ type: "LEFT JOIN", table, on });
256
- return this;
257
- }
258
- innerJoin(table, on) {
259
- this.joinClauses.push({ type: "INNER JOIN", table, on });
260
- return this;
261
- }
262
- rightJoin(table, on) {
263
- this.joinClauses.push({ type: "RIGHT JOIN", table, on });
264
- return this;
265
- }
266
- fullJoin(table, on) {
267
- this.joinClauses.push({ type: "FULL JOIN", table, on });
268
- return this;
269
- }
130
+ havingCondition = null;
131
+ joins = [];
132
+ includeRelations = {};
133
+ selectedTableAlias;
134
+ selectedColumns = [];
270
135
  distinct() {
271
136
  this.isDistinct = true;
272
137
  return this;
273
138
  }
274
139
  groupBy(...columns) {
275
140
  this.groupByColumns.push(...columns);
141
+ const columnNames = columns.map((col) => `${this.selectedTableAlias}.${col._.name}`).join(", ");
142
+ this.query += ` GROUP BY ${columnNames}`;
276
143
  return this;
277
144
  }
278
145
  having(condition) {
279
146
  this.havingCondition = condition;
147
+ this.query += ` HAVING ${condition.sql}`;
148
+ this.params.push(...condition.params);
280
149
  return this;
281
150
  }
282
- orderBy(column, direction = "ASC") {
283
- if ("sql" in column) {
284
- this.orderByClauses.push({
285
- sql: `${column.sql} ${direction}`,
286
- params: column.params
287
- });
288
- } else {
289
- this.orderByClauses.push({
290
- sql: `${column._.name} ${direction}`,
291
- params: []
292
- });
293
- }
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);
294
157
  return this;
295
158
  }
296
- limit(count2) {
297
- this.limitCount = count2;
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);
298
165
  return this;
299
166
  }
300
- offset(count2) {
301
- this.offsetCount = count2;
167
+ include(relations2) {
168
+ this.includeRelations = { ...this.includeRelations, ...relations2 };
302
169
  return this;
303
170
  }
304
- buildSelectQuery() {
305
- const selectionEntries = this.selection ? Object.entries(this.selection) : [];
306
- let columnsClause;
307
- const selectParams = [];
308
- if (selectionEntries.length === 0) {
309
- columnsClause = "*";
310
- } else {
311
- columnsClause = selectionEntries.map(([alias2, col]) => {
312
- if (col instanceof SQLiteColumn) {
313
- return `${col._.table._.name}.${col._.name} AS "${alias2}"`;
314
- } else {
315
- selectParams.push(...col.params);
316
- return `(${col.sql}) AS "${alias2}"`;
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);
317
222
  }
318
- }).join(", ");
319
- }
320
- let query = `SELECT ${this.isDistinct ? "DISTINCT " : ""}${columnsClause} FROM ${this.fromTable._.name}`;
321
- const queryParams = [...selectParams];
322
- if (this.joinClauses.length > 0) {
323
- const joins = this.joinClauses.map((j) => {
324
- queryParams.push(...j.on.params);
325
- return `${j.type} ${j.table._.name} ON ${j.on.sql}`;
326
- });
327
- query += ` ${joins.join(" ")}`;
328
- }
329
- if (this.whereCondition) {
330
- query += ` WHERE ${this.whereCondition.sql}`;
331
- queryParams.push(...this.whereCondition.params);
332
- }
333
- if (this.groupByColumns.length > 0) {
334
- const columnNames = this.groupByColumns.map((c) => c._.name).join(", ");
335
- query += ` GROUP BY ${columnNames}`;
336
- }
337
- if (this.havingCondition) {
338
- query += ` HAVING ${this.havingCondition.sql}`;
339
- queryParams.push(...this.havingCondition.params);
340
- }
341
- if (this.orderByClauses.length > 0) {
342
- const orderBySql = this.orderByClauses.map((c) => c.sql).join(", ");
343
- query += ` ORDER BY ${orderBySql}`;
344
- queryParams.push(...this.orderByClauses.flatMap((c) => c.params));
345
- }
346
- if (this.limitCount !== void 0) {
347
- query += ` LIMIT ${this.limitCount}`;
348
- }
349
- if (this.offsetCount !== void 0) {
350
- query += ` OFFSET ${this.offsetCount}`;
223
+ }
351
224
  }
352
- return {
353
- sql: query,
354
- params: queryParams
355
- };
356
- }
357
- build() {
358
- return this.buildSelectQuery();
225
+ return { sql: sql2, params };
359
226
  }
227
+ // Enhanced execute method that handles relation data mapping
360
228
  async execute() {
361
- const { sql: sql2, params } = this.buildSelectQuery();
362
- return this.db.select(sql2, params);
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);
234
+ const { sql: sql2, params } = this.build();
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
+ });
363
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
364
314
  async all() {
365
315
  return this.execute();
366
316
  }
@@ -370,19 +320,79 @@ var SelectQueryBuilder = class extends BaseQueryBuilder {
370
320
  return result[0];
371
321
  }
372
322
  };
373
- var SelectBuilder = class {
374
- constructor(db, selection) {
375
- this.db = db;
376
- this.selection = selection;
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;
377
340
  }
378
- from(table) {
379
- return new SelectQueryBuilder(
380
- this.db,
381
- table,
382
- this.selection
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
383
390
  );
391
+ return this.returning(...allColumns).execute();
384
392
  }
385
393
  };
394
+
395
+ // src/builders/insert.ts
386
396
  var InsertQueryBuilder = class extends BaseQueryBuilder {
387
397
  constructor(db, table) {
388
398
  super(db);
@@ -400,13 +410,7 @@ var InsertQueryBuilder = class extends BaseQueryBuilder {
400
410
  return this;
401
411
  }
402
412
  returning(...columns) {
403
- for (const col of columns) {
404
- if (typeof col === "string") {
405
- this.returningColumns.push(this.table._.columns[col]);
406
- } else {
407
- this.returningColumns.push(col);
408
- }
409
- }
413
+ this.returningColumns.push(...columns);
410
414
  return this;
411
415
  }
412
416
  onConflictDoNothing(target) {
@@ -491,7 +495,7 @@ var InsertQueryBuilder = class extends BaseQueryBuilder {
491
495
  params.push(...setValues);
492
496
  }
493
497
  if (this.returningColumns.length > 0) {
494
- const returningNames = this.returningColumns.map((col) => col._.name).join(", ");
498
+ const returningNames = this.returningColumns.map((col) => this.table._.columns[col]._.name).join(", ");
495
499
  const queryWithReturning = `${finalQuery} RETURNING ${returningNames}`;
496
500
  const rows = await this.db.select(queryWithReturning, params);
497
501
  results = results.concat(rows);
@@ -513,81 +517,8 @@ var InsertQueryBuilder = class extends BaseQueryBuilder {
513
517
  return this.returning(...allColumns).execute();
514
518
  }
515
519
  };
516
- var UpdateQueryBuilder = class extends BaseQueryBuilder {
517
- constructor(db, table) {
518
- super(db);
519
- this.table = table;
520
- this.query = `UPDATE ${table._.name}`;
521
- }
522
- updateData = {};
523
- returningColumns = [];
524
- set(data) {
525
- this.updateData = { ...this.updateData, ...data };
526
- return this;
527
- }
528
- returning(...columns) {
529
- for (const col of columns) {
530
- if (typeof col === "string") {
531
- this.returningColumns.push(this.table._.columns[col]);
532
- } else {
533
- this.returningColumns.push(col);
534
- }
535
- }
536
- return this;
537
- }
538
- buildUpdateClause() {
539
- const finalUpdateData = { ...this.updateData };
540
- for (const [key, column] of Object.entries(this.table._.columns)) {
541
- const typedKey = key;
542
- if (finalUpdateData[typedKey] === void 0 && column.options.$onUpdateFn) {
543
- finalUpdateData[typedKey] = column.options.$onUpdateFn();
544
- }
545
- }
546
- const baseQuery = this.query;
547
- const whereParams = this.params;
548
- let tablePart = baseQuery;
549
- let whereClause = "";
550
- const whereIndex = baseQuery.indexOf(" WHERE ");
551
- if (whereIndex !== -1) {
552
- tablePart = baseQuery.substring(0, whereIndex);
553
- whereClause = baseQuery.substring(whereIndex);
554
- }
555
- const entries = Object.entries(finalUpdateData);
556
- if (entries.length === 0) {
557
- throw new Error("Cannot execute an update query without a .set() call.");
558
- }
559
- const setClause = entries.map(([key]) => {
560
- const column = this.table._.columns[key];
561
- if (!column) {
562
- throw new Error(
563
- `Column ${key} does not exist on table ${this.table._.name}`
564
- );
565
- }
566
- return `${column._.name} = ?`;
567
- }).join(", ");
568
- const setParams = entries.map(([, value]) => value);
569
- const sql2 = `${tablePart} SET ${setClause}${whereClause}`;
570
- const params = [...setParams, ...whereParams];
571
- return { sql: sql2, params };
572
- }
573
- async execute() {
574
- const { sql: updateSql, params } = this.buildUpdateClause();
575
- if (this.returningColumns.length > 0) {
576
- const returningNames = this.returningColumns.map((col) => col._.name).join(", ");
577
- const sqlWithReturning = `${updateSql} RETURNING ${returningNames}`;
578
- return this.db.select(sqlWithReturning, params);
579
- } else {
580
- const result = await this.db.execute(updateSql, params);
581
- return [{ rowsAffected: result.rowsAffected }];
582
- }
583
- }
584
- async returningAll() {
585
- const allColumns = Object.keys(
586
- this.table._.columns
587
- );
588
- return this.returning(...allColumns).execute();
589
- }
590
- };
520
+
521
+ // src/builders/delete.ts
591
522
  var DeleteQueryBuilder = class extends BaseQueryBuilder {
592
523
  constructor(db, table) {
593
524
  super(db);
@@ -596,19 +527,13 @@ var DeleteQueryBuilder = class extends BaseQueryBuilder {
596
527
  }
597
528
  returningColumns = [];
598
529
  returning(...columns) {
599
- for (const col of columns) {
600
- if (typeof col === "string") {
601
- this.returningColumns.push(this.table._.columns[col]);
602
- } else {
603
- this.returningColumns.push(col);
604
- }
605
- }
530
+ this.returningColumns.push(...columns);
606
531
  return this;
607
532
  }
608
533
  async execute() {
609
534
  const { sql: sql2, params } = this.build();
610
535
  if (this.returningColumns.length > 0) {
611
- const returningNames = this.returningColumns.map((col) => col._.name).join(", ");
536
+ const returningNames = this.returningColumns.map((col) => this.table._.columns[col]._.name).join(", ");
612
537
  const sqlWithReturning = `${sql2} RETURNING ${returningNames}`;
613
538
  return this.db.select(sqlWithReturning, params);
614
539
  } else {
@@ -617,12 +542,12 @@ var DeleteQueryBuilder = class extends BaseQueryBuilder {
617
542
  }
618
543
  }
619
544
  async returningAll() {
620
- const allColumns = Object.keys(
621
- this.table._.columns
622
- );
545
+ const allColumns = Object.keys(this.table._.columns);
623
546
  return this.returning(...allColumns).execute();
624
547
  }
625
548
  };
549
+
550
+ // src/builders/with.ts
626
551
  var WithQueryBuilder = class {
627
552
  constructor(db) {
628
553
  this.db = db;
@@ -632,12 +557,8 @@ var WithQueryBuilder = class {
632
557
  this.ctes.push({ alias: alias2, query: query.sql, params: query.params });
633
558
  return this;
634
559
  }
635
- select(table, selection) {
636
- const builder = new SelectQueryBuilder(
637
- this.db,
638
- table,
639
- selection
640
- );
560
+ select(table, columns) {
561
+ const builder = new SelectQueryBuilder(this.db, table, columns);
641
562
  this.applyWithClause(builder);
642
563
  return builder;
643
564
  }
@@ -669,13 +590,117 @@ var WithQueryBuilder = class {
669
590
  };
670
591
 
671
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
+ };
672
697
  var TauriORM = class {
673
698
  constructor(db, schema = void 0) {
674
699
  this.db = db;
675
700
  if (schema) {
676
- for (const table of Object.values(schema)) {
677
- if (table instanceof Table) {
678
- 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);
679
704
  }
680
705
  }
681
706
  }
@@ -700,31 +725,60 @@ var TauriORM = class {
700
725
  }
701
726
  return sql2;
702
727
  }
703
- 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()));
704
734
  for (const table of this.tables.values()) {
705
- const existingTableInfo = await this.db.select(
706
- `PRAGMA table_info('${table._.name}')`
707
- );
708
- if (existingTableInfo.length === 0) {
735
+ const tableName = table._.name;
736
+ const tableExists = dbTableNames.has(tableName);
737
+ if (!tableExists) {
709
738
  const columnsSql = Object.values(table._.columns).map((col) => this.buildColumnDefinition(col)).join(", ");
710
- const createSql = `CREATE TABLE ${table._.name} (${columnsSql})`;
739
+ const createSql = `CREATE TABLE ${tableName}
740
+ (
741
+ ${columnsSql}
742
+ )`;
711
743
  await this.db.execute(createSql);
712
744
  } else {
713
- const existingColumnNames = new Set(
714
- existingTableInfo.map((c) => c.name)
715
- );
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));
716
748
  for (const column of Object.values(table._.columns)) {
717
749
  if (!existingColumnNames.has(column._.name)) {
718
750
  const columnSql = this.buildColumnDefinition(column, true);
719
- const alterSql = `ALTER TABLE ${table._.name} ADD COLUMN ${columnSql}`;
751
+ const alterSql = `ALTER TABLE ${tableName}
752
+ ADD COLUMN ${columnSql}`;
720
753
  await this.db.execute(alterSql);
721
754
  }
722
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
+ }
723
770
  }
724
771
  }
725
772
  }
726
- select(selection) {
727
- return new SelectBuilder(this.db, selection);
773
+ select(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);
728
782
  }
729
783
  insert(table) {
730
784
  return new InsertQueryBuilder(this.db, table);
@@ -761,13 +815,25 @@ var TauriORM = class {
761
815
  // --- Schema detection / signature ---
762
816
  async ensureSchemaMeta() {
763
817
  await this.db.execute(
764
- `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
+ )`
765
829
  );
766
830
  }
767
831
  async getSchemaMeta(key) {
768
832
  await this.ensureSchemaMeta();
769
833
  const rows = await this.db.select(
770
- `SELECT value FROM _schema_meta WHERE key = ?`,
834
+ `SELECT value
835
+ FROM _schema_meta
836
+ WHERE key = ?`,
771
837
  [key]
772
838
  );
773
839
  return rows?.[0]?.value ?? null;
@@ -775,7 +841,10 @@ var TauriORM = class {
775
841
  async setSchemaMeta(key, value) {
776
842
  await this.ensureSchemaMeta();
777
843
  await this.db.execute(
778
- `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`,
779
848
  [key, value]
780
849
  );
781
850
  }
@@ -812,14 +881,34 @@ var TauriORM = class {
812
881
  const status = await this.isSchemaDirty();
813
882
  if (status.dirty) {
814
883
  await this.migrate();
815
- await this.setSchemaMeta(
816
- "schema_signature",
817
- this.computeModelSignature()
818
- );
884
+ await this.setSchemaMeta("schema_signature", this.computeModelSignature());
819
885
  return true;
820
886
  }
821
887
  return false;
822
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
+ }
823
912
  };
824
913
  var Relation = class {
825
914
  constructor(foreignTable) {
@@ -837,16 +926,47 @@ var ManyRelation = class extends Relation {
837
926
  super(foreignTable);
838
927
  }
839
928
  };
840
- var relations = (_table, relationsCallback) => {
841
- return relationsCallback({
842
- one: (table, config) => {
843
- return new OneRelation(table, config);
929
+ var relations = (table, relationsCallback) => {
930
+ const builtRelations = relationsCallback({
931
+ one: (foreignTable, config) => {
932
+ return new OneRelation(foreignTable, config);
844
933
  },
845
- many: (table) => {
846
- return new ManyRelation(table);
934
+ many: (foreignTable) => {
935
+ return new ManyRelation(foreignTable);
847
936
  }
848
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;
954
+ };
955
+ var getTableColumns = (table) => {
956
+ return table._.columns;
849
957
  };
958
+ var alias = (table, alias2) => {
959
+ return table;
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 });
850
970
  export {
851
971
  BaseQueryBuilder,
852
972
  DeleteQueryBuilder,
@@ -855,7 +975,6 @@ export {
855
975
  OneRelation,
856
976
  Relation,
857
977
  SQLiteColumn,
858
- SelectBuilder,
859
978
  SelectQueryBuilder,
860
979
  Table,
861
980
  TauriORM,
@@ -870,6 +989,7 @@ export {
870
989
  count,
871
990
  countDistinct,
872
991
  desc,
992
+ enumType,
873
993
  eq,
874
994
  getTableColumns,
875
995
  gt,
@@ -884,6 +1004,7 @@ export {
884
1004
  max,
885
1005
  min,
886
1006
  not,
1007
+ numeric,
887
1008
  or,
888
1009
  real,
889
1010
  relations,