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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -7,11 +7,11 @@ var __export = (target, all) => {
7
7
  for (var name in all)
8
8
  __defProp(target, name, { get: all[name], enumerable: true });
9
9
  };
10
- var __copyProps = (to, from, except, desc) => {
10
+ var __copyProps = (to, from, except, desc2) => {
11
11
  if (from && typeof from === "object" || typeof from === "function") {
12
12
  for (let key of __getOwnPropNames(from))
13
13
  if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc2 = __getOwnPropDesc(from, key)) || desc2.enumerable });
15
15
  }
16
16
  return to;
17
17
  };
@@ -20,17 +20,30 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ BaseQueryBuilder: () => BaseQueryBuilder,
23
24
  DeleteQueryBuilder: () => DeleteQueryBuilder,
24
25
  InsertQueryBuilder: () => InsertQueryBuilder,
26
+ ManyRelation: () => ManyRelation,
27
+ OneRelation: () => OneRelation,
28
+ Relation: () => Relation,
25
29
  SQLiteColumn: () => SQLiteColumn,
26
30
  SelectQueryBuilder: () => SelectQueryBuilder,
27
31
  Table: () => Table,
28
32
  TauriORM: () => TauriORM,
29
33
  UpdateQueryBuilder: () => UpdateQueryBuilder,
34
+ WithQueryBuilder: () => WithQueryBuilder,
35
+ alias: () => alias,
30
36
  and: () => and,
37
+ asc: () => asc,
38
+ avg: () => avg,
31
39
  blob: () => blob,
32
40
  boolean: () => boolean,
41
+ count: () => count,
42
+ countDistinct: () => countDistinct,
43
+ desc: () => desc,
44
+ enumType: () => enumType,
33
45
  eq: () => eq,
46
+ getTableColumns: () => getTableColumns,
34
47
  gt: () => gt,
35
48
  gte: () => gte,
36
49
  inArray: () => inArray,
@@ -40,121 +53,65 @@ __export(index_exports, {
40
53
  like: () => like,
41
54
  lt: () => lt,
42
55
  lte: () => lte,
56
+ max: () => max,
57
+ min: () => min,
58
+ not: () => not,
59
+ numeric: () => numeric,
43
60
  or: () => or,
44
61
  real: () => real,
45
62
  relations: () => relations,
63
+ sql: () => sql,
46
64
  sqliteTable: () => sqliteTable,
65
+ sum: () => sum,
47
66
  text: () => text
48
67
  });
49
68
  module.exports = __toCommonJS(index_exports);
50
69
 
