@type32/tauri-sqlite-orm 0.1.3 → 0.1.4
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/LICENSE +21 -21
- package/README.md +247 -210
- package/dist/index.d.mts +43 -27
- package/dist/index.d.ts +43 -27
- package/dist/index.js +237 -130
- package/dist/index.mjs +236 -127
- package/package.json +7 -7
package/dist/index.mjs
CHANGED
|
@@ -1,17 +1,3 @@
|
|
|
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
3
|
const raw = strings.reduce(
|
|
@@ -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(
|
|
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(
|
|
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"
|
|
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({
|
|
81
|
+
return createColumn({
|
|
82
|
+
name: name ?? "",
|
|
83
|
+
type: "REAL",
|
|
84
|
+
_dataType: 0
|
|
85
|
+
});
|
|
81
86
|
}
|
|
82
|
-
function blob(
|
|
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(
|
|
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,22 +110,32 @@ function numeric(name, config) {
|
|
|
101
110
|
_dataType: dt
|
|
102
111
|
});
|
|
103
112
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
+
}
|
|
116
134
|
function defineTable(tableName, schema) {
|
|
117
135
|
const finalizedSchema = { ...schema };
|
|
118
136
|
for (const key of Object.keys(finalizedSchema)) {
|
|
119
137
|
const col = finalizedSchema[key];
|
|
138
|
+
if (!col.name || col.name === "") col.name = key;
|
|
120
139
|
col.tableName = tableName;
|
|
121
140
|
}
|
|
122
141
|
const table = {
|
|
@@ -125,7 +144,7 @@ function defineTable(tableName, schema) {
|
|
|
125
144
|
// The Drizzle-like type inference properties
|
|
126
145
|
$inferSelect: {},
|
|
127
146
|
$inferInsert: {}
|
|
128
|
-
//
|
|
147
|
+
// omit PK columns
|
|
129
148
|
};
|
|
130
149
|
for (const [key, col] of Object.entries(finalizedSchema)) {
|
|
131
150
|
table[key] = col;
|
|
@@ -133,6 +152,45 @@ function defineTable(tableName, schema) {
|
|
|
133
152
|
return table;
|
|
134
153
|
}
|
|
135
154
|
|
|
155
|
+
// src/orm.ts
|
|
156
|
+
import Database from "@tauri-apps/plugin-sql";
|
|
157
|
+
|
|
158
|
+
// src/sql-helpers.ts
|
|
159
|
+
function isColumn(value) {
|
|
160
|
+
return typeof value === "object" && value !== null && "_dataType" in value;
|
|
161
|
+
}
|
|
162
|
+
function getQualifiedName(column) {
|
|
163
|
+
if (column.tableName) return `${column.tableName}.${column.name}`;
|
|
164
|
+
return column.name;
|
|
165
|
+
}
|
|
166
|
+
function comparison(operator, column, value) {
|
|
167
|
+
return {
|
|
168
|
+
toSQL: () => {
|
|
169
|
+
if (isColumn(value)) {
|
|
170
|
+
return {
|
|
171
|
+
clause: `${getQualifiedName(column)} ${operator} ${getQualifiedName(
|
|
172
|
+
value
|
|
173
|
+
)}`,
|
|
174
|
+
bindings: []
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
clause: `${getQualifiedName(column)} ${operator} ?`,
|
|
179
|
+
bindings: [value]
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
var eq = (column, value) => comparison("=", column, value);
|
|
185
|
+
var ne = (column, value) => comparison("!=", column, value);
|
|
186
|
+
var gt = (column, value) => comparison(">", column, value);
|
|
187
|
+
var gte = (column, value) => comparison(">=", column, value);
|
|
188
|
+
var lt = (column, value) => comparison("<", column, value);
|
|
189
|
+
var lte = (column, value) => comparison("<=", column, value);
|
|
190
|
+
var like = (column, value) => comparison("LIKE", column, value);
|
|
191
|
+
var asc = (column) => `${getQualifiedName(column)} ASC`;
|
|
192
|
+
var desc = (column) => `${getQualifiedName(column)} DESC`;
|
|
193
|
+
|
|
136
194
|
// src/orm.ts
|
|
137
195
|
var SelectQueryBuilder = class {
|
|
138
196
|
_table = null;
|
|
@@ -143,7 +201,9 @@ var SelectQueryBuilder = class {
|
|
|
143
201
|
_limit = null;
|
|
144
202
|
_offset = null;
|
|
145
203
|
_eager = {};
|
|
146
|
-
|
|
204
|
+
_dbProvider;
|
|
205
|
+
constructor(dbProvider, fields) {
|
|
206
|
+
this._dbProvider = dbProvider;
|
|
147
207
|
if (fields) {
|
|
148
208
|
this._selectedColumns = Object.values(fields).map((c) => c.name);
|
|
149
209
|
}
|
|
@@ -179,7 +239,7 @@ var SelectQueryBuilder = class {
|
|
|
179
239
|
if (!this._table) {
|
|
180
240
|
throw new Error("Cannot execute select query without a 'from' table.");
|
|
181
241
|
}
|
|
182
|
-
const
|
|
242
|
+
const db = await this._dbProvider();
|
|
183
243
|
const bindings = [];
|
|
184
244
|
let query = `SELECT ${this._selectedColumns.join(", ")} FROM ${this._table._tableName}`;
|
|
185
245
|
if (this._joins.length > 0) {
|
|
@@ -207,7 +267,7 @@ var SelectQueryBuilder = class {
|
|
|
207
267
|
query += ` OFFSET ?`;
|
|
208
268
|
bindings.push(this._offset);
|
|
209
269
|
}
|
|
210
|
-
return
|
|
270
|
+
return db.select(query, bindings);
|
|
211
271
|
}
|
|
212
272
|
};
|
|
213
273
|
var TauriORM = class {
|
|
@@ -215,15 +275,23 @@ var TauriORM = class {
|
|
|
215
275
|
query = {};
|
|
216
276
|
_tables = null;
|
|
217
277
|
_relations = null;
|
|
278
|
+
_dbPromise;
|
|
279
|
+
constructor(dbUri) {
|
|
280
|
+
this._dbPromise = Database.load(dbUri);
|
|
281
|
+
}
|
|
282
|
+
async getDb() {
|
|
283
|
+
return this._dbPromise;
|
|
284
|
+
}
|
|
218
285
|
// Deprecated: use configure()
|
|
219
286
|
configureQuery(tables, relations2) {
|
|
220
287
|
this.configure(tables, relations2);
|
|
221
288
|
}
|
|
222
289
|
select(fields) {
|
|
223
|
-
return new SelectQueryBuilder(fields);
|
|
290
|
+
return new SelectQueryBuilder(this.getDb.bind(this), fields);
|
|
224
291
|
}
|
|
225
292
|
// --- Drizzle-style CRUD builders ---
|
|
226
293
|
insert(table) {
|
|
294
|
+
const self = this;
|
|
227
295
|
return new class InsertBuilder {
|
|
228
296
|
_table = table;
|
|
229
297
|
_rows = [];
|
|
@@ -232,13 +300,17 @@ var TauriORM = class {
|
|
|
232
300
|
return this;
|
|
233
301
|
}
|
|
234
302
|
async execute() {
|
|
235
|
-
const
|
|
303
|
+
const db = await self.getDb();
|
|
236
304
|
for (const data of this._rows) {
|
|
237
305
|
const finalData = { ...data };
|
|
238
306
|
const schema = this._table._schema;
|
|
239
307
|
for (const [key, col] of Object.entries(schema)) {
|
|
240
|
-
if (finalData[key] === void 0
|
|
241
|
-
|
|
308
|
+
if (finalData[key] === void 0) {
|
|
309
|
+
if (col.defaultFn) {
|
|
310
|
+
finalData[key] = col.defaultFn();
|
|
311
|
+
} else if (col.onUpdateFn) {
|
|
312
|
+
finalData[key] = col.onUpdateFn();
|
|
313
|
+
}
|
|
242
314
|
}
|
|
243
315
|
}
|
|
244
316
|
const keys = Object.keys(finalData);
|
|
@@ -247,12 +319,13 @@ var TauriORM = class {
|
|
|
247
319
|
const query = `INSERT INTO ${this._table._tableName} (${keys.join(
|
|
248
320
|
", "
|
|
249
321
|
)}) VALUES (${placeholders})`;
|
|
250
|
-
await
|
|
322
|
+
await db.execute(query, values);
|
|
251
323
|
}
|
|
252
324
|
}
|
|
253
325
|
}();
|
|
254
326
|
}
|
|
255
327
|
update(table) {
|
|
328
|
+
const self = this;
|
|
256
329
|
return new class UpdateBuilder {
|
|
257
330
|
_table = table;
|
|
258
331
|
_data = null;
|
|
@@ -268,10 +341,17 @@ var TauriORM = class {
|
|
|
268
341
|
async execute() {
|
|
269
342
|
if (!this._data)
|
|
270
343
|
throw new Error("Update requires set() before execute()");
|
|
271
|
-
const
|
|
272
|
-
const
|
|
344
|
+
const db = await self.getDb();
|
|
345
|
+
const schema = this._table._schema;
|
|
346
|
+
const dataToSet = { ...this._data };
|
|
347
|
+
for (const [key, col] of Object.entries(schema)) {
|
|
348
|
+
if (!(key in dataToSet) && col.onUpdateFn) {
|
|
349
|
+
dataToSet[key] = col.onUpdateFn();
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
const setKeys = Object.keys(dataToSet);
|
|
273
353
|
const setClause = setKeys.map((k) => `${k} = ?`).join(", ");
|
|
274
|
-
const bindings = Object.values(
|
|
354
|
+
const bindings = Object.values(dataToSet);
|
|
275
355
|
let query = `UPDATE ${this._table._tableName} SET ${setClause}`;
|
|
276
356
|
if (this._where) {
|
|
277
357
|
if (typeof this._where.toSQL === "function") {
|
|
@@ -286,11 +366,12 @@ var TauriORM = class {
|
|
|
286
366
|
}
|
|
287
367
|
}
|
|
288
368
|
}
|
|
289
|
-
await
|
|
369
|
+
await db.execute(query, bindings);
|
|
290
370
|
}
|
|
291
371
|
}();
|
|
292
372
|
}
|
|
293
373
|
delete(table) {
|
|
374
|
+
const self = this;
|
|
294
375
|
return new class DeleteBuilder {
|
|
295
376
|
_table = table;
|
|
296
377
|
_where = null;
|
|
@@ -299,7 +380,7 @@ var TauriORM = class {
|
|
|
299
380
|
return this;
|
|
300
381
|
}
|
|
301
382
|
async execute() {
|
|
302
|
-
const
|
|
383
|
+
const db = await self.getDb();
|
|
303
384
|
let query = `DELETE FROM ${this._table._tableName}`;
|
|
304
385
|
const bindings = [];
|
|
305
386
|
if (this._where) {
|
|
@@ -315,7 +396,7 @@ var TauriORM = class {
|
|
|
315
396
|
}
|
|
316
397
|
}
|
|
317
398
|
}
|
|
318
|
-
await
|
|
399
|
+
await db.execute(query, bindings);
|
|
319
400
|
}
|
|
320
401
|
}();
|
|
321
402
|
}
|
|
@@ -323,8 +404,8 @@ var TauriORM = class {
|
|
|
323
404
|
// legacy direct methods removed in favor of builder APIs
|
|
324
405
|
// legacy direct methods removed in favor of builder APIs
|
|
325
406
|
async run(query, bindings = []) {
|
|
326
|
-
const
|
|
327
|
-
await
|
|
407
|
+
const db = await this.getDb();
|
|
408
|
+
await db.execute(query, bindings);
|
|
328
409
|
}
|
|
329
410
|
// --- Migrations API ---
|
|
330
411
|
generateCreateTableSql(table) {
|
|
@@ -374,16 +455,16 @@ var TauriORM = class {
|
|
|
374
455
|
);
|
|
375
456
|
}
|
|
376
457
|
async hasMigration(name) {
|
|
377
|
-
const
|
|
378
|
-
const rows = await
|
|
458
|
+
const db = await this.getDb();
|
|
459
|
+
const rows = await db.select(
|
|
379
460
|
`SELECT name FROM _migrations WHERE name = ?`,
|
|
380
461
|
[name]
|
|
381
462
|
);
|
|
382
463
|
return Array.isArray(rows) && rows.length > 0;
|
|
383
464
|
}
|
|
384
465
|
async recordMigration(name) {
|
|
385
|
-
const
|
|
386
|
-
await
|
|
466
|
+
const db = await this.getDb();
|
|
467
|
+
await db.execute(
|
|
387
468
|
`INSERT INTO _migrations (name, applied_at) VALUES (?, ?)`,
|
|
388
469
|
[name, Date.now()]
|
|
389
470
|
);
|
|
@@ -405,7 +486,7 @@ var TauriORM = class {
|
|
|
405
486
|
configure(tables, relDefs) {
|
|
406
487
|
this._tables = tables;
|
|
407
488
|
this._relations = relDefs ?? {};
|
|
408
|
-
this.query = makeQueryAPI(tables, this._relations);
|
|
489
|
+
this.query = makeQueryAPI(tables, this._relations, this.getDb.bind(this));
|
|
409
490
|
return this;
|
|
410
491
|
}
|
|
411
492
|
// Convenience: migrate from configured tables
|
|
@@ -417,7 +498,7 @@ var TauriORM = class {
|
|
|
417
498
|
// --- Schema diff and CLI-like helpers ---
|
|
418
499
|
async diffSchema() {
|
|
419
500
|
if (!this._tables) throw new Error("No tables configured.");
|
|
420
|
-
const dbi = getDb();
|
|
501
|
+
const dbi = await this.getDb();
|
|
421
502
|
const configuredNames = Object.values(this._tables).map(
|
|
422
503
|
(t) => t._tableName
|
|
423
504
|
);
|
|
@@ -492,7 +573,7 @@ var TauriORM = class {
|
|
|
492
573
|
return this.pullSchema();
|
|
493
574
|
}
|
|
494
575
|
async studio() {
|
|
495
|
-
const dbi = getDb();
|
|
576
|
+
const dbi = await this.getDb();
|
|
496
577
|
return { driver: "sqlite", path: dbi.path };
|
|
497
578
|
}
|
|
498
579
|
// --- Schema detection / signature ---
|
|
@@ -502,7 +583,7 @@ var TauriORM = class {
|
|
|
502
583
|
);
|
|
503
584
|
}
|
|
504
585
|
async getSchemaMeta(key) {
|
|
505
|
-
const dbi = getDb();
|
|
586
|
+
const dbi = await this.getDb();
|
|
506
587
|
await this.ensureSchemaMeta();
|
|
507
588
|
const rows = await dbi.select(
|
|
508
589
|
`SELECT value FROM _schema_meta WHERE key = ?`,
|
|
@@ -511,7 +592,7 @@ var TauriORM = class {
|
|
|
511
592
|
return rows?.[0]?.value ?? null;
|
|
512
593
|
}
|
|
513
594
|
async setSchemaMeta(key, value) {
|
|
514
|
-
const dbi = getDb();
|
|
595
|
+
const dbi = await this.getDb();
|
|
515
596
|
await this.ensureSchemaMeta();
|
|
516
597
|
await dbi.execute(
|
|
517
598
|
`INSERT INTO _schema_meta(key, value) VALUES(?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value`,
|
|
@@ -560,7 +641,7 @@ var TauriORM = class {
|
|
|
560
641
|
// Pull current DB schema (minimal) for configured tables
|
|
561
642
|
async pullSchema() {
|
|
562
643
|
if (!this._tables) throw new Error("No tables configured.");
|
|
563
|
-
const dbi = getDb();
|
|
644
|
+
const dbi = await this.getDb();
|
|
564
645
|
const result = {};
|
|
565
646
|
for (const tbl of Object.values(this._tables)) {
|
|
566
647
|
const name = tbl._tableName;
|
|
@@ -579,7 +660,7 @@ var TauriORM = class {
|
|
|
579
660
|
return this.generateCreateTableSql(table);
|
|
580
661
|
}
|
|
581
662
|
async tableExists(name) {
|
|
582
|
-
const dbi = getDb();
|
|
663
|
+
const dbi = await this.getDb();
|
|
583
664
|
const rows = await dbi.select(
|
|
584
665
|
`SELECT name FROM sqlite_master WHERE type='table' AND name = ?`,
|
|
585
666
|
[name]
|
|
@@ -589,7 +670,7 @@ var TauriORM = class {
|
|
|
589
670
|
// Force push model to DB: add missing tables/columns, rebuild tables if incompatible
|
|
590
671
|
async forcePush(options) {
|
|
591
672
|
if (!this._tables) throw new Error("No tables configured.");
|
|
592
|
-
const dbi = getDb();
|
|
673
|
+
const dbi = await this.getDb();
|
|
593
674
|
const preserve = options?.preserveData !== false;
|
|
594
675
|
for (const tbl of Object.values(this._tables)) {
|
|
595
676
|
const tableName = tbl._tableName;
|
|
@@ -659,7 +740,6 @@ var TauriORM = class {
|
|
|
659
740
|
await this.setSchemaMeta("schema_signature", this.computeModelSignature());
|
|
660
741
|
}
|
|
661
742
|
};
|
|
662
|
-
var db2 = new TauriORM();
|
|
663
743
|
function relations(baseTable, builder) {
|
|
664
744
|
const ctx = {
|
|
665
745
|
one: (table, cfg) => ({ kind: "one", table, cfg }),
|
|
@@ -685,10 +765,29 @@ function guessChildFk(child, base, rel) {
|
|
|
685
765
|
];
|
|
686
766
|
return childCols.find((c) => guessNames.includes(c.name)) || childCols.find((c) => /.*_id$/i.test(c.name)) || null;
|
|
687
767
|
}
|
|
768
|
+
function guessOneRelationJoin(base, rel) {
|
|
769
|
+
const child = rel.table;
|
|
770
|
+
const basePk = getPrimaryKey(base);
|
|
771
|
+
const childCols = Object.values(child._schema);
|
|
772
|
+
if (rel.cfg?.fields && rel.cfg?.references && rel.cfg.fields[0] && rel.cfg.references[0]) {
|
|
773
|
+
const fk = rel.cfg.fields[0];
|
|
774
|
+
const ref = rel.cfg.references[0];
|
|
775
|
+
if (childCols.some((c) => c.name === fk.name)) {
|
|
776
|
+
return { lhsTable: child, lhsCol: fk, rhsTable: base, rhsCol: ref };
|
|
777
|
+
}
|
|
778
|
+
const baseCols = Object.values(base._schema);
|
|
779
|
+
if (baseCols.some((c) => c.name === fk.name)) {
|
|
780
|
+
return { lhsTable: base, lhsCol: fk, rhsTable: child, rhsCol: ref };
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
const childFk = guessChildFk(child, base, rel);
|
|
784
|
+
if (!childFk) return null;
|
|
785
|
+
return { lhsTable: child, lhsCol: childFk, rhsTable: base, rhsCol: basePk };
|
|
786
|
+
}
|
|
688
787
|
function isFlatWith(spec) {
|
|
689
788
|
return Object.values(spec).every((v) => typeof v === "boolean");
|
|
690
789
|
}
|
|
691
|
-
function makeQueryAPI(tables, relDefs) {
|
|
790
|
+
function makeQueryAPI(tables, relDefs, dbProvider) {
|
|
692
791
|
const api = {};
|
|
693
792
|
const tableKeyByName = {};
|
|
694
793
|
for (const [k, t] of Object.entries(tables)) tableKeyByName[t._tableName] = k;
|
|
@@ -697,7 +796,7 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
697
796
|
async findMany(opts) {
|
|
698
797
|
const base = tbl;
|
|
699
798
|
const withSpec = opts?.with ?? {};
|
|
700
|
-
const dbi =
|
|
799
|
+
const dbi = await dbProvider();
|
|
701
800
|
const rels = relDefs[tblKey] ?? {};
|
|
702
801
|
if (opts?.join && isFlatWith(withSpec)) {
|
|
703
802
|
const baseCols = Object.values(base._schema);
|
|
@@ -723,23 +822,43 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
723
822
|
const child = rel.table;
|
|
724
823
|
const childCols = Object.values(child._schema);
|
|
725
824
|
const childPk = childCols.find((c) => c.isPrimaryKey) || childCols.find((c) => c.name === "id") || null;
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
825
|
+
if (rel.kind === "one") {
|
|
826
|
+
const mapping = guessOneRelationJoin(base, rel);
|
|
827
|
+
if (!mapping) continue;
|
|
828
|
+
if (mapping.lhsTable._tableName === child._tableName) {
|
|
829
|
+
fkMap[relName] = { childFk: mapping.lhsCol, childPk };
|
|
830
|
+
joins.push(
|
|
831
|
+
`LEFT JOIN ${child._tableName} ON ${mapping.lhsTable._tableName}.${mapping.lhsCol.name} = ${mapping.rhsTable._tableName}.${mapping.rhsCol.name}`
|
|
832
|
+
);
|
|
833
|
+
} else {
|
|
834
|
+
fkMap[relName] = { childFk: mapping.rhsCol, childPk };
|
|
835
|
+
joins.push(
|
|
836
|
+
`LEFT JOIN ${child._tableName} ON ${mapping.lhsTable._tableName}.${mapping.lhsCol.name} = ${mapping.rhsTable._tableName}.${mapping.rhsCol.name}`
|
|
837
|
+
);
|
|
838
|
+
}
|
|
839
|
+
} else {
|
|
840
|
+
const childFk = guessChildFk(child, base, rel);
|
|
841
|
+
if (!childFk) continue;
|
|
842
|
+
fkMap[relName] = { childFk, childPk };
|
|
843
|
+
joins.push(
|
|
844
|
+
`LEFT JOIN ${child._tableName} ON ${child._tableName}.${childFk.name} = ${base._tableName}.${basePk.name}`
|
|
845
|
+
);
|
|
846
|
+
}
|
|
729
847
|
const selected = typeof enabled === "object" && enabled.columns?.length ? enabled.columns : childCols.map((c) => c.name);
|
|
730
848
|
relColsMap[relName] = selected;
|
|
731
849
|
for (const name of selected)
|
|
732
850
|
selectParts.push(
|
|
733
851
|
`${child._tableName}.${name} AS __rel_${relName}_${name}`
|
|
734
852
|
);
|
|
735
|
-
joins.push(
|
|
736
|
-
`LEFT JOIN ${child._tableName} ON ${child._tableName}.${childFk.name} = ${base._tableName}.${basePk.name}`
|
|
737
|
-
);
|
|
738
853
|
}
|
|
739
854
|
let sqlText = `SELECT ${selectParts.join(", ")} FROM ${base._tableName}${joins.length ? " " + joins.join(" ") : ""}`;
|
|
740
855
|
const bindings = [];
|
|
741
856
|
if (opts?.where) {
|
|
742
|
-
if (typeof opts.where
|
|
857
|
+
if (typeof opts.where === "function") {
|
|
858
|
+
const w = opts.where(base, { eq, ne, gt, gte, lt, lte, like }).toSQL();
|
|
859
|
+
sqlText += ` WHERE ${w.clause}`;
|
|
860
|
+
bindings.push(...w.bindings);
|
|
861
|
+
} else if (typeof opts.where.toSQL === "function") {
|
|
743
862
|
const w = opts.where.toSQL();
|
|
744
863
|
sqlText += ` WHERE ${w.clause}`;
|
|
745
864
|
bindings.push(...w.bindings);
|
|
@@ -751,8 +870,9 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
751
870
|
}
|
|
752
871
|
}
|
|
753
872
|
}
|
|
754
|
-
|
|
755
|
-
|
|
873
|
+
const orderByClauses = typeof opts?.orderBy === "function" ? opts.orderBy(base, { asc, desc }) : opts?.orderBy;
|
|
874
|
+
if (orderByClauses?.length)
|
|
875
|
+
sqlText += ` ORDER BY ${orderByClauses.join(", ")}`;
|
|
756
876
|
if (typeof opts?.limit === "number")
|
|
757
877
|
sqlText += ` LIMIT ${opts.limit}`;
|
|
758
878
|
if (typeof opts?.offset === "number")
|
|
@@ -819,7 +939,11 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
819
939
|
let baseSql = `SELECT ${baseSelected.join(", ")} FROM ${base._tableName}`;
|
|
820
940
|
const baseBindings = [];
|
|
821
941
|
if (opts?.where) {
|
|
822
|
-
if (typeof opts.where
|
|
942
|
+
if (typeof opts.where === "function") {
|
|
943
|
+
const w = opts.where(base, { eq, ne, gt, gte, lt, lte, like }).toSQL();
|
|
944
|
+
baseSql += ` WHERE ${w.clause}`;
|
|
945
|
+
baseBindings.push(...w.bindings);
|
|
946
|
+
} else if (typeof opts.where.toSQL === "function") {
|
|
823
947
|
const w = opts.where.toSQL();
|
|
824
948
|
baseSql += ` WHERE ${w.clause}`;
|
|
825
949
|
baseBindings.push(...w.bindings);
|
|
@@ -831,8 +955,9 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
831
955
|
}
|
|
832
956
|
}
|
|
833
957
|
}
|
|
834
|
-
|
|
835
|
-
|
|
958
|
+
const orderByClauses2 = typeof opts?.orderBy === "function" ? opts.orderBy(base, { asc, desc }) : opts?.orderBy;
|
|
959
|
+
if (orderByClauses2?.length)
|
|
960
|
+
baseSql += ` ORDER BY ${orderByClauses2.join(", ")}`;
|
|
836
961
|
if (typeof opts?.limit === "number") baseSql += ` LIMIT ${opts.limit}`;
|
|
837
962
|
if (typeof opts?.offset === "number")
|
|
838
963
|
baseSql += ` OFFSET ${opts.offset}`;
|
|
@@ -851,9 +976,9 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
851
976
|
const child = rel.table;
|
|
852
977
|
const childCols = Object.values(child._schema);
|
|
853
978
|
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
979
|
if (rel.kind === "many") {
|
|
980
|
+
const fkCol = guessChildFk(child, parentTable, rel);
|
|
981
|
+
if (!fkCol) continue;
|
|
857
982
|
const sql2 = `SELECT ${selectCols.join(", ")} FROM ${child._tableName} WHERE ${fkCol.name} IN (${parentIds.map(() => "?").join(", ")})`;
|
|
858
983
|
const rows = await dbi.select(sql2, parentIds);
|
|
859
984
|
const buckets = /* @__PURE__ */ new Map();
|
|
@@ -872,14 +997,32 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
872
997
|
await loadRelationsFor(children, child, enabled.with);
|
|
873
998
|
}
|
|
874
999
|
} else {
|
|
875
|
-
const
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
1000
|
+
const mapping = guessOneRelationJoin(parentTable, rel);
|
|
1001
|
+
if (!mapping) continue;
|
|
1002
|
+
if (mapping.lhsTable._tableName === child._tableName) {
|
|
1003
|
+
const sql2 = `SELECT ${selectCols.join(", ")} FROM ${child._tableName} WHERE ${mapping.lhsCol.name} IN (${parentIds.map(() => "?").join(", ")})`;
|
|
1004
|
+
const rows = await dbi.select(sql2, parentIds);
|
|
1005
|
+
const mapOne = /* @__PURE__ */ new Map();
|
|
1006
|
+
for (const r of rows) mapOne.set(r[mapping.lhsCol.name], r);
|
|
1007
|
+
for (const p of parents)
|
|
1008
|
+
p[relName] = mapOne.get(p[parentPk.name]) ?? null;
|
|
1009
|
+
} else {
|
|
1010
|
+
const parentFkName = mapping.lhsCol.name;
|
|
1011
|
+
const childPkName = mapping.rhsCol.name;
|
|
1012
|
+
const childIds = parents.map((p) => p[parentFkName]).filter((v2) => v2 !== void 0 && v2 !== null);
|
|
1013
|
+
if (childIds.length === 0) {
|
|
1014
|
+
for (const p of parents) p[relName] = null;
|
|
1015
|
+
} else {
|
|
1016
|
+
const sql2 = `SELECT ${selectCols.join(", ")} FROM ${child._tableName} WHERE ${childPkName} IN (${childIds.map(() => "?").join(", ")})`;
|
|
1017
|
+
const rows = await dbi.select(sql2, childIds);
|
|
1018
|
+
const mapOne = /* @__PURE__ */ new Map();
|
|
1019
|
+
for (const r of rows) mapOne.set(r[childPkName], r);
|
|
1020
|
+
for (const p of parents)
|
|
1021
|
+
p[relName] = mapOne.get(p[parentFkName]) ?? null;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
881
1024
|
if (enabled?.with) {
|
|
882
|
-
const children = parents.map((p) => p[relName]).filter(Boolean);
|
|
1025
|
+
const children = parents.map((p) => p[relName]).filter((x) => Boolean(x));
|
|
883
1026
|
if (children.length > 0)
|
|
884
1027
|
await loadRelationsFor(children, child, enabled.with);
|
|
885
1028
|
}
|
|
@@ -890,60 +1033,26 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
890
1033
|
await loadRelationsFor(result, base, withSpec);
|
|
891
1034
|
}
|
|
892
1035
|
return result;
|
|
1036
|
+
},
|
|
1037
|
+
async findFirst(opts) {
|
|
1038
|
+
const rows = await api[tblKey].findMany({ ...opts, limit: 1 });
|
|
1039
|
+
return rows?.[0] ?? null;
|
|
893
1040
|
}
|
|
894
1041
|
};
|
|
895
1042
|
}
|
|
896
1043
|
return api;
|
|
897
1044
|
}
|
|
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
1045
|
export {
|
|
935
1046
|
TauriORM,
|
|
936
1047
|
asc,
|
|
937
1048
|
blob,
|
|
938
1049
|
boolean,
|
|
939
|
-
db2 as db,
|
|
940
1050
|
defineTable,
|
|
941
1051
|
desc,
|
|
942
1052
|
eq,
|
|
943
|
-
getDb,
|
|
944
1053
|
gt,
|
|
945
1054
|
gte,
|
|
946
|
-
|
|
1055
|
+
increments,
|
|
947
1056
|
integer,
|
|
948
1057
|
like,
|
|
949
1058
|
lt,
|