flint-orm 0.2.0 → 0.4.0
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/API.md +208 -211
- package/README.md +341 -0
- package/dist/index.js +288 -255
- package/package.json +46 -11
- package/src/cli.ts +103 -48
package/dist/index.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
// src/flint.ts
|
|
3
|
-
import { Database } from "bun:sqlite";
|
|
4
|
-
|
|
5
2
|
// src/query/conditions.ts
|
|
6
3
|
function isColumnDef(value) {
|
|
7
4
|
return value !== null && typeof value === "object" && "__internal" in value;
|
|
@@ -142,9 +139,6 @@ class FlintQueryError extends FlintError {
|
|
|
142
139
|
}
|
|
143
140
|
|
|
144
141
|
// src/query/builder.ts
|
|
145
|
-
function bind(params) {
|
|
146
|
-
return params;
|
|
147
|
-
}
|
|
148
142
|
function getCol(tbl, key) {
|
|
149
143
|
const col = tbl[key];
|
|
150
144
|
if (!col)
|
|
@@ -152,7 +146,7 @@ function getCol(tbl, key) {
|
|
|
152
146
|
return col;
|
|
153
147
|
}
|
|
154
148
|
function columnEntries(tbl) {
|
|
155
|
-
return Object.entries(tbl).filter(([k]) => k !== "_");
|
|
149
|
+
return Object.entries(tbl).filter(([k]) => k !== "_" && k !== "__indexes");
|
|
156
150
|
}
|
|
157
151
|
function decodeRow(raw, tbl) {
|
|
158
152
|
const out = {};
|
|
@@ -231,19 +225,19 @@ function resolveColumns(table, selectedColumns, prefix) {
|
|
|
231
225
|
}
|
|
232
226
|
|
|
233
227
|
class SelectFromBuilder {
|
|
234
|
-
#
|
|
228
|
+
#executor;
|
|
235
229
|
#conditions;
|
|
236
|
-
constructor(
|
|
237
|
-
this.#
|
|
230
|
+
constructor(executor, conditions = []) {
|
|
231
|
+
this.#executor = executor;
|
|
238
232
|
this.#conditions = conditions;
|
|
239
233
|
}
|
|
240
234
|
from(table) {
|
|
241
|
-
return new SelectBuilder(this.#
|
|
235
|
+
return new SelectBuilder(this.#executor, table._.name, table, this.#conditions);
|
|
242
236
|
}
|
|
243
237
|
}
|
|
244
238
|
|
|
245
239
|
class SelectBuilder {
|
|
246
|
-
#
|
|
240
|
+
#executor;
|
|
247
241
|
#tableName;
|
|
248
242
|
#table;
|
|
249
243
|
#conditions;
|
|
@@ -252,8 +246,8 @@ class SelectBuilder {
|
|
|
252
246
|
#limitValue;
|
|
253
247
|
#offsetValue;
|
|
254
248
|
#distinct;
|
|
255
|
-
constructor(
|
|
256
|
-
this.#
|
|
249
|
+
constructor(executor, tableName, table, conditions = [], selectedColumns = null, orderByClauses = [], limitValue = null, offsetValue = null, distinct = false) {
|
|
250
|
+
this.#executor = executor;
|
|
257
251
|
this.#tableName = tableName;
|
|
258
252
|
this.#table = table;
|
|
259
253
|
this.#conditions = conditions;
|
|
@@ -264,26 +258,26 @@ class SelectBuilder {
|
|
|
264
258
|
this.#distinct = distinct;
|
|
265
259
|
}
|
|
266
260
|
where(condition) {
|
|
267
|
-
return new SelectBuilder(this.#
|
|
261
|
+
return new SelectBuilder(this.#executor, this.#tableName, this.#table, [...this.#conditions, condition], this.#selectedColumns, this.#orderByClauses, this.#limitValue, this.#offsetValue, this.#distinct);
|
|
268
262
|
}
|
|
269
263
|
columns(keys) {
|
|
270
|
-
return new NarrowedSelectBuilder(this.#
|
|
264
|
+
return new NarrowedSelectBuilder(this.#executor, this.#tableName, this.#table, this.#conditions, keys, this.#orderByClauses, this.#limitValue, this.#offsetValue, this.#distinct);
|
|
271
265
|
}
|
|
272
266
|
single() {
|
|
273
|
-
return new SingleSelectBuilder(this.#
|
|
267
|
+
return new SingleSelectBuilder(this.#executor, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, this.#orderByClauses, this.#offsetValue, this.#distinct);
|
|
274
268
|
}
|
|
275
269
|
distinct() {
|
|
276
|
-
return new SelectBuilder(this.#
|
|
270
|
+
return new SelectBuilder(this.#executor, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, this.#orderByClauses, this.#limitValue, this.#offsetValue, true);
|
|
277
271
|
}
|
|
278
272
|
orderBy(key, direction = "asc") {
|
|
279
273
|
const column = getCol(this.#table, key);
|
|
280
|
-
return new SelectBuilder(this.#
|
|
274
|
+
return new SelectBuilder(this.#executor, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, [...this.#orderByClauses, { column, direction }], this.#limitValue, this.#offsetValue, this.#distinct);
|
|
281
275
|
}
|
|
282
276
|
limit(n) {
|
|
283
|
-
return new SelectBuilder(this.#
|
|
277
|
+
return new SelectBuilder(this.#executor, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, this.#orderByClauses, n, this.#offsetValue, this.#distinct);
|
|
284
278
|
}
|
|
285
279
|
offset(n) {
|
|
286
|
-
return new SelectBuilder(this.#
|
|
280
|
+
return new SelectBuilder(this.#executor, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, this.#orderByClauses, this.#limitValue, n, this.#distinct);
|
|
287
281
|
}
|
|
288
282
|
toSQL() {
|
|
289
283
|
validateColumnOwnership(this.#conditions, [this.#table], `SELECT from "${this.#tableName}"`);
|
|
@@ -304,14 +298,15 @@ class SelectBuilder {
|
|
|
304
298
|
sql += ` OFFSET ${this.#offsetValue}`;
|
|
305
299
|
return { sql, params };
|
|
306
300
|
}
|
|
307
|
-
execute() {
|
|
301
|
+
async execute() {
|
|
308
302
|
const { sql, params } = this.toSQL();
|
|
309
303
|
try {
|
|
310
|
-
const rows = this.#
|
|
304
|
+
const rows = await this.#executor.all(sql, params);
|
|
305
|
+
const records = rows;
|
|
311
306
|
if (this.#selectedColumns) {
|
|
312
|
-
return
|
|
307
|
+
return records.map((r) => decodeSelectedRow(r, this.#table, this.#selectedColumns));
|
|
313
308
|
}
|
|
314
|
-
return
|
|
309
|
+
return records.map((r) => decodeRow(r, this.#table));
|
|
315
310
|
} catch (e) {
|
|
316
311
|
throw new FlintQueryError(`Failed to execute query: ${sql}`, e);
|
|
317
312
|
}
|
|
@@ -319,7 +314,7 @@ class SelectBuilder {
|
|
|
319
314
|
}
|
|
320
315
|
|
|
321
316
|
class NarrowedSelectBuilder {
|
|
322
|
-
#
|
|
317
|
+
#executor;
|
|
323
318
|
#tableName;
|
|
324
319
|
#table;
|
|
325
320
|
#conditions;
|
|
@@ -328,8 +323,8 @@ class NarrowedSelectBuilder {
|
|
|
328
323
|
#limitValue;
|
|
329
324
|
#offsetValue;
|
|
330
325
|
#distinct;
|
|
331
|
-
constructor(
|
|
332
|
-
this.#
|
|
326
|
+
constructor(executor, tableName, table, conditions, selectedColumns, orderByClauses, limitValue, offsetValue, distinct) {
|
|
327
|
+
this.#executor = executor;
|
|
333
328
|
this.#tableName = tableName;
|
|
334
329
|
this.#table = table;
|
|
335
330
|
this.#conditions = conditions;
|
|
@@ -340,23 +335,23 @@ class NarrowedSelectBuilder {
|
|
|
340
335
|
this.#distinct = distinct;
|
|
341
336
|
}
|
|
342
337
|
where(condition) {
|
|
343
|
-
return new NarrowedSelectBuilder(this.#
|
|
338
|
+
return new NarrowedSelectBuilder(this.#executor, this.#tableName, this.#table, [...this.#conditions, condition], this.#selectedColumns, this.#orderByClauses, this.#limitValue, this.#offsetValue, this.#distinct);
|
|
344
339
|
}
|
|
345
340
|
distinct() {
|
|
346
|
-
return new NarrowedSelectBuilder(this.#
|
|
341
|
+
return new NarrowedSelectBuilder(this.#executor, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, this.#orderByClauses, this.#limitValue, this.#offsetValue, true);
|
|
347
342
|
}
|
|
348
343
|
single() {
|
|
349
|
-
return new NarrowedSingleSelectBuilder(this.#
|
|
344
|
+
return new NarrowedSingleSelectBuilder(this.#executor, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, this.#orderByClauses, this.#offsetValue, this.#distinct);
|
|
350
345
|
}
|
|
351
346
|
orderBy(key, direction = "asc") {
|
|
352
347
|
const column = getCol(this.#table, key);
|
|
353
|
-
return new NarrowedSelectBuilder(this.#
|
|
348
|
+
return new NarrowedSelectBuilder(this.#executor, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, [...this.#orderByClauses, { column, direction }], this.#limitValue, this.#offsetValue, this.#distinct);
|
|
354
349
|
}
|
|
355
350
|
limit(n) {
|
|
356
|
-
return new NarrowedSelectBuilder(this.#
|
|
351
|
+
return new NarrowedSelectBuilder(this.#executor, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, this.#orderByClauses, n, this.#offsetValue, this.#distinct);
|
|
357
352
|
}
|
|
358
353
|
offset(n) {
|
|
359
|
-
return new NarrowedSelectBuilder(this.#
|
|
354
|
+
return new NarrowedSelectBuilder(this.#executor, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, this.#orderByClauses, this.#limitValue, n, this.#distinct);
|
|
360
355
|
}
|
|
361
356
|
toSQL() {
|
|
362
357
|
validateColumnOwnership(this.#conditions, [this.#table], `SELECT from "${this.#tableName}"`);
|
|
@@ -377,10 +372,10 @@ class NarrowedSelectBuilder {
|
|
|
377
372
|
sql += ` OFFSET ${this.#offsetValue}`;
|
|
378
373
|
return { sql, params };
|
|
379
374
|
}
|
|
380
|
-
execute() {
|
|
375
|
+
async execute() {
|
|
381
376
|
const { sql, params } = this.toSQL();
|
|
382
377
|
try {
|
|
383
|
-
const rows = this.#
|
|
378
|
+
const rows = await this.#executor.all(sql, params);
|
|
384
379
|
return rows.map((r) => decodeSelectedRow(r, this.#table, this.#selectedColumns));
|
|
385
380
|
} catch (e) {
|
|
386
381
|
throw new FlintQueryError(`Failed to execute query: ${sql}`, e);
|
|
@@ -389,7 +384,7 @@ class NarrowedSelectBuilder {
|
|
|
389
384
|
}
|
|
390
385
|
|
|
391
386
|
class SingleSelectBuilder {
|
|
392
|
-
#
|
|
387
|
+
#executor;
|
|
393
388
|
#tableName;
|
|
394
389
|
#table;
|
|
395
390
|
#conditions;
|
|
@@ -397,8 +392,8 @@ class SingleSelectBuilder {
|
|
|
397
392
|
#orderByClauses;
|
|
398
393
|
#offsetValue;
|
|
399
394
|
#distinct;
|
|
400
|
-
constructor(
|
|
401
|
-
this.#
|
|
395
|
+
constructor(executor, tableName, table, conditions, selectedColumns = null, orderByClauses = [], offsetValue = null, distinct = false) {
|
|
396
|
+
this.#executor = executor;
|
|
402
397
|
this.#tableName = tableName;
|
|
403
398
|
this.#table = table;
|
|
404
399
|
this.#conditions = conditions;
|
|
@@ -408,14 +403,14 @@ class SingleSelectBuilder {
|
|
|
408
403
|
this.#distinct = distinct;
|
|
409
404
|
}
|
|
410
405
|
where(condition) {
|
|
411
|
-
return new SingleSelectBuilder(this.#
|
|
406
|
+
return new SingleSelectBuilder(this.#executor, this.#tableName, this.#table, [...this.#conditions, condition], this.#selectedColumns, this.#orderByClauses, this.#offsetValue, this.#distinct);
|
|
412
407
|
}
|
|
413
408
|
orderBy(key, direction = "asc") {
|
|
414
409
|
const column = getCol(this.#table, key);
|
|
415
|
-
return new SingleSelectBuilder(this.#
|
|
410
|
+
return new SingleSelectBuilder(this.#executor, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, [...this.#orderByClauses, { column, direction }], this.#offsetValue, this.#distinct);
|
|
416
411
|
}
|
|
417
412
|
offset(n) {
|
|
418
|
-
return new SingleSelectBuilder(this.#
|
|
413
|
+
return new SingleSelectBuilder(this.#executor, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, this.#orderByClauses, n, this.#distinct);
|
|
419
414
|
}
|
|
420
415
|
toSQL() {
|
|
421
416
|
validateColumnOwnership(this.#conditions, [this.#table], `SELECT from "${this.#tableName}"`);
|
|
@@ -435,16 +430,17 @@ class SingleSelectBuilder {
|
|
|
435
430
|
sql += ` OFFSET ${this.#offsetValue}`;
|
|
436
431
|
return { sql, params };
|
|
437
432
|
}
|
|
438
|
-
execute() {
|
|
433
|
+
async execute() {
|
|
439
434
|
const { sql, params } = this.toSQL();
|
|
440
435
|
try {
|
|
441
|
-
const row = this.#
|
|
436
|
+
const row = await this.#executor.get(sql, params);
|
|
442
437
|
if (!row)
|
|
443
438
|
return null;
|
|
439
|
+
const record = row;
|
|
444
440
|
if (this.#selectedColumns) {
|
|
445
|
-
return decodeSelectedRow(
|
|
441
|
+
return decodeSelectedRow(record, this.#table, this.#selectedColumns);
|
|
446
442
|
}
|
|
447
|
-
return decodeRow(
|
|
443
|
+
return decodeRow(record, this.#table);
|
|
448
444
|
} catch (e) {
|
|
449
445
|
throw new FlintQueryError(`Failed to execute query: ${sql}`, e);
|
|
450
446
|
}
|
|
@@ -452,7 +448,7 @@ class SingleSelectBuilder {
|
|
|
452
448
|
}
|
|
453
449
|
|
|
454
450
|
class NarrowedSingleSelectBuilder {
|
|
455
|
-
#
|
|
451
|
+
#executor;
|
|
456
452
|
#tableName;
|
|
457
453
|
#table;
|
|
458
454
|
#conditions;
|
|
@@ -460,8 +456,8 @@ class NarrowedSingleSelectBuilder {
|
|
|
460
456
|
#orderByClauses;
|
|
461
457
|
#offsetValue;
|
|
462
458
|
#distinct;
|
|
463
|
-
constructor(
|
|
464
|
-
this.#
|
|
459
|
+
constructor(executor, tableName, table, conditions, selectedColumns, orderByClauses, offsetValue, distinct) {
|
|
460
|
+
this.#executor = executor;
|
|
465
461
|
this.#tableName = tableName;
|
|
466
462
|
this.#table = table;
|
|
467
463
|
this.#conditions = conditions;
|
|
@@ -471,14 +467,14 @@ class NarrowedSingleSelectBuilder {
|
|
|
471
467
|
this.#distinct = distinct;
|
|
472
468
|
}
|
|
473
469
|
where(condition) {
|
|
474
|
-
return new NarrowedSingleSelectBuilder(this.#
|
|
470
|
+
return new NarrowedSingleSelectBuilder(this.#executor, this.#tableName, this.#table, [...this.#conditions, condition], this.#selectedColumns, this.#orderByClauses, this.#offsetValue, this.#distinct);
|
|
475
471
|
}
|
|
476
472
|
orderBy(key, direction = "asc") {
|
|
477
473
|
const column = getCol(this.#table, key);
|
|
478
|
-
return new NarrowedSingleSelectBuilder(this.#
|
|
474
|
+
return new NarrowedSingleSelectBuilder(this.#executor, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, [...this.#orderByClauses, { column, direction }], this.#offsetValue, this.#distinct);
|
|
479
475
|
}
|
|
480
476
|
offset(n) {
|
|
481
|
-
return new NarrowedSingleSelectBuilder(this.#
|
|
477
|
+
return new NarrowedSingleSelectBuilder(this.#executor, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, this.#orderByClauses, n, this.#distinct);
|
|
482
478
|
}
|
|
483
479
|
toSQL() {
|
|
484
480
|
validateColumnOwnership(this.#conditions, [this.#table], `SELECT from "${this.#tableName}"`);
|
|
@@ -498,10 +494,10 @@ class NarrowedSingleSelectBuilder {
|
|
|
498
494
|
sql += ` OFFSET ${this.#offsetValue}`;
|
|
499
495
|
return { sql, params };
|
|
500
496
|
}
|
|
501
|
-
execute() {
|
|
497
|
+
async execute() {
|
|
502
498
|
const { sql, params } = this.toSQL();
|
|
503
499
|
try {
|
|
504
|
-
const row = this.#
|
|
500
|
+
const row = await this.#executor.get(sql, params);
|
|
505
501
|
if (!row)
|
|
506
502
|
return null;
|
|
507
503
|
return decodeSelectedRow(row, this.#table, this.#selectedColumns);
|
|
@@ -512,12 +508,12 @@ class NarrowedSingleSelectBuilder {
|
|
|
512
508
|
}
|
|
513
509
|
|
|
514
510
|
class JoinStage1 {
|
|
515
|
-
#
|
|
511
|
+
#executor;
|
|
516
512
|
#parent;
|
|
517
513
|
#parentName;
|
|
518
514
|
#joinType;
|
|
519
|
-
constructor(
|
|
520
|
-
this.#
|
|
515
|
+
constructor(executor, parent, parentName, joinType) {
|
|
516
|
+
this.#executor = executor;
|
|
521
517
|
this.#parent = parent;
|
|
522
518
|
this.#parentName = parentName;
|
|
523
519
|
this.#joinType = joinType;
|
|
@@ -525,12 +521,12 @@ class JoinStage1 {
|
|
|
525
521
|
on(child, condition) {
|
|
526
522
|
const childName = child._.name;
|
|
527
523
|
const resolvedCondition = condition ?? resolveForeignKeyCondition(this.#parent, this.#parentName, child, childName);
|
|
528
|
-
return new JoinBuilderImpl(this.#
|
|
524
|
+
return new JoinBuilderImpl(this.#executor, this.#parent, this.#parentName, [{ table: child, name: childName, condition: resolvedCondition }], this.#joinType);
|
|
529
525
|
}
|
|
530
526
|
}
|
|
531
527
|
|
|
532
528
|
class JoinBuilderImpl {
|
|
533
|
-
#
|
|
529
|
+
#executor;
|
|
534
530
|
#parent;
|
|
535
531
|
#parentName;
|
|
536
532
|
#joins;
|
|
@@ -540,8 +536,8 @@ class JoinBuilderImpl {
|
|
|
540
536
|
#orderByClauses;
|
|
541
537
|
#limitValue;
|
|
542
538
|
#offsetValue;
|
|
543
|
-
constructor(
|
|
544
|
-
this.#
|
|
539
|
+
constructor(executor, parent, parentName, joins, joinType, conditions = [], selectedColumns = null, orderByClauses = [], limitValue = null, offsetValue = null) {
|
|
540
|
+
this.#executor = executor;
|
|
545
541
|
this.#parent = parent;
|
|
546
542
|
this.#parentName = parentName;
|
|
547
543
|
this.#joins = joins;
|
|
@@ -555,26 +551,26 @@ class JoinBuilderImpl {
|
|
|
555
551
|
on(child, condition) {
|
|
556
552
|
const childName = child._.name;
|
|
557
553
|
const resolvedCondition = condition ?? resolveForeignKeyCondition(this.#parent, this.#parentName, child, childName);
|
|
558
|
-
return new JoinBuilderImpl(this.#
|
|
554
|
+
return new JoinBuilderImpl(this.#executor, this.#parent, this.#parentName, [...this.#joins, { table: child, name: childName, condition: resolvedCondition }], this.#joinType, this.#conditions, this.#selectedColumns);
|
|
559
555
|
}
|
|
560
556
|
where(condition) {
|
|
561
|
-
return new JoinBuilderImpl(this.#
|
|
557
|
+
return new JoinBuilderImpl(this.#executor, this.#parent, this.#parentName, this.#joins, this.#joinType, [...this.#conditions, condition], this.#selectedColumns);
|
|
562
558
|
}
|
|
563
559
|
columns(keys) {
|
|
564
|
-
return new JoinBuilderImpl(this.#
|
|
560
|
+
return new JoinBuilderImpl(this.#executor, this.#parent, this.#parentName, this.#joins, this.#joinType, this.#conditions, keys, this.#orderByClauses, this.#limitValue, this.#offsetValue);
|
|
565
561
|
}
|
|
566
562
|
orderBy(key, direction = "asc") {
|
|
567
563
|
const column = getCol(this.#parent, key);
|
|
568
|
-
return new JoinBuilderImpl(this.#
|
|
564
|
+
return new JoinBuilderImpl(this.#executor, this.#parent, this.#parentName, this.#joins, this.#joinType, this.#conditions, this.#selectedColumns, [...this.#orderByClauses, { column, direction }], this.#limitValue, this.#offsetValue);
|
|
569
565
|
}
|
|
570
566
|
limit(n) {
|
|
571
|
-
return new JoinBuilderImpl(this.#
|
|
567
|
+
return new JoinBuilderImpl(this.#executor, this.#parent, this.#parentName, this.#joins, this.#joinType, this.#conditions, this.#selectedColumns, this.#orderByClauses, n, this.#offsetValue);
|
|
572
568
|
}
|
|
573
569
|
offset(n) {
|
|
574
|
-
return new JoinBuilderImpl(this.#
|
|
570
|
+
return new JoinBuilderImpl(this.#executor, this.#parent, this.#parentName, this.#joins, this.#joinType, this.#conditions, this.#selectedColumns, this.#orderByClauses, this.#limitValue, n);
|
|
575
571
|
}
|
|
576
572
|
single() {
|
|
577
|
-
return new SingleJoinBuilderImpl(this.#
|
|
573
|
+
return new SingleJoinBuilderImpl(this.#executor, this.#parent, this.#parentName, this.#joins, this.#joinType, this.#conditions, this.#selectedColumns, this.#orderByClauses, this.#offsetValue);
|
|
578
574
|
}
|
|
579
575
|
toSQL() {
|
|
580
576
|
const allowedTables = [this.#parent, ...this.#joins.map((j) => j.table)];
|
|
@@ -609,69 +605,72 @@ class JoinBuilderImpl {
|
|
|
609
605
|
sql += ` OFFSET ${this.#offsetValue}`;
|
|
610
606
|
return { sql, params: [...joinParams, ...whereParams] };
|
|
611
607
|
}
|
|
612
|
-
execute() {
|
|
608
|
+
async execute() {
|
|
613
609
|
const { sql, params } = this.toSQL();
|
|
614
610
|
try {
|
|
615
|
-
const rows = this.#
|
|
616
|
-
|
|
617
|
-
const pkKey = findPKKey(this.#parent);
|
|
618
|
-
const pkColName = getCol(this.#parent, pkKey).name;
|
|
619
|
-
const childEntryMaps = [];
|
|
620
|
-
for (const j of this.#joins) {
|
|
621
|
-
childEntryMaps.push({
|
|
622
|
-
name: j.name,
|
|
623
|
-
entries: columnEntries(j.table),
|
|
624
|
-
table: j.table
|
|
625
|
-
});
|
|
626
|
-
}
|
|
627
|
-
const grouped = new Map;
|
|
628
|
-
for (const row of rows) {
|
|
629
|
-
const pk = row[pkColName];
|
|
630
|
-
if (!grouped.has(pk)) {
|
|
631
|
-
const parentRow = {};
|
|
632
|
-
for (const [key, col] of parentEntries) {
|
|
633
|
-
parentRow[key] = row[col.name];
|
|
634
|
-
}
|
|
635
|
-
grouped.set(pk, {
|
|
636
|
-
parent: parentRow,
|
|
637
|
-
children: childEntryMaps.map(() => [])
|
|
638
|
-
});
|
|
639
|
-
}
|
|
640
|
-
const group = grouped.get(pk);
|
|
641
|
-
childEntryMaps.forEach((childMap, i) => {
|
|
642
|
-
const childRow = {};
|
|
643
|
-
let hasNonNullChild = false;
|
|
644
|
-
for (const [key, col] of childMap.entries) {
|
|
645
|
-
const val = row[`${childMap.name}_${col.name}`];
|
|
646
|
-
childRow[key] = val;
|
|
647
|
-
if (val != null)
|
|
648
|
-
hasNonNullChild = true;
|
|
649
|
-
}
|
|
650
|
-
if (this.#joinType === "left" && !hasNonNullChild)
|
|
651
|
-
return;
|
|
652
|
-
group.children[i].push(childRow);
|
|
653
|
-
});
|
|
654
|
-
}
|
|
655
|
-
const result = [];
|
|
656
|
-
for (const { parent, children } of grouped.values()) {
|
|
657
|
-
const decodedParent = this.#selectedColumns ? decodeSelectedRow(parent, this.#parent, this.#selectedColumns) : decodeRow(parent, this.#parent);
|
|
658
|
-
const nested = { ...decodedParent };
|
|
659
|
-
childEntryMaps.forEach((childMap, i) => {
|
|
660
|
-
nested[childMap.name] = children[i].map((c) => decodeRow(c, childMap.table));
|
|
661
|
-
});
|
|
662
|
-
result.push(nested);
|
|
663
|
-
}
|
|
664
|
-
return result;
|
|
611
|
+
const rows = await this.#executor.all(sql, params);
|
|
612
|
+
return this.#decodeJoinRows(rows);
|
|
665
613
|
} catch (e) {
|
|
666
614
|
if (e instanceof FlintQueryError)
|
|
667
615
|
throw e;
|
|
668
616
|
throw new FlintQueryError(`Failed to execute query: ${sql}`, e);
|
|
669
617
|
}
|
|
670
618
|
}
|
|
619
|
+
#decodeJoinRows(rows) {
|
|
620
|
+
const parentEntries = columnEntries(this.#parent);
|
|
621
|
+
const pkKey = findPKKey(this.#parent);
|
|
622
|
+
const pkColName = getCol(this.#parent, pkKey).name;
|
|
623
|
+
const childEntryMaps = [];
|
|
624
|
+
for (const j of this.#joins) {
|
|
625
|
+
childEntryMaps.push({
|
|
626
|
+
name: j.name,
|
|
627
|
+
entries: columnEntries(j.table),
|
|
628
|
+
table: j.table
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
const grouped = new Map;
|
|
632
|
+
for (const row of rows) {
|
|
633
|
+
const pk = row[pkColName];
|
|
634
|
+
if (!grouped.has(pk)) {
|
|
635
|
+
const parentRow = {};
|
|
636
|
+
for (const [key, col] of parentEntries) {
|
|
637
|
+
parentRow[key] = row[col.name];
|
|
638
|
+
}
|
|
639
|
+
grouped.set(pk, {
|
|
640
|
+
parent: parentRow,
|
|
641
|
+
children: childEntryMaps.map(() => [])
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
const group = grouped.get(pk);
|
|
645
|
+
childEntryMaps.forEach((childMap, i) => {
|
|
646
|
+
const childRow = {};
|
|
647
|
+
let hasNonNullChild = false;
|
|
648
|
+
for (const [key, col] of childMap.entries) {
|
|
649
|
+
const val = row[`${childMap.name}_${col.name}`];
|
|
650
|
+
childRow[key] = val;
|
|
651
|
+
if (val != null)
|
|
652
|
+
hasNonNullChild = true;
|
|
653
|
+
}
|
|
654
|
+
if (this.#joinType === "left" && !hasNonNullChild)
|
|
655
|
+
return;
|
|
656
|
+
group.children[i].push(childRow);
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
const result = [];
|
|
660
|
+
for (const { parent, children } of grouped.values()) {
|
|
661
|
+
const decodedParent = this.#selectedColumns ? decodeSelectedRow(parent, this.#parent, this.#selectedColumns) : decodeRow(parent, this.#parent);
|
|
662
|
+
const nested = { ...decodedParent };
|
|
663
|
+
childEntryMaps.forEach((childMap, i) => {
|
|
664
|
+
nested[childMap.name] = children[i].map((c) => decodeRow(c, childMap.table));
|
|
665
|
+
});
|
|
666
|
+
result.push(nested);
|
|
667
|
+
}
|
|
668
|
+
return result;
|
|
669
|
+
}
|
|
671
670
|
}
|
|
672
671
|
|
|
673
672
|
class SingleJoinBuilderImpl {
|
|
674
|
-
#
|
|
673
|
+
#executor;
|
|
675
674
|
#parent;
|
|
676
675
|
#parentName;
|
|
677
676
|
#joins;
|
|
@@ -680,8 +679,8 @@ class SingleJoinBuilderImpl {
|
|
|
680
679
|
#selectedColumns;
|
|
681
680
|
#orderByClauses;
|
|
682
681
|
#offsetValue;
|
|
683
|
-
constructor(
|
|
684
|
-
this.#
|
|
682
|
+
constructor(executor, parent, parentName, joins, joinType, conditions, selectedColumns = null, orderByClauses = [], offsetValue = null) {
|
|
683
|
+
this.#executor = executor;
|
|
685
684
|
this.#parent = parent;
|
|
686
685
|
this.#parentName = parentName;
|
|
687
686
|
this.#joins = joins;
|
|
@@ -692,14 +691,14 @@ class SingleJoinBuilderImpl {
|
|
|
692
691
|
this.#offsetValue = offsetValue;
|
|
693
692
|
}
|
|
694
693
|
where(condition) {
|
|
695
|
-
return new SingleJoinBuilderImpl(this.#
|
|
694
|
+
return new SingleJoinBuilderImpl(this.#executor, this.#parent, this.#parentName, this.#joins, this.#joinType, [...this.#conditions, condition], this.#selectedColumns, this.#orderByClauses, this.#offsetValue);
|
|
696
695
|
}
|
|
697
696
|
orderBy(key, direction = "asc") {
|
|
698
697
|
const column = getCol(this.#parent, key);
|
|
699
|
-
return new SingleJoinBuilderImpl(this.#
|
|
698
|
+
return new SingleJoinBuilderImpl(this.#executor, this.#parent, this.#parentName, this.#joins, this.#joinType, this.#conditions, this.#selectedColumns, [...this.#orderByClauses, { column, direction }], this.#offsetValue);
|
|
700
699
|
}
|
|
701
700
|
offset(n) {
|
|
702
|
-
return new SingleJoinBuilderImpl(this.#
|
|
701
|
+
return new SingleJoinBuilderImpl(this.#executor, this.#parent, this.#parentName, this.#joins, this.#joinType, this.#conditions, this.#selectedColumns, this.#orderByClauses, n);
|
|
703
702
|
}
|
|
704
703
|
toSQL() {
|
|
705
704
|
const allowedTables = [this.#parent, ...this.#joins.map((j) => j.table)];
|
|
@@ -733,91 +732,95 @@ class SingleJoinBuilderImpl {
|
|
|
733
732
|
sql += ` OFFSET ${this.#offsetValue}`;
|
|
734
733
|
return { sql, params: [...joinParams, ...whereParams] };
|
|
735
734
|
}
|
|
736
|
-
execute() {
|
|
735
|
+
async execute() {
|
|
737
736
|
const { sql, params } = this.toSQL();
|
|
738
737
|
try {
|
|
739
|
-
const
|
|
740
|
-
|
|
738
|
+
const rows = await this.#executor.all(sql, params);
|
|
739
|
+
const records = rows;
|
|
740
|
+
if (records.length === 0)
|
|
741
741
|
return null;
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
742
|
+
return this.#decodeJoinRow(records);
|
|
743
|
+
} catch (e) {
|
|
744
|
+
if (e instanceof FlintQueryError)
|
|
745
|
+
throw e;
|
|
746
|
+
throw new FlintQueryError(`Failed to execute query: ${sql}`, e);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
#decodeJoinRow(rows) {
|
|
750
|
+
const parentEntries = columnEntries(this.#parent);
|
|
751
|
+
const pkKey = findPKKey(this.#parent);
|
|
752
|
+
const pkColName = getCol(this.#parent, pkKey).name;
|
|
753
|
+
const childEntryMaps = [];
|
|
754
|
+
for (const j of this.#joins) {
|
|
755
|
+
childEntryMaps.push({
|
|
756
|
+
name: j.name,
|
|
757
|
+
entries: columnEntries(j.table),
|
|
758
|
+
table: j.table
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
const grouped = new Map;
|
|
762
|
+
for (const r of rows) {
|
|
763
|
+
const pk = r[pkColName];
|
|
764
|
+
if (!grouped.has(pk)) {
|
|
765
|
+
const parentRow = {};
|
|
766
|
+
for (const [key, col] of parentEntries) {
|
|
767
|
+
parentRow[key] = r[col.name];
|
|
765
768
|
}
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
let hasNonNullChild = false;
|
|
770
|
-
for (const [key, col] of childMap.entries) {
|
|
771
|
-
const val = r[`${childMap.name}_${col.name}`];
|
|
772
|
-
childRow[key] = val;
|
|
773
|
-
if (val != null)
|
|
774
|
-
hasNonNullChild = true;
|
|
775
|
-
}
|
|
776
|
-
if (this.#joinType === "left" && !hasNonNullChild)
|
|
777
|
-
return;
|
|
778
|
-
group.children[i].push(childRow);
|
|
769
|
+
grouped.set(pk, {
|
|
770
|
+
parent: parentRow,
|
|
771
|
+
children: childEntryMaps.map(() => [])
|
|
779
772
|
});
|
|
780
773
|
}
|
|
781
|
-
const
|
|
782
|
-
if (!first)
|
|
783
|
-
return null;
|
|
784
|
-
const decodedParent = this.#selectedColumns ? decodeSelectedRow(first.parent, this.#parent, this.#selectedColumns) : decodeRow(first.parent, this.#parent);
|
|
785
|
-
const nested = { ...decodedParent };
|
|
774
|
+
const group = grouped.get(pk);
|
|
786
775
|
childEntryMaps.forEach((childMap, i) => {
|
|
787
|
-
|
|
776
|
+
const childRow = {};
|
|
777
|
+
let hasNonNullChild = false;
|
|
778
|
+
for (const [key, col] of childMap.entries) {
|
|
779
|
+
const val = r[`${childMap.name}_${col.name}`];
|
|
780
|
+
childRow[key] = val;
|
|
781
|
+
if (val != null)
|
|
782
|
+
hasNonNullChild = true;
|
|
783
|
+
}
|
|
784
|
+
if (this.#joinType === "left" && !hasNonNullChild)
|
|
785
|
+
return;
|
|
786
|
+
group.children[i].push(childRow);
|
|
788
787
|
});
|
|
789
|
-
return nested;
|
|
790
|
-
} catch (e) {
|
|
791
|
-
if (e instanceof FlintQueryError)
|
|
792
|
-
throw e;
|
|
793
|
-
throw new FlintQueryError(`Failed to execute query: ${sql}`, e);
|
|
794
788
|
}
|
|
789
|
+
const first = grouped.values().next().value;
|
|
790
|
+
if (!first)
|
|
791
|
+
return null;
|
|
792
|
+
const decodedParent = this.#selectedColumns ? decodeSelectedRow(first.parent, this.#parent, this.#selectedColumns) : decodeRow(first.parent, this.#parent);
|
|
793
|
+
const nested = { ...decodedParent };
|
|
794
|
+
childEntryMaps.forEach((childMap, i) => {
|
|
795
|
+
nested[childMap.name] = first.children[i].map((c) => decodeRow(c, childMap.table));
|
|
796
|
+
});
|
|
797
|
+
return nested;
|
|
795
798
|
}
|
|
796
799
|
}
|
|
797
800
|
|
|
798
801
|
class InsertValuesBuilder {
|
|
799
|
-
#
|
|
802
|
+
#executor;
|
|
800
803
|
#tableName;
|
|
801
804
|
#table;
|
|
802
|
-
constructor(
|
|
803
|
-
this.#
|
|
805
|
+
constructor(executor, tableName, table) {
|
|
806
|
+
this.#executor = executor;
|
|
804
807
|
this.#tableName = tableName;
|
|
805
808
|
this.#table = table;
|
|
806
809
|
}
|
|
807
810
|
values(rowOrRows) {
|
|
808
|
-
return new InsertBuilder(this.#
|
|
811
|
+
return new InsertBuilder(this.#executor, this.#tableName, this.#table, rowOrRows);
|
|
809
812
|
}
|
|
810
813
|
}
|
|
811
814
|
|
|
812
815
|
class InsertBuilder {
|
|
813
|
-
#
|
|
816
|
+
#executor;
|
|
814
817
|
#tableName;
|
|
815
818
|
#table;
|
|
816
819
|
#rows;
|
|
817
820
|
#returning;
|
|
818
821
|
#onConflict;
|
|
819
|
-
constructor(
|
|
820
|
-
this.#
|
|
822
|
+
constructor(executor, tableName, table, rowOrRows, returning = false, onConflict) {
|
|
823
|
+
this.#executor = executor;
|
|
821
824
|
this.#tableName = tableName;
|
|
822
825
|
this.#table = table;
|
|
823
826
|
this.#rows = Array.isArray(rowOrRows) ? rowOrRows : [rowOrRows];
|
|
@@ -825,13 +828,13 @@ class InsertBuilder {
|
|
|
825
828
|
this.#onConflict = onConflict;
|
|
826
829
|
}
|
|
827
830
|
returning(keys) {
|
|
828
|
-
return new InsertBuilder(this.#
|
|
831
|
+
return new InsertBuilder(this.#executor, this.#tableName, this.#table, this.#rows, keys ?? true, this.#onConflict);
|
|
829
832
|
}
|
|
830
833
|
onConflictDoNothing() {
|
|
831
|
-
return new InsertBuilder(this.#
|
|
834
|
+
return new InsertBuilder(this.#executor, this.#tableName, this.#table, this.#rows, this.#returning, { mode: "nothing" });
|
|
832
835
|
}
|
|
833
836
|
onConflictDoUpdate(options) {
|
|
834
|
-
return new InsertBuilder(this.#
|
|
837
|
+
return new InsertBuilder(this.#executor, this.#tableName, this.#table, this.#rows, this.#returning, {
|
|
835
838
|
mode: "update",
|
|
836
839
|
target: options.target,
|
|
837
840
|
set: options.set
|
|
@@ -900,17 +903,18 @@ class InsertBuilder {
|
|
|
900
903
|
}
|
|
901
904
|
return { sql, params };
|
|
902
905
|
}
|
|
903
|
-
execute() {
|
|
906
|
+
async execute() {
|
|
904
907
|
const { sql, params } = this.toSQL();
|
|
905
908
|
try {
|
|
906
909
|
if (this.#returning) {
|
|
907
|
-
const rows = this.#
|
|
910
|
+
const rows = await this.#executor.all(sql, params);
|
|
911
|
+
const records = rows;
|
|
908
912
|
if (Array.isArray(this.#returning)) {
|
|
909
|
-
return
|
|
913
|
+
return records.map((r) => decodeSelectedRow(r, this.#table, this.#returning));
|
|
910
914
|
}
|
|
911
|
-
return
|
|
915
|
+
return records.map((r) => decodeRow(r, this.#table));
|
|
912
916
|
}
|
|
913
|
-
this.#
|
|
917
|
+
await this.#executor.run(sql, params);
|
|
914
918
|
return;
|
|
915
919
|
} catch (e) {
|
|
916
920
|
throw new FlintQueryError(`Failed to execute query: ${sql}`, e);
|
|
@@ -919,28 +923,28 @@ class InsertBuilder {
|
|
|
919
923
|
}
|
|
920
924
|
|
|
921
925
|
class UpdateSetBuilder {
|
|
922
|
-
#
|
|
926
|
+
#executor;
|
|
923
927
|
#tableName;
|
|
924
928
|
#table;
|
|
925
|
-
constructor(
|
|
926
|
-
this.#
|
|
929
|
+
constructor(executor, tableName, table) {
|
|
930
|
+
this.#executor = executor;
|
|
927
931
|
this.#tableName = tableName;
|
|
928
932
|
this.#table = table;
|
|
929
933
|
}
|
|
930
934
|
set(partial) {
|
|
931
|
-
return new UpdateBuilder(this.#
|
|
935
|
+
return new UpdateBuilder(this.#executor, this.#tableName, this.#table, partial);
|
|
932
936
|
}
|
|
933
937
|
}
|
|
934
938
|
|
|
935
939
|
class UpdateBuilder {
|
|
936
|
-
#
|
|
940
|
+
#executor;
|
|
937
941
|
#tableName;
|
|
938
942
|
#table;
|
|
939
943
|
#set;
|
|
940
944
|
#conditions;
|
|
941
945
|
#returning;
|
|
942
|
-
constructor(
|
|
943
|
-
this.#
|
|
946
|
+
constructor(executor, tableName, table, set, conditions = [], returning = false) {
|
|
947
|
+
this.#executor = executor;
|
|
944
948
|
this.#tableName = tableName;
|
|
945
949
|
this.#table = table;
|
|
946
950
|
this.#set = set;
|
|
@@ -948,13 +952,13 @@ class UpdateBuilder {
|
|
|
948
952
|
this.#returning = returning;
|
|
949
953
|
}
|
|
950
954
|
set(partial) {
|
|
951
|
-
return new UpdateBuilder(this.#
|
|
955
|
+
return new UpdateBuilder(this.#executor, this.#tableName, this.#table, { ...this.#set, ...partial }, this.#conditions, this.#returning);
|
|
952
956
|
}
|
|
953
957
|
where(condition) {
|
|
954
|
-
return new UpdateBuilder(this.#
|
|
958
|
+
return new UpdateBuilder(this.#executor, this.#tableName, this.#table, this.#set, [...this.#conditions, condition], this.#returning);
|
|
955
959
|
}
|
|
956
960
|
returning(keys) {
|
|
957
|
-
return new UpdateBuilder(this.#
|
|
961
|
+
return new UpdateBuilder(this.#executor, this.#tableName, this.#table, this.#set, this.#conditions, keys ?? true);
|
|
958
962
|
}
|
|
959
963
|
toSQL() {
|
|
960
964
|
validateColumnOwnership(this.#conditions, [this.#table], `UPDATE "${this.#tableName}"`);
|
|
@@ -984,17 +988,18 @@ class UpdateBuilder {
|
|
|
984
988
|
}
|
|
985
989
|
return { sql, params };
|
|
986
990
|
}
|
|
987
|
-
execute() {
|
|
991
|
+
async execute() {
|
|
988
992
|
const { sql, params } = this.toSQL();
|
|
989
993
|
try {
|
|
990
994
|
if (this.#returning) {
|
|
991
|
-
const rows = this.#
|
|
995
|
+
const rows = await this.#executor.all(sql, params);
|
|
996
|
+
const records = rows;
|
|
992
997
|
if (Array.isArray(this.#returning)) {
|
|
993
|
-
return
|
|
998
|
+
return records.map((r) => decodeSelectedRow(r, this.#table, this.#returning));
|
|
994
999
|
}
|
|
995
|
-
return
|
|
1000
|
+
return records.map((r) => decodeRow(r, this.#table));
|
|
996
1001
|
}
|
|
997
|
-
this.#
|
|
1002
|
+
await this.#executor.run(sql, params);
|
|
998
1003
|
return;
|
|
999
1004
|
} catch (e) {
|
|
1000
1005
|
throw new FlintQueryError(`Failed to execute query: ${sql}`, e);
|
|
@@ -1003,23 +1008,23 @@ class UpdateBuilder {
|
|
|
1003
1008
|
}
|
|
1004
1009
|
|
|
1005
1010
|
class DeleteBuilder {
|
|
1006
|
-
#
|
|
1011
|
+
#executor;
|
|
1007
1012
|
#tableName;
|
|
1008
1013
|
#table;
|
|
1009
1014
|
#conditions;
|
|
1010
1015
|
#returning;
|
|
1011
|
-
constructor(
|
|
1012
|
-
this.#
|
|
1016
|
+
constructor(executor, tableName, table, conditions = [], returning = false) {
|
|
1017
|
+
this.#executor = executor;
|
|
1013
1018
|
this.#tableName = tableName;
|
|
1014
1019
|
this.#table = table;
|
|
1015
1020
|
this.#conditions = conditions;
|
|
1016
1021
|
this.#returning = returning;
|
|
1017
1022
|
}
|
|
1018
1023
|
where(condition) {
|
|
1019
|
-
return new DeleteBuilder(this.#
|
|
1024
|
+
return new DeleteBuilder(this.#executor, this.#tableName, this.#table, [...this.#conditions, condition], this.#returning);
|
|
1020
1025
|
}
|
|
1021
1026
|
returning(keys) {
|
|
1022
|
-
return new DeleteBuilder(this.#
|
|
1027
|
+
return new DeleteBuilder(this.#executor, this.#tableName, this.#table, this.#conditions, keys ?? true);
|
|
1023
1028
|
}
|
|
1024
1029
|
toSQL() {
|
|
1025
1030
|
validateColumnOwnership(this.#conditions, [this.#table], `DELETE from "${this.#tableName}"`);
|
|
@@ -1038,17 +1043,18 @@ class DeleteBuilder {
|
|
|
1038
1043
|
}
|
|
1039
1044
|
return { sql, params };
|
|
1040
1045
|
}
|
|
1041
|
-
execute() {
|
|
1046
|
+
async execute() {
|
|
1042
1047
|
const { sql, params } = this.toSQL();
|
|
1043
1048
|
try {
|
|
1044
1049
|
if (this.#returning) {
|
|
1045
|
-
const rows = this.#
|
|
1050
|
+
const rows = await this.#executor.all(sql, params);
|
|
1051
|
+
const records = rows;
|
|
1046
1052
|
if (Array.isArray(this.#returning)) {
|
|
1047
|
-
return
|
|
1053
|
+
return records.map((r) => decodeSelectedRow(r, this.#table, this.#returning));
|
|
1048
1054
|
}
|
|
1049
|
-
return
|
|
1055
|
+
return records.map((r) => decodeRow(r, this.#table));
|
|
1050
1056
|
}
|
|
1051
|
-
this.#
|
|
1057
|
+
await this.#executor.run(sql, params);
|
|
1052
1058
|
return;
|
|
1053
1059
|
} catch (e) {
|
|
1054
1060
|
throw new FlintQueryError(`Failed to execute query: ${sql}`, e);
|
|
@@ -1071,83 +1077,81 @@ function compileWhere(condition) {
|
|
|
1071
1077
|
const whereSql = compileCondition(condition, params);
|
|
1072
1078
|
return { whereSql: ` WHERE ${whereSql}`, params };
|
|
1073
1079
|
}
|
|
1074
|
-
function count(
|
|
1080
|
+
async function count(executor, table, condition) {
|
|
1075
1081
|
const tableName = getTableName(table);
|
|
1076
1082
|
const { whereSql, params } = compileWhere(condition);
|
|
1077
1083
|
const sql = `SELECT count(*) as cnt FROM ${tableName}${whereSql}`;
|
|
1078
|
-
const result =
|
|
1084
|
+
const result = await executor.get(sql, params);
|
|
1079
1085
|
return result.cnt;
|
|
1080
1086
|
}
|
|
1081
|
-
function countColumn(
|
|
1087
|
+
async function countColumn(executor, table, column, condition) {
|
|
1082
1088
|
const tableName = getTableName(table);
|
|
1083
1089
|
const columnName = getColumnName(column);
|
|
1084
1090
|
const { whereSql, params } = compileWhere(condition);
|
|
1085
1091
|
const sql = `SELECT count(${columnName}) as cnt FROM ${tableName}${whereSql}`;
|
|
1086
|
-
const result =
|
|
1092
|
+
const result = await executor.get(sql, params);
|
|
1087
1093
|
return result.cnt;
|
|
1088
1094
|
}
|
|
1089
|
-
function sum(
|
|
1095
|
+
async function sum(executor, table, column, condition) {
|
|
1090
1096
|
const tableName = getTableName(table);
|
|
1091
1097
|
const columnName = getColumnName(column);
|
|
1092
1098
|
const { whereSql, params } = compileWhere(condition);
|
|
1093
1099
|
const sql = `SELECT sum(${columnName}) as total FROM ${tableName}${whereSql}`;
|
|
1094
|
-
const result =
|
|
1100
|
+
const result = await executor.get(sql, params);
|
|
1095
1101
|
return result.total;
|
|
1096
1102
|
}
|
|
1097
|
-
function avg(
|
|
1103
|
+
async function avg(executor, table, column, condition) {
|
|
1098
1104
|
const tableName = getTableName(table);
|
|
1099
1105
|
const columnName = getColumnName(column);
|
|
1100
1106
|
const { whereSql, params } = compileWhere(condition);
|
|
1101
1107
|
const sql = `SELECT avg(${columnName}) as average FROM ${tableName}${whereSql}`;
|
|
1102
|
-
const result =
|
|
1108
|
+
const result = await executor.get(sql, params);
|
|
1103
1109
|
return result.average;
|
|
1104
1110
|
}
|
|
1105
|
-
function min(
|
|
1111
|
+
async function min(executor, table, column, condition) {
|
|
1106
1112
|
const tableName = getTableName(table);
|
|
1107
1113
|
const columnName = getColumnName(column);
|
|
1108
1114
|
const { whereSql, params } = compileWhere(condition);
|
|
1109
1115
|
const sql = `SELECT min(${columnName}) as minimum FROM ${tableName}${whereSql}`;
|
|
1110
|
-
const result =
|
|
1116
|
+
const result = await executor.get(sql, params);
|
|
1111
1117
|
return result.minimum;
|
|
1112
1118
|
}
|
|
1113
|
-
function max(
|
|
1119
|
+
async function max(executor, table, column, condition) {
|
|
1114
1120
|
const tableName = getTableName(table);
|
|
1115
1121
|
const columnName = getColumnName(column);
|
|
1116
1122
|
const { whereSql, params } = compileWhere(condition);
|
|
1117
1123
|
const sql = `SELECT max(${columnName}) as maximum FROM ${tableName}${whereSql}`;
|
|
1118
|
-
const result =
|
|
1124
|
+
const result = await executor.get(sql, params);
|
|
1119
1125
|
return result.maximum;
|
|
1120
1126
|
}
|
|
1121
1127
|
|
|
1122
1128
|
// src/flint.ts
|
|
1123
|
-
function
|
|
1124
|
-
const client = new Database(details.url);
|
|
1129
|
+
function createClient(executor) {
|
|
1125
1130
|
return {
|
|
1126
|
-
select: () => new SelectFromBuilder(
|
|
1127
|
-
insert: (table) => new InsertValuesBuilder(
|
|
1128
|
-
update: (table) => new UpdateSetBuilder(
|
|
1129
|
-
delete: (table) => new DeleteBuilder(
|
|
1130
|
-
leftJoin: (parent) => new JoinStage1(
|
|
1131
|
-
innerJoin: (parent) => new JoinStage1(
|
|
1131
|
+
select: () => new SelectFromBuilder(executor),
|
|
1132
|
+
insert: (table) => new InsertValuesBuilder(executor, table._.name, table),
|
|
1133
|
+
update: (table) => new UpdateSetBuilder(executor, table._.name, table),
|
|
1134
|
+
delete: (table) => new DeleteBuilder(executor, table._.name, table),
|
|
1135
|
+
leftJoin: (parent) => new JoinStage1(executor, parent, parent._.name, "left"),
|
|
1136
|
+
innerJoin: (parent) => new JoinStage1(executor, parent, parent._.name, "inner"),
|
|
1132
1137
|
batch: (queries) => {
|
|
1133
1138
|
const stmts = queries.map((q) => q.toSQL());
|
|
1134
|
-
|
|
1135
|
-
for (const
|
|
1136
|
-
|
|
1139
|
+
return executor.transaction(async () => {
|
|
1140
|
+
for (const stmt of stmts) {
|
|
1141
|
+
await executor.run(stmt.sql, stmt.params);
|
|
1137
1142
|
}
|
|
1138
1143
|
});
|
|
1139
|
-
tx();
|
|
1140
1144
|
},
|
|
1141
|
-
count: (table, condition) => count(
|
|
1142
|
-
countColumn: (table, column, condition) => countColumn(
|
|
1143
|
-
sum: (table, column, condition) => sum(
|
|
1144
|
-
avg: (table, column, condition) => avg(
|
|
1145
|
-
min: (table, column, condition) => min(
|
|
1146
|
-
max: (table, column, condition) => max(
|
|
1147
|
-
$run(
|
|
1148
|
-
return
|
|
1145
|
+
count: (table, condition) => count(executor, table, condition),
|
|
1146
|
+
countColumn: (table, column, condition) => countColumn(executor, table, column, condition),
|
|
1147
|
+
sum: (table, column, condition) => sum(executor, table, column, condition),
|
|
1148
|
+
avg: (table, column, condition) => avg(executor, table, column, condition),
|
|
1149
|
+
min: (table, column, condition) => min(executor, table, column, condition),
|
|
1150
|
+
max: (table, column, condition) => max(executor, table, column, condition),
|
|
1151
|
+
$run(query, ...params) {
|
|
1152
|
+
return executor.run(query, params);
|
|
1149
1153
|
},
|
|
1150
|
-
$
|
|
1154
|
+
$executor: executor
|
|
1151
1155
|
};
|
|
1152
1156
|
}
|
|
1153
1157
|
function sql(strings, ...values) {
|
|
@@ -1183,6 +1187,8 @@ function makeColumn(config) {
|
|
|
1183
1187
|
hasOnUpdate: false,
|
|
1184
1188
|
referencesTable: null,
|
|
1185
1189
|
referencesColumn: null,
|
|
1190
|
+
onDelete: null,
|
|
1191
|
+
onUpdate: null,
|
|
1186
1192
|
encode: config.encode,
|
|
1187
1193
|
decode: config.decode,
|
|
1188
1194
|
tableName: null
|
|
@@ -1214,6 +1220,12 @@ function makeColumn(config) {
|
|
|
1214
1220
|
referencesColumn: target.name
|
|
1215
1221
|
}
|
|
1216
1222
|
};
|
|
1223
|
+
},
|
|
1224
|
+
onDelete(action) {
|
|
1225
|
+
return { ...this, __internal: { ...this.__internal, onDelete: action } };
|
|
1226
|
+
},
|
|
1227
|
+
onUpdate(action) {
|
|
1228
|
+
return { ...this, __internal: { ...this.__internal, onUpdate: action } };
|
|
1217
1229
|
}
|
|
1218
1230
|
};
|
|
1219
1231
|
return col;
|
|
@@ -1317,7 +1329,7 @@ function date(name) {
|
|
|
1317
1329
|
defaultNow() {
|
|
1318
1330
|
return { ...this, __internal: { ...this.__internal, hasDefaultNow: true } };
|
|
1319
1331
|
},
|
|
1320
|
-
|
|
1332
|
+
onUpdateTimestamp() {
|
|
1321
1333
|
return { ...this, __internal: { ...this.__internal, hasOnUpdate: true } };
|
|
1322
1334
|
}
|
|
1323
1335
|
};
|
|
@@ -1367,6 +1379,12 @@ function table(name, columns, indexFn) {
|
|
|
1367
1379
|
referencesColumn: target.name
|
|
1368
1380
|
}
|
|
1369
1381
|
};
|
|
1382
|
+
},
|
|
1383
|
+
onDelete(action) {
|
|
1384
|
+
return { ...this, __internal: { ...stampedInternal, onDelete: action } };
|
|
1385
|
+
},
|
|
1386
|
+
onUpdate(action) {
|
|
1387
|
+
return { ...this, __internal: { ...stampedInternal, onUpdate: action } };
|
|
1370
1388
|
}
|
|
1371
1389
|
};
|
|
1372
1390
|
if ("autoIncrement" in col) {
|
|
@@ -1379,8 +1397,8 @@ function table(name, columns, indexFn) {
|
|
|
1379
1397
|
return { ...this, __internal: { ...stampedInternal, hasDefaultNow: true } };
|
|
1380
1398
|
};
|
|
1381
1399
|
}
|
|
1382
|
-
if ("
|
|
1383
|
-
stampedCol.
|
|
1400
|
+
if ("onUpdateTimestamp" in col) {
|
|
1401
|
+
stampedCol.onUpdateTimestamp = function() {
|
|
1384
1402
|
return { ...this, __internal: { ...stampedInternal, hasOnUpdate: true } };
|
|
1385
1403
|
};
|
|
1386
1404
|
}
|
|
@@ -1437,6 +1455,12 @@ function snakeCaseTable(tableName, columns, indexFn) {
|
|
|
1437
1455
|
referencesColumn: target.name
|
|
1438
1456
|
}
|
|
1439
1457
|
};
|
|
1458
|
+
},
|
|
1459
|
+
onDelete(action) {
|
|
1460
|
+
return { ...this, __internal: { ...stampedInternal, onDelete: action } };
|
|
1461
|
+
},
|
|
1462
|
+
onUpdate(action) {
|
|
1463
|
+
return { ...this, __internal: { ...stampedInternal, onUpdate: action } };
|
|
1440
1464
|
}
|
|
1441
1465
|
};
|
|
1442
1466
|
if ("autoIncrement" in col) {
|
|
@@ -1449,8 +1473,8 @@ function snakeCaseTable(tableName, columns, indexFn) {
|
|
|
1449
1473
|
return { ...this, __internal: { ...stampedInternal, hasDefaultNow: true } };
|
|
1450
1474
|
};
|
|
1451
1475
|
}
|
|
1452
|
-
if ("
|
|
1453
|
-
stampedCol.
|
|
1476
|
+
if ("onUpdateTimestamp" in col) {
|
|
1477
|
+
stampedCol.onUpdateTimestamp = function() {
|
|
1454
1478
|
return { ...this, __internal: { ...stampedInternal, hasOnUpdate: true } };
|
|
1455
1479
|
};
|
|
1456
1480
|
}
|
|
@@ -1528,7 +1552,12 @@ function introspectColumns(client, tableName) {
|
|
|
1528
1552
|
const indexRows = client.query(`PRAGMA index_list('${tableName}')`).all();
|
|
1529
1553
|
const fkMap = new Map;
|
|
1530
1554
|
for (const fk of fkRows) {
|
|
1531
|
-
fkMap.set(fk.from, {
|
|
1555
|
+
fkMap.set(fk.from, {
|
|
1556
|
+
referencesTable: fk.table,
|
|
1557
|
+
referencesColumn: fk.to,
|
|
1558
|
+
onDelete: fk.on_delete !== "NO ACTION" ? fk.on_delete.toLowerCase() : undefined,
|
|
1559
|
+
onUpdate: fk.on_update !== "NO ACTION" ? fk.on_update.toLowerCase() : undefined
|
|
1560
|
+
});
|
|
1532
1561
|
}
|
|
1533
1562
|
const uniqueColumns = new Set;
|
|
1534
1563
|
for (const idx of indexRows) {
|
|
@@ -1554,6 +1583,10 @@ function introspectColumns(client, tableName) {
|
|
|
1554
1583
|
if (fk) {
|
|
1555
1584
|
col.referencesTable = fk.referencesTable;
|
|
1556
1585
|
col.referencesColumn = fk.referencesColumn;
|
|
1586
|
+
if (fk.onDelete)
|
|
1587
|
+
col.onDelete = fk.onDelete;
|
|
1588
|
+
if (fk.onUpdate)
|
|
1589
|
+
col.onUpdate = fk.onUpdate;
|
|
1557
1590
|
}
|
|
1558
1591
|
return col;
|
|
1559
1592
|
});
|
|
@@ -1616,9 +1649,9 @@ export {
|
|
|
1616
1649
|
gte,
|
|
1617
1650
|
gt,
|
|
1618
1651
|
glob,
|
|
1619
|
-
flint,
|
|
1620
1652
|
eq,
|
|
1621
1653
|
date,
|
|
1654
|
+
createClient,
|
|
1622
1655
|
countColumn,
|
|
1623
1656
|
count,
|
|
1624
1657
|
boolean,
|