51
- // src/orm.ts
52
- var SQLiteColumn = class _SQLiteColumn {
53
- constructor(name, type, options = {}, mode) {
54
- this.type = type;
55
- this.options = options;
56
- this._ = {
57
- name,
58
- dataType: type,
59
- mode: mode || "default",
60
- notNull: options.notNull ?? false,
61
- hasDefault: options.default !== void 0 || options.$defaultFn !== void 0,
62
- autoincrement: options.autoincrement ?? false
63
- };
64
- }
65
- _;
66
- notNull() {
67
- return new _SQLiteColumn(
68
- this._.name,
69
- this.type,
70
- { ...this.options, notNull: true },
71
- this._.mode
72
- );
73
- }
74
- default(value) {
75
- return new _SQLiteColumn(
76
- this._.name,
77
- this.type,
78
- { ...this.options, default: value },
79
- this._.mode
80
- );
81
- }
82
- $defaultFn(fn) {
83
- return new _SQLiteColumn(
84
- this._.name,
85
- this.type,
86
- { ...this.options, $defaultFn: fn },
87
- this._.mode
88
- );
89
- }
90
- primaryKey() {
91
- return new _SQLiteColumn(
92
- this._.name,
93
- this.type,
94
- { ...this.options, primaryKey: true },
95
- this._.mode
96
- );
70
+ // src/builders/query-base.ts
71
+ var BaseQueryBuilder = class {
72
+ constructor(db) {
73
+ this.db = db;
97
74
  }
98
- autoincrement() {
99
- return new _SQLiteColumn(
100
- this._.name,
101
- this.type,
102
- { ...this.options, autoincrement: true },
103
- this._.mode
104
- );
75
+ query = "";
76
+ params = [];
77
+ where(condition) {
78
+ this.query += ` WHERE ${condition.sql}`;
79
+ this.params.push(...condition.params);
80
+ return this;
105
81
  }
106
- unique() {
107
- return new _SQLiteColumn(
108
- this._.name,
109
- this.type,
110
- { ...this.options, unique: true },
111
- this._.mode
112
- );
82
+ orderBy(column, direction = "ASC") {
83
+ if ("sql" in column) {
84
+ this.query += ` ORDER BY ${column.sql} ${direction}`;
85
+ this.params.push(...column.params);
86
+ } else {
87
+ this.query += ` ORDER BY ${column._.name} ${direction}`;
88
+ }
89
+ return this;
113
90
  }
114
- references(ref, column) {
115
- return new _SQLiteColumn(
116
- this._.name,
117
- this.type,
118
- {
119
- ...this.options,
120
- references: {
121
- table: ref,
122
- column: ref._.columns[column]
123
- }
124
- },
125
- this._.mode
126
- );
91
+ limit(count2) {
92
+ this.query += ` LIMIT ${count2}`;
93
+ return this;
127
94
  }
128
- $onUpdateFn(fn) {
129
- return new _SQLiteColumn(
130
- this._.name,
131
- this.type,
132
- { ...this.options, $onUpdateFn: fn },
133
- this._.mode
134
- );
95
+ offset(count2) {
96
+ this.query += ` OFFSET ${count2}`;
97
+ return this;
135
98
  }
136
- };
137
- var text = (name) => new SQLiteColumn(name, "TEXT");
138
- var integer = (name, config) => new SQLiteColumn(name, "INTEGER", {}, config?.mode || "default");
139
- var real = (name) => new SQLiteColumn(name, "REAL");
140
- var blob = (name) => new SQLiteColumn(name, "BLOB");
141
- var boolean = (name) => new SQLiteColumn(name, "BOOLEAN");
142
- var Table = class {
143
- _;
144
- constructor(name, columns) {
145
- this._ = {
146
- name,
147
- columns
99
+ build() {
100
+ return {
101
+ sql: this.query,
102
+ params: this.params
148
103
  };
149
104
  }
150
105
  };
151
- var sqliteTable = (tableName, columns) => {
152
- return new Table(tableName, columns);
106
+
107
+ // src/operators.ts
108
+ var eq = (column, value, tableAlias) => {
109
+ const columnName = tableAlias ? `${tableAlias}.${column._.name}` : column._.name;
110
+ return {
111
+ sql: `${columnName} = ?`,
112
+ params: [value]
113
+ };
153
114
  };
154
- var eq = (column, value) => ({
155
- sql: `${column._.name} = ?`,
156
- params: [value]
157
- });
158
115
  var and = (...conditions) => ({
159
116
  sql: conditions.map((c) => `(${c.sql})`).join(" AND "),
160
117
  params: conditions.flatMap((c) => c.params)
@@ -163,6 +120,10 @@ var or = (...conditions) => ({
163
120
  sql: conditions.map((c) => `(${c.sql})`).join(" OR "),
164
121
  params: conditions.flatMap((c) => c.params)
165
122
  });
123
+ var not = (condition) => ({
124
+ sql: `NOT (${condition.sql})`,
125
+ params: condition.params
126
+ });
166
127
  var gt = (column, value) => ({
167
128
  sql: `${column._.name} > ?`,
168
129
  params: [value]
@@ -195,81 +156,241 @@ var inArray = (column, values) => ({
195
156
  sql: `${column._.name} IN (${values.map(() => "?").join(",")})`,
196
157
  params: values
197
158
  });
198
- var BaseQueryBuilder = class {
199
- constructor(db) {
200
- this.db = db;
159
+ var count = (column) => ({
160
+ sql: `COUNT(${column ? column._.name : "*"})`,
161
+ params: []
162
+ });
163
+ var countDistinct = (column) => ({
164
+ sql: `COUNT(DISTINCT ${column._.name})`,
165
+ params: []
166
+ });
167
+ var sum = (column) => ({
168
+ sql: `SUM(${column._.name})`,
169
+ params: []
170
+ });
171
+ var avg = (column) => ({
172
+ sql: `AVG(${column._.name})`,
173
+ params: []
174
+ });
175
+ var max = (column) => ({
176
+ sql: `MAX(${column._.name})`,
177
+ params: []
178
+ });
179
+ var min = (column) => ({
180
+ sql: `MIN(${column._.name})`,
181
+ params: []
182
+ });
183
+
184
+ // src/builders/select.ts
185
+ var SelectQueryBuilder = class extends BaseQueryBuilder {
186
+ constructor(db, table, columns) {
187
+ super(db);
188
+ this.table = table;
189
+ this.columns = columns;
190
+ this.selectedTableAlias = table._.name;
191
+ const selected = columns ? columns.map((c) => this.table._.columns[c]) : Object.values(this.table._.columns);
192
+ this.selectedColumns = selected.map(
193
+ (col) => `${this.selectedTableAlias}.${col._.name} AS "${this.selectedTableAlias}.${col._.name}"`
194
+ );
195
+ this.query = `FROM ${table._.name} ${this.selectedTableAlias}`;
201
196
  }
202
- query = "";
203
- params = [];
204
- where(condition) {
205
- this.query += ` WHERE ${condition.sql}`;
206
- this.params.push(...condition.params);
197
+ isDistinct = false;
198
+ groupByColumns = [];
199
+ havingCondition = null;
200
+ joins = [];
201
+ includeRelations = {};
202
+ selectedTableAlias;
203
+ selectedColumns = [];
204
+ distinct() {
205
+ this.isDistinct = true;
207
206
  return this;
208
207
  }
209
- orderBy(column, direction = "ASC") {
210
- this.query += ` ORDER BY ${column._.name} ${direction}`;
208
+ groupBy(...columns) {
209
+ this.groupByColumns.push(...columns);
210
+ const columnNames = columns.map((col) => `${this.selectedTableAlias}.${col._.name}`).join(", ");
211
+ this.query += ` GROUP BY ${columnNames}`;
211
212
  return this;
212
213
  }
213
- limit(count) {
214
- this.query += ` LIMIT ${count}`;
214
+ having(condition) {
215
+ this.havingCondition = condition;
216
+ this.query += ` HAVING ${condition.sql}`;
217
+ this.params.push(...condition.params);
215
218
  return this;
216
219
  }
217
- offset(count) {
218
- this.query += ` OFFSET ${count}`;
220
+ leftJoin(table, condition, alias2) {
221
+ this.joins.push({ type: "LEFT", table, condition, alias: alias2 });
222
+ const aliasedColumns = Object.values(table._.columns).map(
223
+ (col) => `${alias2}.${col._.name} AS "${alias2}.${col._.name}"`
224
+ );
225
+ this.selectedColumns.push(...aliasedColumns);
219
226
  return this;
220
227
  }
221
- build() {
222
- return {
223
- sql: this.query,
224
- params: this.params
225
- };
228
+ innerJoin(table, condition, alias2) {
229
+ this.joins.push({ type: "INNER", table, condition, alias: alias2 });
230
+ const aliasedColumns = Object.values(table._.columns).map(
231
+ (col) => `${alias2}.${col._.name} AS "${alias2}.${col._.name}"`
232
+ );
233
+ this.selectedColumns.push(...aliasedColumns);
234
+ return this;
226
235
  }
227
- };
228
- var SelectQueryBuilder = class extends BaseQueryBuilder {
229
- constructor(db, table, columns) {
230
- super(db);
231
- this.table = table;
232
- this.columns = columns;
233
- const columnNames = columns ? columns.map((c) => table._.columns[c]._.name) : ["*"];
234
- this.query = `SELECT ${columnNames.join(", ")} FROM ${table._.name}`;
236
+ include(relations2) {
237
+ this.includeRelations = { ...this.includeRelations, ...relations2 };
238
+ return this;
239
+ }
240
+ buildJoins() {
241
+ let sql2 = "";
242
+ const params = [];
243
+ for (const join of this.joins) {
244
+ sql2 += ` ${join.type} JOIN ${join.table._.name} ${join.alias} ON ${join.condition.sql}`;
245
+ params.push(...join.condition.params);
246
+ }
247
+ for (const [relationName, include] of Object.entries(this.includeRelations)) {
248
+ if (!include) continue;
249
+ const relation = this.table.relations[relationName];
250
+ if (!relation) {
251
+ console.warn(
252
+ `[Tauri-ORM] Relation "${relationName}" not found on table "${this.table._.name}". Skipping include.`
253
+ );
254
+ continue;
255
+ }
256
+ const foreignTable = relation.foreignTable;
257
+ const foreignAlias = `${this.selectedTableAlias}_${relationName}`;
258
+ const aliasedColumns = Object.values(foreignTable._.columns).map(
259
+ (col) => `${foreignAlias}.${col._.name} AS "${foreignAlias}.${col._.name}"`
260
+ );
261
+ this.selectedColumns.push(...aliasedColumns);
262
+ if (relation.type === "one" && relation.fields && relation.references) {
263
+ const conditions = relation.fields.map((field, i) => {
264
+ const localColumn = `${this.selectedTableAlias}.${field._.name}`;
265
+ const foreignColumn = `${foreignAlias}.${relation.references[i]._.name}`;
266
+ return {
267
+ sql: `${localColumn} = ${foreignColumn}`,
268
+ params: []
269
+ };
270
+ });
271
+ const condition = conditions.length > 1 ? and(...conditions) : conditions[0];
272
+ sql2 += ` LEFT JOIN ${foreignTable._.name} ${foreignAlias} ON ${condition.sql}`;
273
+ params.push(...condition.params);
274
+ } else if (relation.type === "many") {
275
+ const refRelation = Object.entries(foreignTable.relations).find(
276
+ ([_, r]) => r.foreignTable === this.table
277
+ );
278
+ if (refRelation && refRelation[1].fields && refRelation[1].references) {
279
+ const [_, relationConfig] = refRelation;
280
+ const conditions = relationConfig.fields.map((field, i) => {
281
+ const localColumn = `${foreignAlias}.${field._.name}`;
282
+ const foreignColumn = `${this.selectedTableAlias}.${relationConfig.references[i]._.name}`;
283
+ return {
284
+ sql: `${localColumn} = ${foreignColumn}`,
285
+ params: []
286
+ };
287
+ });
288
+ const condition = conditions.length > 1 ? and(...conditions) : conditions[0];
289
+ sql2 += ` LEFT JOIN ${foreignTable._.name} ${foreignAlias} ON ${condition.sql}`;
290
+ params.push(...condition.params);
291
+ }
292
+ }
293
+ }
294
+ return { sql: sql2, params };
235
295
  }
296
+ // Enhanced execute method that handles relation data mapping
236
297
  async execute() {
237
- const { sql, params } = this.build();
238
- return this.db.select(sql, params);
298
+ const { sql: joinSql, params: joinParams } = this.buildJoins();
299
+ const distinct = this.isDistinct ? "DISTINCT " : "";
300
+ this.query = `SELECT ${distinct}${this.selectedColumns.join(", ")} ${this.query}`;
301
+ this.query += joinSql;
302
+ this.params.push(...joinParams);
303
+ const { sql: sql2, params } = this.build();
304
+ console.log("Executing SQL:", sql2, "with params:", params);
305
+ const rawResults = await this.db.select(sql2, params);
306
+ const hasIncludes = Object.values(this.includeRelations).some((i) => i);
307
+ if (hasIncludes) {
308
+ return this.processRelationResults(rawResults);
309
+ }
310
+ const hasJoins = this.joins.length > 0;
311
+ if (hasJoins) {
312
+ return rawResults;
313
+ }
314
+ const prefix = `${this.selectedTableAlias}.`;
315
+ return rawResults.map((row) => {
316
+ const newRow = {};
317
+ for (const key in row) {
318
+ if (key.startsWith(prefix)) {
319
+ newRow[key.substring(prefix.length)] = row[key];
320
+ } else {
321
+ newRow[key] = row[key];
322
+ }
323
+ }
324
+ return newRow;
325
+ });
239
326
  }
240
- };
241
- var InsertQueryBuilder = class extends BaseQueryBuilder {
242
- constructor(db, table) {
243
- super(db);
244
- this.table = table;
245
- this.query = `INSERT INTO ${table._.name}`;
327
+ processRelationResults(rawResults) {
328
+ if (!rawResults.length) return [];
329
+ const mainTablePks = Object.values(this.table._.columns).filter((c) => c.options.primaryKey).map((c) => c._.name);
330
+ if (mainTablePks.length === 0) {
331
+ return rawResults;
332
+ }
333
+ const groupedResults = /* @__PURE__ */ new Map();
334
+ for (const row of rawResults) {
335
+ const mainTableKey = mainTablePks.map((pk) => row[`${this.selectedTableAlias}.${pk}`] ?? row[pk]).join("_");
336
+ if (!groupedResults.has(mainTableKey)) {
337
+ groupedResults.set(mainTableKey, {});
338
+ }
339
+ const result = groupedResults.get(mainTableKey);
340
+ const relations2 = {};
341
+ for (const [key, value] of Object.entries(row)) {
342
+ if (key.includes(".")) {
343
+ const [tableAlias, columnName] = key.split(".");
344
+ if (tableAlias === this.selectedTableAlias) {
345
+ result[columnName] = value;
346
+ } else {
347
+ const parts = tableAlias.split("_");
348
+ if (parts.length >= 2 && parts[0] === this.selectedTableAlias) {
349
+ const relationName = parts.slice(1).join("_");
350
+ if (!relations2[relationName]) relations2[relationName] = {};
351
+ relations2[relationName][columnName] = value;
352
+ } else {
353
+ if (!result[tableAlias]) result[tableAlias] = {};
354
+ result[tableAlias][columnName] = value;
355
+ }
356
+ }
357
+ } else {
358
+ result[key] = value;
359
+ }
360
+ }
361
+ for (const [relName, relData] of Object.entries(relations2)) {
362
+ const relationConfig = this.table.relations[relName];
363
+ if (!relationConfig) continue;
364
+ const hasData = Object.values(relData).some(
365
+ (v) => v !== null && v !== void 0 && v !== ""
366
+ );
367
+ if (!hasData) continue;
368
+ if (relationConfig.type === "many") {
369
+ if (!result[relName]) result[relName] = [];
370
+ const relatedPks = Object.values(relationConfig.foreignTable._.columns).filter((c) => c.options.primaryKey).map((c) => c._.name);
371
+ const relDataKey = relatedPks.map((pk) => relData[pk]).join("_");
372
+ if (relatedPks.length === 0 || !result[relName].some((r) => relatedPks.map((pk) => r[pk]).join("_") === relDataKey)) {
373
+ result[relName].push(relData);
374
+ }
375
+ } else {
376
+ result[relName] = relData;
377
+ }
378
+ }
379
+ }
380
+ return Array.from(groupedResults.values());
246
381
  }
247
- dataSets = [];
248
- values(data) {
249
- const dataArray = Array.isArray(data) ? data : [data];
250
- this.dataSets.push(...dataArray);
251
- return this;
382
+ // Update the return type signatures
383
+ async all() {
384
+ return this.execute();
252
385
  }
253
- async execute() {
254
- if (this.dataSets.length === 0) {
255
- throw new Error("No data provided for insert");
256
- }
257
- const columns = Object.keys(
258
- this.dataSets[0]
259
- );
260
- const columnNames = columns.map(
261
- (c) => this.table._.columns[c]._.name
262
- );
263
- const placeholders = `(${columnNames.map(() => "?").join(", ")})`;
264
- const valuesSql = this.dataSets.map(() => placeholders).join(", ");
265
- this.query += ` (${columnNames.join(", ")}) VALUES ${valuesSql}`;
266
- const params = this.dataSets.flatMap(
267
- (data) => columns.map((col) => data[col])
268
- );
269
- const result = await this.db.execute(this.query, params);
270
- return result.lastInsertId ?? 0;
386
+ async get() {
387
+ this.limit(1);
388
+ const result = await this.execute();
389
+ return result[0];
271
390
  }
272
391
  };
392
+
393
+ // src/builders/update.ts
273
394
  var UpdateQueryBuilder = class extends BaseQueryBuilder {
274
395
  constructor(db, table) {
275
396
  super(db);
@@ -277,11 +398,23 @@ var UpdateQueryBuilder = class extends BaseQueryBuilder {
277
398
  this.query = `UPDATE ${table._.name}`;
278
399
  }
279
400
  updateData = {};
401
+ returningColumns = [];
280
402
  set(data) {
281
403
  this.updateData = { ...this.updateData, ...data };
282
404
  return this;
283
405
  }
284
- build() {
406
+ returning(...columns) {
407
+ this.returningColumns.push(...columns);
408
+ return this;
409
+ }
410
+ buildUpdateClause() {
411
+ const finalUpdateData = { ...this.updateData };
412
+ for (const [key, column] of Object.entries(this.table._.columns)) {
413
+ const typedKey = key;
414
+ if (finalUpdateData[typedKey] === void 0 && column.options.$onUpdateFn) {
415
+ finalUpdateData[typedKey] = column.options.$onUpdateFn();
416
+ }
417
+ }
285
418
  const baseQuery = this.query;
286
419
  const whereParams = this.params;
287
420
  let tablePart = baseQuery;
@@ -291,7 +424,7 @@ var UpdateQueryBuilder = class extends BaseQueryBuilder {
291
424
  tablePart = baseQuery.substring(0, whereIndex);
292
425
  whereClause = baseQuery.substring(whereIndex);
293
426
  }
294
- const entries = Object.entries(this.updateData);
427
+ const entries = Object.entries(finalUpdateData);
295
428
  if (entries.length === 0) {
296
429
  throw new Error("Cannot execute an update query without a .set() call.");
297
430
  }
@@ -305,61 +438,416 @@ var UpdateQueryBuilder = class extends BaseQueryBuilder {
305
438
  return `${column._.name} = ?`;
306
439
  }).join(", ");
307
440
  const setParams = entries.map(([, value]) => value);
308
- const sql = `${tablePart} SET ${setClause}${whereClause}`;
441
+ const sql2 = `${tablePart} SET ${setClause}${whereClause}`;
309
442
  const params = [...setParams, ...whereParams];
310
- return { sql, params };
443
+ return { sql: sql2, params };
311
444
  }
312
445
  async execute() {
313
- const { sql, params } = this.build();
314
- const result = await this.db.execute(sql, params);
315
- return result.rowsAffected;
446
+ const { sql: updateSql, params } = this.buildUpdateClause();
447
+ if (this.returningColumns.length > 0) {
448
+ const returningNames = this.returningColumns.map((col) => this.table._.columns[col]._.name).join(", ");
449
+ const sqlWithReturning = `${updateSql} RETURNING ${returningNames}`;
450
+ return this.db.select(sqlWithReturning, params);
451
+ } else {
452
+ const result = await this.db.execute(updateSql, params);
453
+ return [{ rowsAffected: result.rowsAffected }];
454
+ }
455
+ }
456
+ async returningAll() {
457
+ const allColumns = Object.keys(
458
+ this.table._.columns
459
+ );
460
+ return this.returning(...allColumns).execute();
316
461
  }
317
462
  };
463
+
464
+ // src/builders/insert.ts
465
+ var InsertQueryBuilder = class extends BaseQueryBuilder {
466
+ constructor(db, table) {
467
+ super(db);
468
+ this.table = table;
469
+ this.query = `INSERT INTO ${table._.name}`;
470
+ }
471
+ dataSets = [];
472
+ returningColumns = [];
473
+ onConflictAction = null;
474
+ conflictTarget = [];
475
+ updateSet = {};
476
+ values(data) {
477
+ const dataArray = Array.isArray(data) ? data : [data];
478
+ this.dataSets.push(...dataArray);
479
+ return this;
480
+ }
481
+ returning(...columns) {
482
+ this.returningColumns.push(...columns);
483
+ return this;
484
+ }
485
+ onConflictDoNothing(target) {
486
+ this.onConflictAction = "nothing";
487
+ if (target) {
488
+ this.conflictTarget = Array.isArray(target) ? target : [target];
489
+ }
490
+ return this;
491
+ }
492
+ onConflictDoUpdate(config) {
493
+ this.onConflictAction = "update";
494
+ this.conflictTarget = Array.isArray(config.target) ? config.target : [config.target];
495
+ this.updateSet = config.set;
496
+ return this;
497
+ }
498
+ processDefaultValues(data) {
499
+ const finalData = { ...data };
500
+ for (const [key, column] of Object.entries(this.table._.columns)) {
501
+ const typedKey = key;
502
+ if (finalData[typedKey] === void 0) {
503
+ if (column.options.$defaultFn) {
504
+ finalData[typedKey] = column.options.$defaultFn();
505
+ }
506
+ }
507
+ }
508
+ return finalData;
509
+ }
510
+ buildConflictClause() {
511
+ if (!this.onConflictAction) return "";
512
+ let clause = " ON CONFLICT";
513
+ if (this.conflictTarget.length > 0) {
514
+ const targetNames = this.conflictTarget.map((col) => col._.name).join(", ");
515
+ clause += ` (${targetNames})`;
516
+ }
517
+ if (this.onConflictAction === "nothing") {
518
+ clause += " DO NOTHING";
519
+ } else if (this.onConflictAction === "update") {
520
+ const setEntries = Object.entries(this.updateSet);
521
+ if (setEntries.length > 0) {
522
+ const setClause = setEntries.map(([key]) => `${key} = ?`).join(", ");
523
+ clause += ` DO UPDATE SET ${setClause}`;
524
+ }
525
+ }
526
+ return clause;
527
+ }
528
+ async execute() {
529
+ if (this.dataSets.length === 0) {
530
+ throw new Error("No data provided for insert");
531
+ }
532
+ const processedDataSets = this.dataSets.map(
533
+ (data) => this.processDefaultValues(data)
534
+ );
535
+ const groups = /* @__PURE__ */ new Map();
536
+ for (const dataSet of processedDataSets) {
537
+ const keys = Object.keys(dataSet).sort().join(",");
538
+ if (!groups.has(keys)) {
539
+ groups.set(keys, []);
540
+ }
541
+ groups.get(keys).push(dataSet);
542
+ }
543
+ let results = [];
544
+ let lastInsertId;
545
+ let rowsAffected = 0;
546
+ for (const [_, dataSets] of groups) {
547
+ const columns = Object.keys(dataSets[0]);
548
+ const columnNames = columns.map(
549
+ (key) => this.table._.columns[key]._.name
550
+ );
551
+ const placeholders = `(${columns.map(() => "?").join(", ")})`;
552
+ const valuesSql = dataSets.map(() => placeholders).join(", ");
553
+ const conflictClause = this.buildConflictClause();
554
+ const finalQuery = `${this.query} (${columnNames.join(
555
+ ", "
556
+ )}) VALUES ${valuesSql}${conflictClause}`;
557
+ const params = dataSets.flatMap(
558
+ (data) => columns.map((col) => data[col] ?? null)
559
+ );
560
+ if (this.onConflictAction === "update") {
561
+ const setValues = Object.entries(this.updateSet).map(
562
+ ([, value]) => value
563
+ );
564
+ params.push(...setValues);
565
+ }
566
+ if (this.returningColumns.length > 0) {
567
+ const returningNames = this.returningColumns.map((col) => this.table._.columns[col]._.name).join(", ");
568
+ const queryWithReturning = `${finalQuery} RETURNING ${returningNames}`;
569
+ const rows = await this.db.select(queryWithReturning, params);
570
+ results = results.concat(rows);
571
+ } else {
572
+ const result = await this.db.execute(finalQuery, params);
573
+ lastInsertId = result.lastInsertId;
574
+ rowsAffected += result.rowsAffected;
575
+ }
576
+ }
577
+ if (this.returningColumns.length > 0) {
578
+ return results;
579
+ }
580
+ return [{ lastInsertId, rowsAffected }];
581
+ }
582
+ async returningAll() {
583
+ const allColumns = Object.keys(
584
+ this.table._.columns
585
+ );
586
+ return this.returning(...allColumns).execute();
587
+ }
588
+ };
589
+
590
+ // src/builders/delete.ts
318
591
  var DeleteQueryBuilder = class extends BaseQueryBuilder {
319
592
  constructor(db, table) {
320
593
  super(db);
321
594
  this.table = table;
322
595
  this.query = `DELETE FROM ${table._.name}`;
323
596
  }
597
+ returningColumns = [];
598
+ returning(...columns) {
599
+ this.returningColumns.push(...columns);
600
+ return this;
601
+ }
324
602
  async execute() {
325
- const { sql, params } = this.build();
326
- const result = await this.db.execute(sql, params);
327
- return result.rowsAffected;
603
+ const { sql: sql2, params } = this.build();
604
+ if (this.returningColumns.length > 0) {
605
+ const returningNames = this.returningColumns.map((col) => this.table._.columns[col]._.name).join(", ");
606
+ const sqlWithReturning = `${sql2} RETURNING ${returningNames}`;
607
+ return this.db.select(sqlWithReturning, params);
608
+ } else {
609
+ const result = await this.db.execute(sql2, params);
610
+ return [{ rowsAffected: result.rowsAffected }];
611
+ }
612
+ }
613
+ async returningAll() {
614
+ const allColumns = Object.keys(this.table._.columns);
615
+ return this.returning(...allColumns).execute();
616
+ }
617
+ };
618
+
619
+ // src/builders/with.ts
620
+ var WithQueryBuilder = class {
621
+ constructor(db) {
622
+ this.db = db;
623
+ }
624
+ ctes = [];
625
+ with(alias2, query) {
626
+ this.ctes.push({ alias: alias2, query: query.sql, params: query.params });
627
+ return this;
628
+ }
629
+ select(table, columns) {
630
+ const builder = new SelectQueryBuilder(this.db, table, columns);
631
+ this.applyWithClause(builder);
632
+ return builder;
633
+ }
634
+ insert(table) {
635
+ const builder = new InsertQueryBuilder(this.db, table);
636
+ this.applyWithClause(builder);
637
+ return builder;
638
+ }
639
+ update(table) {
640
+ const builder = new UpdateQueryBuilder(this.db, table);
641
+ this.applyWithClause(builder);
642
+ return builder;
643
+ }
644
+ delete(table) {
645
+ const builder = new DeleteQueryBuilder(this.db, table);
646
+ this.applyWithClause(builder);
647
+ return builder;
648
+ }
649
+ applyWithClause(builder) {
650
+ if (this.ctes.length > 0) {
651
+ const cteSql = this.ctes.map((cte) => `${cte.alias} AS (${cte.query})`).join(", ");
652
+ builder["query"] = `WITH ${cteSql} ${builder["query"]}`;
653
+ builder["params"] = [
654
+ ...this.ctes.flatMap((cte) => cte.params),
655
+ ...builder["params"]
656
+ ];
657
+ }
658
+ }
659
+ };
660
+
661
+ // src/orm.ts
662
+ var SQLiteColumn = class _SQLiteColumn {
663
+ constructor(name, type, options = {}, mode) {
664
+ this.type = type;
665
+ this.options = options;
666
+ this._ = {
667
+ name,
668
+ dataType: type,
669
+ mode: mode || "default",
670
+ notNull: options.notNull ?? false,
671
+ hasDefault: options.default !== void 0 || options.$defaultFn !== void 0,
672
+ autoincrement: options.autoincrement ?? false,
673
+ enum: options.enum,
674
+ customType: void 0
675
+ };
676
+ }
677
+ _;
678
+ notNull() {
679
+ return new _SQLiteColumn(this._.name, this.type, { ...this.options, notNull: true }, this._.mode);
680
+ }
681
+ default(value) {
682
+ return new _SQLiteColumn(this._.name, this.type, { ...this.options, default: value }, this._.mode);
683
+ }
684
+ $defaultFn(fn) {
685
+ return new _SQLiteColumn(this._.name, this.type, { ...this.options, $defaultFn: fn }, this._.mode);
686
+ }
687
+ primaryKey() {
688
+ return new _SQLiteColumn(
689
+ this._.name,
690
+ this.type,
691
+ { ...this.options, primaryKey: true, notNull: true },
692
+ this._.mode
693
+ );
694
+ }
695
+ autoincrement() {
696
+ return new _SQLiteColumn(this._.name, this.type, { ...this.options, autoincrement: true }, this._.mode);
697
+ }
698
+ unique() {
699
+ return new _SQLiteColumn(this._.name, this.type, { ...this.options, unique: true }, this._.mode);
700
+ }
701
+ references(ref, column) {
702
+ return new _SQLiteColumn(
703
+ this._.name,
704
+ this.type,
705
+ {
706
+ ...this.options,
707
+ references: {
708
+ table: ref,
709
+ column: ref._.columns[column]
710
+ }
711
+ },
712
+ this._.mode
713
+ );
714
+ }
715
+ $onUpdateFn(fn) {
716
+ return new _SQLiteColumn(this._.name, this.type, { ...this.options, $onUpdateFn: fn }, this._.mode);
717
+ }
718
+ $type() {
719
+ return this;
720
+ }
721
+ as(alias2) {
722
+ return this;
723
+ }
724
+ };
725
+ var Table = class {
726
+ _;
727
+ relations = {};
728
+ constructor(name, columns) {
729
+ this._ = {
730
+ name,
731
+ columns
732
+ };
328
733
  }
329
734
  };
735
+ var sqliteTable = (tableName, columns) => {
736
+ return new Table(tableName, columns);
737
+ };
738
+ var asc = (column) => ({
739
+ sql: `${column._.name} ASC`,
740
+ params: []
741
+ });
742
+ var desc = (column) => ({
743
+ sql: `${column._.name} DESC`,
744
+ params: []
745
+ });
746
+ var sql = (strings, ...values) => {
747
+ const queryParts = [];
748
+ const params = [];
749
+ strings.forEach((str, i) => {
750
+ queryParts.push(str);
751
+ if (values[i] !== void 0) {
752
+ if (typeof values[i] === "object" && values[i].sql) {
753
+ queryParts.push(values[i].sql);
754
+ params.push(...values[i].params);
755
+ } else {
756
+ queryParts.push("?");
757
+ params.push(values[i]);
758
+ }
759
+ }
760
+ });
761
+ return {
762
+ sql: queryParts.join(""),
763
+ params
764
+ };
765
+ };
330
766
  var TauriORM = class {
331
767
  constructor(db, schema = void 0) {
332
768
  this.db = db;
333
769
  if (schema) {
334
- for (const table of Object.values(schema)) {
335
- this.tables.set(table._.name, table);
770
+ for (const [key, value] of Object.entries(schema)) {
771
+ if (value instanceof Table) {
772
+ this.tables.set(value._.name, value);
773
+ }
336
774
  }
337
775
  }
338
776
  }
339
777
  tables = /* @__PURE__ */ new Map();
340
- async migrate() {
778
+ buildColumnDefinition(col, forAlterTable = false) {
779
+ let sql2 = `${col._.name} ${col.type}`;
780
+ if (col.options.primaryKey && !forAlterTable) {
781
+ sql2 += " PRIMARY KEY";
782
+ if (col._.autoincrement) {
783
+ sql2 += " AUTOINCREMENT";
784
+ }
785
+ }
786
+ if (col._.notNull) sql2 += " NOT NULL";
787
+ if (col.options.unique) sql2 += " UNIQUE";
788
+ if (col.options.default !== void 0) {
789
+ const value = col.options.default;
790
+ sql2 += ` DEFAULT ${typeof value === "string" ? `'${value.replace(/'/g, "''")}'` : value}`;
791
+ }
792
+ if (col.options.references) {
793
+ sql2 += ` REFERENCES ${col.options.references.table._.name}(${col.options.references.column._.name})`;
794
+ }
795
+ return sql2;
796
+ }
797
+ async migrate(options) {
798
+ const dbTables = await this.db.select(
799
+ `SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'`
800
+ );
801
+ const dbTableNames = new Set(dbTables.map((t) => t.name));
802
+ const schemaTableNames = new Set(Array.from(this.tables.keys()));
341
803
  for (const table of this.tables.values()) {
342
- const columnsSql = Object.entries(table._.columns).map(([name, col]) => {
343
- let sql = `${col._.name} ${col.type}`;
344
- if (col.options.primaryKey) sql += " PRIMARY KEY";
345
- if (col._.autoincrement) sql += " AUTOINCREMENT";
346
- if (col._.notNull) sql += " NOT NULL";
347
- if (col.options.unique) sql += " UNIQUE";
348
- if (col.options.default !== void 0) {
349
- const value = col.options.default;
350
- sql += ` DEFAULT ${typeof value === "string" ? `'${value}'` : value}`;
804
+ const tableName = table._.name;
805
+ const tableExists = dbTableNames.has(tableName);
806
+ if (!tableExists) {
807
+ const columnsSql = Object.values(table._.columns).map((col) => this.buildColumnDefinition(col)).join(", ");
808
+ const createSql = `CREATE TABLE ${tableName}
809
+ (
810
+ ${columnsSql}
811
+ )`;
812
+ await this.db.execute(createSql);
813
+ } else {
814
+ const existingTableInfo = await this.db.select(`PRAGMA table_info('${tableName}')`);
815
+ const existingColumnNames = new Set(existingTableInfo.map((c) => c.name));
816
+ const schemaColumnNames = new Set(Object.keys(table._.columns));
817
+ for (const column of Object.values(table._.columns)) {
818
+ if (!existingColumnNames.has(column._.name)) {
819
+ const columnSql = this.buildColumnDefinition(column, true);
820
+ const alterSql = `ALTER TABLE ${tableName}
821
+ ADD COLUMN ${columnSql}`;
822
+ await this.db.execute(alterSql);
823
+ }
824
+ }
825
+ if (options?.performDestructiveActions) {
826
+ for (const colName of existingColumnNames) {
827
+ if (!schemaColumnNames.has(colName)) {
828
+ await this.dropColumn(tableName, colName);
829
+ }
830
+ }
351
831
  }
352
- if (col.options.references) {
353
- sql += ` REFERENCES ${col.options.references.table._.name}(${col.options.references.column._.name})`;
832
+ }
833
+ }
834
+ if (options?.performDestructiveActions) {
835
+ for (const tableName of dbTableNames) {
836
+ if (!schemaTableNames.has(tableName)) {
837
+ await this.dropTable(tableName);
354
838
  }
355
- return sql;
356
- }).join(", ");
357
- const createSql = `CREATE TABLE IF NOT EXISTS ${table._.name} (${columnsSql})`;
358
- await this.db.execute(createSql);
839
+ }
359
840
  }
360
841
  }
361
842
  select(table, columns) {
362
- return new SelectQueryBuilder(this.db, table, columns);
843
+ const internalTable = this.tables.get(table._.name);
844
+ if (!internalTable) {
845
+ console.warn(
846
+ `[Tauri-ORM] Table "${table._.name}" was not passed in the schema to the ORM constructor. Relations will not be available.`
847
+ );
848
+ return new SelectQueryBuilder(this.db, table, columns);
849
+ }
850
+ return new SelectQueryBuilder(this.db, internalTable, columns);
363
851
  }
364
852
  insert(table) {
365
853
  return new InsertQueryBuilder(this.db, table);
@@ -370,6 +858,15 @@ var TauriORM = class {
370
858
  delete(table) {
371
859
  return new DeleteQueryBuilder(this.db, table);
372
860
  }
861
+ $with(alias2) {
862
+ const withBuilder = new WithQueryBuilder(this.db);
863
+ return {
864
+ as: (query) => {
865
+ withBuilder.with(alias2, query);
866
+ return withBuilder;
867
+ }
868
+ };
869
+ }
373
870
  async transaction(callback) {
374
871
  await this.db.execute("BEGIN TRANSACTION");
375
872
  try {
@@ -381,16 +878,31 @@ var TauriORM = class {
381
878
  throw error;
382
879
  }
383
880
  }
881
+ rollback() {
882
+ throw new Error("Transaction rolled back");
883
+ }
384
884
  // --- Schema detection / signature ---
385
885
  async ensureSchemaMeta() {
386
886
  await this.db.execute(
387
- `CREATE TABLE IF NOT EXISTS _schema_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)`
887
+ `CREATE TABLE IF NOT EXISTS _schema_meta
888
+ (
889
+ key
890
+ TEXT
891
+ PRIMARY
892
+ KEY,
893
+ value
894
+ TEXT
895
+ NOT
896
+ NULL
897
+ )`
388
898
  );
389
899
  }
390
900
  async getSchemaMeta(key) {
391
901
  await this.ensureSchemaMeta();
392
902
  const rows = await this.db.select(
393
- `SELECT value FROM _schema_meta WHERE key = ?`,
903
+ `SELECT value
904
+ FROM _schema_meta
905
+ WHERE key = ?`,
394
906
  [key]
395
907
  );
396
908
  return rows?.[0]?.value ?? null;
@@ -398,7 +910,10 @@ var TauriORM = class {
398
910
  async setSchemaMeta(key, value) {
399
911
  await this.ensureSchemaMeta();
400
912
  await this.db.execute(
401
- `INSERT INTO _schema_meta(key, value) VALUES(?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value`,
913
+ `INSERT INTO _schema_meta(key, value)
914
+ VALUES (?, ?) ON CONFLICT(key) DO
915
+ UPDATE
916
+ SET value = excluded.value`,
402
917
  [key, value]
403
918
  );
404
919
  }
@@ -409,7 +924,10 @@ var TauriORM = class {
409
924
  pk: !!col.options.primaryKey,
410
925
  ai: !!col._.autoincrement,
411
926
  nn: !!col._.notNull,
412
- dv: col.options.default && typeof col.options.default === "object" && col.options.default.raw ? { raw: col.options.default.raw } : col.options.default ?? null
927
+ unique: !!col.options.unique,
928
+ dv: col.options.default && typeof col.options.default === "object" && col.options.default.raw ? { raw: col.options.default.raw } : col.options.default ?? null,
929
+ hasDefaultFn: col.options.$defaultFn !== void 0,
930
+ hasOnUpdateFn: col.options.$onUpdateFn !== void 0
413
931
  };
414
932
  }
415
933
  computeModelSignature() {
@@ -432,42 +950,118 @@ var TauriORM = class {
432
950
  const status = await this.isSchemaDirty();
433
951
  if (status.dirty) {
434
952
  await this.migrate();
435
- await this.setSchemaMeta(
436
- "schema_signature",
437
- this.computeModelSignature()
438
- );
953
+ await this.setSchemaMeta("schema_signature", this.computeModelSignature());
439
954
  return true;
440
955
  }
441
956
  return false;
442
957
  }
958
+ async doesTableExist(tableName) {
959
+ const result = await this.db.select(
960
+ `SELECT name FROM sqlite_master WHERE type='table' AND name=?`,
961
+ [tableName]
962
+ );
963
+ return result.length > 0;
964
+ }
965
+ async dropTable(tableName) {
966
+ await this.db.execute(`DROP TABLE IF EXISTS ${tableName}`);
967
+ }
968
+ async doesColumnExist(tableName, columnName) {
969
+ const result = await this.db.select(`PRAGMA table_info('${tableName}')`);
970
+ return result.some((col) => col.name === columnName);
971
+ }
972
+ async renameTable(from, to) {
973
+ await this.db.execute(`ALTER TABLE ${from} RENAME TO ${to}`);
974
+ }
975
+ async dropColumn(tableName, columnName) {
976
+ await this.db.execute(`ALTER TABLE ${tableName} DROP COLUMN ${columnName}`);
977
+ }
978
+ async renameColumn(tableName, from, to) {
979
+ await this.db.execute(`ALTER TABLE ${tableName} RENAME COLUMN ${from} TO ${to}`);
980
+ }
981
+ };
982
+ var Relation = class {
983
+ constructor(foreignTable) {
984
+ this.foreignTable = foreignTable;
985
+ }
986
+ };
987
+ var OneRelation = class extends Relation {
988
+ constructor(foreignTable, config) {
989
+ super(foreignTable);
990
+ this.config = config;
991
+ }
992
+ };
993
+ var ManyRelation = class extends Relation {
994
+ constructor(foreignTable) {
995
+ super(foreignTable);
996
+ }
443
997
  };
444
998
  var relations = (table, relationsCallback) => {
445
- return relationsCallback({
446
- one: (table2, config) => ({
447
- table: table2,
448
- type: "one",
449
- foreignKey: config.fields[0],
450
- localKey: config.references[0]
451
- }),
452
- many: (table2) => ({
453
- table: table2,
454
- type: "many"
455
- })
999
+ const builtRelations = relationsCallback({
1000
+ one: (foreignTable, config) => {
1001
+ return new OneRelation(foreignTable, config);
1002
+ },
1003
+ many: (foreignTable) => {
1004
+ return new ManyRelation(foreignTable);
1005
+ }
456
1006
  });
1007
+ for (const [name, relation] of Object.entries(builtRelations)) {
1008
+ if (relation instanceof OneRelation) {
1009
+ table.relations[name] = {
1010
+ type: "one",
1011
+ foreignTable: relation.foreignTable,
1012
+ fields: relation.config?.fields,
1013
+ references: relation.config?.references
1014
+ };
1015
+ } else if (relation instanceof ManyRelation) {
1016
+ table.relations[name] = {
1017
+ type: "many",
1018
+ foreignTable: relation.foreignTable
1019
+ };
1020
+ }
1021
+ }
1022
+ return builtRelations;
1023
+ };
1024
+ var getTableColumns = (table) => {
1025
+ return table._.columns;
457
1026
  };
1027
+ var alias = (table, alias2) => {
1028
+ return table;
1029
+ };
1030
+
1031
+ // src/column-helpers.ts
1032
+ var text = (name, config) => new SQLiteColumn(name, "TEXT", config, config?.mode);
1033
+ var integer = (name, config) => new SQLiteColumn(name, "INTEGER", {}, config?.mode || "default");
1034
+ var real = (name) => new SQLiteColumn(name, "REAL");
1035
+ var blob = (name, config) => new SQLiteColumn(name, "BLOB", {}, config?.mode);
1036
+ var boolean = (name) => new SQLiteColumn(name, "BOOLEAN");
1037
+ var numeric = (name, config) => new SQLiteColumn(name, "NUMERIC", {}, config?.mode);
1038
+ var enumType = (name, values) => text(name, { enum: values });
458
1039
  // Annotate the CommonJS export names for ESM import in node:
459
1040
  0 && (module.exports = {
1041
+ BaseQueryBuilder,
460
1042
  DeleteQueryBuilder,
461
1043
  InsertQueryBuilder,
1044
+ ManyRelation,
1045
+ OneRelation,
1046
+ Relation,
462
1047
  SQLiteColumn,
463
1048
  SelectQueryBuilder,
464
1049
  Table,
465
1050
  TauriORM,
466
1051
  UpdateQueryBuilder,
1052
+ WithQueryBuilder,
1053
+ alias,
467
1054
  and,
1055
+ asc,
1056
+ avg,
468
1057
  blob,
469
1058
  boolean,
1059
+ count,
1060
+ countDistinct,
1061
+ desc,
1062
+ enumType,
470
1063
  eq,
1064
+ getTableColumns,
471
1065
  gt,
472
1066
  gte,
473
1067
  inArray,
@@ -477,9 +1071,15 @@ var relations = (table, relationsCallback) => {
477
1071
  like,
478
1072
  lt,
479
1073
  lte,
1074
+ max,
1075
+ min,
1076
+ not,
1077
+ numeric,
480
1078
  or,
481
1079
  real,
482
1080
  relations,
1081
+ sql,
483
1082
  sqliteTable,
1083
+ sum,
484
1084
  text
485
1085
  });