@type32/tauri-sqlite-orm 0.1.2 → 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 +97 -27
- package/dist/index.d.ts +97 -27
- package/dist/index.js +474 -123
- package/dist/index.mjs +473 -120
- 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
|
|
@@ -414,8 +495,251 @@ var TauriORM = class {
|
|
|
414
495
|
throw new Error("No tables configured. Call db.configure({...}) first.");
|
|
415
496
|
await this.migrate(Object.values(this._tables), options);
|
|
416
497
|
}
|
|
498
|
+
// --- Schema diff and CLI-like helpers ---
|
|
499
|
+
async diffSchema() {
|
|
500
|
+
if (!this._tables) throw new Error("No tables configured.");
|
|
501
|
+
const dbi = await this.getDb();
|
|
502
|
+
const configuredNames = Object.values(this._tables).map(
|
|
503
|
+
(t) => t._tableName
|
|
504
|
+
);
|
|
505
|
+
const existing = await dbi.select(
|
|
506
|
+
`SELECT name FROM sqlite_master WHERE type='table'`
|
|
507
|
+
);
|
|
508
|
+
const existingNames = existing.map((r) => r.name);
|
|
509
|
+
const extraTables = existingNames.filter(
|
|
510
|
+
(n) => !configuredNames.includes(n)
|
|
511
|
+
);
|
|
512
|
+
const missingTables = configuredNames.filter(
|
|
513
|
+
(n) => !existingNames.includes(n)
|
|
514
|
+
);
|
|
515
|
+
const tables = {};
|
|
516
|
+
for (const tbl of Object.values(this._tables)) {
|
|
517
|
+
const tableName = tbl._tableName;
|
|
518
|
+
if (!existingNames.includes(tableName)) {
|
|
519
|
+
tables[tableName] = {
|
|
520
|
+
missingColumns: Object.keys(tbl._schema),
|
|
521
|
+
extraColumns: [],
|
|
522
|
+
changedColumns: []
|
|
523
|
+
};
|
|
524
|
+
continue;
|
|
525
|
+
}
|
|
526
|
+
const cols = await dbi.select(`PRAGMA table_info('${tableName}')`);
|
|
527
|
+
const colMap = new Map(cols.map((c) => [c.name, c]));
|
|
528
|
+
const modelCols = Object.values(
|
|
529
|
+
tbl._schema
|
|
530
|
+
);
|
|
531
|
+
const missingColumns = [];
|
|
532
|
+
const extraColumns = [];
|
|
533
|
+
const changedColumns = [];
|
|
534
|
+
const modelNamesSet = new Set(modelCols.map((c) => c.name));
|
|
535
|
+
for (const m of modelCols) {
|
|
536
|
+
const info = colMap.get(m.name);
|
|
537
|
+
if (!info) {
|
|
538
|
+
missingColumns.push(m.name);
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
const diffs = {};
|
|
542
|
+
if ((info.type || "").toUpperCase() !== m.type.toUpperCase())
|
|
543
|
+
diffs.type = true;
|
|
544
|
+
if (!!info.pk !== !!m.isPrimaryKey) diffs.pk = true;
|
|
545
|
+
if (!!info.notnull !== !!m.isNotNull) diffs.notNull = true;
|
|
546
|
+
const modelDv = m.defaultValue && typeof m.defaultValue === "object" && m.defaultValue.raw ? m.defaultValue.raw : m.defaultValue ?? null;
|
|
547
|
+
if ((info.dflt_value ?? null) !== modelDv)
|
|
548
|
+
diffs.default = true;
|
|
549
|
+
if (Object.keys(diffs).length)
|
|
550
|
+
changedColumns.push({ name: m.name, diffs });
|
|
551
|
+
}
|
|
552
|
+
for (const c of cols)
|
|
553
|
+
if (!modelNamesSet.has(c.name)) extraColumns.push(c.name);
|
|
554
|
+
tables[tableName] = { missingColumns, extraColumns, changedColumns };
|
|
555
|
+
}
|
|
556
|
+
return { extraTables, missingTables, tables };
|
|
557
|
+
}
|
|
558
|
+
async generate() {
|
|
559
|
+
if (!this._tables) throw new Error("No tables configured.");
|
|
560
|
+
return {
|
|
561
|
+
statements: Object.values(this._tables).map(
|
|
562
|
+
(t) => this.buildCreateTableSQL(t)
|
|
563
|
+
)
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
async migrateCli(opts) {
|
|
567
|
+
return this.migrateConfigured(opts);
|
|
568
|
+
}
|
|
569
|
+
async push(opts) {
|
|
570
|
+
return this.forcePush(opts);
|
|
571
|
+
}
|
|
572
|
+
async pull() {
|
|
573
|
+
return this.pullSchema();
|
|
574
|
+
}
|
|
575
|
+
async studio() {
|
|
576
|
+
const dbi = await this.getDb();
|
|
577
|
+
return { driver: "sqlite", path: dbi.path };
|
|
578
|
+
}
|
|
579
|
+
// --- Schema detection / signature ---
|
|
580
|
+
async ensureSchemaMeta() {
|
|
581
|
+
await this.run(
|
|
582
|
+
`CREATE TABLE IF NOT EXISTS _schema_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)`
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
async getSchemaMeta(key) {
|
|
586
|
+
const dbi = await this.getDb();
|
|
587
|
+
await this.ensureSchemaMeta();
|
|
588
|
+
const rows = await dbi.select(
|
|
589
|
+
`SELECT value FROM _schema_meta WHERE key = ?`,
|
|
590
|
+
[key]
|
|
591
|
+
);
|
|
592
|
+
return rows?.[0]?.value ?? null;
|
|
593
|
+
}
|
|
594
|
+
async setSchemaMeta(key, value) {
|
|
595
|
+
const dbi = await this.getDb();
|
|
596
|
+
await this.ensureSchemaMeta();
|
|
597
|
+
await dbi.execute(
|
|
598
|
+
`INSERT INTO _schema_meta(key, value) VALUES(?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value`,
|
|
599
|
+
[key, value]
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
normalizeColumn(col) {
|
|
603
|
+
return {
|
|
604
|
+
name: col.name,
|
|
605
|
+
type: col.type,
|
|
606
|
+
pk: !!col.isPrimaryKey,
|
|
607
|
+
ai: !!col.autoIncrement,
|
|
608
|
+
nn: !!col.isNotNull,
|
|
609
|
+
dv: col.defaultValue && typeof col.defaultValue === "object" && col.defaultValue.raw ? { raw: col.defaultValue.raw } : col.defaultValue ?? null
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
computeModelSignature() {
|
|
613
|
+
if (!this._tables) return "";
|
|
614
|
+
const entries = Object.entries(this._tables).map(([k, tbl]) => {
|
|
615
|
+
const cols = Object.values(
|
|
616
|
+
tbl._schema
|
|
617
|
+
).map((c) => this.normalizeColumn(c)).sort((a, b) => a.name.localeCompare(b.name));
|
|
618
|
+
return { table: tbl._tableName, columns: cols };
|
|
619
|
+
});
|
|
620
|
+
entries.sort((a, b) => a.table.localeCompare(b.table));
|
|
621
|
+
return JSON.stringify(entries);
|
|
622
|
+
}
|
|
623
|
+
async isSchemaDirty() {
|
|
624
|
+
const sig = this.computeModelSignature();
|
|
625
|
+
const stored = await this.getSchemaMeta("schema_signature");
|
|
626
|
+
return { dirty: sig !== stored, current: sig, stored };
|
|
627
|
+
}
|
|
628
|
+
async migrateIfDirty(options) {
|
|
629
|
+
const status = await this.isSchemaDirty();
|
|
630
|
+
if (!this._tables) throw new Error("No tables configured.");
|
|
631
|
+
if (status.dirty) {
|
|
632
|
+
await this.migrate(Object.values(this._tables), options);
|
|
633
|
+
await this.setSchemaMeta(
|
|
634
|
+
"schema_signature",
|
|
635
|
+
this.computeModelSignature()
|
|
636
|
+
);
|
|
637
|
+
return true;
|
|
638
|
+
}
|
|
639
|
+
return false;
|
|
640
|
+
}
|
|
641
|
+
// Pull current DB schema (minimal) for configured tables
|
|
642
|
+
async pullSchema() {
|
|
643
|
+
if (!this._tables) throw new Error("No tables configured.");
|
|
644
|
+
const dbi = await this.getDb();
|
|
645
|
+
const result = {};
|
|
646
|
+
for (const tbl of Object.values(this._tables)) {
|
|
647
|
+
const name = tbl._tableName;
|
|
648
|
+
const cols = await dbi.select(`PRAGMA table_info('${name}')`);
|
|
649
|
+
result[name] = cols.map((c) => ({
|
|
650
|
+
name: c.name,
|
|
651
|
+
type: c.type,
|
|
652
|
+
notnull: !!c.notnull,
|
|
653
|
+
pk: !!c.pk,
|
|
654
|
+
dflt_value: c.dflt_value ?? null
|
|
655
|
+
}));
|
|
656
|
+
}
|
|
657
|
+
return result;
|
|
658
|
+
}
|
|
659
|
+
buildCreateTableSQL(table) {
|
|
660
|
+
return this.generateCreateTableSql(table);
|
|
661
|
+
}
|
|
662
|
+
async tableExists(name) {
|
|
663
|
+
const dbi = await this.getDb();
|
|
664
|
+
const rows = await dbi.select(
|
|
665
|
+
`SELECT name FROM sqlite_master WHERE type='table' AND name = ?`,
|
|
666
|
+
[name]
|
|
667
|
+
);
|
|
668
|
+
return rows.length > 0;
|
|
669
|
+
}
|
|
670
|
+
// Force push model to DB: add missing tables/columns, rebuild tables if incompatible
|
|
671
|
+
async forcePush(options) {
|
|
672
|
+
if (!this._tables) throw new Error("No tables configured.");
|
|
673
|
+
const dbi = await this.getDb();
|
|
674
|
+
const preserve = options?.preserveData !== false;
|
|
675
|
+
for (const tbl of Object.values(this._tables)) {
|
|
676
|
+
const tableName = tbl._tableName;
|
|
677
|
+
const exists = await this.tableExists(tableName);
|
|
678
|
+
if (!exists) {
|
|
679
|
+
await this.run(this.buildCreateTableSQL(tbl));
|
|
680
|
+
continue;
|
|
681
|
+
}
|
|
682
|
+
const existingCols = await dbi.select(
|
|
683
|
+
`PRAGMA table_info('${tableName}')`
|
|
684
|
+
);
|
|
685
|
+
const existingMap = new Map(existingCols.map((c) => [c.name, c]));
|
|
686
|
+
const modelCols = Object.values(
|
|
687
|
+
tbl._schema
|
|
688
|
+
);
|
|
689
|
+
const missing = [];
|
|
690
|
+
let requiresRebuild = false;
|
|
691
|
+
for (const m of modelCols) {
|
|
692
|
+
const info = existingMap.get(m.name);
|
|
693
|
+
if (!info) {
|
|
694
|
+
missing.push(m);
|
|
695
|
+
continue;
|
|
696
|
+
}
|
|
697
|
+
const typeDiff = (info.type || "").toUpperCase() !== m.type.toUpperCase();
|
|
698
|
+
const pkDiff = !!info.pk !== !!m.isPrimaryKey;
|
|
699
|
+
const nnDiff = !!info.notnull !== !!m.isNotNull;
|
|
700
|
+
const modelDv = m.defaultValue && typeof m.defaultValue === "object" && m.defaultValue.raw ? m.defaultValue.raw : m.defaultValue ?? null;
|
|
701
|
+
const defDiff = (info.dflt_value ?? null) !== modelDv;
|
|
702
|
+
if (typeDiff || pkDiff || nnDiff && !modelDv || defDiff) {
|
|
703
|
+
requiresRebuild = true;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
if (requiresRebuild) {
|
|
707
|
+
const tmp = `_new_${tableName}`;
|
|
708
|
+
await this.run(this.buildCreateTableSQL(tbl));
|
|
709
|
+
await this.run(
|
|
710
|
+
this.buildCreateTableSQL({ ...tbl, _tableName: tmp })
|
|
711
|
+
);
|
|
712
|
+
const existingNames = existingCols.map((c) => c.name);
|
|
713
|
+
const modelNames = modelCols.map((c) => c.name);
|
|
714
|
+
const shared = existingNames.filter((n) => modelNames.includes(n));
|
|
715
|
+
if (preserve && shared.length > 0) {
|
|
716
|
+
await this.run(
|
|
717
|
+
`INSERT INTO ${tmp} (${shared.join(", ")}) SELECT ${shared.join(
|
|
718
|
+
", "
|
|
719
|
+
)} FROM ${tableName}`
|
|
720
|
+
);
|
|
721
|
+
}
|
|
722
|
+
await this.run(`DROP TABLE ${tableName}`);
|
|
723
|
+
await this.run(`ALTER TABLE ${tmp} RENAME TO ${tableName}`);
|
|
724
|
+
} else {
|
|
725
|
+
for (const m of missing) {
|
|
726
|
+
let clause = `${m.name} ${m.type}`;
|
|
727
|
+
if (m.isNotNull) clause += " NOT NULL";
|
|
728
|
+
if (m.defaultValue !== void 0) {
|
|
729
|
+
const dv = m.defaultValue;
|
|
730
|
+
if (dv && typeof dv === "object" && "raw" in dv)
|
|
731
|
+
clause += ` DEFAULT ${dv.raw}`;
|
|
732
|
+
else if (typeof dv === "string")
|
|
733
|
+
clause += ` DEFAULT '${dv.replace(/'/g, "''")}'`;
|
|
734
|
+
else clause += ` DEFAULT ${dv}`;
|
|
735
|
+
}
|
|
736
|
+
await this.run(`ALTER TABLE ${tableName} ADD COLUMN ${clause}`);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
await this.setSchemaMeta("schema_signature", this.computeModelSignature());
|
|
741
|
+
}
|
|
417
742
|
};
|
|
418
|
-
var db2 = new TauriORM();
|
|
419
743
|
function relations(baseTable, builder) {
|
|
420
744
|
const ctx = {
|
|
421
745
|
one: (table, cfg) => ({ kind: "one", table, cfg }),
|
|
@@ -441,10 +765,29 @@ function guessChildFk(child, base, rel) {
|
|
|
441
765
|
];
|
|
442
766
|
return childCols.find((c) => guessNames.includes(c.name)) || childCols.find((c) => /.*_id$/i.test(c.name)) || null;
|
|
443
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
|
+
}
|
|
444
787
|
function isFlatWith(spec) {
|
|
445
788
|
return Object.values(spec).every((v) => typeof v === "boolean");
|
|
446
789
|
}
|
|
447
|
-
function makeQueryAPI(tables, relDefs) {
|
|
790
|
+
function makeQueryAPI(tables, relDefs, dbProvider) {
|
|
448
791
|
const api = {};
|
|
449
792
|
const tableKeyByName = {};
|
|
450
793
|
for (const [k, t] of Object.entries(tables)) tableKeyByName[t._tableName] = k;
|
|
@@ -453,7 +796,7 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
453
796
|
async findMany(opts) {
|
|
454
797
|
const base = tbl;
|
|
455
798
|
const withSpec = opts?.with ?? {};
|
|
456
|
-
const dbi =
|
|
799
|
+
const dbi = await dbProvider();
|
|
457
800
|
const rels = relDefs[tblKey] ?? {};
|
|
458
801
|
if (opts?.join && isFlatWith(withSpec)) {
|
|
459
802
|
const baseCols = Object.values(base._schema);
|
|
@@ -479,23 +822,43 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
479
822
|
const child = rel.table;
|
|
480
823
|
const childCols = Object.values(child._schema);
|
|
481
824
|
const childPk = childCols.find((c) => c.isPrimaryKey) || childCols.find((c) => c.name === "id") || null;
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
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
|
+
}
|
|
485
847
|
const selected = typeof enabled === "object" && enabled.columns?.length ? enabled.columns : childCols.map((c) => c.name);
|
|
486
848
|
relColsMap[relName] = selected;
|
|
487
849
|
for (const name of selected)
|
|
488
850
|
selectParts.push(
|
|
489
851
|
`${child._tableName}.${name} AS __rel_${relName}_${name}`
|
|
490
852
|
);
|
|
491
|
-
joins.push(
|
|
492
|
-
`LEFT JOIN ${child._tableName} ON ${child._tableName}.${childFk.name} = ${base._tableName}.${basePk.name}`
|
|
493
|
-
);
|
|
494
853
|
}
|
|
495
854
|
let sqlText = `SELECT ${selectParts.join(", ")} FROM ${base._tableName}${joins.length ? " " + joins.join(" ") : ""}`;
|
|
496
855
|
const bindings = [];
|
|
497
856
|
if (opts?.where) {
|
|
498
|
-
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") {
|
|
499
862
|
const w = opts.where.toSQL();
|
|
500
863
|
sqlText += ` WHERE ${w.clause}`;
|
|
501
864
|
bindings.push(...w.bindings);
|
|
@@ -507,8 +870,9 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
507
870
|
}
|
|
508
871
|
}
|
|
509
872
|
}
|
|
510
|
-
|
|
511
|
-
|
|
873
|
+
const orderByClauses = typeof opts?.orderBy === "function" ? opts.orderBy(base, { asc, desc }) : opts?.orderBy;
|
|
874
|
+
if (orderByClauses?.length)
|
|
875
|
+
sqlText += ` ORDER BY ${orderByClauses.join(", ")}`;
|
|
512
876
|
if (typeof opts?.limit === "number")
|
|
513
877
|
sqlText += ` LIMIT ${opts.limit}`;
|
|
514
878
|
if (typeof opts?.offset === "number")
|
|
@@ -575,7 +939,11 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
575
939
|
let baseSql = `SELECT ${baseSelected.join(", ")} FROM ${base._tableName}`;
|
|
576
940
|
const baseBindings = [];
|
|
577
941
|
if (opts?.where) {
|
|
578
|
-
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") {
|
|
579
947
|
const w = opts.where.toSQL();
|
|
580
948
|
baseSql += ` WHERE ${w.clause}`;
|
|
581
949
|
baseBindings.push(...w.bindings);
|
|
@@ -587,8 +955,9 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
587
955
|
}
|
|
588
956
|
}
|
|
589
957
|
}
|
|
590
|
-
|
|
591
|
-
|
|
958
|
+
const orderByClauses2 = typeof opts?.orderBy === "function" ? opts.orderBy(base, { asc, desc }) : opts?.orderBy;
|
|
959
|
+
if (orderByClauses2?.length)
|
|
960
|
+
baseSql += ` ORDER BY ${orderByClauses2.join(", ")}`;
|
|
592
961
|
if (typeof opts?.limit === "number") baseSql += ` LIMIT ${opts.limit}`;
|
|
593
962
|
if (typeof opts?.offset === "number")
|
|
594
963
|
baseSql += ` OFFSET ${opts.offset}`;
|
|
@@ -607,9 +976,9 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
607
976
|
const child = rel.table;
|
|
608
977
|
const childCols = Object.values(child._schema);
|
|
609
978
|
const selectCols = enabled?.columns && enabled.columns.length > 0 ? enabled.columns : childCols.map((c) => c.name);
|
|
610
|
-
const fkCol = guessChildFk(child, parentTable, rel);
|
|
611
|
-
if (!fkCol) continue;
|
|
612
979
|
if (rel.kind === "many") {
|
|
980
|
+
const fkCol = guessChildFk(child, parentTable, rel);
|
|
981
|
+
if (!fkCol) continue;
|
|
613
982
|
const sql2 = `SELECT ${selectCols.join(", ")} FROM ${child._tableName} WHERE ${fkCol.name} IN (${parentIds.map(() => "?").join(", ")})`;
|
|
614
983
|
const rows = await dbi.select(sql2, parentIds);
|
|
615
984
|
const buckets = /* @__PURE__ */ new Map();
|
|
@@ -628,14 +997,32 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
628
997
|
await loadRelationsFor(children, child, enabled.with);
|
|
629
998
|
}
|
|
630
999
|
} else {
|
|
631
|
-
const
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
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
|
+
}
|
|
637
1024
|
if (enabled?.with) {
|
|
638
|
-
const children = parents.map((p) => p[relName]).filter(Boolean);
|
|
1025
|
+
const children = parents.map((p) => p[relName]).filter((x) => Boolean(x));
|
|
639
1026
|
if (children.length > 0)
|
|
640
1027
|
await loadRelationsFor(children, child, enabled.with);
|
|
641
1028
|
}
|
|
@@ -646,60 +1033,26 @@ function makeQueryAPI(tables, relDefs) {
|
|
|
646
1033
|
await loadRelationsFor(result, base, withSpec);
|
|
647
1034
|
}
|
|
648
1035
|
return result;
|
|
1036
|
+
},
|
|
1037
|
+
async findFirst(opts) {
|
|
1038
|
+
const rows = await api[tblKey].findMany({ ...opts, limit: 1 });
|
|
1039
|
+
return rows?.[0] ?? null;
|
|
649
1040
|
}
|
|
650
1041
|
};
|
|
651
1042
|
}
|
|
652
1043
|
return api;
|
|
653
1044
|
}
|
|
654
|
-
|
|
655
|
-
// src/sql-helpers.ts
|
|
656
|
-
function isColumn(value) {
|
|
657
|
-
return typeof value === "object" && value !== null && "_dataType" in value;
|
|
658
|
-
}
|
|
659
|
-
function getQualifiedName(column) {
|
|
660
|
-
if (column.tableName) return `${column.tableName}.${column.name}`;
|
|
661
|
-
return column.name;
|
|
662
|
-
}
|
|
663
|
-
function comparison(operator, column, value) {
|
|
664
|
-
return {
|
|
665
|
-
toSQL: () => {
|
|
666
|
-
if (isColumn(value)) {
|
|
667
|
-
return {
|
|
668
|
-
clause: `${getQualifiedName(column)} ${operator} ${getQualifiedName(
|
|
669
|
-
value
|
|
670
|
-
)}`,
|
|
671
|
-
bindings: []
|
|
672
|
-
};
|
|
673
|
-
}
|
|
674
|
-
return {
|
|
675
|
-
clause: `${getQualifiedName(column)} ${operator} ?`,
|
|
676
|
-
bindings: [value]
|
|
677
|
-
};
|
|
678
|
-
}
|
|
679
|
-
};
|
|
680
|
-
}
|
|
681
|
-
var eq = (column, value) => comparison("=", column, value);
|
|
682
|
-
var ne = (column, value) => comparison("!=", column, value);
|
|
683
|
-
var gt = (column, value) => comparison(">", column, value);
|
|
684
|
-
var gte = (column, value) => comparison(">=", column, value);
|
|
685
|
-
var lt = (column, value) => comparison("<", column, value);
|
|
686
|
-
var lte = (column, value) => comparison("<=", column, value);
|
|
687
|
-
var like = (column, value) => comparison("LIKE", column, value);
|
|
688
|
-
var asc = (column) => `${column.name} ASC`;
|
|
689
|
-
var desc = (column) => `${column.name} DESC`;
|
|
690
1045
|
export {
|
|
691
1046
|
TauriORM,
|
|
692
1047
|
asc,
|
|
693
1048
|
blob,
|
|
694
1049
|
boolean,
|
|
695
|
-
db2 as db,
|
|
696
1050
|
defineTable,
|
|
697
1051
|
desc,
|
|
698
1052
|
eq,
|
|
699
|
-
getDb,
|
|
700
1053
|
gt,
|
|
701
1054
|
gte,
|
|
702
|
-
|
|
1055
|
+
increments,
|
|
703
1056
|
integer,
|
|
704
1057
|
like,
|
|
705
1058
|
lt,
|