@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.js CHANGED
@@ -31,53 +31,58 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  TauriORM: () => TauriORM,
34
+ and: () => and,
34
35
  asc: () => asc,
36
+ between: () => between,
35
37
  blob: () => blob,
36
38
  boolean: () => boolean,
37
- db: () => db2,
39
+ check: () => check,
38
40
  defineTable: () => defineTable,
39
41
  desc: () => desc,
40
42
  eq: () => eq,
41
- getDb: () => getDb,
43
+ exists: () => exists,
44
+ foreignKey: () => foreignKey,
45
+ getQualifiedName: () => getQualifiedName,
42
46
  gt: () => gt,
43
47
  gte: () => gte,
44
- initDb: () => initDb,
48
+ ilike: () => ilike,
49
+ inArray: () => inArray,
50
+ increments: () => increments,
51
+ index: () => index,
45
52
  integer: () => integer,
53
+ isNotNull: () => isNotNull,
54
+ isNull: () => isNull,
46
55
  like: () => like,
47
56
  lt: () => lt,
48
57
  lte: () => lte,
49
58
  makeQueryAPI: () => makeQueryAPI,
50
59
  ne: () => ne,
60
+ not: () => not,
61
+ notBetween: () => notBetween,
62
+ notExists: () => notExists,
63
+ notIlike: () => notIlike,
64
+ notInArray: () => notInArray,
51
65
  numeric: () => numeric,
66
+ or: () => or,
67
+ primaryKey: () => primaryKey,
68
+ raw: () => raw,
52
69
  real: () => real,
53
70
  relations: () => relations,
54
71
  sql: () => sql,
55
72
  text: () => text,
56
- timestamp: () => timestamp
73
+ timestamp: () => timestamp,
74
+ unique: () => unique,
75
+ uniqueIndex: () => uniqueIndex
57
76
  });
58
77
  module.exports = __toCommonJS(index_exports);
59
78
 
60
- // src/connection.ts
61
- var import_plugin_sql = __toESM(require("@tauri-apps/plugin-sql"));
62
- var db = null;
63
- async function initDb(dbPath) {
64
- db = await import_plugin_sql.default.load(dbPath);
65
- return db;
66
- }
67
- function getDb() {
68
- if (!db) {
69
- throw new Error("Database not initialized. Please call initDb() first.");
70
- }
71
- return db;
72
- }
73
-
74
79
  // src/schema-builder.ts
