@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.js
CHANGED
|
@@ -34,14 +34,12 @@ __export(index_exports, {
|
|
|
34
34
|
asc: () => asc,
|
|
35
35
|
blob: () => blob,
|
|
36
36
|
boolean: () => boolean,
|
|
37
|
-
db: () => db2,
|
|
38
37
|
defineTable: () => defineTable,
|
|
39
38
|
desc: () => desc,
|
|
40
39
|
eq: () => eq,
|
|
41
|
-
getDb: () => getDb,
|
|
42
40
|
gt: () => gt,
|
|
43
41
|
gte: () => gte,
|
|
44
|
-
|
|
42
|
+
increments: () => increments,
|
|
45
43
|
integer: () => integer,
|
|
46
44
|
like: () => like,
|
|
47
45
|
lt: () => lt,
|
|
@@ -57,20 +55,6 @@ __export(index_exports, {
|
|
|
57
55
|
});
|
|
58
56
|
module.exports = __toCommonJS(index_exports);
|
|
59
57
|
|
|
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
58
|
// src/schema-builder.ts
|
|
75
59
|
function sql(strings, ...values) {
|
|
76
60
|
const raw = strings.reduce(
|
|
@@ -99,6 +83,18 @@ function createColumn(params) {
|
|
|
99
83
|
col.defaultFn = fn;
|
|
100
84
|
return col;
|
|
101
85
|
};
|
|
86
|
+
col.$default = (fn) => {
|
|
87
|
+
col.defaultFn = fn;
|
|
88
|
+
return col;
|
|
89
|
+
};
|
|
90
|
+
col.$onUpdate = (fn) => {
|
|
91
|
+
col.onUpdateFn = fn;
|
|
92
|
+
return col;
|
|
93
|
+
};
|
|
94
|
+
col.$onUpdateFn = (fn) => {
|
|
95
|
+
col.onUpdateFn = fn;
|
|
96
|
+
return col;
|
|
97
|
+
};
|
|
102
98
|
col.references = (target, actions) => {
|
|
103
99
|
const t = target();
|
|
104
100
|
col.references = {
|
|
@@ -111,34 +107,43 @@ function createColumn(params) {
|
|
|
111
107
|
};
|
|
112
108
|
return col;
|
|
113
109
|
}
|
|
114
|
-
function text(
|
|
110
|
+
function text(nameOrConfig, maybeConfig) {
|
|
111
|
+
const name = typeof nameOrConfig === "string" ? nameOrConfig : "";
|
|
112
|
+
const config = typeof nameOrConfig === "string" ? maybeConfig : nameOrConfig;
|
|
115
113
|
const col = createColumn({
|
|
116
114
|
name,
|
|
117
115
|
type: "TEXT",
|
|
118
|
-
isPrimaryKey: config?.isPrimaryKey,
|
|
119
116
|
_dataType: ""
|
|
120
117
|
});
|
|
121
118
|
if (config?.enum) col.enumValues = config.enum;
|
|
119
|
+
if (config?.mode) col.mode = config.mode;
|
|
122
120
|
return col;
|
|
123
121
|
}
|
|
124
|
-
function integer(
|
|
122
|
+
function integer(nameOrConfig, maybeConfig) {
|
|
123
|
+
const name = typeof nameOrConfig === "string" ? nameOrConfig : "";
|
|
124
|
+
const config = typeof nameOrConfig === "string" ? maybeConfig : nameOrConfig;
|
|
125
125
|
let dt = 0;
|
|
126
126
|
if (config?.mode === "boolean") dt = false;
|
|
127
|
-
if (config?.mode === "timestamp"
|
|
127
|
+
if (config?.mode === "timestamp" || config?.mode === "timestamp_ms")
|
|
128
|
+
dt = /* @__PURE__ */ new Date();
|
|
128
129
|
const col = createColumn({
|
|
129
130
|
name,
|
|
130
131
|
type: "INTEGER",
|
|
131
|
-
isPrimaryKey: config?.isPrimaryKey,
|
|
132
|
-
autoIncrement: config?.autoIncrement,
|
|
133
132
|
mode: config?.mode ?? "number",
|
|
134
133
|
_dataType: dt
|
|
135
134
|
});
|
|
136
135
|
return col;
|
|
137
136
|
}
|
|
138
137
|
function real(name) {
|
|
139
|
-
return createColumn({
|
|
138
|
+
return createColumn({
|
|
139
|
+
name: name ?? "",
|
|
140
|
+
type: "REAL",
|
|
141
|
+
_dataType: 0
|
|
142
|
+
});
|
|
140
143
|
}
|
|
141
|
-
function blob(
|
|
144
|
+
function blob(nameOrConfig, maybeConfig) {
|
|
145
|
+
const name = typeof nameOrConfig === "string" ? nameOrConfig : "";
|
|
146
|
+
const config = typeof nameOrConfig === "string" ? maybeConfig : nameOrConfig;
|
|
142
147
|
let dt = new Uint8Array();
|
|
143
148
|
if (config?.mode === "bigint") dt = 0n;
|
|
144
149
|
if (config?.mode === "json") dt = void 0;
|
|
@@ -149,7 +154,9 @@ function blob(name, config) {
|
|
|
149
154
|
_dataType: dt
|
|
150
155
|
});
|
|
151
156
|
}
|
|
152
|
-
function numeric(
|
|
157
|
+
function numeric(nameOrConfig, maybeConfig) {
|
|
158
|
+
const name = typeof nameOrConfig === "string" ? nameOrConfig : "";
|
|
159
|
+
const config = typeof nameOrConfig === "string" ? maybeConfig : nameOrConfig;
|
|
153
160
|
let dt = "";
|
|
154
161
|
if (config?.mode === "number") dt = 0;
|
|
155
162
|
if (config?.mode === "bigint") dt = 0n;
|
|
@@ -160,22 +167,32 @@ function numeric(name, config) {
|
|
|
160
167
|
_dataType: dt
|
|
161
168
|
});
|
|
162
169
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
170
|
+
function boolean(name) {
|
|
171
|
+
return createColumn({
|
|
172
|
+
name: name ?? "",
|
|
173
|
+
type: "INTEGER",
|
|
174
|
+
_dataType: false,
|
|
175
|
+
mode: "boolean"
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
function timestamp(name) {
|
|
179
|
+
return createColumn({
|
|
180
|
+
name: name ?? "",
|
|
181
|
+
type: "INTEGER",
|
|
182
|
+
_dataType: /* @__PURE__ */ new Date(),
|
|
183
|
+
mode: "timestamp"
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
function increments(name) {
|
|
187
|
+
return integer(name ?? "").primaryKey({
|
|
188
|
+
autoIncrement: true
|
|
189
|
+
});
|
|
190
|
+
}
|
|
175
191
|
function defineTable(tableName, schema) {
|
|
176
192
|
const finalizedSchema = { ...schema };
|
|
177
193
|
for (const key of Object.keys(finalizedSchema)) {
|
|
178
194
|
const col = finalizedSchema[key];
|
|
195
|
+
if (!col.name || col.name === "") col.name = key;
|
|
179
196
|
col.tableName = tableName;
|
|
180
197
|
}
|
|
181
198
|
const table = {
|
|
@@ -184,7 +201,7 @@ function defineTable(tableName, schema) {
|
|
|
184
201
|
// The Drizzle-like type inference properties
|
|
185
202
|
$inferSelect: {},
|
|
186
203
|
$inferInsert: {}
|
|
187
|
-
//
|
|
204
|
+
// omit PK columns
|
|
188
205
|
};
|
|
189
206
|
for (const [key, col] of Object.entries(finalizedSchema)) {
|
|
190
207
|
table[key] = col;
|
|
@@ -192,6 +209,45 @@ function defineTable(tableName, schema) {
|
|
|
192
209
|
return table;
|
|
193
210
|
}
|
|
194
211
|
|
|
212
|
+
// src/orm.ts
|
|
213
|
+
var import_plugin_sql = __toESM(require("@tauri-apps/plugin-sql"));
|
|
214
|
+
|
|
215
|
+
// src/sql-helpers.ts
|
|
216
|
+
function isColumn(value) {
|
|
217
|
+
return typeof value === "object" && value !== null && "_dataType" in value;
|
|
218
|
+
}
|
|
219
|
+
function getQualifiedName(column) {
|
|
220
|
+
if (column.tableName) return `${column.tableName}.${column.name}`;
|
|
221
|
+
return column.name;
|
|
222
|
+
}
|
|
223
|
+
function comparison(operator, column, value) {
|
|
224
|
+
return {
|
|
225
|
+
toSQL: () => {
|
|
226
|
+
if (isColumn(value)) {
|
|
227
|
+
return {
|
|
228
|
+
clause: `${getQualifiedName(column)} ${operator} ${getQualifiedName(
|
|
229
|
+
value
|
|
230
|
+
)}`,
|
|
231
|
+
bindings: []
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
clause: `${getQualifiedName(column)} ${operator} ?`,
|
|
236
|
+
bindings: [value]
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
var eq = (column, value) => comparison("=", column, value);
|
|
242
|
+
var ne = (column, value) => comparison("!=", column, value);
|
|
243
|
+
var gt = (column, value) => comparison(">", column, value);
|
|
244
|
+
var gte = (column, value) => comparison(">=", column, value);
|
|
245
|
+
var lt = (column, value) => comparison("<", column, value);
|
|
246
|
+
var lte = (column, value) => comparison("<=", column, value);
|
|
247
|
+
var like = (column, value) => comparison("LIKE", column, value);
|
|
248
|
+
var asc = (column) => `${getQualifiedName(column)} ASC`;
|
|
249
|
+
var desc = (column) => `${getQualifiedName(column)} DESC`;
|
|
250
|
+
|
|
195
251
|
// src/orm.ts
|
|
196
252
|
var SelectQueryBuilder = class {
|
|
197
253
|
_table = null;
|
|
@@ -202,7 +258,9 @@ var SelectQueryBuilder = class {
|
|
|
202
258
|
_limit = null;
|
|
203
259
|
_offset = null;
|
|
204
260
|
_eager = {};
|
|
205
|
-
|
|
261
|
+
_dbProvider;
|
|
262
|
+
constructor(dbProvider, fields) {
|
|
263
|
+
this._dbProvider = dbProvider;
|
|
206
264
|
if (fields) {
|
|
207
265
|
this._selectedColumns = Object.values(fields).map((c) => c.name);
|
|
208
266
|
}
|
|
@@ -238,7 +296,7 @@ var SelectQueryBuilder = class {
|
|
|
238
296
|
if (!this._table) {
|
|
239
297
|
throw new Error("Cannot execute select query without a 'from' table.");
|
|
240
298
|
}
|
|
241
|
-
const
|
|
299
|
+
const db = await this._dbProvider();
|
|
242
300
|
const bindings = [];
|
|
243
301
|
let query = `SELECT ${this._selectedColumns.join(", ")} FROM ${this._table._tableName}`;
|
|
244
302
|
if (this._joins.length > 0) {
|
|
@@ -266,7 +324,7 @@ var SelectQueryBuilder = class {
|
|
|
266
324
|
query += ` OFFSET ?`;
|
|
267
325
|
bindings.push(this._offset);
|
|
268
326
|
}
|
|
269
|
-
return
|
|
327
|
+
return db.select(query, bindings);
|
|
270
328
|
}
|
|
271
329
|
};
|
|
272
330
|
var TauriORM = class {
|
|
@@ -274,15 +332,23 @@ var TauriORM = class {
|
|
|
274
332
|
query = {};
|
|
275
333
|
_tables = null;
|
|
276
334
|
_relations = null;
|
|
335
|
+
_dbPromise;
|
|
336
|
+
constructor(dbUri) {
|
|
337
|
+
this._dbPromise = import_plugin_sql.default.load(dbUri);
|
|
338
|
+
}
|
|
339
|
+
async getDb() {
|
|
340
|
+
return this._dbPromise;
|
|
341
|
+
}
|
|
277
342
|
// Deprecated: use configure()
|
|
278
343
|
configureQuery(tables, relations2) {
|
|
279
344
|
this.configure(tables, relations2);
|
|
280
345
|
}
|
|
281
346
|
select(fields) {
|
|
282
|
-
return new SelectQueryBuilder(fields);
|
|
347
|
+
return new SelectQueryBuilder(this.getDb.bind(this), fields);
|
|
283
348
|
}
|
|
284
349
|
// --- Drizzle-style CRUD builders ---
|
|
285
350
|
insert(table) {
|
|
351
|
+
const self = this;
|
|
286
352
|
return new class InsertBuilder {
|
|
287
353
|
_table = table;
|
|
288
354
|
_rows = [];
|
|
@@ -291,13 +357,17 @@ var TauriORM = class {
|
|
|
291
357
|
return this;
|
|
292
358
|
}
|
|
293
359
|
async execute() {
|
|
294
|
-
const
|
|
360
|
+
const db = await self.getDb();
|
|
295
361
|
for (const data of this._rows) {
|
|
296
362
|
const finalData = { ...data };
|
|
297
363
|
const schema = this._table._schema;
|
|
298
364
|
for (const [key, col] of Object.entries(schema)) {
|
|
299
|
-
if (finalData[key] === void 0
|
|
300
|
-
|
|
365
|
+
if (finalData[key] === void 0) {
|
|
366
|
+
if (col.defaultFn) {
|
|
367
|
+
finalData[key] = col.defaultFn();
|
|
368
|
+
} else if (col.onUpdateFn) {
|
|
369
|
+
finalData[key] = col.onUpdateFn();
|
|
370
|
+
}
|
|
301
371
|
}
|
|
302
372
|
}
|
|
303
373
|
const keys = Object.keys(finalData);
|
|
@@ -306,12 +376,13 @@ var TauriORM = class {
|
|
|
306
376
|
const query = `INSERT INTO ${this._table._tableName} (${keys.join(
|
|
307
377
|
", "
|
|
308
378
|
)}) VALUES (${placeholders})`;
|
|
309
|
-
await
|
|
379
|
+
await db.execute(query, values);
|
|
310
380
|
}
|
|
311
381
|
}
|
|
312
382
|
}();
|
|
313
383
|
}
|
|
314
384
|
update(table) {
|
|
385
|
+
const self = this;
|
|
315
386
|
return new class UpdateBuilder {
|
|
316
387
|
_table = table;
|
|
317
388
|
_data = null;
|
|
@@ -327,10 +398,17 @@ var TauriORM = class {
|
|
|
327
398
|
async execute() {
|
|
328
399
|
if (!this._data)
|
|
329
400
|
throw new Error("Update requires set() before execute()");
|
|
330
|
-
const
|
|
331
|
-
const
|
|
401
|
+
const db = await self.getDb();
|
|
402
|
+
const schema = this._table._schema;
|
|
403
|
+
const dataToSet = { ...this._data };
|
|
404
|
+
for (const [key, col] of Object.entries(schema)) {
|
|
405
|
+
if (!(key in dataToSet) && col.onUpdateFn) {
|
|
406
|
+
dataToSet[key] = col.onUpdateFn();
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
const setKeys = Object.keys(dataToSet);
|
|
332
410
|
const setClause = setKeys.map((k) => `${k} = ?`).join(", ");
|
|
333
|
-
const bindings = Object.values(
|
|
411
|
+
const bindings = Object.values(dataToSet);
|
|
334
412
|
let query = `UPDATE ${this._table._tableName} SET ${setClause}`;
|
|
335
413
|
if (this._where) {
|
|
336
414
|
if (typeof this._where.toSQL === "function") {
|
|
@@ -345,11 +423,12 @@ var TauriORM = class {
|
|
|
345
423
|
}
|
|
346
424
|
}
|
|
347
425
|
}
|
|
348
|
-
await
|
|
426
|
+
await db.execute(query, bindings);
|
|
349
427
|
}
|
|
350
428
|
}();
|
|
351
429
|
}
|
|
352
430
|
delete(table) {
|
|
431
|
+
const self = this;
|
|
353
432
|
return new class DeleteBuilder {
|
|
354
433
|
_table = table;
|
|
355
434
|
_where = null;
|
|
@@ -358,7 +437,7 @@ var TauriORM = class {
|
|
|
358
437
|
return this;
|
|
359
438
|
}
|
|
360
439
|
async execute() {
|
|
361
|
-
const
|
|
440
|
+
const db = await self.getDb();
|
|
362
441
|
let query = `DELETE FROM ${this._table._tableName}`;
|
|
363
442
|
const bindings = [];
|
|
364
443
|
if (this._where) {
|
|
@@ -374,7 +453,7 @@ var TauriORM = class {
|
|
|
374
453
|
}
|
|
375
454
|
}
|
|
376
455
|
}
|
|
377
|
-
await
|
|
456
|
+
await db.execute(query, bindings);
|
|
378
457
|
}
|
|
379
458
|
}();
|
|
380
459
|
}
|
|
@@ -382,8 +461,8 @@ var TauriORM = class {
|
|
|
382
461
|
// legacy direct methods removed in favor of builder APIs
|
|
383
462
|
// legacy direct methods removed in favor of builder APIs
|
|
384
463
|
async run(query, bindings = []) {
|
|
385
|
-
const
|
|
386
|
-
await
|
|
464
|
+
const db = await this.getDb();
|
|
465
|
+
await db.execute(query, bindings);
|
|
387
466
|
}
|
|
388
467
|
// --- Migrations API ---
|
|
389
468
|
generateCreateTableSql(table) {
|
|
@@ -433,16 +512,16 @@ var TauriORM = class {
|
|
|
433
512
|
);
|
|
434
513
|
}
|
|
435
514
|
async hasMigration(name) {
|
|
436
|
-
const
|
|
437
|
-
const rows = await
|
|
515
|
+
const db = await this.getDb();
|
|
516
|
+
const rows = await db.select(
|
|
438
517
|
`SELECT name FROM _migrations WHERE name = ?`,
|
|
439
518
|
[name]
|
|
440
519
|
);
|
|
441
520
|
return Array.isArray(rows) && rows.length > 0;
|
|
442
521
|
}
|
|
443
522
|
async recordMigration(name) {
|
|
444
|
-
const
|
|
445
|
-
await
|
|
523
|
+
const db = await this.getDb();
|
|
524
|
+
await db.execute(
|
|
446
525
|
`INSERT INTO _migrations (name, applied_at) VALUES (?, ?)`,
|
|
447
526
|
[name, Date.now()]
|
|
448
527
|
);
|
|
@@ -464,7 +543,7 @@ var TauriORM = class {
|
|
|
464
543
|
configure(tables, relDefs) {
|
|
465
544
|
this._tables = tables;
|
|
466
545
|
this._relations = relDefs ?? {};
|
|
467
|
-
this.query = makeQueryAPI(tables, this._relations);
|
|
546
|
+
this.query = makeQueryAPI(tables, this._relations, this.getDb.bind(this));
|
|
468
547
|
return this;
|
|
469
548
|
}
|
|
470
549
|
// Convenience: migrate from configured tables
|
|
@@ -476,7 +555,7 @@ var TauriORM = class {
|
|
|
476
555
|
// --- Schema diff and CLI-like helpers ---
|
|
477
556
|
async diffSchema() {
|
|
478
557
|
if (!this._tables) throw new Error("No tables configured.");
|
|
479
|
-
const dbi = getDb();
|
|
558
|
+
const dbi = await this.getDb();
|
|
480
559
|
const configuredNames = Object.values(this._tables).map(
|
|
481
560
|
(t) => t._tableName
|
|
482
561
|
);
|
|
@@ -551,7 +630,7 @@ var TauriORM = class {
|
|
|
551
630
|
return this.pullSchema();
|
|
552
631
|
}
|
|
553
632
|
async studio() {
|
|
554
|
-
const dbi = getDb();
|
|
633
|
+
const dbi = await this.getDb();
|
|
555
634
|
return { driver: "sqlite", path: dbi.path };
|
|
556
635
|
}
|
|
557
636
|
// --- Schema detection / signature ---
|
|
@@ -561,7 +640,7 @@ var TauriORM = class {
|
|
|
561
640
|
);
|
|
562
641
|
}
|
|
563
642
|
async getSchemaMeta(key) {
|
|
564
|
-
const dbi = getDb();
|
|
643
|
+
const dbi = await this.getDb();
|
|
565
644
|
await this.ensureSchemaMeta();
|
|
566
645
|
const rows = await dbi.select(
|
|
567
646
|
`SELECT value FROM _schema_meta WHERE key = ?`,
|
|
@@ -570,7 +649,7 @@ var TauriORM = class {
|
|
|
570
649
|
return rows?.[0]?.value ?? null;
|
|
571
650
|
}
|
|
572
651
|
async setSchemaMeta(key, value) {
|
|
573
|
-
const dbi = getDb();
|
|
652
|
+
const dbi = await this.getDb();
|
|
574
653
|
await this.ensureSchemaMeta();
|
|
575
654
|
await dbi.execute(
|
|
576
655
|
`INSERT INTO _schema_meta(key, value) VALUES(?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value`,
|
|
@@ -619,7 +698,7 @@ var TauriORM = class {
|
|
|
619
698
|
// Pull current DB schema (minimal) for configured tables
|
|
620
699
|
async pullSchema() {
|
|
621
700
|
if (!this._tables) throw new Error("No tables configured.");
|
|
622
|
-
const dbi = getDb();
|
|
701
|
+
const dbi = await this.getDb();
|
|
623
702
|
const result = {};
|
|
624
703
|
for (const tbl of Object.values(this._tables)) {
|
|
625
704
|
const name = tbl._tableName;
|
|
@@ -638,7 +717,7 @@ var TauriORM = class {
|
|
|
638
717
|
return this.generateCreateTableSql(table);
|
|
639
718
|
}
|
|
640
719
|
async tableExists(name) {
|
|
641
|
-
const dbi = getDb();
|
|
720
|
+
const dbi = await this.getDb();
|
|
642
721
|
const rows = await dbi.select(
|
|
643
722
|
`SELECT name FROM sqlite_master WHERE type='table' AND name = ?`,
|
|
644
723
|
[name]
|
|
@@ -648,7 +727,7 @@ var TauriORM = class {
|
|
|
648
727
|
// Force push model to DB: add missing tables/columns, rebuild tables if incompatible
|
|
649
728
|
async forcePush(options) {
|
|
650
729
|
if (!this._tables) throw new Error("No tables configured.");
|
|
651
|
-
const dbi = getDb();
|
|
730
|
+
const dbi = await this.getDb();
|
|
652
731
|
const preserve = options?.preserveData !== false;
|
|
653
732
|
for (const tbl of Object.values(this._tables)) {
|
|
654
733
|
const tableName = tbl._tableName;
|
|
@@ -718,7 +797,6 @@ var TauriORM = class {
|
|
|
718
797
|
await this.setSchemaMeta("schema_signature", this.computeModelSignature());
|
|
719
798
|
}
|
|
720
799
|
};
|
|
721
|
-
var db2 = new TauriORM();
|
|
722
800
|
function relations(baseTable, builder) {
|
|
723
801
|
const ctx = {
|
|
724
802
|
one: (table, cfg) => ({ kind: "one", table, cfg }),
|
|
@@ -744,10 +822,29 @@ function guessChildFk(child, base, rel) {
|
|
|
744
822
|
];
|
|
745
823
|
return childCols.find((c) => guessNames.includes(c.name)) || childCols.find((c) => /.*_id$/i.test(c.name)) || null;
|
|
746
824
|
}
|
|
825
|
+
function guessOneRelationJoin(base, rel) {
|
|
826
|
+
const child = rel.table;
|
|
827
|
+
const basePk = getPrimaryKey(base);
|
|
828
|
+
const childCols = Object.values(child._schema);
|
|
829
|
+
if (rel.cfg?.fields && rel.cfg?.references && rel.cfg.fields[0] && rel.cfg.references[0]) {
|
|
830
|
+
const fk = rel.cfg.fields[0];
|
|
831
|
+
const ref = rel.cfg.references[0];
|
|
832
|
+
if (childCols.some((c) => c.name === fk.name)) {
|
|
833
|
+
return { lhsTable: child, lhsCol: fk, rhsTable: base, rhsCol: ref };
|
|
834
|
+
}
|
|
835
|
+
const baseCols = Object.values(base._schema);
|
|
836
|
+
if (baseCols.some((c) => c.name === fk.name)) {
|
|
837
|
+
return { lhsTable: base, lhsCol: fk, rhsTable: child, rhsCol: ref };
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
const childFk = guessChildFk(child, base, rel);
|
|
841
|
+
if (!childFk) return null;
|
|
842
|
+
return { lhsTable: child, lhsCol: childFk, rhsTable: base, rhsCol: basePk };
|
|
843
|
+
}
|
|
747
844
|
function isFlatWith(spec) {
|
|
748
845
|
return Object.values(spec).every((v) => typeof v === "boolean");
|
|
749
846
|
}
|
|
750
|
-
function makeQueryAPI(tables, relDefs) {
|
|
847
|
+
function makeQueryAPI(tables, relDefs, dbProvider) {
|
|
751
848
|
const api = {};
|
|
752
849
|
const tableKeyByName = {};
|
|
753
850
|
for (const [k, t] of Object.entries(tables)) tableKeyByName[t._tableName] = k;
|
|
@@ -756,7 +853,7 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
756
853
|
async findMany(opts) {
|
|
757
854
|
const base = tbl;
|
|
758
855
|
const withSpec = opts?.with ?? {};
|
|
759
|
-
const dbi =
|
|
856
|
+
const dbi = await dbProvider();
|
|
760
857
|
const rels = relDefs[tblKey] ?? {};
|
|
761
858
|
if (opts?.join && isFlatWith(withSpec)) {
|
|
762
859
|
const baseCols = Object.values(base._schema);
|
|
@@ -782,23 +879,43 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
782
879
|
const child = rel.table;
|
|
783
880
|
const childCols = Object.values(child._schema);
|
|
784
881
|
const childPk = childCols.find((c) => c.isPrimaryKey) || childCols.find((c) => c.name === "id") || null;
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
882
|
+
if (rel.kind === "one") {
|
|
883
|
+
const mapping = guessOneRelationJoin(base, rel);
|
|
884
|
+
if (!mapping) continue;
|
|
885
|
+
if (mapping.lhsTable._tableName === child._tableName) {
|
|
886
|
+
fkMap[relName] = { childFk: mapping.lhsCol, childPk };
|
|
887
|
+
joins.push(
|
|
888
|
+
`LEFT JOIN ${child._tableName} ON ${mapping.lhsTable._tableName}.${mapping.lhsCol.name} = ${mapping.rhsTable._tableName}.${mapping.rhsCol.name}`
|
|
889
|
+
);
|
|
890
|
+
} else {
|
|
891
|
+
fkMap[relName] = { childFk: mapping.rhsCol, childPk };
|
|
892
|
+
joins.push(
|
|
893
|
+
`LEFT JOIN ${child._tableName} ON ${mapping.lhsTable._tableName}.${mapping.lhsCol.name} = ${mapping.rhsTable._tableName}.${mapping.rhsCol.name}`
|
|
894
|
+
);
|
|
895
|
+
}
|
|
896
|
+
} else {
|
|
897
|
+
const childFk = guessChildFk(child, base, rel);
|
|
898
|
+
if (!childFk) continue;
|
|
899
|
+
fkMap[relName] = { childFk, childPk };
|
|
900
|
+
joins.push(
|
|
901
|
+
`LEFT JOIN ${child._tableName} ON ${child._tableName}.${childFk.name} = ${base._tableName}.${basePk.name}`
|
|
902
|
+
);
|
|
903
|
+
}
|
|
788
904
|
const selected = typeof enabled === "object" && enabled.columns?.length ? enabled.columns : childCols.map((c) => c.name);
|
|
789
905
|
relColsMap[relName] = selected;
|
|
790
906
|
for (const name of selected)
|
|
791
907
|
selectParts.push(
|
|
792
908
|
`${child._tableName}.${name} AS __rel_${relName}_${name}`
|
|
793
909
|
);
|
|
794
|
-
joins.push(
|
|
795
|
-
`LEFT JOIN ${child._tableName} ON ${child._tableName}.${childFk.name} = ${base._tableName}.${basePk.name}`
|
|
796
|
-
);
|
|
797
910
|
}
|
|
798
911
|
let sqlText = `SELECT ${selectParts.join(", ")} FROM ${base._tableName}${joins.length ? " " + joins.join(" ") : ""}`;
|
|
799
912
|
const bindings = [];
|
|
800
913
|
if (opts?.where) {
|
|
801
|
-
if (typeof opts.where
|
|
914
|
+
if (typeof opts.where === "function") {
|
|
915
|
+
const w = opts.where(base, { eq, ne, gt, gte, lt, lte, like }).toSQL();
|
|
916
|
+
sqlText += ` WHERE ${w.clause}`;
|
|
917
|
+
bindings.push(...w.bindings);
|
|
918
|
+
} else if (typeof opts.where.toSQL === "function") {
|
|
802
919
|
const w = opts.where.toSQL();
|
|
803
920
|
sqlText += ` WHERE ${w.clause}`;
|
|
804
921
|
bindings.push(...w.bindings);
|
|
@@ -810,8 +927,9 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
810
927
|
}
|
|
811
928
|
}
|
|
812
929
|
}
|
|
813
|
-
|
|
814
|
-
|
|
930
|
+
const orderByClauses = typeof opts?.orderBy === "function" ? opts.orderBy(base, { asc, desc }) : opts?.orderBy;
|
|
931
|
+
if (orderByClauses?.length)
|
|
932
|
+
sqlText += ` ORDER BY ${orderByClauses.join(", ")}`;
|
|
815
933
|
if (typeof opts?.limit === "number")
|
|
816
934
|
sqlText += ` LIMIT ${opts.limit}`;
|
|
817
935
|
if (typeof opts?.offset === "number")
|
|
@@ -878,7 +996,11 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
878
996
|
let baseSql = `SELECT ${baseSelected.join(", ")} FROM ${base._tableName}`;
|
|
879
997
|
const baseBindings = [];
|
|
880
998
|
if (opts?.where) {
|
|
881
|
-
if (typeof opts.where
|
|
999
|
+
if (typeof opts.where === "function") {
|
|
1000
|
+
const w = opts.where(base, { eq, ne, gt, gte, lt, lte, like }).toSQL();
|
|
1001
|
+
baseSql += ` WHERE ${w.clause}`;
|
|
1002
|
+
baseBindings.push(...w.bindings);
|
|
1003
|
+
} else if (typeof opts.where.toSQL === "function") {
|
|
882
1004
|
const w = opts.where.toSQL();
|
|
883
1005
|
baseSql += ` WHERE ${w.clause}`;
|
|
884
1006
|
baseBindings.push(...w.bindings);
|
|
@@ -890,8 +1012,9 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
890
1012
|
}
|
|
891
1013
|
}
|
|
892
1014
|
}
|
|
893
|
-
|
|
894
|
-
|
|
1015
|
+
const orderByClauses2 = typeof opts?.orderBy === "function" ? opts.orderBy(base, { asc, desc }) : opts?.orderBy;
|
|
1016
|
+
if (orderByClauses2?.length)
|
|
1017
|
+
baseSql += ` ORDER BY ${orderByClauses2.join(", ")}`;
|
|
895
1018
|
if (typeof opts?.limit === "number") baseSql += ` LIMIT ${opts.limit}`;
|
|
896
1019
|
if (typeof opts?.offset === "number")
|
|
897
1020
|
baseSql += ` OFFSET ${opts.offset}`;
|
|
@@ -910,9 +1033,9 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
910
1033
|
const child = rel.table;
|
|
911
1034
|
const childCols = Object.values(child._schema);
|
|
912
1035
|
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
1036
|
if (rel.kind === "many") {
|
|
1037
|
+
const fkCol = guessChildFk(child, parentTable, rel);
|
|
1038
|
+
if (!fkCol) continue;
|
|
916
1039
|
const sql2 = `SELECT ${selectCols.join(", ")} FROM ${child._tableName} WHERE ${fkCol.name} IN (${parentIds.map(() => "?").join(", ")})`;
|
|
917
1040
|
const rows = await dbi.select(sql2, parentIds);
|
|
918
1041
|
const buckets = /* @__PURE__ */ new Map();
|
|
@@ -931,14 +1054,32 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
931
1054
|
await loadRelationsFor(children, child, enabled.with);
|
|
932
1055
|
}
|
|
933
1056
|
} else {
|
|
934
|
-
const
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
1057
|
+
const mapping = guessOneRelationJoin(parentTable, rel);
|
|
1058
|
+
if (!mapping) continue;
|
|
1059
|
+
if (mapping.lhsTable._tableName === child._tableName) {
|
|
1060
|
+
const sql2 = `SELECT ${selectCols.join(", ")} FROM ${child._tableName} WHERE ${mapping.lhsCol.name} IN (${parentIds.map(() => "?").join(", ")})`;
|
|
1061
|
+
const rows = await dbi.select(sql2, parentIds);
|
|
1062
|
+
const mapOne = /* @__PURE__ */ new Map();
|
|
1063
|
+
for (const r of rows) mapOne.set(r[mapping.lhsCol.name], r);
|
|
1064
|
+
for (const p of parents)
|
|
1065
|
+
p[relName] = mapOne.get(p[parentPk.name]) ?? null;
|
|
1066
|
+
} else {
|
|
1067
|
+
const parentFkName = mapping.lhsCol.name;
|
|
1068
|
+
const childPkName = mapping.rhsCol.name;
|
|
1069
|
+
const childIds = parents.map((p) => p[parentFkName]).filter((v2) => v2 !== void 0 && v2 !== null);
|
|
1070
|
+
if (childIds.length === 0) {
|
|
1071
|
+
for (const p of parents) p[relName] = null;
|
|
1072
|
+
} else {
|
|
1073
|
+
const sql2 = `SELECT ${selectCols.join(", ")} FROM ${child._tableName} WHERE ${childPkName} IN (${childIds.map(() => "?").join(", ")})`;
|
|
1074
|
+
const rows = await dbi.select(sql2, childIds);
|
|
1075
|
+
const mapOne = /* @__PURE__ */ new Map();
|
|
1076
|
+
for (const r of rows) mapOne.set(r[childPkName], r);
|
|
1077
|
+
for (const p of parents)
|
|
1078
|
+
p[relName] = mapOne.get(p[parentFkName]) ?? null;
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
940
1081
|
if (enabled?.with) {
|
|
941
|
-
const children = parents.map((p) => p[relName]).filter(Boolean);
|
|
1082
|
+
const children = parents.map((p) => p[relName]).filter((x) => Boolean(x));
|
|
942
1083
|
if (children.length > 0)
|
|
943
1084
|
await loadRelationsFor(children, child, enabled.with);
|
|
944
1085
|
}
|
|
@@ -949,61 +1090,27 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
949
1090
|
await loadRelationsFor(result, base, withSpec);
|
|
950
1091
|
}
|
|
951
1092
|
return result;
|
|
1093
|
+
},
|
|
1094
|
+
async findFirst(opts) {
|
|
1095
|
+
const rows = await api[tblKey].findMany({ ...opts, limit: 1 });
|
|
1096
|
+
return rows?.[0] ?? null;
|
|
952
1097
|
}
|
|
953
1098
|
};
|
|
954
1099
|
}
|
|
955
1100
|
return api;
|
|
956
1101
|
}
|
|
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
1102
|
// Annotate the CommonJS export names for ESM import in node:
|
|
994
1103
|
0 && (module.exports = {
|
|
995
1104
|
TauriORM,
|
|
996
1105
|
asc,
|
|
997
1106
|
blob,
|
|
998
1107
|
boolean,
|
|
999
|
-
db,
|
|
1000
1108
|
defineTable,
|
|
1001
1109
|
desc,
|
|
1002
1110
|
eq,
|
|
1003
|
-
getDb,
|
|
1004
1111
|
gt,
|
|
1005
1112
|
gte,
|
|
1006
|
-
|
|
1113
|
+
increments,
|
|
1007
1114
|
integer,
|
|
1008
1115
|
like,
|
|
1009
1116
|
lt,
|