@type32/tauri-sqlite-orm 0.1.3 → 0.1.5

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,24 +1,10 @@
1
- // src/connection.ts
2
- import Database from "@tauri-apps/plugin-sql";
3
- var db = null;
4
- async function initDb(dbPath) {
5
- db = await Database.load(dbPath);
6
- return db;
7
- }
8
- function getDb() {
9
- if (!db) {
10
- throw new Error("Database not initialized. Please call initDb() first.");
11
- }
12
- return db;
13
- }
14
-
15
1
  // src/schema-builder.ts
16
2
  function sql(strings, ...values) {
17
- const raw = strings.reduce(
3
+ const raw2 = strings.reduce(
18
4
  (acc, part, idx) => acc + part + (idx < values.length ? String(values[idx]) : ""),
19
5
  ""
20
6
  );
21
- return { raw };
7
+ return { raw: raw2 };
22
8
  }
23
9
  function createColumn(params) {
24
10
  const col = { ...params };
@@ -40,6 +26,18 @@ function createColumn(params) {
40
26
  col.defaultFn = fn;
41
27
  return col;
42
28
  };
29
+ col.$default = (fn) => {
30
+ col.defaultFn = fn;
31
+ return col;
32
+ };
33
+ col.$onUpdate = (fn) => {
34
+ col.onUpdateFn = fn;
35
+ return col;
36
+ };
37
+ col.$onUpdateFn = (fn) => {
38
+ col.onUpdateFn = fn;
39
+ return col;
40
+ };
43
41
  col.references = (target, actions) => {
44
42
  const t = target();
45
43
  col.references = {
@@ -52,34 +50,43 @@ function createColumn(params) {
52
50
  };
53
51
  return col;
54
52
  }
55
- function text(name, config) {
53
+ function text(nameOrConfig, maybeConfig) {
54
+ const name = typeof nameOrConfig === "string" ? nameOrConfig : "";
55
+ const config = typeof nameOrConfig === "string" ? maybeConfig : nameOrConfig;
56
56
  const col = createColumn({
57
57
  name,
58
58
  type: "TEXT",
59
- isPrimaryKey: config?.isPrimaryKey,
60
59
  _dataType: ""
61
60
  });
62
61
  if (config?.enum) col.enumValues = config.enum;
62
+ if (config?.mode) col.mode = config.mode;
63
63
  return col;
64
64
  }
65
- function integer(name, config) {
65
+ function integer(nameOrConfig, maybeConfig) {
66
+ const name = typeof nameOrConfig === "string" ? nameOrConfig : "";
67
+ const config = typeof nameOrConfig === "string" ? maybeConfig : nameOrConfig;
66
68
  let dt = 0;
67
69
  if (config?.mode === "boolean") dt = false;
68
- if (config?.mode === "timestamp") dt = /* @__PURE__ */ new Date();
70
+ if (config?.mode === "timestamp" || config?.mode === "timestamp_ms")
71
+ dt = /* @__PURE__ */ new Date();
69
72
  const col = createColumn({
70
73
  name,
71
74
  type: "INTEGER",
72
- isPrimaryKey: config?.isPrimaryKey,
73
- autoIncrement: config?.autoIncrement,
74
75
  mode: config?.mode ?? "number",
75
76
  _dataType: dt
76
77
  });
77
78
  return col;
78
79
  }
79
80
  function real(name) {
80
- return createColumn({ name, type: "REAL", _dataType: 0 });
81
+ return createColumn({
82
+ name: name ?? "",
83
+ type: "REAL",
84
+ _dataType: 0
85
+ });
81
86
  }
82
- function blob(name, config) {
87
+ function blob(nameOrConfig, maybeConfig) {
88
+ const name = typeof nameOrConfig === "string" ? nameOrConfig : "";
89
+ const config = typeof nameOrConfig === "string" ? maybeConfig : nameOrConfig;
83
90
  let dt = new Uint8Array();
84
91
  if (config?.mode === "bigint") dt = 0n;
85
92
  if (config?.mode === "json") dt = void 0;
@@ -90,7 +97,9 @@ function blob(name, config) {
90
97
  _dataType: dt
91
98
  });
92
99
  }
93
- function numeric(name, config) {
100
+ function numeric(nameOrConfig, maybeConfig) {
101
+ const name = typeof nameOrConfig === "string" ? nameOrConfig : "";
102
+ const config = typeof nameOrConfig === "string" ? maybeConfig : nameOrConfig;
94
103
  let dt = "";
95
104
  if (config?.mode === "number") dt = 0;
96
105
  if (config?.mode === "bigint") dt = 0n;
@@ -101,59 +110,346 @@ function numeric(name, config) {
101
110
  _dataType: dt
102
111
  });
103
112
  }
104
- var boolean = (name) => createColumn({
105
- name,
106
- type: "INTEGER",
107
- _dataType: false,
108
- mode: "boolean"
109
- });
110
- var timestamp = (name) => createColumn({
111
- name,
112
- type: "INTEGER",
113
- _dataType: /* @__PURE__ */ new Date(),
114
- mode: "timestamp"
115
- });
116
- function defineTable(tableName, schema) {
113
+ function boolean(name) {
114
+ return createColumn({
115
+ name: name ?? "",
116
+ type: "INTEGER",
117
+ _dataType: false,
118
+ mode: "boolean"
119
+ });
120
+ }
121
+ function timestamp(name) {
122
+ return createColumn({
123
+ name: name ?? "",
124
+ type: "INTEGER",
125
+ _dataType: /* @__PURE__ */ new Date(),
126
+ mode: "timestamp"
127
+ });
128
+ }
129
+ function increments(name) {
130
+ return integer(name ?? "").primaryKey({
131
+ autoIncrement: true
132
+ });
133
+ }
134
+ function unique(name) {
135
+ return {
136
+ on: (...cols) => ({ name, columns: cols.map((c) => c.name) })
137
+ };
138
+ }
139
+ function primaryKey(opts) {
140
+ return { name: opts.name, columns: opts.columns.map((c) => c.name) };
141
+ }
142
+ function check(name, expr) {
143
+ return { name, expr };
144
+ }
145
+ function foreignKey(opts) {
146
+ const first = opts.columns[0];
147
+ return {
148
+ name: opts.name,
149
+ columns: opts.columns.map((c) => c.name),
150
+ foreignTable: first?.tableName || opts.foreignColumns[0]?.tableName || "",
151
+ foreignColumns: opts.foreignColumns.map((c) => c.name),
152
+ onDelete: opts.onDelete,
153
+ onUpdate: opts.onUpdate
154
+ };
155
+ }
156
+ function index(name) {
157
+ return {
158
+ on: (...cols) => ({ name, columns: cols.map((c) => c.name) }),
159
+ where: (expr) => ({ name, columns: [], where: expr })
160
+ };
161
+ }
162
+ function uniqueIndex(name) {
163
+ return {
164
+ on: (...cols) => ({ name, columns: cols.map((c) => c.name), unique: true }),
165
+ where: (expr) => ({ name, columns: [], unique: true, where: expr })
166
+ };
167
+ }
168
+ function defineTable(tableName, schema, extras) {
117
169
  const finalizedSchema = { ...schema };
118
170
  for (const key of Object.keys(finalizedSchema)) {
119
171
  const col = finalizedSchema[key];
172
+ if (!col.name || col.name === "") col.name = key;
120
173
  col.tableName = tableName;
121
174
  }
122
175
  const table = {
123
176
  _tableName: tableName,
124
177
  _schema: finalizedSchema,
178
+ _constraints: [],
179
+ _indexes: [],
125
180
  // The Drizzle-like type inference properties
126
181
  $inferSelect: {},
127
182
  $inferInsert: {}
128
- // Example: omit 'id' for inserts
183
+ // omit PK columns
129
184
  };
130
185
  for (const [key, col] of Object.entries(finalizedSchema)) {
131
186
  table[key] = col;
132
187
  }
188
+ if (extras) {
189
+ const specs = extras(table) || [];
190
+ for (const s of specs) {
191
+ if (s.columns && s.unique !== void 0) {
192
+ table._indexes.push(s);
193
+ } else if (s.columns && s.foreignColumns) {
194
+ table._constraints.push(s);
195
+ } else if (s.columns && (s.name || s.name === void 0)) {
196
+ if (s.columns && s.name !== void 0 && s.columns.length > 0) {
197
+ const pk = s;
198
+ if (pk.columns.length > 1 || pk.name && pk.name.length > 0) {
199
+ table._constraints.push(s);
200
+ } else {
201
+ table._constraints.push(s);
202
+ }
203
+ } else {
204
+ table._constraints.push(s);
205
+ }
206
+ } else if (s.expr) {
207
+ table._constraints.push(s);
208
+ }
209
+ }
210
+ }
133
211
  return table;
134
212
  }
135
213
 
214
+ // src/orm.ts
215
+ import Database from "@tauri-apps/plugin-sql";
216
+
217
+ // src/sql-helpers.ts
218
+ function raw(strings, ...values) {
219
+ return {
220
+ toSQL: () => {
221
+ let clause = "";
222
+ const bindings = [];
223
+ for (let i = 0; i < strings.length; i++) {
224
+ clause += strings[i];
225
+ if (i < values.length) {
226
+ const v = values[i];
227
+ if (v && typeof v === "object" && typeof v.toSQL === "function") {
228
+ const s = v.toSQL();
229
+ clause += s.clause;
230
+ bindings.push(...s.bindings);
231
+ } else if (v && typeof v === "object" && "_dataType" in v) {
232
+ clause += getQualifiedName(v);
233
+ } else {
234
+ clause += "?";
235
+ bindings.push(v);
236
+ }
237
+ }
238
+ }
239
+ return { clause, bindings };
240
+ }
241
+ };
242
+ }
243
+ function isColumn(value) {
244
+ return typeof value === "object" && value !== null && "_dataType" in value;
245
+ }
246
+ function getQualifiedName(column) {
247
+ if (column.tableName) return `${column.tableName}.${column.name}`;
248
+ return column.name;
249
+ }
250
+ function comparison(operator, column, value) {
251
+ return {
252
+ toSQL: () => {
253
+ if (isColumn(value)) {
254
+ return {
255
+ clause: `${getQualifiedName(column)} ${operator} ${getQualifiedName(
256
+ value
257
+ )}`,
258
+ bindings: []
259
+ };
260
+ }
261
+ return {
262
+ clause: `${getQualifiedName(column)} ${operator} ?`,
263
+ bindings: [value]
264
+ };
265
+ }
266
+ };
267
+ }
268
+ var and = (...conditions) => ({
269
+ toSQL: () => {
270
+ const parts = [];
271
+ const bindings = [];
272
+ for (const c of conditions) {
273
+ const s = c.toSQL();
274
+ parts.push(`(${s.clause})`);
275
+ bindings.push(...s.bindings);
276
+ }
277
+ return { clause: parts.join(" AND "), bindings };
278
+ }
279
+ });
280
+ var or = (...conditions) => ({
281
+ toSQL: () => {
282
+ const parts = [];
283
+ const bindings = [];
284
+ for (const c of conditions) {
285
+ const s = c.toSQL();
286
+ parts.push(`(${s.clause})`);
287
+ bindings.push(...s.bindings);
288
+ }
289
+ return { clause: parts.join(" OR "), bindings };
290
+ }
291
+ });
292
+ var not = (condition) => ({
293
+ toSQL: () => {
294
+ const s = condition.toSQL();
295
+ return { clause: `NOT (${s.clause})`, bindings: s.bindings };
296
+ }
297
+ });
298
+ var eq = (column, value) => comparison("=", column, value);
299
+ var ne = (column, value) => comparison("!=", column, value);
300
+ var gt = (column, value) => comparison(">", column, value);
301
+ var gte = (column, value) => comparison(">=", column, value);
302
+ var lt = (column, value) => comparison("<", column, value);
303
+ var lte = (column, value) => comparison("<=", column, value);
304
+ var like = (column, value) => comparison("LIKE", column, value);
305
+ var ilike = (column, value) => ({
306
+ toSQL: () => {
307
+ const colExpr = `LOWER(${getQualifiedName(column)})`;
308
+ if (isColumn(value)) {
309
+ return {
310
+ clause: `${colExpr} LIKE LOWER(${getQualifiedName(value)})`,
311
+ bindings: []
312
+ };
313
+ }
314
+ return { clause: `${colExpr} LIKE LOWER(?)`, bindings: [value] };
315
+ }
316
+ });
317
+ var notIlike = (column, value) => ({
318
+ toSQL: () => {
319
+ const colExpr = `LOWER(${getQualifiedName(column)})`;
320
+ if (isColumn(value)) {
321
+ return {
322
+ clause: `${colExpr} NOT LIKE LOWER(${getQualifiedName(value)})`,
323
+ bindings: []
324
+ };
325
+ }
326
+ return { clause: `${colExpr} NOT LIKE LOWER(?)`, bindings: [value] };
327
+ }
328
+ });
329
+ var isNull = (column) => ({
330
+ toSQL: () => ({
331
+ clause: `${getQualifiedName(column)} IS NULL`,
332
+ bindings: []
333
+ })
334
+ });
335
+ var isNotNull = (column) => ({
336
+ toSQL: () => ({
337
+ clause: `${getQualifiedName(column)} IS NOT NULL`,
338
+ bindings: []
339
+ })
340
+ });
341
+ var between = (column, from, to) => ({
342
+ toSQL: () => {
343
+ const left = getQualifiedName(column);
344
+ const [fromClause, fromBindings] = isColumn(from) ? [getQualifiedName(from), []] : ["?", [from]];
345
+ const [toClause, toBindings] = isColumn(to) ? [getQualifiedName(to), []] : ["?", [to]];
346
+ return {
347
+ clause: `${left} BETWEEN ${fromClause} AND ${toClause}`,
348
+ bindings: [...fromBindings, ...toBindings]
349
+ };
350
+ }
351
+ });
352
+ var notBetween = (column, from, to) => ({
353
+ toSQL: () => {
354
+ const left = getQualifiedName(column);
355
+ const [fromClause, fromBindings] = isColumn(from) ? [getQualifiedName(from), []] : ["?", [from]];
356
+ const [toClause, toBindings] = isColumn(to) ? [getQualifiedName(to), []] : ["?", [to]];
357
+ return {
358
+ clause: `${left} NOT BETWEEN ${fromClause} AND ${toClause}`,
359
+ bindings: [...fromBindings, ...toBindings]
360
+ };
361
+ }
362
+ });
363
+ var inArray = (column, valuesOrQuery) => ({
364
+ toSQL: () => {
365
+ const left = getQualifiedName(column);
366
+ if (Array.isArray(valuesOrQuery)) {
367
+ const placeholders = valuesOrQuery.map(() => "?").join(", ");
368
+ return {
369
+ clause: `${left} IN (${placeholders})`,
370
+ bindings: valuesOrQuery
371
+ };
372
+ }
373
+ const sq = valuesOrQuery.toSQL ? valuesOrQuery.toSQL() : valuesOrQuery.toSQL();
374
+ return { clause: `${left} IN (${sq.clause})`, bindings: sq.bindings };
375
+ }
376
+ });
377
+ var notInArray = (column, valuesOrQuery) => ({
378
+ toSQL: () => {
379
+ const left = getQualifiedName(column);
380
+ if (Array.isArray(valuesOrQuery)) {
381
+ const placeholders = valuesOrQuery.map(() => "?").join(", ");
382
+ return {
383
+ clause: `${left} NOT IN (${placeholders})`,
384
+ bindings: valuesOrQuery
385
+ };
386
+ }
387
+ const sq = valuesOrQuery.toSQL ? valuesOrQuery.toSQL() : valuesOrQuery.toSQL();
388
+ return { clause: `${left} NOT IN (${sq.clause})`, bindings: sq.bindings };
389
+ }
390
+ });
391
+ var exists = (subquery) => ({
392
+ toSQL: () => {
393
+ const sq = subquery.toSQL ? subquery.toSQL() : subquery.toSQL();
394
+ return { clause: `EXISTS (${sq.clause})`, bindings: sq.bindings };
395
+ }
396
+ });
397
+ var notExists = (subquery) => ({
398
+ toSQL: () => {
399
+ const sq = subquery.toSQL ? subquery.toSQL() : subquery.toSQL();
400
+ return { clause: `NOT EXISTS (${sq.clause})`, bindings: sq.bindings };
401
+ }
402
+ });
403
+ var asc = (column) => `${getQualifiedName(column)} ASC`;
404
+ var desc = (column) => `${getQualifiedName(column)} DESC`;
405
+
136
406
  // src/orm.ts
137
407
  var SelectQueryBuilder = class {
138
408
  _table = null;
139
- _selectedColumns = ["*"];
409
+ _selectedColumns = [];
140
410
  _joins = [];
141
411
  _where = [];
142
412
  _orderBy = [];
143
413
  _limit = null;
144
414
  _offset = null;
145
- _eager = {};
146
- constructor(fields) {
415
+ _groupBy = [];
416
+ _having = [];
417
+ _distinct = false;
418
+ _dbProvider;
419
+ constructor(dbProvider, fields) {
420
+ this._dbProvider = dbProvider;
147
421
  if (fields) {
148
- this._selectedColumns = Object.values(fields).map((c) => c.name);
422
+ for (const [alias, col] of Object.entries(fields)) {
423
+ const sql2 = getQualifiedName(col);
424
+ this._selectedColumns.push({ sql: sql2, alias });
425
+ }
149
426
  }
150
427
  }
428
+ distinct() {
429
+ this._distinct = true;
430
+ return this;
431
+ }
432
+ select(fields) {
433
+ this._selectedColumns = [];
434
+ for (const [alias, expr] of Object.entries(fields)) {
435
+ if (typeof expr.toSQL === "function") {
436
+ const s = expr.toSQL();
437
+ this._selectedColumns.push({ sql: s.clause, alias });
438
+ } else {
439
+ this._selectedColumns.push({
440
+ sql: getQualifiedName(expr),
441
+ alias
442
+ });
443
+ }
444
+ }
445
+ return this;
446
+ }
151
447
  from(table) {
152
448
  this._table = table;
153
449
  return this;
154
450
  }
155
451
  where(...conditions) {
156
- this._where.push(...conditions);
452
+ this._where.push(...conditions.filter(Boolean));
157
453
  return this;
158
454
  }
159
455
  leftJoin(otherTable, on) {
@@ -162,8 +458,26 @@ var SelectQueryBuilder = class {
162
458
  this._joins.push(joinClause);
163
459
  return this;
164
460
  }
461
+ groupBy(...exprs) {
462
+ for (const e of exprs) {
463
+ if (!e) continue;
464
+ if (typeof e === "string") this._groupBy.push(e);
465
+ else this._groupBy.push(getQualifiedName(e));
466
+ }
467
+ return this;
468
+ }
469
+ having(...conditions) {
470
+ this._having.push(...conditions);
471
+ return this;
472
+ }
165
473
  orderBy(...clauses) {
166
- this._orderBy.push(...clauses);
474
+ for (const c of clauses) {
475
+ if (!c) continue;
476
+ if (typeof c === "string") this._orderBy.push(c);
477
+ else if (typeof c.toSQL === "function")
478
+ this._orderBy.push(c);
479
+ else this._orderBy.push(getQualifiedName(c));
480
+ }
167
481
  return this;
168
482
  }
169
483
  limit(value) {
@@ -174,17 +488,15 @@ var SelectQueryBuilder = class {
174
488
  this._offset = value;
175
489
  return this;
176
490
  }
177
- // The final execution step
178
491
  async execute() {
179
492
  if (!this._table) {
180
493
  throw new Error("Cannot execute select query without a 'from' table.");
181
494
  }
182
- const db3 = getDb();
495
+ const db = await this._dbProvider();
183
496
  const bindings = [];
184
- let query = `SELECT ${this._selectedColumns.join(", ")} FROM ${this._table._tableName}`;
185
- if (this._joins.length > 0) {
186
- query += ` ${this._joins.join(" ")}`;
187
- }
497
+ const selectList = this._selectedColumns.length > 0 ? this._selectedColumns.map((c) => c.alias ? `${c.sql} AS ${c.alias}` : c.sql).join(", ") : Object.values(this._table._schema).map((c) => `${this._table._tableName}.${c.name}`).join(", ");
498
+ let query = `SELECT ${this._distinct ? "DISTINCT " : ""}${selectList} FROM ${this._table._tableName}`;
499
+ if (this._joins.length > 0) query += ` ${this._joins.join(" ")}`;
188
500
  if (this._where.length > 0) {
189
501
  const whereClauses = this._where.map((condition) => {
190
502
  const sql2 = condition.toSQL();
@@ -193,21 +505,46 @@ var SelectQueryBuilder = class {
193
505
  });
194
506
  query += ` WHERE ${whereClauses.join(" AND ")}`;
195
507
  }
508
+ if (this._groupBy.length > 0) {
509
+ query += ` GROUP BY ${this._groupBy.join(", ")}`;
510
+ }
511
+ if (this._having.length > 0) {
512
+ const havingClauses = this._having.map((h) => {
513
+ const sql2 = h.toSQL();
514
+ bindings.push(...sql2.bindings);
515
+ return `(${sql2.clause})`;
516
+ });
517
+ query += ` HAVING ${havingClauses.join(" AND ")}`;
518
+ }
196
519
  if (this._orderBy.length > 0) {
197
- query += ` ORDER BY ${this._orderBy.join(", ")}`;
520
+ const ordParts = [];
521
+ for (const ob of this._orderBy) {
522
+ if (typeof ob === "string") ordParts.push(ob);
523
+ else {
524
+ const s = ob.toSQL();
525
+ ordParts.push(s.clause);
526
+ bindings.push(...s.bindings);
527
+ }
528
+ }
529
+ query += ` ORDER BY ${ordParts.join(", ")}`;
198
530
  }
199
531
  if (this._limit !== null) {
200
532
  query += ` LIMIT ?`;
201
533
  bindings.push(this._limit);
202
534
  }
203
535
  if (this._offset !== null) {
204
- if (this._limit === null) {
205
- query += ` LIMIT -1`;
206
- }
536
+ if (this._limit === null) query += ` LIMIT -1`;
207
537
  query += ` OFFSET ?`;
208
538
  bindings.push(this._offset);
209
539
  }
210
- return db3.select(query, bindings);
540
+ return db.select(query, bindings);
541
+ }
542
+ async iterator() {
543
+ const rows = await this.execute();
544
+ async function* gen() {
545
+ for (const r of rows) yield r;
546
+ }
547
+ return gen();
211
548
  }
212
549
  };
213
550
  var TauriORM = class {
@@ -215,48 +552,154 @@ var TauriORM = class {
215
552
  query = {};
216
553
  _tables = null;
217
554
  _relations = null;
555
+ _dbPromise;
556
+ constructor(dbUri) {
557
+ this._dbPromise = Database.load(dbUri);
558
+ }
559
+ async getDb() {
560
+ return this._dbPromise;
561
+ }
218
562
  // Deprecated: use configure()
219
563
  configureQuery(tables, relations2) {
220
564
  this.configure(tables, relations2);
221
565
  }
222
566
  select(fields) {
223
- return new SelectQueryBuilder(fields);
567
+ return new SelectQueryBuilder(this.getDb.bind(this), fields);
568
+ }
569
+ selectDistinct(fields) {
570
+ const qb = new SelectQueryBuilder(this.getDb.bind(this), fields);
571
+ qb.distinct();
572
+ return qb;
224
573
  }
225
574
  // --- Drizzle-style CRUD builders ---
226
575
  insert(table) {
576
+ const self = this;
227
577
  return new class InsertBuilder {
228
578
  _table = table;
229
579
  _rows = [];
580
+ _selectSql = null;
581
+ _conflict = null;
582
+ _returning = null;
230
583
  values(rowOrRows) {
231
584
  this._rows = Array.isArray(rowOrRows) ? rowOrRows : [rowOrRows];
232
585
  return this;
233
586
  }
587
+ select(qb) {
588
+ if (qb.toSQL) this._selectSql = qb.toSQL();
589
+ else this._selectSql = qb.toSQL();
590
+ return this;
591
+ }
592
+ returning(fields) {
593
+ this._returning = fields ?? {};
594
+ return this;
595
+ }
596
+ $returningId() {
597
+ this._returning = "__RETURNING_ID__";
598
+ return this;
599
+ }
600
+ onConflictDoNothing(opts) {
601
+ const target = opts?.target ? Array.isArray(opts.target) ? opts.target.map((c) => c.name) : opts.target.name : void 0;
602
+ this._conflict = {
603
+ kind: "doNothing",
604
+ target,
605
+ where: opts?.where
606
+ };
607
+ return this;
608
+ }
609
+ onConflictDoUpdate(opts) {
610
+ const target = Array.isArray(opts.target) ? opts.target.map((c) => c.name) : opts.target.name;
611
+ this._conflict = {
612
+ kind: "doUpdate",
613
+ target,
614
+ targetWhere: opts.targetWhere,
615
+ set: opts.set,
616
+ setWhere: opts.setWhere
617
+ };
618
+ return this;
619
+ }
234
620
  async execute() {
235
- const db3 = getDb();
621
+ const db = await self.getDb();
622
+ if (this._selectSql) {
623
+ const cols = Object.keys(this._table._schema);
624
+ let query = `INSERT INTO ${this._table._tableName} (${cols.join(", ")}) ${this._selectSql.clause}`;
625
+ const bindings = [...this._selectSql.bindings];
626
+ query += this._buildConflictClause();
627
+ const ret = await this._executeWithReturning(db, query, bindings);
628
+ return ret;
629
+ }
236
630
  for (const data of this._rows) {
237
631
  const finalData = { ...data };
238
632
  const schema = this._table._schema;
239
633
  for (const [key, col] of Object.entries(schema)) {
240
- if (finalData[key] === void 0 && col.defaultFn) {
241
- finalData[key] = col.defaultFn();
634
+ if (finalData[key] === void 0) {
635
+ if (col.defaultFn) {
636
+ finalData[key] = col.defaultFn();
637
+ } else if (col.onUpdateFn) {
638
+ finalData[key] = col.onUpdateFn();
639
+ }
242
640
  }
243
641
  }
244
642
  const keys = Object.keys(finalData);
245
643
  const values = Object.values(finalData);
246
644
  const placeholders = values.map(() => "?").join(", ");
247
- const query = `INSERT INTO ${this._table._tableName} (${keys.join(
248
- ", "
249
- )}) VALUES (${placeholders})`;
250
- await db3.execute(query, values);
645
+ let query = `INSERT INTO ${this._table._tableName} (${keys.join(", ")}) VALUES (${placeholders})`;
646
+ const bindings = [...values];
647
+ query += this._buildConflictClause();
648
+ const ret = await this._executeWithReturning(db, query, bindings);
649
+ if (ret !== void 0) return ret;
650
+ }
651
+ }
652
+ _buildConflictClause() {
653
+ if (!this._conflict) return "";
654
+ if (this._conflict.kind === "doNothing") {
655
+ const tgt2 = this._conflict.target ? Array.isArray(this._conflict.target) ? `(${this._conflict.target.join(", ")})` : `(${this._conflict.target})` : "";
656
+ const where = this._conflict.where ? ` WHERE ${this._conflict.where.toSQL().clause}` : "";
657
+ return ` ON CONFLICT ${tgt2} DO NOTHING${where}`;
251
658
  }
659
+ const c = this._conflict;
660
+ const tgt = Array.isArray(c.target) ? `(${c.target.join(", ")})` : `(${c.target})`;
661
+ const setKeys = Object.keys(c.set ?? {});
662
+ const setClause = setKeys.map((k) => {
663
+ const v = c.set[k];
664
+ return `${k} = ${typeof v === "object" && v && typeof v.toSQL === "function" ? v.toSQL().clause : "?"}`;
665
+ }).join(", ");
666
+ const targetWhere = c.targetWhere ? ` WHERE ${c.targetWhere.toSQL().clause}` : "";
667
+ const setWhere = c.setWhere ? ` WHERE ${c.setWhere.toSQL().clause}` : "";
668
+ return ` ON CONFLICT ${tgt}${targetWhere} DO UPDATE SET ${setClause}${setWhere}`;
669
+ }
670
+ async _executeWithReturning(db, query, bindings) {
671
+ if (this._returning === null) {
672
+ await db.execute(query, bindings);
673
+ return void 0;
674
+ }
675
+ if (this._returning === "__RETURNING_ID__") {
676
+ const rows = await db.select(`SELECT last_insert_rowid() as id`);
677
+ return rows.map((r) => ({ id: r.id }));
678
+ }
679
+ if (typeof this._returning === "object") {
680
+ const cols = Object.entries(
681
+ this._returning
682
+ ).map(
683
+ ([alias, col]) => `${col.tableName}.${col.name} AS ${alias}`
684
+ ).join(", ");
685
+ const retSql = `${query} RETURNING ${cols}`;
686
+ const res = await db.select(retSql, bindings);
687
+ return res;
688
+ }
689
+ return void 0;
252
690
  }
253
691
  }();
254
692
  }
255
693
  update(table) {
694
+ const self = this;
256
695
  return new class UpdateBuilder {
257
696
  _table = table;
258
697
  _data = null;
259
698
  _where = null;
699
+ _orderBy = [];
700
+ _limit = null;
701
+ _from = null;
702
+ _returning = null;
260
703
  set(data) {
261
704
  this._data = data;
262
705
  return this;
@@ -265,14 +708,54 @@ var TauriORM = class {
265
708
  this._where = cond;
266
709
  return this;
267
710
  }
711
+ orderBy(...clauses) {
712
+ for (const c of clauses) {
713
+ if (!c) continue;
714
+ if (typeof c === "string") this._orderBy.push(c);
715
+ else if (typeof c.toSQL === "function")
716
+ this._orderBy.push(c);
717
+ else this._orderBy.push(getQualifiedName(c));
718
+ }
719
+ return this;
720
+ }
721
+ limit(n) {
722
+ this._limit = n;
723
+ return this;
724
+ }
725
+ from(tbl) {
726
+ this._from = tbl;
727
+ return this;
728
+ }
729
+ returning(fields) {
730
+ this._returning = fields ?? {};
731
+ return this;
732
+ }
268
733
  async execute() {
269
734
  if (!this._data)
270
735
  throw new Error("Update requires set() before execute()");
271
- const db3 = getDb();
272
- const setKeys = Object.keys(this._data);
273
- const setClause = setKeys.map((k) => `${k} = ?`).join(", ");
274
- const bindings = Object.values(this._data);
275
- let query = `UPDATE ${this._table._tableName} SET ${setClause}`;
736
+ const db = await self.getDb();
737
+ const schema = this._table._schema;
738
+ const dataToSet = { ...this._data };
739
+ for (const [key, col] of Object.entries(schema)) {
740
+ if (!(key in dataToSet) && col.onUpdateFn) {
741
+ dataToSet[key] = col.onUpdateFn();
742
+ }
743
+ }
744
+ const setParts = [];
745
+ const bindings = [];
746
+ for (const [k, v] of Object.entries(dataToSet)) {
747
+ if (v === void 0) continue;
748
+ if (v && typeof v === "object" && typeof v.toSQL === "function") {
749
+ const s = v.toSQL();
750
+ setParts.push(`${k} = ${s.clause}`);
751
+ bindings.push(...s.bindings);
752
+ } else {
753
+ setParts.push(`${k} = ?`);
754
+ bindings.push(v);
755
+ }
756
+ }
757
+ let query = `UPDATE ${this._table._tableName} SET ${setParts.join(", ")}`;
758
+ if (this._from) query += ` FROM ${this._from._tableName}`;
276
759
  if (this._where) {
277
760
  if (typeof this._where.toSQL === "function") {
278
761
  const sql2 = this._where.toSQL();
@@ -286,20 +769,67 @@ var TauriORM = class {
286
769
  }
287
770
  }
288
771
  }
289
- await db3.execute(query, bindings);
772
+ if (this._orderBy.length > 0) {
773
+ const ordParts = [];
774
+ for (const ob of this._orderBy) {
775
+ if (typeof ob === "string") ordParts.push(ob);
776
+ else {
777
+ const s = ob.toSQL();
778
+ ordParts.push(s.clause);
779
+ bindings.push(...s.bindings);
780
+ }
781
+ }
782
+ query += ` ORDER BY ${ordParts.join(", ")}`;
783
+ }
784
+ if (this._limit !== null) {
785
+ query += ` LIMIT ?`;
786
+ bindings.push(this._limit);
787
+ }
788
+ if (this._returning) {
789
+ const cols = Object.entries(
790
+ this._returning
791
+ ).map(
792
+ ([alias, col]) => `${col.tableName}.${col.name} AS ${alias}`
793
+ ).join(", ");
794
+ const retSql = `${query} RETURNING ${cols}`;
795
+ return await db.select(retSql, bindings);
796
+ }
797
+ await db.execute(query, bindings);
290
798
  }
291
799
  }();
292
800
  }
293
801
  delete(table) {
802
+ const self = this;
294
803
  return new class DeleteBuilder {
295
804
  _table = table;
296
805
  _where = null;
806
+ _orderBy = [];
807
+ _limit = null;
808
+ _returning = null;
297
809
  where(cond) {
298
810
  this._where = cond;
299
811
  return this;
300
812
  }
813
+ orderBy(...clauses) {
814
+ for (const c of clauses) {
815
+ if (!c) continue;
816
+ if (typeof c === "string") this._orderBy.push(c);
817
+ else if (typeof c.toSQL === "function")
818
+ this._orderBy.push(c);
819
+ else this._orderBy.push(getQualifiedName(c));
820
+ }
821
+ return this;
822
+ }
823
+ limit(n) {
824
+ this._limit = n;
825
+ return this;
826
+ }
827
+ returning(fields) {
828
+ this._returning = fields ?? {};
829
+ return this;
830
+ }
301
831
  async execute() {
302
- const db3 = getDb();
832
+ const db = await self.getDb();
303
833
  let query = `DELETE FROM ${this._table._tableName}`;
304
834
  const bindings = [];
305
835
  if (this._where) {
@@ -315,7 +845,32 @@ var TauriORM = class {
315
845
  }
316
846
  }
317
847
  }
318
- await db3.execute(query, bindings);
848
+ if (this._orderBy.length > 0) {
849
+ const ordParts = [];
850
+ for (const ob of this._orderBy) {
851
+ if (typeof ob === "string") ordParts.push(ob);
852
+ else {
853
+ const s = ob.toSQL();
854
+ ordParts.push(s.clause);
855
+ bindings.push(...s.bindings);
856
+ }
857
+ }
858
+ query += ` ORDER BY ${ordParts.join(", ")}`;
859
+ }
860
+ if (this._limit !== null) {
861
+ query += ` LIMIT ?`;
862
+ bindings.push(this._limit);
863
+ }
864
+ if (this._returning) {
865
+ const cols = Object.entries(
866
+ this._returning
867
+ ).map(
868
+ ([alias, col]) => `${col.tableName}.${col.name} AS ${alias}`
869
+ ).join(", ");
870
+ const retSql = `${query} RETURNING ${cols}`;
871
+ return await db.select(retSql, bindings);
872
+ }
873
+ await db.execute(query, bindings);
319
874
  }
320
875
  }();
321
876
  }
@@ -323,8 +878,8 @@ var TauriORM = class {
323
878
  // legacy direct methods removed in favor of builder APIs
324
879
  // legacy direct methods removed in favor of builder APIs
325
880
  async run(query, bindings = []) {
326
- const db3 = getDb();
327
- await db3.execute(query, bindings);
881
+ const db = await this.getDb();
882
+ await db.execute(query, bindings);
328
883
  }
329
884
  // --- Migrations API ---
330
885
  generateCreateTableSql(table) {
@@ -374,16 +929,16 @@ var TauriORM = class {
374
929
  );
375
930
  }
376
931
  async hasMigration(name) {
377
- const db3 = getDb();
378
- const rows = await db3.select(
932
+ const db = await this.getDb();
933
+ const rows = await db.select(
379
934
  `SELECT name FROM _migrations WHERE name = ?`,
380
935
  [name]
381
936
  );
382
937
  return Array.isArray(rows) && rows.length > 0;
383
938
  }
384
939
  async recordMigration(name) {
385
- const db3 = getDb();
386
- await db3.execute(
940
+ const db = await this.getDb();
941
+ await db.execute(
387
942
  `INSERT INTO _migrations (name, applied_at) VALUES (?, ?)`,
388
943
  [name, Date.now()]
389
944
  );
@@ -405,7 +960,7 @@ var TauriORM = class {
405
960
  configure(tables, relDefs) {
406
961
  this._tables = tables;
407
962
  this._relations = relDefs ?? {};
408
- this.query = makeQueryAPI(tables, this._relations);
963
+ this.query = makeQueryAPI(tables, this._relations, this.getDb.bind(this));
409
964
  return this;
410
965
  }
411
966
  // Convenience: migrate from configured tables
@@ -417,7 +972,7 @@ var TauriORM = class {
417
972
  // --- Schema diff and CLI-like helpers ---
418
973
  async diffSchema() {
419
974
  if (!this._tables) throw new Error("No tables configured.");
420
- const dbi = getDb();
975
+ const dbi = await this.getDb();
421
976
  const configuredNames = Object.values(this._tables).map(
422
977
  (t) => t._tableName
423
978
  );
@@ -492,7 +1047,7 @@ var TauriORM = class {
492
1047
  return this.pullSchema();
493
1048
  }
494
1049
  async studio() {
495
- const dbi = getDb();
1050
+ const dbi = await this.getDb();
496
1051
  return { driver: "sqlite", path: dbi.path };
497
1052
  }
498
1053
  // --- Schema detection / signature ---
@@ -502,7 +1057,7 @@ var TauriORM = class {
502
1057
  );
503
1058
  }
504
1059
  async getSchemaMeta(key) {
505
- const dbi = getDb();
1060
+ const dbi = await this.getDb();
506
1061
  await this.ensureSchemaMeta();
507
1062
  const rows = await dbi.select(
508
1063
  `SELECT value FROM _schema_meta WHERE key = ?`,
@@ -511,7 +1066,7 @@ var TauriORM = class {
511
1066
  return rows?.[0]?.value ?? null;
512
1067
  }
513
1068
  async setSchemaMeta(key, value) {
514
- const dbi = getDb();
1069
+ const dbi = await this.getDb();
515
1070
  await this.ensureSchemaMeta();
516
1071
  await dbi.execute(
517
1072
  `INSERT INTO _schema_meta(key, value) VALUES(?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value`,
@@ -560,7 +1115,7 @@ var TauriORM = class {
560
1115
  // Pull current DB schema (minimal) for configured tables
561
1116
  async pullSchema() {
562
1117
  if (!this._tables) throw new Error("No tables configured.");
563
- const dbi = getDb();
1118
+ const dbi = await this.getDb();
564
1119
  const result = {};
565
1120
  for (const tbl of Object.values(this._tables)) {
566
1121
  const name = tbl._tableName;
@@ -579,7 +1134,7 @@ var TauriORM = class {
579
1134
  return this.generateCreateTableSql(table);
580
1135
  }
581
1136
  async tableExists(name) {
582
- const dbi = getDb();
1137
+ const dbi = await this.getDb();
583
1138
  const rows = await dbi.select(
584
1139
  `SELECT name FROM sqlite_master WHERE type='table' AND name = ?`,
585
1140
  [name]
@@ -589,12 +1144,12 @@ var TauriORM = class {
589
1144
  // Force push model to DB: add missing tables/columns, rebuild tables if incompatible
590
1145
  async forcePush(options) {
591
1146
  if (!this._tables) throw new Error("No tables configured.");
592
- const dbi = getDb();
1147
+ const dbi = await this.getDb();
593
1148
  const preserve = options?.preserveData !== false;
594
1149
  for (const tbl of Object.values(this._tables)) {
595
1150
  const tableName = tbl._tableName;
596
- const exists = await this.tableExists(tableName);
597
- if (!exists) {
1151
+ const exists2 = await this.tableExists(tableName);
1152
+ if (!exists2) {
598
1153
  await this.run(this.buildCreateTableSQL(tbl));
599
1154
  continue;
600
1155
  }
@@ -659,7 +1214,6 @@ var TauriORM = class {
659
1214
  await this.setSchemaMeta("schema_signature", this.computeModelSignature());
660
1215
  }
661
1216
  };
662
- var db2 = new TauriORM();
663
1217
  function relations(baseTable, builder) {
664
1218
  const ctx = {
665
1219
  one: (table, cfg) => ({ kind: "one", table, cfg }),
@@ -685,10 +1239,29 @@ function guessChildFk(child, base, rel) {
685
1239
  ];
686
1240
  return childCols.find((c) => guessNames.includes(c.name)) || childCols.find((c) => /.*_id$/i.test(c.name)) || null;
687
1241
  }
1242
+ function guessOneRelationJoin(base, rel) {
1243
+ const child = rel.table;
1244
+ const basePk = getPrimaryKey(base);
1245
+ const childCols = Object.values(child._schema);
1246
+ if (rel.cfg?.fields && rel.cfg?.references && rel.cfg.fields[0] && rel.cfg.references[0]) {
1247
+ const fk = rel.cfg.fields[0];
1248
+ const ref = rel.cfg.references[0];
1249
+ if (childCols.some((c) => c.name === fk.name)) {
1250
+ return { lhsTable: child, lhsCol: fk, rhsTable: base, rhsCol: ref };
1251
+ }
1252
+ const baseCols = Object.values(base._schema);
1253
+ if (baseCols.some((c) => c.name === fk.name)) {
1254
+ return { lhsTable: base, lhsCol: fk, rhsTable: child, rhsCol: ref };
1255
+ }
1256
+ }
1257
+ const childFk = guessChildFk(child, base, rel);
1258
+ if (!childFk) return null;
1259
+ return { lhsTable: child, lhsCol: childFk, rhsTable: base, rhsCol: basePk };
1260
+ }
688
1261
  function isFlatWith(spec) {
689
1262
  return Object.values(spec).every((v) => typeof v === "boolean");
690
1263
  }
691
- function makeQueryAPI(tables, relDefs) {
1264
+ function makeQueryAPI(tables, relDefs, dbProvider) {
692
1265
  const api = {};
693
1266
  const tableKeyByName = {};
694
1267
  for (const [k, t] of Object.entries(tables)) tableKeyByName[t._tableName] = k;
@@ -697,7 +1270,7 @@ function makeQueryAPI(tables, relDefs) {
697
1270
  async findMany(opts) {
698
1271
  const base = tbl;
699
1272
  const withSpec = opts?.with ?? {};
700
- const dbi = getDb();
1273
+ const dbi = await dbProvider();
701
1274
  const rels = relDefs[tblKey] ?? {};
702
1275
  if (opts?.join && isFlatWith(withSpec)) {
703
1276
  const baseCols = Object.values(base._schema);
@@ -723,23 +1296,43 @@ function makeQueryAPI(tables, relDefs) {
723
1296
  const child = rel.table;
724
1297
  const childCols = Object.values(child._schema);
725
1298
  const childPk = childCols.find((c) => c.isPrimaryKey) || childCols.find((c) => c.name === "id") || null;
726
- const childFk = guessChildFk(child, base, rel);
727
- if (!childFk) continue;
728
- fkMap[relName] = { childFk, childPk };
1299
+ if (rel.kind === "one") {
1300
+ const mapping = guessOneRelationJoin(base, rel);
1301
+ if (!mapping) continue;
1302
+ if (mapping.lhsTable._tableName === child._tableName) {
1303
+ fkMap[relName] = { childFk: mapping.lhsCol, childPk };
1304
+ joins.push(
1305
+ `LEFT JOIN ${child._tableName} ON ${mapping.lhsTable._tableName}.${mapping.lhsCol.name} = ${mapping.rhsTable._tableName}.${mapping.rhsCol.name}`
1306
+ );
1307
+ } else {
1308
+ fkMap[relName] = { childFk: mapping.rhsCol, childPk };
1309
+ joins.push(
1310
+ `LEFT JOIN ${child._tableName} ON ${mapping.lhsTable._tableName}.${mapping.lhsCol.name} = ${mapping.rhsTable._tableName}.${mapping.rhsCol.name}`
1311
+ );
1312
+ }
1313
+ } else {
1314
+ const childFk = guessChildFk(child, base, rel);
1315
+ if (!childFk) continue;
1316
+ fkMap[relName] = { childFk, childPk };
1317
+ joins.push(
1318
+ `LEFT JOIN ${child._tableName} ON ${child._tableName}.${childFk.name} = ${base._tableName}.${basePk.name}`
1319
+ );
1320
+ }
729
1321
  const selected = typeof enabled === "object" && enabled.columns?.length ? enabled.columns : childCols.map((c) => c.name);
730
1322
  relColsMap[relName] = selected;
731
1323
  for (const name of selected)
732
1324
  selectParts.push(
733
1325
  `${child._tableName}.${name} AS __rel_${relName}_${name}`
734
1326
  );
735
- joins.push(
736
- `LEFT JOIN ${child._tableName} ON ${child._tableName}.${childFk.name} = ${base._tableName}.${basePk.name}`
737
- );
738
1327
  }
739
1328
  let sqlText = `SELECT ${selectParts.join(", ")} FROM ${base._tableName}${joins.length ? " " + joins.join(" ") : ""}`;
740
1329
  const bindings = [];
741
1330
  if (opts?.where) {
742
- if (typeof opts.where.toSQL === "function") {
1331
+ if (typeof opts.where === "function") {
1332
+ const w = opts.where(base, { eq, ne, gt, gte, lt, lte, like }).toSQL();
1333
+ sqlText += ` WHERE ${w.clause}`;
1334
+ bindings.push(...w.bindings);
1335
+ } else if (typeof opts.where.toSQL === "function") {
743
1336
  const w = opts.where.toSQL();
744
1337
  sqlText += ` WHERE ${w.clause}`;
745
1338
  bindings.push(...w.bindings);
@@ -751,8 +1344,9 @@ function makeQueryAPI(tables, relDefs) {
751
1344
  }
752
1345
  }
753
1346
  }
754
- if (opts?.orderBy?.length)
755
- sqlText += ` ORDER BY ${opts.orderBy.join(", ")}`;
1347
+ const orderByClauses = typeof opts?.orderBy === "function" ? opts.orderBy(base, { asc, desc }) : opts?.orderBy;
1348
+ if (orderByClauses?.length)
1349
+ sqlText += ` ORDER BY ${orderByClauses.join(", ")}`;
756
1350
  if (typeof opts?.limit === "number")
757
1351
  sqlText += ` LIMIT ${opts.limit}`;
758
1352
  if (typeof opts?.offset === "number")
@@ -792,10 +1386,10 @@ function makeQueryAPI(tables, relDefs) {
792
1386
  const childPk = fkMap[relName].childPk;
793
1387
  if (childPk) {
794
1388
  if (!acc[relName]) acc[relName] = [];
795
- const exists = acc[relName].some(
1389
+ const exists2 = acc[relName].some(
796
1390
  (r) => r[childPk.name] === childObj[childPk.name]
797
1391
  );
798
- if (!exists) acc[relName].push(childObj);
1392
+ if (!exists2) acc[relName].push(childObj);
799
1393
  } else {
800
1394
  acc[relName].push(childObj);
801
1395
  }
@@ -819,7 +1413,11 @@ function makeQueryAPI(tables, relDefs) {
819
1413
  let baseSql = `SELECT ${baseSelected.join(", ")} FROM ${base._tableName}`;
820
1414
  const baseBindings = [];
821
1415
  if (opts?.where) {
822
- if (typeof opts.where.toSQL === "function") {
1416
+ if (typeof opts.where === "function") {
1417
+ const w = opts.where(base, { eq, ne, gt, gte, lt, lte, like }).toSQL();
1418
+ baseSql += ` WHERE ${w.clause}`;
1419
+ baseBindings.push(...w.bindings);
1420
+ } else if (typeof opts.where.toSQL === "function") {
823
1421
  const w = opts.where.toSQL();
824
1422
  baseSql += ` WHERE ${w.clause}`;
825
1423
  baseBindings.push(...w.bindings);
@@ -831,8 +1429,9 @@ function makeQueryAPI(tables, relDefs) {
831
1429
  }
832
1430
  }
833
1431
  }
834
- if (opts?.orderBy?.length)
835
- baseSql += ` ORDER BY ${opts.orderBy.join(", ")}`;
1432
+ const orderByClauses2 = typeof opts?.orderBy === "function" ? opts.orderBy(base, { asc, desc }) : opts?.orderBy;
1433
+ if (orderByClauses2?.length)
1434
+ baseSql += ` ORDER BY ${orderByClauses2.join(", ")}`;
836
1435
  if (typeof opts?.limit === "number") baseSql += ` LIMIT ${opts.limit}`;
837
1436
  if (typeof opts?.offset === "number")
838
1437
  baseSql += ` OFFSET ${opts.offset}`;
@@ -851,9 +1450,9 @@ function makeQueryAPI(tables, relDefs) {
851
1450
  const child = rel.table;
852
1451
  const childCols = Object.values(child._schema);
853
1452
  const selectCols = enabled?.columns && enabled.columns.length > 0 ? enabled.columns : childCols.map((c) => c.name);
854
- const fkCol = guessChildFk(child, parentTable, rel);
855
- if (!fkCol) continue;
856
1453
  if (rel.kind === "many") {
1454
+ const fkCol = guessChildFk(child, parentTable, rel);
1455
+ if (!fkCol) continue;
857
1456
  const sql2 = `SELECT ${selectCols.join(", ")} FROM ${child._tableName} WHERE ${fkCol.name} IN (${parentIds.map(() => "?").join(", ")})`;
858
1457
  const rows = await dbi.select(sql2, parentIds);
859
1458
  const buckets = /* @__PURE__ */ new Map();
@@ -872,14 +1471,32 @@ function makeQueryAPI(tables, relDefs) {
872
1471
  await loadRelationsFor(children, child, enabled.with);
873
1472
  }
874
1473
  } else {
875
- const sql2 = `SELECT ${selectCols.join(", ")} FROM ${child._tableName} WHERE ${fkCol.name} IN (${parentIds.map(() => "?").join(", ")})`;
876
- const rows = await dbi.select(sql2, parentIds);
877
- const mapOne = /* @__PURE__ */ new Map();
878
- for (const r of rows) mapOne.set(r[fkCol.name], r);
879
- for (const p of parents)
880
- p[relName] = mapOne.get(p[parentPk.name]) ?? null;
1474
+ const mapping = guessOneRelationJoin(parentTable, rel);
1475
+ if (!mapping) continue;
1476
+ if (mapping.lhsTable._tableName === child._tableName) {
1477
+ const sql2 = `SELECT ${selectCols.join(", ")} FROM ${child._tableName} WHERE ${mapping.lhsCol.name} IN (${parentIds.map(() => "?").join(", ")})`;
1478
+ const rows = await dbi.select(sql2, parentIds);
1479
+ const mapOne = /* @__PURE__ */ new Map();
1480
+ for (const r of rows) mapOne.set(r[mapping.lhsCol.name], r);
1481
+ for (const p of parents)
1482
+ p[relName] = mapOne.get(p[parentPk.name]) ?? null;
1483
+ } else {
1484
+ const parentFkName = mapping.lhsCol.name;
1485
+ const childPkName = mapping.rhsCol.name;
1486
+ const childIds = parents.map((p) => p[parentFkName]).filter((v2) => v2 !== void 0 && v2 !== null);
1487
+ if (childIds.length === 0) {
1488
+ for (const p of parents) p[relName] = null;
1489
+ } else {
1490
+ const sql2 = `SELECT ${selectCols.join(", ")} FROM ${child._tableName} WHERE ${childPkName} IN (${childIds.map(() => "?").join(", ")})`;
1491
+ const rows = await dbi.select(sql2, childIds);
1492
+ const mapOne = /* @__PURE__ */ new Map();
1493
+ for (const r of rows) mapOne.set(r[childPkName], r);
1494
+ for (const p of parents)
1495
+ p[relName] = mapOne.get(p[parentFkName]) ?? null;
1496
+ }
1497
+ }
881
1498
  if (enabled?.with) {
882
- const children = parents.map((p) => p[relName]).filter(Boolean);
1499
+ const children = parents.map((p) => p[relName]).filter((x) => Boolean(x));
883
1500
  if (children.length > 0)
884
1501
  await loadRelationsFor(children, child, enabled.with);
885
1502
  }
@@ -890,70 +1507,57 @@ function makeQueryAPI(tables, relDefs) {
890
1507
  await loadRelationsFor(result, base, withSpec);
891
1508
  }
892
1509
  return result;
1510
+ },
1511
+ async findFirst(opts) {
1512
+ const rows = await api[tblKey].findMany({ ...opts, limit: 1 });
1513
+ return rows?.[0] ?? null;
893
1514
  }
894
1515
  };
895
1516
  }
896
1517
  return api;
897
1518
  }
898
-
899
- // src/sql-helpers.ts
900
- function isColumn(value) {
901
- return typeof value === "object" && value !== null && "_dataType" in value;
902
- }
903
- function getQualifiedName(column) {
904
- if (column.tableName) return `${column.tableName}.${column.name}`;
905
- return column.name;
906
- }
907
- function comparison(operator, column, value) {
908
- return {
909
- toSQL: () => {
910
- if (isColumn(value)) {
911
- return {
912
- clause: `${getQualifiedName(column)} ${operator} ${getQualifiedName(
913
- value
914
- )}`,
915
- bindings: []
916
- };
917
- }
918
- return {
919
- clause: `${getQualifiedName(column)} ${operator} ?`,
920
- bindings: [value]
921
- };
922
- }
923
- };
924
- }
925
- var eq = (column, value) => comparison("=", column, value);
926
- var ne = (column, value) => comparison("!=", column, value);
927
- var gt = (column, value) => comparison(">", column, value);
928
- var gte = (column, value) => comparison(">=", column, value);
929
- var lt = (column, value) => comparison("<", column, value);
930
- var lte = (column, value) => comparison("<=", column, value);
931
- var like = (column, value) => comparison("LIKE", column, value);
932
- var asc = (column) => `${column.name} ASC`;
933
- var desc = (column) => `${column.name} DESC`;
934
1519
  export {
935
1520
  TauriORM,
1521
+ and,
936
1522
  asc,
1523
+ between,
937
1524
  blob,
938
1525
  boolean,
939
- db2 as db,
1526
+ check,
940
1527
  defineTable,
941
1528
  desc,
942
1529
  eq,
943
- getDb,
1530
+ exists,
1531
+ foreignKey,
1532
+ getQualifiedName,
944
1533
  gt,
945
1534
  gte,
946
- initDb,
1535
+ ilike,
1536
+ inArray,
1537
+ increments,
1538
+ index,
947
1539
  integer,
1540
+ isNotNull,
1541
+ isNull,
948
1542
  like,
949
1543
  lt,
950
1544
  lte,
951
1545
  makeQueryAPI,
952
1546
  ne,
1547
+ not,
1548
+ notBetween,
1549
+ notExists,
1550
+ notIlike,
1551
+ notInArray,
953
1552
  numeric,
1553
+ or,
1554
+ primaryKey,
1555
+ raw,
954
1556
  real,
955
1557
  relations,
956
1558
  sql,
957
1559
  text,
958
- timestamp
1560
+ timestamp,
1561
+ unique,
1562
+ uniqueIndex
959
1563
  };