@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.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;
235
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 };
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,394 @@ 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
+ }
328
658
  }
329
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
+ };
733
+ }
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();
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
+ }
340
797
  async migrate() {
341
798
  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}`;
799
+ const existingTableInfo = await this.db.select(`PRAGMA table_info('${table._.name}')`);
800
+ if (existingTableInfo.length === 0) {
801
+ const columnsSql = Object.values(table._.columns).map((col) => this.buildColumnDefinition(col)).join(", ");
802
+ const createSql = `CREATE TABLE ${table._.name}
803
+ (
804
+ ${columnsSql}
805
+ )`;
806
+ await this.db.execute(createSql);
807
+ } else {
808
+ const existingColumnNames = new Set(existingTableInfo.map((c) => c.name));
809
+ for (const column of Object.values(table._.columns)) {
810
+ if (!existingColumnNames.has(column._.name)) {
811
+ const columnSql = this.buildColumnDefinition(column, true);
812
+ const alterSql = `ALTER TABLE ${table._.name}
813
+ ADD COLUMN ${columnSql}`;
814
+ await this.db.execute(alterSql);
815
+ }
351
816
  }
352
- if (col.options.references) {
353
- sql += ` REFERENCES ${col.options.references.table._.name}(${col.options.references.column._.name})`;
354
- }
355
- return sql;
356
- }).join(", ");
357
- const createSql = `CREATE TABLE IF NOT EXISTS ${table._.name} (${columnsSql})`;
358
- await this.db.execute(createSql);
817
+ }
359
818
  }
360
819
  }
361
820
  select(table, columns) {
362
- return new SelectQueryBuilder(this.db, table, columns);
821
+ const internalTable = this.tables.get(table._.name);
822
+ if (!internalTable) {
823
+ console.warn(
824
+ `[Tauri-ORM] Table "${table._.name}" was not passed in the schema to the ORM constructor. Relations will not be available.`
825
+ );
826
+ return new SelectQueryBuilder(this.db, table, columns);
827
+ }
828
+ return new SelectQueryBuilder(this.db, internalTable, columns);
363
829
  }
364
830
  insert(table) {
365
831
  return new InsertQueryBuilder(this.db, table);
@@ -370,6 +836,15 @@ var TauriORM = class {
370
836
  delete(table) {
371
837
  return new DeleteQueryBuilder(this.db, table);
372
838
  }
839
+ $with(alias2) {
840
+ const withBuilder = new WithQueryBuilder(this.db);
841
+ return {
842
+ as: (query) => {
843
+ withBuilder.with(alias2, query);
844
+ return withBuilder;
845
+ }
846
+ };
847
+ }
373
848
  async transaction(callback) {
374
849
  await this.db.execute("BEGIN TRANSACTION");
375
850
  try {
@@ -381,16 +856,31 @@ var TauriORM = class {
381
856
  throw error;
382
857
  }
383
858
  }
859
+ rollback() {
860
+ throw new Error("Transaction rolled back");
861
+ }
384
862
  // --- Schema detection / signature ---
385
863
  async ensureSchemaMeta() {
386
864
  await this.db.execute(
387
- `CREATE TABLE IF NOT EXISTS _schema_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)`
865
+ `CREATE TABLE IF NOT EXISTS _schema_meta
866
+ (
867
+ key
868
+ TEXT
869
+ PRIMARY
870
+ KEY,
871
+ value
872
+ TEXT
873
+ NOT
874
+ NULL
875
+ )`
388
876
  );
389
877
  }
390
878
  async getSchemaMeta(key) {
391
879
  await this.ensureSchemaMeta();
392
880
  const rows = await this.db.select(
393
- `SELECT value FROM _schema_meta WHERE key = ?`,
881
+ `SELECT value
882
+ FROM _schema_meta
883
+ WHERE key = ?`,
394
884
  [key]
395
885
  );
396
886
  return rows?.[0]?.value ?? null;
@@ -398,7 +888,10 @@ var TauriORM = class {
398
888
  async setSchemaMeta(key, value) {
399
889
  await this.ensureSchemaMeta();
400
890
  await this.db.execute(
401
- `INSERT INTO _schema_meta(key, value) VALUES(?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value`,
891
+ `INSERT INTO _schema_meta(key, value)
892
+ VALUES (?, ?) ON CONFLICT(key) DO
893
+ UPDATE
894
+ SET value = excluded.value`,
402
895
  [key, value]
403
896
  );
404
897
  }
@@ -409,7 +902,10 @@ var TauriORM = class {
409
902
  pk: !!col.options.primaryKey,
410
903
  ai: !!col._.autoincrement,
411
904
  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
905
+ unique: !!col.options.unique,
906
+ dv: col.options.default && typeof col.options.default === "object" && col.options.default.raw ? { raw: col.options.default.raw } : col.options.default ?? null,
907
+ hasDefaultFn: col.options.$defaultFn !== void 0,
908
+ hasOnUpdateFn: col.options.$onUpdateFn !== void 0
413
909
  };
414
910
  }
415
911
  computeModelSignature() {
@@ -432,42 +928,95 @@ var TauriORM = class {
432
928
  const status = await this.isSchemaDirty();
433
929
  if (status.dirty) {
434
930
  await this.migrate();
435
- await this.setSchemaMeta(
436
- "schema_signature",
437
- this.computeModelSignature()
438
- );
931
+ await this.setSchemaMeta("schema_signature", this.computeModelSignature());
439
932
  return true;
440
933
  }
441
934
  return false;
442
935
  }
443
936
  };
937
+ var Relation = class {
938
+ constructor(foreignTable) {
939
+ this.foreignTable = foreignTable;
940
+ }
941
+ };
942
+ var OneRelation = class extends Relation {
943
+ constructor(foreignTable, config) {
944
+ super(foreignTable);
945
+ this.config = config;
946
+ }
947
+ };
948
+ var ManyRelation = class extends Relation {
949
+ constructor(foreignTable) {
950
+ super(foreignTable);
951
+ }
952
+ };
444
953
  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
- })
954
+ const builtRelations = relationsCallback({
955
+ one: (foreignTable, config) => {
956
+ return new OneRelation(foreignTable, config);
957
+ },
958
+ many: (foreignTable) => {
959
+ return new ManyRelation(foreignTable);
960
+ }
456
961
  });
962
+ for (const [name, relation] of Object.entries(builtRelations)) {
963
+ if (relation instanceof OneRelation) {
964
+ table.relations[name] = {
965
+ type: "one",
966
+ foreignTable: relation.foreignTable,
967
+ fields: relation.config?.fields,
968
+ references: relation.config?.references
969
+ };
970
+ } else if (relation instanceof ManyRelation) {
971
+ table.relations[name] = {
972
+ type: "many",
973
+ foreignTable: relation.foreignTable
974
+ };
975
+ }
976
+ }
977
+ return builtRelations;
978
+ };
979
+ var getTableColumns = (table) => {
980
+ return table._.columns;
457
981
  };
982
+ var alias = (table, alias2) => {
983
+ return table;
984
+ };
985
+
986
+ // src/column-helpers.ts
987
+ var text = (name, config) => new SQLiteColumn(name, "TEXT", config, config?.mode);
988
+ var integer = (name, config) => new SQLiteColumn(name, "INTEGER", {}, config?.mode || "default");
989
+ var real = (name) => new SQLiteColumn(name, "REAL");
990
+ var blob = (name, config) => new SQLiteColumn(name, "BLOB", {}, config?.mode);
991
+ var boolean = (name) => new SQLiteColumn(name, "BOOLEAN");
992
+ var numeric = (name, config) => new SQLiteColumn(name, "NUMERIC", {}, config?.mode);
993
+ var enumType = (name, values) => text(name, { enum: values });
458
994
  // Annotate the CommonJS export names for ESM import in node:
459
995
  0 && (module.exports = {
996
+ BaseQueryBuilder,
460
997
  DeleteQueryBuilder,
461
998
  InsertQueryBuilder,
999
+ ManyRelation,
1000
+ OneRelation,
1001
+ Relation,
462
1002
  SQLiteColumn,
463
1003
  SelectQueryBuilder,
464
1004
  Table,
465
1005
  TauriORM,
466
1006
  UpdateQueryBuilder,
1007
+ WithQueryBuilder,
1008
+ alias,
467
1009
  and,
1010
+ asc,
1011
+ avg,
468
1012
  blob,
469
1013
  boolean,
1014
+ count,
1015
+ countDistinct,
1016
+ desc,
1017
+ enumType,
470
1018
  eq,
1019
+ getTableColumns,
471
1020
  gt,
472
1021
  gte,
473
1022
  inArray,
@@ -477,9 +1026,15 @@ var relations = (table, relationsCallback) => {
477
1026
  like,
478
1027
  lt,
479
1028
  lte,
1029
+ max,
1030
+ min,
1031
+ not,
1032
+ numeric,
480
1033
  or,
481
1034
  real,
482
1035
  relations,
1036
+ sql,
483
1037
  sqliteTable,
1038
+ sum,
484
1039
  text
485
1040
  });