@type32/tauri-sqlite-orm 0.1.18-2 → 0.1.18-20

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,110 +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 },
45
- this._.mode
46
- );
1
+ // src/builders/query-base.ts
2
+ var BaseQueryBuilder = class {
3
+ constructor(db) {
4
+ this.db = db;
47
5
  }
48
- autoincrement() {
49
- return new _SQLiteColumn(
50
- this._.name,
51
- this.type,
52
- { ...this.options, autoincrement: true },
53
- this._.mode
54
- );
6
+ query = "";
7
+ params = [];
8
+ where(condition) {
9
+ this.query += ` WHERE ${condition.sql}`;
10
+ this.params.push(...condition.params);
11
+ return this;
55
12
  }
56
- unique() {
57
- return new _SQLiteColumn(
58
- this._.name,
59
- this.type,
60
- { ...this.options, unique: true },
61
- this._.mode
62
- );
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;
63
21
  }
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
- );
22
+ limit(count2) {
23
+ this.query += ` LIMIT ${count2}`;
24
+ return this;
77
25
  }
78
- $onUpdateFn(fn) {
79
- return new _SQLiteColumn(
80
- this._.name,
81
- this.type,
82
- { ...this.options, $onUpdateFn: fn },
83
- this._.mode
84
- );
26
+ offset(count2) {
27
+ this.query += ` OFFSET ${count2}`;
28
+ return this;
85
29
  }
86
- };
87
- var text = (name) => new SQLiteColumn(name, "TEXT");
88
- var integer = (name, config) => new SQLiteColumn(name, "INTEGER", {}, config?.mode || "default");
89
- var real = (name) => new SQLiteColumn(name, "REAL");
90
- var blob = (name) => new SQLiteColumn(name, "BLOB");
91
- var boolean = (name) => new SQLiteColumn(name, "BOOLEAN");
92
- var Table = class {
93
- _;
94
- constructor(name, columns) {
95
- this._ = {
96
- name,
97
- columns
30
+ build() {
31
+ return {
32
+ sql: this.query,
33
+ params: this.params
98
34
  };
99
35
  }
100
36
  };
101
- var sqliteTable = (tableName, columns) => {
102
- 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
+ };
103
45
  };
104
- var eq = (column, value) => ({
105
- sql: `${column._.name} = ?`,
106
- params: [value]
107
- });
108
46
  var and = (...conditions) => ({
109
47
  sql: conditions.map((c) => `(${c.sql})`).join(" AND "),
110
48
  params: conditions.flatMap((c) => c.params)
@@ -113,6 +51,10 @@ var or = (...conditions) => ({
113
51
  sql: conditions.map((c) => `(${c.sql})`).join(" OR "),
114
52
  params: conditions.flatMap((c) => c.params)
115
53
  });
54
+ var not = (condition) => ({
55
+ sql: `NOT (${condition.sql})`,
56
+ params: condition.params
57
+ });
116
58
  var gt = (column, value) => ({
117
59
  sql: `${column._.name} > ?`,
118
60
  params: [value]
@@ -145,81 +87,241 @@ var inArray = (column, values) => ({
145
87
  sql: `${column._.name} IN (${values.map(() => "?").join(",")})`,
146
88
  params: values
147
89
  });
148
- var BaseQueryBuilder = class {
149
- constructor(db) {
150
- this.db = db;
90
+ var count = (column) => ({
91
+ sql: `COUNT(${column ? column._.name : "*"})`,
92
+ params: []
93
+ });
94
+ var countDistinct = (column) => ({
95
+ sql: `COUNT(DISTINCT ${column._.name})`,
96
+ params: []
97
+ });
98
+ var sum = (column) => ({
99
+ sql: `SUM(${column._.name})`,
100
+ params: []
101
+ });
102
+ var avg = (column) => ({
103
+ sql: `AVG(${column._.name})`,
104
+ params: []
105
+ });
106
+ var max = (column) => ({
107
+ sql: `MAX(${column._.name})`,
108
+ params: []
109
+ });
110
+ var min = (column) => ({
111
+ sql: `MIN(${column._.name})`,
112
+ params: []
113
+ });
114
+
115
+ // src/builders/select.ts
116
+ var SelectQueryBuilder = class extends BaseQueryBuilder {
117
+ constructor(db, table, columns) {
118
+ super(db);
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}`;
127
+ }
128
+ isDistinct = false;
129
+ groupByColumns = [];
130
+ havingCondition = null;
131
+ joins = [];
132
+ includeRelations = {};
133
+ selectedTableAlias;
134
+ selectedColumns = [];
135
+ distinct() {
136
+ this.isDistinct = true;
137
+ return this;
151
138
  }
152
- query = "";
153
- params = [];
154
- where(condition) {
155
- this.query += ` WHERE ${condition.sql}`;
156
- this.params.push(...condition.params);
139
+ groupBy(...columns) {
140
+ this.groupByColumns.push(...columns);
141
+ const columnNames = columns.map((col) => `${this.selectedTableAlias}.${col._.name}`).join(", ");
142
+ this.query += ` GROUP BY ${columnNames}`;
157
143
  return this;
158
144
  }
159
- orderBy(column, direction = "ASC") {
160
- this.query += ` ORDER BY ${column._.name} ${direction}`;
145
+ having(condition) {
146
+ this.havingCondition = condition;
147
+ this.query += ` HAVING ${condition.sql}`;
148
+ this.params.push(...condition.params);
161
149
  return this;
162
150
  }
163
- limit(count) {
164
- this.query += ` LIMIT ${count}`;
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);
165
157
  return this;
166
158
  }
167
- offset(count) {
168
- this.query += ` OFFSET ${count}`;
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);
169
165
  return this;
170
166
  }
171
- build() {
172
- return {
173
- sql: this.query,
174
- params: this.params
175
- };
167
+ include(relations2) {
168
+ this.includeRelations = { ...this.includeRelations, ...relations2 };
169
+ return this;
176
170
  }
177
- };
178
- var SelectQueryBuilder = class extends BaseQueryBuilder {
179
- constructor(db, table, columns) {
180
- super(db);
181
- this.table = table;
182
- this.columns = columns;
183
- const columnNames = columns ? columns.map((c) => table._.columns[c]._.name) : ["*"];
184
- this.query = `SELECT ${columnNames.join(", ")} FROM ${table._.name}`;
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 };
185
226
  }
227
+ // Enhanced execute method that handles relation data mapping
186
228
  async execute() {
187
- const { sql, params } = this.build();
188
- return this.db.select(sql, 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
+ });
189
257
  }
190
- };
191
- var InsertQueryBuilder = class extends BaseQueryBuilder {
192
- constructor(db, table) {
193
- super(db);
194
- this.table = table;
195
- this.query = `INSERT INTO ${table._.name}`;
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());
196
312
  }
197
- dataSets = [];
198
- values(data) {
199
- const dataArray = Array.isArray(data) ? data : [data];
200
- this.dataSets.push(...dataArray);
201
- return this;
313
+ // Update the return type signatures
314
+ async all() {
315
+ return this.execute();
202
316
  }
203
- async execute() {
204
- if (this.dataSets.length === 0) {
205
- throw new Error("No data provided for insert");
206
- }
207
- const columns = Object.keys(
208
- this.dataSets[0]
209
- );
210
- const columnNames = columns.map(
211
- (c) => this.table._.columns[c]._.name
212
- );
213
- const placeholders = `(${columnNames.map(() => "?").join(", ")})`;
214
- const valuesSql = this.dataSets.map(() => placeholders).join(", ");
215
- this.query += ` (${columnNames.join(", ")}) VALUES ${valuesSql}`;
216
- const params = this.dataSets.flatMap(
217
- (data) => columns.map((col) => data[col])
218
- );
219
- const result = await this.db.execute(this.query, params);
220
- return result.lastInsertId ?? 0;
317
+ async get() {
318
+ this.limit(1);
319
+ const result = await this.execute();
320
+ return result[0];
221
321
  }
222
322
  };
323
+
324
+ // src/builders/update.ts
223
325
  var UpdateQueryBuilder = class extends BaseQueryBuilder {
224
326
  constructor(db, table) {
225
327
  super(db);
@@ -227,11 +329,23 @@ var UpdateQueryBuilder = class extends BaseQueryBuilder {
227
329
  this.query = `UPDATE ${table._.name}`;
228
330
  }
229
331
  updateData = {};
332
+ returningColumns = [];
230
333
  set(data) {
231
334
  this.updateData = { ...this.updateData, ...data };
232
335
  return this;
233
336
  }
234
- build() {
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
+ }
235
349
  const baseQuery = this.query;
236
350
  const whereParams = this.params;
237
351
  let tablePart = baseQuery;
@@ -241,7 +355,7 @@ var UpdateQueryBuilder = class extends BaseQueryBuilder {
241
355
  tablePart = baseQuery.substring(0, whereIndex);
242
356
  whereClause = baseQuery.substring(whereIndex);
243
357
  }
244
- const entries = Object.entries(this.updateData);
358
+ const entries = Object.entries(finalUpdateData);
245
359
  if (entries.length === 0) {
246
360
  throw new Error("Cannot execute an update query without a .set() call.");
247
361
  }
@@ -255,61 +369,394 @@ var UpdateQueryBuilder = class extends BaseQueryBuilder {
255
369
  return `${column._.name} = ?`;
256
370
  }).join(", ");
257
371
  const setParams = entries.map(([, value]) => value);
258
- const sql = `${tablePart} SET ${setClause}${whereClause}`;
372
+ const sql2 = `${tablePart} SET ${setClause}${whereClause}`;
259
373
  const params = [...setParams, ...whereParams];
260
- return { sql, params };
374
+ return { sql: sql2, params };
261
375
  }
262
376
  async execute() {
263
- const { sql, params } = this.build();
264
- const result = await this.db.execute(sql, params);
265
- return result.rowsAffected;
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
396
+ var InsertQueryBuilder = class extends BaseQueryBuilder {
397
+ constructor(db, table) {
398
+ super(db);
399
+ this.table = table;
400
+ this.query = `INSERT INTO ${table._.name}`;
401
+ }
402
+ dataSets = [];
403
+ returningColumns = [];
404
+ onConflictAction = null;
405
+ conflictTarget = [];
406
+ updateSet = {};
407
+ values(data) {
408
+ const dataArray = Array.isArray(data) ? data : [data];
409
+ this.dataSets.push(...dataArray);
410
+ return this;
411
+ }
412
+ returning(...columns) {
413
+ this.returningColumns.push(...columns);
414
+ return this;
415
+ }
416
+ onConflictDoNothing(target) {
417
+ this.onConflictAction = "nothing";
418
+ if (target) {
419
+ this.conflictTarget = Array.isArray(target) ? target : [target];
420
+ }
421
+ return this;
422
+ }
423
+ onConflictDoUpdate(config) {
424
+ this.onConflictAction = "update";
425
+ this.conflictTarget = Array.isArray(config.target) ? config.target : [config.target];
426
+ this.updateSet = config.set;
427
+ return this;
428
+ }
429
+ processDefaultValues(data) {
430
+ const finalData = { ...data };
431
+ for (const [key, column] of Object.entries(this.table._.columns)) {
432
+ const typedKey = key;
433
+ if (finalData[typedKey] === void 0) {
434
+ if (column.options.$defaultFn) {
435
+ finalData[typedKey] = column.options.$defaultFn();
436
+ }
437
+ }
438
+ }
439
+ return finalData;
440
+ }
441
+ buildConflictClause() {
442
+ if (!this.onConflictAction) return "";
443
+ let clause = " ON CONFLICT";
444
+ if (this.conflictTarget.length > 0) {
445
+ const targetNames = this.conflictTarget.map((col) => col._.name).join(", ");
446
+ clause += ` (${targetNames})`;
447
+ }
448
+ if (this.onConflictAction === "nothing") {
449
+ clause += " DO NOTHING";
450
+ } else if (this.onConflictAction === "update") {
451
+ const setEntries = Object.entries(this.updateSet);
452
+ if (setEntries.length > 0) {
453
+ const setClause = setEntries.map(([key]) => `${key} = ?`).join(", ");
454
+ clause += ` DO UPDATE SET ${setClause}`;
455
+ }
456
+ }
457
+ return clause;
458
+ }
459
+ async execute() {
460
+ if (this.dataSets.length === 0) {
461
+ throw new Error("No data provided for insert");
462
+ }
463
+ const processedDataSets = this.dataSets.map(
464
+ (data) => this.processDefaultValues(data)
465
+ );
466
+ const groups = /* @__PURE__ */ new Map();
467
+ for (const dataSet of processedDataSets) {
468
+ const keys = Object.keys(dataSet).sort().join(",");
469
+ if (!groups.has(keys)) {
470
+ groups.set(keys, []);
471
+ }
472
+ groups.get(keys).push(dataSet);
473
+ }
474
+ let results = [];
475
+ let lastInsertId;
476
+ let rowsAffected = 0;
477
+ for (const [_, dataSets] of groups) {
478
+ const columns = Object.keys(dataSets[0]);
479
+ const columnNames = columns.map(
480
+ (key) => this.table._.columns[key]._.name
481
+ );
482
+ const placeholders = `(${columns.map(() => "?").join(", ")})`;
483
+ const valuesSql = dataSets.map(() => placeholders).join(", ");
484
+ const conflictClause = this.buildConflictClause();
485
+ const finalQuery = `${this.query} (${columnNames.join(
486
+ ", "
487
+ )}) VALUES ${valuesSql}${conflictClause}`;
488
+ const params = dataSets.flatMap(
489
+ (data) => columns.map((col) => data[col] ?? null)
490
+ );
491
+ if (this.onConflictAction === "update") {
492
+ const setValues = Object.entries(this.updateSet).map(
493
+ ([, value]) => value
494
+ );
495
+ params.push(...setValues);
496
+ }
497
+ if (this.returningColumns.length > 0) {
498
+ const returningNames = this.returningColumns.map((col) => this.table._.columns[col]._.name).join(", ");
499
+ const queryWithReturning = `${finalQuery} RETURNING ${returningNames}`;
500
+ const rows = await this.db.select(queryWithReturning, params);
501
+ results = results.concat(rows);
502
+ } else {
503
+ const result = await this.db.execute(finalQuery, params);
504
+ lastInsertId = result.lastInsertId;
505
+ rowsAffected += result.rowsAffected;
506
+ }
507
+ }
508
+ if (this.returningColumns.length > 0) {
509
+ return results;
510
+ }
511
+ return [{ lastInsertId, rowsAffected }];
512
+ }
513
+ async returningAll() {
514
+ const allColumns = Object.keys(
515
+ this.table._.columns
516
+ );
517
+ return this.returning(...allColumns).execute();
266
518
  }
267
519
  };
520
+
521
+ // src/builders/delete.ts
268
522
  var DeleteQueryBuilder = class extends BaseQueryBuilder {
269
523
  constructor(db, table) {
270
524
  super(db);
271
525
  this.table = table;
272
526
  this.query = `DELETE FROM ${table._.name}`;
273
527
  }
528
+ returningColumns = [];
529
+ returning(...columns) {
530
+ this.returningColumns.push(...columns);
531
+ return this;
532
+ }
274
533
  async execute() {
275
- const { sql, params } = this.build();
276
- const result = await this.db.execute(sql, params);
277
- return result.rowsAffected;
534
+ const { sql: sql2, params } = this.build();
535
+ if (this.returningColumns.length > 0) {
536
+ const returningNames = this.returningColumns.map((col) => this.table._.columns[col]._.name).join(", ");
537
+ const sqlWithReturning = `${sql2} RETURNING ${returningNames}`;
538
+ return this.db.select(sqlWithReturning, params);
539
+ } else {
540
+ const result = await this.db.execute(sql2, params);
541
+ return [{ rowsAffected: result.rowsAffected }];
542
+ }
543
+ }
544
+ async returningAll() {
545
+ const allColumns = Object.keys(this.table._.columns);
546
+ return this.returning(...allColumns).execute();
547
+ }
548
+ };
549
+
550
+ // src/builders/with.ts
551
+ var WithQueryBuilder = class {
552
+ constructor(db) {
553
+ this.db = db;
554
+ }
555
+ ctes = [];
556
+ with(alias2, query) {
557
+ this.ctes.push({ alias: alias2, query: query.sql, params: query.params });
558
+ return this;
559
+ }
560
+ select(table, columns) {
561
+ const builder = new SelectQueryBuilder(this.db, table, columns);
562
+ this.applyWithClause(builder);
563
+ return builder;
564
+ }
565
+ insert(table) {
566
+ const builder = new InsertQueryBuilder(this.db, table);
567
+ this.applyWithClause(builder);
568
+ return builder;
569
+ }
570
+ update(table) {
571
+ const builder = new UpdateQueryBuilder(this.db, table);
572
+ this.applyWithClause(builder);
573
+ return builder;
574
+ }
575
+ delete(table) {
576
+ const builder = new DeleteQueryBuilder(this.db, table);
577
+ this.applyWithClause(builder);
578
+ return builder;
579
+ }
580
+ applyWithClause(builder) {
581
+ if (this.ctes.length > 0) {
582
+ const cteSql = this.ctes.map((cte) => `${cte.alias} AS (${cte.query})`).join(", ");
583
+ builder["query"] = `WITH ${cteSql} ${builder["query"]}`;
584
+ builder["params"] = [
585
+ ...this.ctes.flatMap((cte) => cte.params),
586
+ ...builder["params"]
587
+ ];
588
+ }
589
+ }
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
+ };
278
664
  }
279
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
+ };
280
697
  var TauriORM = class {
281
698
  constructor(db, schema = void 0) {
282
699
  this.db = db;
283
700
  if (schema) {
284
- for (const table of Object.values(schema)) {
285
- 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);
704
+ }
286
705
  }
287
706
  }
288
707
  }
289
708
  tables = /* @__PURE__ */ new Map();
709
+ buildColumnDefinition(col, forAlterTable = false) {
710
+ let sql2 = `${col._.name} ${col.type}`;
711
+ if (col.options.primaryKey && !forAlterTable) {
712
+ sql2 += " PRIMARY KEY";
713
+ if (col._.autoincrement) {
714
+ sql2 += " AUTOINCREMENT";
715
+ }
716
+ }
717
+ if (col._.notNull) sql2 += " NOT NULL";
718
+ if (col.options.unique) sql2 += " UNIQUE";
719
+ if (col.options.default !== void 0) {
720
+ const value = col.options.default;
721
+ sql2 += ` DEFAULT ${typeof value === "string" ? `'${value.replace(/'/g, "''")}'` : value}`;
722
+ }
723
+ if (col.options.references) {
724
+ sql2 += ` REFERENCES ${col.options.references.table._.name}(${col.options.references.column._.name})`;
725
+ }
726
+ return sql2;
727
+ }
290
728
  async migrate() {
291
729
  for (const table of this.tables.values()) {
292
- const columnsSql = Object.entries(table._.columns).map(([name, col]) => {
293
- let sql = `${col._.name} ${col.type}`;
294
- if (col.options.primaryKey) sql += " PRIMARY KEY";
295
- if (col._.autoincrement) sql += " AUTOINCREMENT";
296
- if (col._.notNull) sql += " NOT NULL";
297
- if (col.options.unique) sql += " UNIQUE";
298
- if (col.options.default !== void 0) {
299
- const value = col.options.default;
300
- sql += ` DEFAULT ${typeof value === "string" ? `'${value}'` : value}`;
730
+ const existingTableInfo = await this.db.select(`PRAGMA table_info('${table._.name}')`);
731
+ if (existingTableInfo.length === 0) {
732
+ const columnsSql = Object.values(table._.columns).map((col) => this.buildColumnDefinition(col)).join(", ");
733
+ const createSql = `CREATE TABLE ${table._.name}
734
+ (
735
+ ${columnsSql}
736
+ )`;
737
+ await this.db.execute(createSql);
738
+ } else {
739
+ const existingColumnNames = new Set(existingTableInfo.map((c) => c.name));
740
+ for (const column of Object.values(table._.columns)) {
741
+ if (!existingColumnNames.has(column._.name)) {
742
+ const columnSql = this.buildColumnDefinition(column, true);
743
+ const alterSql = `ALTER TABLE ${table._.name}
744
+ ADD COLUMN ${columnSql}`;
745
+ await this.db.execute(alterSql);
746
+ }
301
747
  }
302
- if (col.options.references) {
303
- sql += ` REFERENCES ${col.options.references.table._.name}(${col.options.references.column._.name})`;
304
- }
305
- return sql;
306
- }).join(", ");
307
- const createSql = `CREATE TABLE IF NOT EXISTS ${table._.name} (${columnsSql})`;
308
- await this.db.execute(createSql);
748
+ }
309
749
  }
310
750
  }
311
751
  select(table, columns) {
312
- return new SelectQueryBuilder(this.db, table, columns);
752
+ const internalTable = this.tables.get(table._.name);
753
+ if (!internalTable) {
754
+ console.warn(
755
+ `[Tauri-ORM] Table "${table._.name}" was not passed in the schema to the ORM constructor. Relations will not be available.`
756
+ );
757
+ return new SelectQueryBuilder(this.db, table, columns);
758
+ }
759
+ return new SelectQueryBuilder(this.db, internalTable, columns);
313
760
  }
314
761
  insert(table) {
315
762
  return new InsertQueryBuilder(this.db, table);
@@ -320,6 +767,15 @@ var TauriORM = class {
320
767
  delete(table) {
321
768
  return new DeleteQueryBuilder(this.db, table);
322
769
  }
770
+ $with(alias2) {
771
+ const withBuilder = new WithQueryBuilder(this.db);
772
+ return {
773
+ as: (query) => {
774
+ withBuilder.with(alias2, query);
775
+ return withBuilder;
776
+ }
777
+ };
778
+ }
323
779
  async transaction(callback) {
324
780
  await this.db.execute("BEGIN TRANSACTION");
325
781
  try {
@@ -331,16 +787,31 @@ var TauriORM = class {
331
787
  throw error;
332
788
  }
333
789
  }
790
+ rollback() {
791
+ throw new Error("Transaction rolled back");
792
+ }
334
793
  // --- Schema detection / signature ---
335
794
  async ensureSchemaMeta() {
336
795
  await this.db.execute(
337
- `CREATE TABLE IF NOT EXISTS _schema_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)`
796
+ `CREATE TABLE IF NOT EXISTS _schema_meta
797
+ (
798
+ key
799
+ TEXT
800
+ PRIMARY
801
+ KEY,
802
+ value
803
+ TEXT
804
+ NOT
805
+ NULL
806
+ )`
338
807
  );
339
808
  }
340
809
  async getSchemaMeta(key) {
341
810
  await this.ensureSchemaMeta();
342
811
  const rows = await this.db.select(
343
- `SELECT value FROM _schema_meta WHERE key = ?`,
812
+ `SELECT value
813
+ FROM _schema_meta
814
+ WHERE key = ?`,
344
815
  [key]
345
816
  );
346
817
  return rows?.[0]?.value ?? null;
@@ -348,7 +819,10 @@ var TauriORM = class {
348
819
  async setSchemaMeta(key, value) {
349
820
  await this.ensureSchemaMeta();
350
821
  await this.db.execute(
351
- `INSERT INTO _schema_meta(key, value) VALUES(?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value`,
822
+ `INSERT INTO _schema_meta(key, value)
823
+ VALUES (?, ?) ON CONFLICT(key) DO
824
+ UPDATE
825
+ SET value = excluded.value`,
352
826
  [key, value]
353
827
  );
354
828
  }
@@ -359,7 +833,10 @@ var TauriORM = class {
359
833
  pk: !!col.options.primaryKey,
360
834
  ai: !!col._.autoincrement,
361
835
  nn: !!col._.notNull,
362
- dv: col.options.default && typeof col.options.default === "object" && col.options.default.raw ? { raw: col.options.default.raw } : col.options.default ?? null
836
+ unique: !!col.options.unique,
837
+ dv: col.options.default && typeof col.options.default === "object" && col.options.default.raw ? { raw: col.options.default.raw } : col.options.default ?? null,
838
+ hasDefaultFn: col.options.$defaultFn !== void 0,
839
+ hasOnUpdateFn: col.options.$onUpdateFn !== void 0
363
840
  };
364
841
  }
365
842
  computeModelSignature() {
@@ -382,41 +859,94 @@ var TauriORM = class {
382
859
  const status = await this.isSchemaDirty();
383
860
  if (status.dirty) {
384
861
  await this.migrate();
385
- await this.setSchemaMeta(
386
- "schema_signature",
387
- this.computeModelSignature()
388
- );
862
+ await this.setSchemaMeta("schema_signature", this.computeModelSignature());
389
863
  return true;
390
864
  }
391
865
  return false;
392
866
  }
393
867
  };
868
+ var Relation = class {
869
+ constructor(foreignTable) {
870
+ this.foreignTable = foreignTable;
871
+ }
872
+ };
873
+ var OneRelation = class extends Relation {
874
+ constructor(foreignTable, config) {
875
+ super(foreignTable);
876
+ this.config = config;
877
+ }
878
+ };
879
+ var ManyRelation = class extends Relation {
880
+ constructor(foreignTable) {
881
+ super(foreignTable);
882
+ }
883
+ };
394
884
  var relations = (table, relationsCallback) => {
395
- return relationsCallback({
396
- one: (table2, config) => ({
397
- table: table2,
398
- type: "one",
399
- foreignKey: config.fields[0],
400
- localKey: config.references[0]
401
- }),
402
- many: (table2) => ({
403
- table: table2,
404
- type: "many"
405
- })
885
+ const builtRelations = relationsCallback({
886
+ one: (foreignTable, config) => {
887
+ return new OneRelation(foreignTable, config);
888
+ },
889
+ many: (foreignTable) => {
890
+ return new ManyRelation(foreignTable);
891
+ }
406
892
  });
893
+ for (const [name, relation] of Object.entries(builtRelations)) {
894
+ if (relation instanceof OneRelation) {
895
+ table.relations[name] = {
896
+ type: "one",
897
+ foreignTable: relation.foreignTable,
898
+ fields: relation.config?.fields,
899
+ references: relation.config?.references
900
+ };
901
+ } else if (relation instanceof ManyRelation) {
902
+ table.relations[name] = {
903
+ type: "many",
904
+ foreignTable: relation.foreignTable
905
+ };
906
+ }
907
+ }
908
+ return builtRelations;
407
909
  };
910
+ var getTableColumns = (table) => {
911
+ return table._.columns;
912
+ };
913
+ var alias = (table, alias2) => {
914
+ return table;
915
+ };
916
+
917
+ // src/column-helpers.ts
918
+ var text = (name, config) => new SQLiteColumn(name, "TEXT", config, config?.mode);
919
+ var integer = (name, config) => new SQLiteColumn(name, "INTEGER", {}, config?.mode || "default");
920
+ var real = (name) => new SQLiteColumn(name, "REAL");
921
+ var blob = (name, config) => new SQLiteColumn(name, "BLOB", {}, config?.mode);
922
+ var boolean = (name) => new SQLiteColumn(name, "BOOLEAN");
923
+ var numeric = (name, config) => new SQLiteColumn(name, "NUMERIC", {}, config?.mode);
924
+ var enumType = (name, values) => text(name, { enum: values });
408
925
  export {
926
+ BaseQueryBuilder,
409
927
  DeleteQueryBuilder,
410
928
  InsertQueryBuilder,
929
+ ManyRelation,
930
+ OneRelation,
931
+ Relation,
411
932
  SQLiteColumn,
412
933
  SelectQueryBuilder,
413
934
  Table,
414
935
  TauriORM,
415
936
  UpdateQueryBuilder,
937
+ WithQueryBuilder,
938
+ alias,
416
939
  and,
940
+ asc,
941
+ avg,
417
942
  blob,
418
943
  boolean,
944
+ count,
945
+ countDistinct,
946
+ desc,
947
+ enumType,
419
948
  eq,
949
+ getTableColumns,
420
950
  gt,
421
951
  gte,
422
952
  inArray,
@@ -426,9 +956,15 @@ export {
426
956
  like,
427
957
  lt,
428
958
  lte,
959
+ max,
960
+ min,
961
+ not,
962
+ numeric,
429
963
  or,
430
964
  real,
431
965
  relations,
966
+ sql,
432
967
  sqliteTable,
968
+ sum,
433
969
  text
434
970
  };