75
80
  function sql(strings, ...values) {
76
- const raw = strings.reduce(
81
+ const raw2 = strings.reduce(
77
82
  (acc, part, idx) => acc + part + (idx < values.length ? String(values[idx]) : ""),
78
83
  ""
79
84
  );
80
- return { raw };
85
+ return { raw: raw2 };
81
86
  }
82
87
  function createColumn(params) {
83
88
  const col = { ...params };
@@ -99,6 +104,18 @@ function createColumn(params) {
99
104
  col.defaultFn = fn;
100
105
  return col;
101
106
  };
107
+ col.$default = (fn) => {
108
+ col.defaultFn = fn;
109
+ return col;
110
+ };
111
+ col.$onUpdate = (fn) => {
112
+ col.onUpdateFn = fn;
113
+ return col;
114
+ };
115
+ col.$onUpdateFn = (fn) => {
116
+ col.onUpdateFn = fn;
117
+ return col;
118
+ };
102
119
  col.references = (target, actions) => {
103
120
  const t = target();
104
121
  col.references = {
@@ -111,34 +128,43 @@ function createColumn(params) {
111
128
  };
112
129
  return col;
113
130
  }
114
- function text(name, config) {
131
+ function text(nameOrConfig, maybeConfig) {
132
+ const name = typeof nameOrConfig === "string" ? nameOrConfig : "";
133
+ const config = typeof nameOrConfig === "string" ? maybeConfig : nameOrConfig;
115
134
  const col = createColumn({
116
135
  name,
117
136
  type: "TEXT",
118
- isPrimaryKey: config?.isPrimaryKey,
119
137
  _dataType: ""
120
138
  });
121
139
  if (config?.enum) col.enumValues = config.enum;
140
+ if (config?.mode) col.mode = config.mode;
122
141
  return col;
123
142
  }
124
- function integer(name, config) {
143
+ function integer(nameOrConfig, maybeConfig) {
144
+ const name = typeof nameOrConfig === "string" ? nameOrConfig : "";
145
+ const config = typeof nameOrConfig === "string" ? maybeConfig : nameOrConfig;
125
146
  let dt = 0;
126
147
  if (config?.mode === "boolean") dt = false;
127
- if (config?.mode === "timestamp") dt = /* @__PURE__ */ new Date();
148
+ if (config?.mode === "timestamp" || config?.mode === "timestamp_ms")
149
+ dt = /* @__PURE__ */ new Date();
128
150
  const col = createColumn({
129
151
  name,
130
152
  type: "INTEGER",
131
- isPrimaryKey: config?.isPrimaryKey,
132
- autoIncrement: config?.autoIncrement,
133
153
  mode: config?.mode ?? "number",
134
154
  _dataType: dt
135
155
  });
136
156
  return col;
137
157
  }
138
158
  function real(name) {
139
- return createColumn({ name, type: "REAL", _dataType: 0 });
159
+ return createColumn({
160
+ name: name ?? "",
161
+ type: "REAL",
162
+ _dataType: 0
163
+ });
140
164
  }
141
- function blob(name, config) {
165
+ function blob(nameOrConfig, maybeConfig) {
166
+ const name = typeof nameOrConfig === "string" ? nameOrConfig : "";
167
+ const config = typeof nameOrConfig === "string" ? maybeConfig : nameOrConfig;
142
168
  let dt = new Uint8Array();
143
169
  if (config?.mode === "bigint") dt = 0n;
144
170
  if (config?.mode === "json") dt = void 0;
@@ -149,7 +175,9 @@ function blob(name, config) {
149
175
  _dataType: dt
150
176
  });
151
177
  }
152
- function numeric(name, config) {
178
+ function numeric(nameOrConfig, maybeConfig) {
179
+ const name = typeof nameOrConfig === "string" ? nameOrConfig : "";
180
+ const config = typeof nameOrConfig === "string" ? maybeConfig : nameOrConfig;
153
181
  let dt = "";
154
182
  if (config?.mode === "number") dt = 0;
155
183
  if (config?.mode === "bigint") dt = 0n;
@@ -160,59 +188,346 @@ function numeric(name, config) {
160
188
  _dataType: dt
161
189
  });
162
190
  }
163
- var boolean = (name) => createColumn({
164
- name,
165
- type: "INTEGER",
166
- _dataType: false,
167
- mode: "boolean"
168
- });
169
- var timestamp = (name) => createColumn({
170
- name,
171
- type: "INTEGER",
172
- _dataType: /* @__PURE__ */ new Date(),
173
- mode: "timestamp"
174
- });
175
- function defineTable(tableName, schema) {
191
+ function boolean(name) {
192
+ return createColumn({
193
+ name: name ?? "",
194
+ type: "INTEGER",
195
+ _dataType: false,
196
+ mode: "boolean"
197
+ });
198
+ }
199
+ function timestamp(name) {
200
+ return createColumn({
201
+ name: name ?? "",
202
+ type: "INTEGER",
203
+ _dataType: /* @__PURE__ */ new Date(),
204
+ mode: "timestamp"
205
+ });
206
+ }
207
+ function increments(name) {
208
+ return integer(name ?? "").primaryKey({
209
+ autoIncrement: true
210
+ });
211
+ }
212
+ function unique(name) {
213
+ return {
214
+ on: (...cols) => ({ name, columns: cols.map((c) => c.name) })
215
+ };
216
+ }
217
+ function primaryKey(opts) {
218
+ return { name: opts.name, columns: opts.columns.map((c) => c.name) };
219
+ }
220
+ function check(name, expr) {
221
+ return { name, expr };
222
+ }
223
+ function foreignKey(opts) {
224
+ const first = opts.columns[0];
225
+ return {
226
+ name: opts.name,
227
+ columns: opts.columns.map((c) => c.name),
228
+ foreignTable: first?.tableName || opts.foreignColumns[0]?.tableName || "",
229
+ foreignColumns: opts.foreignColumns.map((c) => c.name),
230
+ onDelete: opts.onDelete,
231
+ onUpdate: opts.onUpdate
232
+ };
233
+ }
234
+ function index(name) {
235
+ return {
236
+ on: (...cols) => ({ name, columns: cols.map((c) => c.name) }),
237
+ where: (expr) => ({ name, columns: [], where: expr })
238
+ };
239
+ }
240
+ function uniqueIndex(name) {
241
+ return {
242
+ on: (...cols) => ({ name, columns: cols.map((c) => c.name), unique: true }),
243
+ where: (expr) => ({ name, columns: [], unique: true, where: expr })
244
+ };
245
+ }
246
+ function defineTable(tableName, schema, extras) {
176
247
  const finalizedSchema = { ...schema };
177
248
  for (const key of Object.keys(finalizedSchema)) {
178
249
  const col = finalizedSchema[key];
250
+ if (!col.name || col.name === "") col.name = key;
179
251
  col.tableName = tableName;
180
252
  }
181
253
  const table = {
182
254
  _tableName: tableName,
183
255
  _schema: finalizedSchema,
256
+ _constraints: [],
257
+ _indexes: [],
184
258
  // The Drizzle-like type inference properties
185
259
  $inferSelect: {},
186
260
  $inferInsert: {}
187
- // Example: omit 'id' for inserts
261
+ // omit PK columns
188
262
  };
189
263
  for (const [key, col] of Object.entries(finalizedSchema)) {
190
264
  table[key] = col;
191
265
  }
266
+ if (extras) {
267
+ const specs = extras(table) || [];
268
+ for (const s of specs) {
269
+ if (s.columns && s.unique !== void 0) {
270
+ table._indexes.push(s);
271
+ } else if (s.columns && s.foreignColumns) {
272
+ table._constraints.push(s);
273
+ } else if (s.columns && (s.name || s.name === void 0)) {
274
+ if (s.columns && s.name !== void 0 && s.columns.length > 0) {
275
+ const pk = s;
276
+ if (pk.columns.length > 1 || pk.name && pk.name.length > 0) {
277
+ table._constraints.push(s);
278
+ } else {
279
+ table._constraints.push(s);
280
+ }
281
+ } else {
282
+ table._constraints.push(s);
283
+ }
284
+ } else if (s.expr) {
285
+ table._constraints.push(s);
286
+ }
287
+ }
288
+ }
192
289
  return table;
193
290
  }
194
291
 
292
+ // src/orm.ts
293
+ var import_plugin_sql = __toESM(require("@tauri-apps/plugin-sql"));
294
+
295
+ // src/sql-helpers.ts
296
+ function raw(strings, ...values) {
297
+ return {
298
+ toSQL: () => {
299
+ let clause = "";
300
+ const bindings = [];
301
+ for (let i = 0; i < strings.length; i++) {
302
+ clause += strings[i];
303
+ if (i < values.length) {
304
+ const v = values[i];
305
+ if (v && typeof v === "object" && typeof v.toSQL === "function") {
306
+ const s = v.toSQL();
307
+ clause += s.clause;
308
+ bindings.push(...s.bindings);
309
+ } else if (v && typeof v === "object" && "_dataType" in v) {
310
+ clause += getQualifiedName(v);
311
+ } else {
312
+ clause += "?";
313
+ bindings.push(v);
314
+ }
315
+ }
316
+ }
317
+ return { clause, bindings };
318
+ }
319
+ };
320
+ }
321
+ function isColumn(value) {
322
+ return typeof value === "object" && value !== null && "_dataType" in value;
323
+ }
324
+ function getQualifiedName(column) {
325
+ if (column.tableName) return `${column.tableName}.${column.name}`;
326
+ return column.name;
327
+ }
328
+ function comparison(operator, column, value) {
329
+ return {
330
+ toSQL: () => {
331
+ if (isColumn(value)) {
332
+ return {
333
+ clause: `${getQualifiedName(column)} ${operator} ${getQualifiedName(
334
+ value
335
+ )}`,
336
+ bindings: []
337
+ };
338
+ }
339
+ return {
340
+ clause: `${getQualifiedName(column)} ${operator} ?`,
341
+ bindings: [value]
342
+ };
343
+ }
344
+ };
345
+ }
346
+ var and = (...conditions) => ({
347
+ toSQL: () => {
348
+ const parts = [];
349
+ const bindings = [];
350
+ for (const c of conditions) {
351
+ const s = c.toSQL();
352
+ parts.push(`(${s.clause})`);
353
+ bindings.push(...s.bindings);
354
+ }
355
+ return { clause: parts.join(" AND "), bindings };
356
+ }
357
+ });
358
+ var or = (...conditions) => ({
359
+ toSQL: () => {
360
+ const parts = [];
361
+ const bindings = [];
362
+ for (const c of conditions) {
363
+ const s = c.toSQL();
364
+ parts.push(`(${s.clause})`);
365
+ bindings.push(...s.bindings);
366
+ }
367
+ return { clause: parts.join(" OR "), bindings };
368
+ }
369
+ });
370
+ var not = (condition) => ({
371
+ toSQL: () => {
372
+ const s = condition.toSQL();
373
+ return { clause: `NOT (${s.clause})`, bindings: s.bindings };
374
+ }
375
+ });
376
+ var eq = (column, value) => comparison("=", column, value);
377
+ var ne = (column, value) => comparison("!=", column, value);
378
+ var gt = (column, value) => comparison(">", column, value);
379
+ var gte = (column, value) => comparison(">=", column, value);
380
+ var lt = (column, value) => comparison("<", column, value);
381
+ var lte = (column, value) => comparison("<=", column, value);
382
+ var like = (column, value) => comparison("LIKE", column, value);
383
+ var ilike = (column, value) => ({
384
+ toSQL: () => {
385
+ const colExpr = `LOWER(${getQualifiedName(column)})`;
386
+ if (isColumn(value)) {
387
+ return {
388
+ clause: `${colExpr} LIKE LOWER(${getQualifiedName(value)})`,
389
+ bindings: []
390
+ };
391
+ }
392
+ return { clause: `${colExpr} LIKE LOWER(?)`, bindings: [value] };
393
+ }
394
+ });
395
+ var notIlike = (column, value) => ({
396
+ toSQL: () => {
397
+ const colExpr = `LOWER(${getQualifiedName(column)})`;
398
+ if (isColumn(value)) {
399
+ return {
400
+ clause: `${colExpr} NOT LIKE LOWER(${getQualifiedName(value)})`,
401
+ bindings: []
402
+ };
403
+ }
404
+ return { clause: `${colExpr} NOT LIKE LOWER(?)`, bindings: [value] };
405
+ }
406
+ });
407
+ var isNull = (column) => ({
408
+ toSQL: () => ({
409
+ clause: `${getQualifiedName(column)} IS NULL`,
410
+ bindings: []
411
+ })
412
+ });
413
+ var isNotNull = (column) => ({
414
+ toSQL: () => ({
415
+ clause: `${getQualifiedName(column)} IS NOT NULL`,
416
+ bindings: []
417
+ })
418
+ });
419
+ var between = (column, from, to) => ({
420
+ toSQL: () => {
421
+ const left = getQualifiedName(column);
422
+ const [fromClause, fromBindings] = isColumn(from) ? [getQualifiedName(from), []] : ["?", [from]];
423
+ const [toClause, toBindings] = isColumn(to) ? [getQualifiedName(to), []] : ["?", [to]];
424
+ return {
425
+ clause: `${left} BETWEEN ${fromClause} AND ${toClause}`,
426
+ bindings: [...fromBindings, ...toBindings]
427
+ };
428
+ }
429
+ });
430
+ var notBetween = (column, from, to) => ({
431
+ toSQL: () => {
432
+ const left = getQualifiedName(column);
433
+ const [fromClause, fromBindings] = isColumn(from) ? [getQualifiedName(from), []] : ["?", [from]];
434
+ const [toClause, toBindings] = isColumn(to) ? [getQualifiedName(to), []] : ["?", [to]];
435
+ return {
436
+ clause: `${left} NOT BETWEEN ${fromClause} AND ${toClause}`,
437
+ bindings: [...fromBindings, ...toBindings]
438
+ };
439
+ }
440
+ });
441
+ var inArray = (column, valuesOrQuery) => ({
442
+ toSQL: () => {
443
+ const left = getQualifiedName(column);
444
+ if (Array.isArray(valuesOrQuery)) {
445
+ const placeholders = valuesOrQuery.map(() => "?").join(", ");
446
+ return {
447
+ clause: `${left} IN (${placeholders})`,
448
+ bindings: valuesOrQuery
449
+ };
450
+ }
451
+ const sq = valuesOrQuery.toSQL ? valuesOrQuery.toSQL() : valuesOrQuery.toSQL();
452
+ return { clause: `${left} IN (${sq.clause})`, bindings: sq.bindings };
453
+ }
454
+ });
455
+ var notInArray = (column, valuesOrQuery) => ({
456
+ toSQL: () => {
457
+ const left = getQualifiedName(column);
458
+ if (Array.isArray(valuesOrQuery)) {
459
+ const placeholders = valuesOrQuery.map(() => "?").join(", ");
460
+ return {
461
+ clause: `${left} NOT IN (${placeholders})`,
462
+ bindings: valuesOrQuery
463
+ };
464
+ }
465
+ const sq = valuesOrQuery.toSQL ? valuesOrQuery.toSQL() : valuesOrQuery.toSQL();
466
+ return { clause: `${left} NOT IN (${sq.clause})`, bindings: sq.bindings };
467
+ }
468
+ });
469
+ var exists = (subquery) => ({
470
+ toSQL: () => {
471
+ const sq = subquery.toSQL ? subquery.toSQL() : subquery.toSQL();
472
+ return { clause: `EXISTS (${sq.clause})`, bindings: sq.bindings };
473
+ }
474
+ });
475
+ var notExists = (subquery) => ({
476
+ toSQL: () => {
477
+ const sq = subquery.toSQL ? subquery.toSQL() : subquery.toSQL();
478
+ return { clause: `NOT EXISTS (${sq.clause})`, bindings: sq.bindings };
479
+ }
480
+ });
481
+ var asc = (column) => `${getQualifiedName(column)} ASC`;
482
+ var desc = (column) => `${getQualifiedName(column)} DESC`;
483
+
195
484
  // src/orm.ts
196
485
  var SelectQueryBuilder = class {
197
486
  _table = null;
198
- _selectedColumns = ["*"];
487
+ _selectedColumns = [];
199
488
  _joins = [];
200
489
  _where = [];
201
490
  _orderBy = [];
202
491
  _limit = null;
203
492
  _offset = null;
204
- _eager = {};
205
- constructor(fields) {
493
+ _groupBy = [];
494
+ _having = [];
495
+ _distinct = false;
496
+ _dbProvider;
497
+ constructor(dbProvider, fields) {
498
+ this._dbProvider = dbProvider;
206
499
  if (fields) {
207
- this._selectedColumns = Object.values(fields).map((c) => c.name);
500
+ for (const [alias, col] of Object.entries(fields)) {
501
+ const sql2 = getQualifiedName(col);
502
+ this._selectedColumns.push({ sql: sql2, alias });
503
+ }
208
504
  }
209
505
  }
506
+ distinct() {
507
+ this._distinct = true;
508
+ return this;
509
+ }
510
+ select(fields) {
511
+ this._selectedColumns = [];
512
+ for (const [alias, expr] of Object.entries(fields)) {
513
+ if (typeof expr.toSQL === "function") {
514
+ const s = expr.toSQL();
515
+ this._selectedColumns.push({ sql: s.clause, alias });
516
+ } else {
517
+ this._selectedColumns.push({
518
+ sql: getQualifiedName(expr),
519
+ alias
520
+ });
521
+ }
522
+ }
523
+ return this;
524
+ }
210
525
  from(table) {
211
526
  this._table = table;
212
527
  return this;
213
528
  }
214
529
  where(...conditions) {
215
- this._where.push(...conditions);
530
+ this._where.push(...conditions.filter(Boolean));
216
531
  return this;
217
532
  }
218
533
  leftJoin(otherTable, on) {
@@ -221,8 +536,26 @@ var SelectQueryBuilder = class {
221
536
  this._joins.push(joinClause);
222
537
  return this;
223
538
  }
539
+ groupBy(...exprs) {
540
+ for (const e of exprs) {
541
+ if (!e) continue;
542
+ if (typeof e === "string") this._groupBy.push(e);
543
+ else this._groupBy.push(getQualifiedName(e));
544
+ }
545
+ return this;
546
+ }
547
+ having(...conditions) {
548
+ this._having.push(...conditions);
549
+ return this;
550
+ }
224
551
  orderBy(...clauses) {
225
- this._orderBy.push(...clauses);
552
+ for (const c of clauses) {
553
+ if (!c) continue;
554
+ if (typeof c === "string") this._orderBy.push(c);
555
+ else if (typeof c.toSQL === "function")
556
+ this._orderBy.push(c);
557
+ else this._orderBy.push(getQualifiedName(c));
558
+ }
226
559
  return this;
227
560
  }
228
561
  limit(value) {
@@ -233,17 +566,15 @@ var SelectQueryBuilder = class {
233
566
  this._offset = value;
234
567
  return this;
235
568
  }
236
- // The final execution step
237
569
  async execute() {
238
570
  if (!this._table) {
239
571
  throw new Error("Cannot execute select query without a 'from' table.");
240
572
  }
241
- const db3 = getDb();
573
+ const db = await this._dbProvider();
242
574
  const bindings = [];
243
- let query = `SELECT ${this._selectedColumns.join(", ")} FROM ${this._table._tableName}`;
244
- if (this._joins.length > 0) {
245
- query += ` ${this._joins.join(" ")}`;
246
- }
575
+ 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(", ");
576
+ let query = `SELECT ${this._distinct ? "DISTINCT " : ""}${selectList} FROM ${this._table._tableName}`;
577
+ if (this._joins.length > 0) query += ` ${this._joins.join(" ")}`;
247
578
  if (this._where.length > 0) {
248
579
  const whereClauses = this._where.map((condition) => {
249
580
  const sql2 = condition.toSQL();
@@ -252,21 +583,46 @@ var SelectQueryBuilder = class {
252
583
  });
253
584
  query += ` WHERE ${whereClauses.join(" AND ")}`;
254
585
  }
586
+ if (this._groupBy.length > 0) {
587
+ query += ` GROUP BY ${this._groupBy.join(", ")}`;
588
+ }
589
+ if (this._having.length > 0) {
590
+ const havingClauses = this._having.map((h) => {
591
+ const sql2 = h.toSQL();
592
+ bindings.push(...sql2.bindings);
593
+ return `(${sql2.clause})`;
594
+ });
595
+ query += ` HAVING ${havingClauses.join(" AND ")}`;
596
+ }
255
597
  if (this._orderBy.length > 0) {
256
- query += ` ORDER BY ${this._orderBy.join(", ")}`;
598
+ const ordParts = [];
599
+ for (const ob of this._orderBy) {
600
+ if (typeof ob === "string") ordParts.push(ob);
601
+ else {
602
+ const s = ob.toSQL();
603
+ ordParts.push(s.clause);
604
+ bindings.push(...s.bindings);
605
+ }
606
+ }
607
+ query += ` ORDER BY ${ordParts.join(", ")}`;
257
608
  }
258
609
  if (this._limit !== null) {
259
610
  query += ` LIMIT ?`;
260
611
  bindings.push(this._limit);
261
612
  }
262
613
  if (this._offset !== null) {
263
- if (this._limit === null) {
264
- query += ` LIMIT -1`;
265
- }
614
+ if (this._limit === null) query += ` LIMIT -1`;
266
615
  query += ` OFFSET ?`;
267
616
  bindings.push(this._offset);
268
617
  }
269
- return db3.select(query, bindings);
618
+ return db.select(query, bindings);
619
+ }
620
+ async iterator() {
621
+ const rows = await this.execute();
622
+ async function* gen() {
623
+ for (const r of rows) yield r;
624
+ }
625
+ return gen();
270
626
  }
271
627
  };
272
628
  var TauriORM = class {
@@ -274,48 +630,154 @@ var TauriORM = class {
274
630
  query = {};
275
631
  _tables = null;
276
632
  _relations = null;
633
+ _dbPromise;
634
+ constructor(dbUri) {
635
+ this._dbPromise = import_plugin_sql.default.load(dbUri);
636
+ }
637
+ async getDb() {
638
+ return this._dbPromise;
639
+ }
277
640
  // Deprecated: use configure()
278
641
  configureQuery(tables, relations2) {
279
642
  this.configure(tables, relations2);
280
643
  }
281
644
  select(fields) {
282
- return new SelectQueryBuilder(fields);
645
+ return new SelectQueryBuilder(this.getDb.bind(this), fields);
646
+ }
647
+ selectDistinct(fields) {
648
+ const qb = new SelectQueryBuilder(this.getDb.bind(this), fields);
649
+ qb.distinct();
650
+ return qb;
283
651
  }
284
652
  // --- Drizzle-style CRUD builders ---
285
653
  insert(table) {
654
+ const self = this;
286
655
  return new class InsertBuilder {
287
656
  _table = table;
288
657
  _rows = [];
658
+ _selectSql = null;
659
+ _conflict = null;
660
+ _returning = null;
289
661
  values(rowOrRows) {
290
662
  this._rows = Array.isArray(rowOrRows) ? rowOrRows : [rowOrRows];
291
663
  return this;
292
664
  }
665
+ select(qb) {
666
+ if (qb.toSQL) this._selectSql = qb.toSQL();
667
+ else this._selectSql = qb.toSQL();
668
+ return this;
669
+ }
670
+ returning(fields) {
671
+ this._returning = fields ?? {};
672
+ return this;
673
+ }
674
+ $returningId() {
675
+ this._returning = "__RETURNING_ID__";
676
+ return this;
677
+ }
678
+ onConflictDoNothing(opts) {
679
+ const target = opts?.target ? Array.isArray(opts.target) ? opts.target.map((c) => c.name) : opts.target.name : void 0;
680
+ this._conflict = {
681
+ kind: "doNothing",
682
+ target,
683
+ where: opts?.where
684
+ };
685
+ return this;
686
+ }
687
+ onConflictDoUpdate(opts) {
688
+ const target = Array.isArray(opts.target) ? opts.target.map((c) => c.name) : opts.target.name;
689
+ this._conflict = {
690
+ kind: "doUpdate",
691
+ target,
692
+ targetWhere: opts.targetWhere,
693
+ set: opts.set,
694
+ setWhere: opts.setWhere
695
+ };
696
+ return this;
697
+ }
293
698
  async execute() {
294
- const db3 = getDb();
699
+ const db = await self.getDb();
700
+ if (this._selectSql) {
701
+ const cols = Object.keys(this._table._schema);
702
+ let query = `INSERT INTO ${this._table._tableName} (${cols.join(", ")}) ${this._selectSql.clause}`;
703
+ const bindings = [...this._selectSql.bindings];
704
+ query += this._buildConflictClause();
705
+ const ret = await this._executeWithReturning(db, query, bindings);
706
+ return ret;
707
+ }
295
708
  for (const data of this._rows) {
296
709
  const finalData = { ...data };
297
710
  const schema = this._table._schema;
298
711
  for (const [key, col] of Object.entries(schema)) {
299
- if (finalData[key] === void 0 && col.defaultFn) {
300
- finalData[key] = col.defaultFn();
712
+ if (finalData[key] === void 0) {
713
+ if (col.defaultFn) {
714
+ finalData[key] = col.defaultFn();
715
+ } else if (col.onUpdateFn) {
716
+ finalData[key] = col.onUpdateFn();
717
+ }
301
718
  }
302
719
  }
303
720
  const keys = Object.keys(finalData);
304
721
  const values = Object.values(finalData);
305
722
  const placeholders = values.map(() => "?").join(", ");
306
- const query = `INSERT INTO ${this._table._tableName} (${keys.join(
307
- ", "
308
- )}) VALUES (${placeholders})`;
309
- await db3.execute(query, values);
723
+ let query = `INSERT INTO ${this._table._tableName} (${keys.join(", ")}) VALUES (${placeholders})`;
724
+ const bindings = [...values];
725
+ query += this._buildConflictClause();
726
+ const ret = await this._executeWithReturning(db, query, bindings);
727
+ if (ret !== void 0) return ret;
728
+ }
729
+ }
730
+ _buildConflictClause() {
731
+ if (!this._conflict) return "";
732
+ if (this._conflict.kind === "doNothing") {
733
+ const tgt2 = this._conflict.target ? Array.isArray(this._conflict.target) ? `(${this._conflict.target.join(", ")})` : `(${this._conflict.target})` : "";
734
+ const where = this._conflict.where ? ` WHERE ${this._conflict.where.toSQL().clause}` : "";
735
+ return ` ON CONFLICT ${tgt2} DO NOTHING${where}`;
310
736
  }
737
+ const c = this._conflict;
738
+ const tgt = Array.isArray(c.target) ? `(${c.target.join(", ")})` : `(${c.target})`;
739
+ const setKeys = Object.keys(c.set ?? {});
740
+ const setClause = setKeys.map((k) => {
741
+ const v = c.set[k];
742
+ return `${k} = ${typeof v === "object" && v && typeof v.toSQL === "function" ? v.toSQL().clause : "?"}`;
743
+ }).join(", ");
744
+ const targetWhere = c.targetWhere ? ` WHERE ${c.targetWhere.toSQL().clause}` : "";
745
+ const setWhere = c.setWhere ? ` WHERE ${c.setWhere.toSQL().clause}` : "";
746
+ return ` ON CONFLICT ${tgt}${targetWhere} DO UPDATE SET ${setClause}${setWhere}`;
747
+ }
748
+ async _executeWithReturning(db, query, bindings) {
749
+ if (this._returning === null) {
750
+ await db.execute(query, bindings);
751
+ return void 0;
752
+ }
753
+ if (this._returning === "__RETURNING_ID__") {
754
+ const rows = await db.select(`SELECT last_insert_rowid() as id`);
755
+ return rows.map((r) => ({ id: r.id }));
756
+ }
757
+ if (typeof this._returning === "object") {
758
+ const cols = Object.entries(
759
+ this._returning
760
+ ).map(
761
+ ([alias, col]) => `${col.tableName}.${col.name} AS ${alias}`
762
+ ).join(", ");
763
+ const retSql = `${query} RETURNING ${cols}`;
764
+ const res = await db.select(retSql, bindings);
765
+ return res;
766
+ }
767
+ return void 0;
311
768
  }
312
769
  }();
313
770
  }
314
771
  update(table) {
772
+ const self = this;
315
773
  return new class UpdateBuilder {
316
774
  _table = table;
317
775
  _data = null;
318
776
  _where = null;
777
+ _orderBy = [];
778
+ _limit = null;
779
+ _from = null;
780
+ _returning = null;
319
781
  set(data) {
320
782
  this._data = data;
321
783
  return this;
@@ -324,14 +786,54 @@ var TauriORM = class {
324
786
  this._where = cond;
325
787
  return this;
326
788
  }
789
+ orderBy(...clauses) {
790
+ for (const c of clauses) {
791
+ if (!c) continue;
792
+ if (typeof c === "string") this._orderBy.push(c);
793
+ else if (typeof c.toSQL === "function")
794
+ this._orderBy.push(c);
795
+ else this._orderBy.push(getQualifiedName(c));
796
+ }
797
+ return this;
798
+ }
799
+ limit(n) {
800
+ this._limit = n;
801
+ return this;
802
+ }
803
+ from(tbl) {
804
+ this._from = tbl;
805
+ return this;
806
+ }
807
+ returning(fields) {
808
+ this._returning = fields ?? {};
809
+ return this;
810
+ }
327
811
  async execute() {
328
812
  if (!this._data)
329
813
  throw new Error("Update requires set() before execute()");
330
- const db3 = getDb();
331
- const setKeys = Object.keys(this._data);
332
- const setClause = setKeys.map((k) => `${k} = ?`).join(", ");
333
- const bindings = Object.values(this._data);
334
- let query = `UPDATE ${this._table._tableName} SET ${setClause}`;
814
+ const db = await self.getDb();
815
+ const schema = this._table._schema;
816
+ const dataToSet = { ...this._data };
817
+ for (const [key, col] of Object.entries(schema)) {
818
+ if (!(key in dataToSet) && col.onUpdateFn) {
819
+ dataToSet[key] = col.onUpdateFn();
820
+ }
821
+ }
822
+ const setParts = [];
823
+ const bindings = [];
824
+ for (const [k, v] of Object.entries(dataToSet)) {
825
+ if (v === void 0) continue;
826
+ if (v && typeof v === "object" && typeof v.toSQL === "function") {
827
+ const s = v.toSQL();
828
+ setParts.push(`${k} = ${s.clause}`);
829
+ bindings.push(...s.bindings);
830
+ } else {
831
+ setParts.push(`${k} = ?`);
832
+ bindings.push(v);
833
+ }
834
+ }
835
+ let query = `UPDATE ${this._table._tableName} SET ${setParts.join(", ")}`;
836
+ if (this._from) query += ` FROM ${this._from._tableName}`;
335
837
  if (this._where) {
336
838
  if (typeof this._where.toSQL === "function") {
337
839
  const sql2 = this._where.toSQL();
@@ -345,20 +847,67 @@ var TauriORM = class {
345
847
  }
346
848
  }
347
849
  }
348
- await db3.execute(query, bindings);
850
+ if (this._orderBy.length > 0) {
851
+ const ordParts = [];
852
+ for (const ob of this._orderBy) {
853
+ if (typeof ob === "string") ordParts.push(ob);
854
+ else {
855
+ const s = ob.toSQL();
856
+ ordParts.push(s.clause);
857
+ bindings.push(...s.bindings);
858
+ }
859
+ }
860
+ query += ` ORDER BY ${ordParts.join(", ")}`;
861
+ }
862
+ if (this._limit !== null) {
863
+ query += ` LIMIT ?`;
864
+ bindings.push(this._limit);
865
+ }
866
+ if (this._returning) {
867
+ const cols = Object.entries(
868
+ this._returning
869
+ ).map(
870
+ ([alias, col]) => `${col.tableName}.${col.name} AS ${alias}`
871
+ ).join(", ");
872
+ const retSql = `${query} RETURNING ${cols}`;
873
+ return await db.select(retSql, bindings);
874
+ }
875
+ await db.execute(query, bindings);
349
876
  }
350
877
  }();
351
878
  }
352
879
  delete(table) {
880
+ const self = this;
353
881
  return new class DeleteBuilder {
354
882
  _table = table;
355
883
  _where = null;
884
+ _orderBy = [];
885
+ _limit = null;
886
+ _returning = null;
356
887
  where(cond) {
357
888
  this._where = cond;
358
889
  return this;
359
890
  }
891
+ orderBy(...clauses) {
892
+ for (const c of clauses) {
893
+ if (!c) continue;
894
+ if (typeof c === "string") this._orderBy.push(c);
895
+ else if (typeof c.toSQL === "function")
896
+ this._orderBy.push(c);
897
+ else this._orderBy.push(getQualifiedName(c));
898
+ }
899
+ return this;
900
+ }
901
+ limit(n) {
902
+ this._limit = n;
903
+ return this;
904
+ }
905
+ returning(fields) {
906
+ this._returning = fields ?? {};
907
+ return this;
908
+ }
360
909
  async execute() {
361
- const db3 = getDb();
910
+ const db = await self.getDb();
362
911
  let query = `DELETE FROM ${this._table._tableName}`;
363
912
  const bindings = [];
364
913
  if (this._where) {
@@ -374,7 +923,32 @@ var TauriORM = class {
374
923
  }
375
924
  }
376
925
  }
377
- await db3.execute(query, bindings);
926
+ if (this._orderBy.length > 0) {
927
+ const ordParts = [];
928
+ for (const ob of this._orderBy) {
929
+ if (typeof ob === "string") ordParts.push(ob);
930
+ else {
931
+ const s = ob.toSQL();
932
+ ordParts.push(s.clause);
933
+ bindings.push(...s.bindings);
934
+ }
935
+ }
936
+ query += ` ORDER BY ${ordParts.join(", ")}`;
937
+ }
938
+ if (this._limit !== null) {
939
+ query += ` LIMIT ?`;
940
+ bindings.push(this._limit);
941
+ }
942
+ if (this._returning) {
943
+ const cols = Object.entries(
944
+ this._returning
945
+ ).map(
946
+ ([alias, col]) => `${col.tableName}.${col.name} AS ${alias}`
947
+ ).join(", ");
948
+ const retSql = `${query} RETURNING ${cols}`;
949
+ return await db.select(retSql, bindings);
950
+ }
951
+ await db.execute(query, bindings);
378
952
  }
379
953
  }();
380
954
  }
@@ -382,8 +956,8 @@ var TauriORM = class {
382
956
  // legacy direct methods removed in favor of builder APIs
383
957
  // legacy direct methods removed in favor of builder APIs
384
958
  async run(query, bindings = []) {
385
- const db3 = getDb();
386
- await db3.execute(query, bindings);
959
+ const db = await this.getDb();
960
+ await db.execute(query, bindings);
387
961
  }
388
962
  // --- Migrations API ---
389
963
  generateCreateTableSql(table) {
@@ -433,16 +1007,16 @@ var TauriORM = class {
433
1007
  );
434
1008
  }
435
1009
  async hasMigration(name) {
436
- const db3 = getDb();
437
- const rows = await db3.select(
1010
+ const db = await this.getDb();
1011
+ const rows = await db.select(
438
1012
  `SELECT name FROM _migrations WHERE name = ?`,
439
1013
  [name]
440
1014
  );
441
1015
  return Array.isArray(rows) && rows.length > 0;
442
1016
  }
443
1017
  async recordMigration(name) {
444
- const db3 = getDb();
445
- await db3.execute(
1018
+ const db = await this.getDb();
1019
+ await db.execute(
446
1020
  `INSERT INTO _migrations (name, applied_at) VALUES (?, ?)`,
447
1021
  [name, Date.now()]
448
1022
  );
@@ -464,7 +1038,7 @@ var TauriORM = class {
464
1038
  configure(tables, relDefs) {
465
1039
  this._tables = tables;
466
1040
  this._relations = relDefs ?? {};
467
- this.query = makeQueryAPI(tables, this._relations);
1041
+ this.query = makeQueryAPI(tables, this._relations, this.getDb.bind(this));
468
1042
  return this;
469
1043
  }
470
1044
  // Convenience: migrate from configured tables
@@ -476,7 +1050,7 @@ var TauriORM = class {
476
1050
  // --- Schema diff and CLI-like helpers ---
477
1051
  async diffSchema() {
478
1052
  if (!this._tables) throw new Error("No tables configured.");
479
- const dbi = getDb();
1053
+ const dbi = await this.getDb();
480
1054
  const configuredNames = Object.values(this._tables).map(
481
1055
  (t) => t._tableName
482
1056
  );
@@ -551,7 +1125,7 @@ var TauriORM = class {
551
1125
  return this.pullSchema();
552
1126
  }
553
1127
  async studio() {
554
- const dbi = getDb();
1128
+ const dbi = await this.getDb();
555
1129
  return { driver: "sqlite", path: dbi.path };
556
1130
  }
557
1131
  // --- Schema detection / signature ---
@@ -561,7 +1135,7 @@ var TauriORM = class {
561
1135
  );
562
1136
  }
563
1137
  async getSchemaMeta(key) {
564
- const dbi = getDb();
1138
+ const dbi = await this.getDb();
565
1139
  await this.ensureSchemaMeta();
566
1140
  const rows = await dbi.select(
567
1141
  `SELECT value FROM _schema_meta WHERE key = ?`,
@@ -570,7 +1144,7 @@ var TauriORM = class {
570
1144
  return rows?.[0]?.value ?? null;
571
1145
  }
572
1146
  async setSchemaMeta(key, value) {
573
- const dbi = getDb();
1147
+ const dbi = await this.getDb();
574
1148
  await this.ensureSchemaMeta();
575
1149
  await dbi.execute(
576
1150
  `INSERT INTO _schema_meta(key, value) VALUES(?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value`,
@@ -619,7 +1193,7 @@ var TauriORM = class {
619
1193
  // Pull current DB schema (minimal) for configured tables
620
1194
  async pullSchema() {
621
1195
  if (!this._tables) throw new Error("No tables configured.");
622
- const dbi = getDb();
1196
+ const dbi = await this.getDb();
623
1197
  const result = {};
624
1198
  for (const tbl of Object.values(this._tables)) {
625
1199
  const name = tbl._tableName;
@@ -638,7 +1212,7 @@ var TauriORM = class {
638
1212
  return this.generateCreateTableSql(table);
639
1213
  }
640
1214
  async tableExists(name) {
641
- const dbi = getDb();
1215
+ const dbi = await this.getDb();
642
1216
  const rows = await dbi.select(
643
1217
  `SELECT name FROM sqlite_master WHERE type='table' AND name = ?`,
644
1218
  [name]
@@ -648,12 +1222,12 @@ var TauriORM = class {
648
1222
  // Force push model to DB: add missing tables/columns, rebuild tables if incompatible
649
1223
  async forcePush(options) {
650
1224
  if (!this._tables) throw new Error("No tables configured.");
651
- const dbi = getDb();
1225
+ const dbi = await this.getDb();
652
1226
  const preserve = options?.preserveData !== false;
653
1227
  for (const tbl of Object.values(this._tables)) {
654
1228
  const tableName = tbl._tableName;
655
- const exists = await this.tableExists(tableName);
656
- if (!exists) {
1229
+ const exists2 = await this.tableExists(tableName);
1230
+ if (!exists2) {
657
1231
  await this.run(this.buildCreateTableSQL(tbl));
658
1232
  continue;
659
1233
  }
@@ -718,7 +1292,6 @@ var TauriORM = class {
718
1292
  await this.setSchemaMeta("schema_signature", this.computeModelSignature());
719
1293
  }
720
1294
  };
721
- var db2 = new TauriORM();
722
1295
  function relations(baseTable, builder) {
723
1296
  const ctx = {
724
1297
  one: (table, cfg) => ({ kind: "one", table, cfg }),
@@ -744,10 +1317,29 @@ function guessChildFk(child, base, rel) {
744
1317
  ];
745
1318
  return childCols.find((c) => guessNames.includes(c.name)) || childCols.find((c) => /.*_id$/i.test(c.name)) || null;
746
1319
  }
1320
+ function guessOneRelationJoin(base, rel) {
1321
+ const child = rel.table;
1322
+ const basePk = getPrimaryKey(base);
1323
+ const childCols = Object.values(child._schema);
1324
+ if (rel.cfg?.fields && rel.cfg?.references && rel.cfg.fields[0] && rel.cfg.references[0]) {
1325
+ const fk = rel.cfg.fields[0];
1326
+ const ref = rel.cfg.references[0];
1327
+ if (childCols.some((c) => c.name === fk.name)) {
1328
+ return { lhsTable: child, lhsCol: fk, rhsTable: base, rhsCol: ref };
1329
+ }
1330
+ const baseCols = Object.values(base._schema);
1331
+ if (baseCols.some((c) => c.name === fk.name)) {
1332
+ return { lhsTable: base, lhsCol: fk, rhsTable: child, rhsCol: ref };
1333
+ }
1334
+ }
1335
+ const childFk = guessChildFk(child, base, rel);
1336
+ if (!childFk) return null;
1337
+ return { lhsTable: child, lhsCol: childFk, rhsTable: base, rhsCol: basePk };
1338
+ }
747
1339
  function isFlatWith(spec) {
748
1340
  return Object.values(spec).every((v) => typeof v === "boolean");
749
1341
  }
750
- function makeQueryAPI(tables, relDefs) {
1342
+ function makeQueryAPI(tables, relDefs, dbProvider) {
751
1343
  const api = {};
752
1344
  const tableKeyByName = {};
753
1345
  for (const [k, t] of Object.entries(tables)) tableKeyByName[t._tableName] = k;
@@ -756,7 +1348,7 @@ function makeQueryAPI(tables, relDefs) {
756
1348
  async findMany(opts) {
757
1349
  const base = tbl;
758
1350
  const withSpec = opts?.with ?? {};
759
- const dbi = getDb();
1351
+ const dbi = await dbProvider();
760
1352
  const rels = relDefs[tblKey] ?? {};
761
1353
  if (opts?.join && isFlatWith(withSpec)) {
762
1354
  const baseCols = Object.values(base._schema);
@@ -782,23 +1374,43 @@ function makeQueryAPI(tables, relDefs) {
782
1374
  const child = rel.table;
783
1375
  const childCols = Object.values(child._schema);
784
1376
  const childPk = childCols.find((c) => c.isPrimaryKey) || childCols.find((c) => c.name === "id") || null;
785
- const childFk = guessChildFk(child, base, rel);
786
- if (!childFk) continue;
787
- fkMap[relName] = { childFk, childPk };
1377
+ if (rel.kind === "one") {
1378
+ const mapping = guessOneRelationJoin(base, rel);
1379
+ if (!mapping) continue;
1380
+ if (mapping.lhsTable._tableName === child._tableName) {
1381
+ fkMap[relName] = { childFk: mapping.lhsCol, childPk };
1382
+ joins.push(
1383
+ `LEFT JOIN ${child._tableName} ON ${mapping.lhsTable._tableName}.${mapping.lhsCol.name} = ${mapping.rhsTable._tableName}.${mapping.rhsCol.name}`
1384
+ );
1385
+ } else {
1386
+ fkMap[relName] = { childFk: mapping.rhsCol, childPk };
1387
+ joins.push(
1388
+ `LEFT JOIN ${child._tableName} ON ${mapping.lhsTable._tableName}.${mapping.lhsCol.name} = ${mapping.rhsTable._tableName}.${mapping.rhsCol.name}`
1389
+ );
1390
+ }
1391
+ } else {
1392
+ const childFk = guessChildFk(child, base, rel);
1393
+ if (!childFk) continue;
1394
+ fkMap[relName] = { childFk, childPk };
1395
+ joins.push(
1396
+ `LEFT JOIN ${child._tableName} ON ${child._tableName}.${childFk.name} = ${base._tableName}.${basePk.name}`
1397
+ );
1398
+ }
788
1399
  const selected = typeof enabled === "object" && enabled.columns?.length ? enabled.columns : childCols.map((c) => c.name);
789
1400
  relColsMap[relName] = selected;
790
1401
  for (const name of selected)
791
1402
  selectParts.push(
792
1403
  `${child._tableName}.${name} AS __rel_${relName}_${name}`
793
1404
  );
794
- joins.push(
795
- `LEFT JOIN ${child._tableName} ON ${child._tableName}.${childFk.name} = ${base._tableName}.${basePk.name}`
796
- );
797
1405
  }
798
1406
  let sqlText = `SELECT ${selectParts.join(", ")} FROM ${base._tableName}${joins.length ? " " + joins.join(" ") : ""}`;
799
1407
  const bindings = [];
800
1408
  if (opts?.where) {
801
- if (typeof opts.where.toSQL === "function") {
1409
+ if (typeof opts.where === "function") {
1410
+ const w = opts.where(base, { eq, ne, gt, gte, lt, lte, like }).toSQL();
1411
+ sqlText += ` WHERE ${w.clause}`;
1412
+ bindings.push(...w.bindings);
1413
+ } else if (typeof opts.where.toSQL === "function") {
802
1414
  const w = opts.where.toSQL();
803
1415
  sqlText += ` WHERE ${w.clause}`;
804
1416
  bindings.push(...w.bindings);
@@ -810,8 +1422,9 @@ function makeQueryAPI(tables, relDefs) {
810
1422
  }
811
1423
  }
812
1424
  }
813
- if (opts?.orderBy?.length)
814
- sqlText += ` ORDER BY ${opts.orderBy.join(", ")}`;
1425
+ const orderByClauses = typeof opts?.orderBy === "function" ? opts.orderBy(base, { asc, desc }) : opts?.orderBy;
1426
+ if (orderByClauses?.length)
1427
+ sqlText += ` ORDER BY ${orderByClauses.join(", ")}`;
815
1428
  if (typeof opts?.limit === "number")
816
1429
  sqlText += ` LIMIT ${opts.limit}`;
817
1430
  if (typeof opts?.offset === "number")
@@ -851,10 +1464,10 @@ function makeQueryAPI(tables, relDefs) {
851
1464
  const childPk = fkMap[relName].childPk;
852
1465
  if (childPk) {
853
1466
  if (!acc[relName]) acc[relName] = [];
854
- const exists = acc[relName].some(
1467
+ const exists2 = acc[relName].some(
855
1468
  (r) => r[childPk.name] === childObj[childPk.name]
856
1469
  );
857
- if (!exists) acc[relName].push(childObj);
1470
+ if (!exists2) acc[relName].push(childObj);
858
1471
  } else {
859
1472
  acc[relName].push(childObj);
860
1473
  }
@@ -878,7 +1491,11 @@ function makeQueryAPI(tables, relDefs) {
878
1491
  let baseSql = `SELECT ${baseSelected.join(", ")} FROM ${base._tableName}`;
879
1492
  const baseBindings = [];
880
1493
  if (opts?.where) {
881
- if (typeof opts.where.toSQL === "function") {
1494
+ if (typeof opts.where === "function") {
1495
+ const w = opts.where(base, { eq, ne, gt, gte, lt, lte, like }).toSQL();
1496
+ baseSql += ` WHERE ${w.clause}`;
1497
+ baseBindings.push(...w.bindings);
1498
+ } else if (typeof opts.where.toSQL === "function") {
882
1499
  const w = opts.where.toSQL();
883
1500
  baseSql += ` WHERE ${w.clause}`;
884
1501
  baseBindings.push(...w.bindings);
@@ -890,8 +1507,9 @@ function makeQueryAPI(tables, relDefs) {
890
1507
  }
891
1508
  }
892
1509
  }
893
- if (opts?.orderBy?.length)
894
- baseSql += ` ORDER BY ${opts.orderBy.join(", ")}`;
1510
+ const orderByClauses2 = typeof opts?.orderBy === "function" ? opts.orderBy(base, { asc, desc }) : opts?.orderBy;
1511
+ if (orderByClauses2?.length)
1512
+ baseSql += ` ORDER BY ${orderByClauses2.join(", ")}`;
895
1513
  if (typeof opts?.limit === "number") baseSql += ` LIMIT ${opts.limit}`;
896
1514
  if (typeof opts?.offset === "number")
897
1515
  baseSql += ` OFFSET ${opts.offset}`;
@@ -910,9 +1528,9 @@ function makeQueryAPI(tables, relDefs) {
910
1528
  const child = rel.table;
911
1529
  const childCols = Object.values(child._schema);
912
1530
  const selectCols = enabled?.columns && enabled.columns.length > 0 ? enabled.columns : childCols.map((c) => c.name);
913
- const fkCol = guessChildFk(child, parentTable, rel);
914
- if (!fkCol) continue;
915
1531
  if (rel.kind === "many") {
1532
+ const fkCol = guessChildFk(child, parentTable, rel);
1533
+ if (!fkCol) continue;
916
1534
  const sql2 = `SELECT ${selectCols.join(", ")} FROM ${child._tableName} WHERE ${fkCol.name} IN (${parentIds.map(() => "?").join(", ")})`;
917
1535
  const rows = await dbi.select(sql2, parentIds);
918
1536
  const buckets = /* @__PURE__ */ new Map();
@@ -931,14 +1549,32 @@ function makeQueryAPI(tables, relDefs) {
931
1549
  await loadRelationsFor(children, child, enabled.with);
932
1550
  }
933
1551
  } else {
934
- const sql2 = `SELECT ${selectCols.join(", ")} FROM ${child._tableName} WHERE ${fkCol.name} IN (${parentIds.map(() => "?").join(", ")})`;
935
- const rows = await dbi.select(sql2, parentIds);
936
- const mapOne = /* @__PURE__ */ new Map();
937
- for (const r of rows) mapOne.set(r[fkCol.name], r);
938
- for (const p of parents)
939
- p[relName] = mapOne.get(p[parentPk.name]) ?? null;
1552
+ const mapping = guessOneRelationJoin(parentTable, rel);
1553
+ if (!mapping) continue;
1554
+ if (mapping.lhsTable._tableName === child._tableName) {
1555
+ const sql2 = `SELECT ${selectCols.join(", ")} FROM ${child._tableName} WHERE ${mapping.lhsCol.name} IN (${parentIds.map(() => "?").join(", ")})`;
1556
+ const rows = await dbi.select(sql2, parentIds);
1557
+ const mapOne = /* @__PURE__ */ new Map();
1558
+ for (const r of rows) mapOne.set(r[mapping.lhsCol.name], r);
1559
+ for (const p of parents)
1560
+ p[relName] = mapOne.get(p[parentPk.name]) ?? null;
1561
+ } else {
1562
+ const parentFkName = mapping.lhsCol.name;
1563
+ const childPkName = mapping.rhsCol.name;
1564
+ const childIds = parents.map((p) => p[parentFkName]).filter((v2) => v2 !== void 0 && v2 !== null);
1565
+ if (childIds.length === 0) {
1566
+ for (const p of parents) p[relName] = null;
1567
+ } else {
1568
+ const sql2 = `SELECT ${selectCols.join(", ")} FROM ${child._tableName} WHERE ${childPkName} IN (${childIds.map(() => "?").join(", ")})`;
1569
+ const rows = await dbi.select(sql2, childIds);
1570
+ const mapOne = /* @__PURE__ */ new Map();
1571
+ for (const r of rows) mapOne.set(r[childPkName], r);
1572
+ for (const p of parents)
1573
+ p[relName] = mapOne.get(p[parentFkName]) ?? null;
1574
+ }
1575
+ }
940
1576
  if (enabled?.with) {
941
- const children = parents.map((p) => p[relName]).filter(Boolean);
1577
+ const children = parents.map((p) => p[relName]).filter((x) => Boolean(x));
942
1578
  if (children.length > 0)
943
1579
  await loadRelationsFor(children, child, enabled.with);
944
1580
  }
@@ -949,71 +1585,58 @@ function makeQueryAPI(tables, relDefs) {
949
1585
  await loadRelationsFor(result, base, withSpec);
950
1586
  }
951
1587
  return result;
1588
+ },
1589
+ async findFirst(opts) {
1590
+ const rows = await api[tblKey].findMany({ ...opts, limit: 1 });
1591
+ return rows?.[0] ?? null;
952
1592
  }
953
1593
  };
954
1594
  }
955
1595
  return api;
956
1596
  }
957
-
958
- // src/sql-helpers.ts
959
- function isColumn(value) {
960
- return typeof value === "object" && value !== null && "_dataType" in value;
961
- }
962
- function getQualifiedName(column) {
963
- if (column.tableName) return `${column.tableName}.${column.name}`;
964
- return column.name;
965
- }
966
- function comparison(operator, column, value) {
967
- return {
968
- toSQL: () => {
969
- if (isColumn(value)) {
970
- return {
971
- clause: `${getQualifiedName(column)} ${operator} ${getQualifiedName(
972
- value
973
- )}`,
974
- bindings: []
975
- };
976
- }
977
- return {
978
- clause: `${getQualifiedName(column)} ${operator} ?`,
979
- bindings: [value]
980
- };
981
- }
982
- };
983
- }
984
- var eq = (column, value) => comparison("=", column, value);
985
- var ne = (column, value) => comparison("!=", column, value);
986
- var gt = (column, value) => comparison(">", column, value);
987
- var gte = (column, value) => comparison(">=", column, value);
988
- var lt = (column, value) => comparison("<", column, value);
989
- var lte = (column, value) => comparison("<=", column, value);
990
- var like = (column, value) => comparison("LIKE", column, value);
991
- var asc = (column) => `${column.name} ASC`;
992
- var desc = (column) => `${column.name} DESC`;
993
1597
  // Annotate the CommonJS export names for ESM import in node:
994
1598
  0 && (module.exports = {
995
1599
  TauriORM,
1600
+ and,
996
1601
  asc,
1602
+ between,
997
1603
  blob,
998
1604
  boolean,
999
- db,
1605
+ check,
1000
1606
  defineTable,
1001
1607
  desc,
1002
1608
  eq,
1003
- getDb,
1609
+ exists,
1610
+ foreignKey,
1611
+ getQualifiedName,
1004
1612
  gt,
1005
1613
  gte,
1006
- initDb,
1614
+ ilike,
1615
+ inArray,
1616
+ increments,
1617
+ index,
1007
1618
  integer,
1619
+ isNotNull,
1620
+ isNull,
1008
1621
  like,
1009
1622
  lt,
1010
1623
  lte,
1011
1624
  makeQueryAPI,
1012
1625
  ne,
1626
+ not,
1627
+ notBetween,
1628
+ notExists,
1629
+ notIlike,
1630
+ notInArray,
1013
1631
  numeric,
1632
+ or,
1633
+ primaryKey,
1634
+ raw,
1014
1635
  real,
1015
1636
  relations,
1016
1637
  sql,
1017
1638
  text,
1018
- timestamp
1639
+ timestamp,
1640
+ unique,
1641
+ uniqueIndex
1019
1642
  });