flint-orm 0.3.0 → 0.4.1

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.
Files changed (5) hide show
  1. package/API.md +158 -317
  2. package/README.md +239 -134
  3. package/dist/index.js +288 -255
  4. package/package.json +43 -12
  5. package/src/cli.ts +0 -314
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
- #client;
228
+ #executor;
235
229
  #conditions;
236
- constructor(client, conditions = []) {
237
- this.#client = client;
230
+ constructor(executor, conditions = []) {
231
+ this.#executor = executor;
238
232
  this.#conditions = conditions;
239
233
  }
240
234
  from(table) {
241
- return new SelectBuilder(this.#client, table._.name, table, this.#conditions);
235
+ return new SelectBuilder(this.#executor, table._.name, table, this.#conditions);
242
236
  }
243
237
  }
244
238
 
245
239
  class SelectBuilder {
246
- #client;
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(client, tableName, table, conditions = [], selectedColumns = null, orderByClauses = [], limitValue = null, offsetValue = null, distinct = false) {
256
- this.#client = client;
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.#client, this.#tableName, this.#table, [...this.#conditions, condition], this.#selectedColumns, this.#orderByClauses, this.#limitValue, this.#offsetValue, this.#distinct);
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.#client, this.#tableName, this.#table, this.#conditions, keys, this.#orderByClauses, this.#limitValue, this.#offsetValue, this.#distinct);
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.#client, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, this.#orderByClauses, this.#offsetValue, this.#distinct);
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.#client, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, this.#orderByClauses, this.#limitValue, this.#offsetValue, true);
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.#client, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, [...this.#orderByClauses, { column, direction }], this.#limitValue, this.#offsetValue, this.#distinct);
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.#client, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, this.#orderByClauses, n, this.#offsetValue, this.#distinct);
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.#client, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, this.#orderByClauses, this.#limitValue, n, this.#distinct);
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.#client.prepare(sql).all(...bind(params));
304
+ const rows = await this.#executor.all(sql, params);
305
+ const records = rows;
311
306
  if (this.#selectedColumns) {
312
- return rows.map((r) => decodeSelectedRow(r, this.#table, this.#selectedColumns));
307
+ return records.map((r) => decodeSelectedRow(r, this.#table, this.#selectedColumns));
313
308
  }
314
- return rows.map((r) => decodeRow(r, this.#table));
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
- #client;
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(client, tableName, table, conditions, selectedColumns, orderByClauses, limitValue, offsetValue, distinct) {
332
- this.#client = client;
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.#client, this.#tableName, this.#table, [...this.#conditions, condition], this.#selectedColumns, this.#orderByClauses, this.#limitValue, this.#offsetValue, this.#distinct);
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.#client, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, this.#orderByClauses, this.#limitValue, this.#offsetValue, true);
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.#client, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, this.#orderByClauses, this.#offsetValue, this.#distinct);
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.#client, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, [...this.#orderByClauses, { column, direction }], this.#limitValue, this.#offsetValue, this.#distinct);
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.#client, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, this.#orderByClauses, n, this.#offsetValue, this.#distinct);
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.#client, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, this.#orderByClauses, this.#limitValue, n, this.#distinct);
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.#client.prepare(sql).all(...bind(params));
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
- #client;
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(client, tableName, table, conditions, selectedColumns = null, orderByClauses = [], offsetValue = null, distinct = false) {
401
- this.#client = client;
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.#client, this.#tableName, this.#table, [...this.#conditions, condition], this.#selectedColumns, this.#orderByClauses, this.#offsetValue, this.#distinct);
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.#client, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, [...this.#orderByClauses, { column, direction }], this.#offsetValue, this.#distinct);
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.#client, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, this.#orderByClauses, n, this.#distinct);
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.#client.prepare(sql).get(...bind(params));
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(row, this.#table, this.#selectedColumns);
441
+ return decodeSelectedRow(record, this.#table, this.#selectedColumns);
446
442
  }
447
- return decodeRow(row, this.#table);
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
- #client;
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(client, tableName, table, conditions, selectedColumns, orderByClauses, offsetValue, distinct) {
464
- this.#client = client;
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.#client, this.#tableName, this.#table, [...this.#conditions, condition], this.#selectedColumns, this.#orderByClauses, this.#offsetValue, this.#distinct);
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.#client, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, [...this.#orderByClauses, { column, direction }], this.#offsetValue, this.#distinct);
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.#client, this.#tableName, this.#table, this.#conditions, this.#selectedColumns, this.#orderByClauses, n, this.#distinct);
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.#client.prepare(sql).get(...bind(params));
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
- #client;
511
+ #executor;
516
512
  #parent;
517
513
  #parentName;
518
514
  #joinType;
519
- constructor(client, parent, parentName, joinType) {
520
- this.#client = client;
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.#client, this.#parent, this.#parentName, [{ table: child, name: childName, condition: resolvedCondition }], this.#joinType);
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
- #client;
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(client, parent, parentName, joins, joinType, conditions = [], selectedColumns = null, orderByClauses = [], limitValue = null, offsetValue = null) {
544
- this.#client = client;
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.#client, this.#parent, this.#parentName, [...this.#joins, { table: child, name: childName, condition: resolvedCondition }], this.#joinType, this.#conditions, this.#selectedColumns);
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.#client, this.#parent, this.#parentName, this.#joins, this.#joinType, [...this.#conditions, condition], this.#selectedColumns);
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.#client, this.#parent, this.#parentName, this.#joins, this.#joinType, this.#conditions, keys, this.#orderByClauses, this.#limitValue, this.#offsetValue);
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.#client, this.#parent, this.#parentName, this.#joins, this.#joinType, this.#conditions, this.#selectedColumns, [...this.#orderByClauses, { column, direction }], this.#limitValue, this.#offsetValue);
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.#client, this.#parent, this.#parentName, this.#joins, this.#joinType, this.#conditions, this.#selectedColumns, this.#orderByClauses, n, this.#offsetValue);
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.#client, this.#parent, this.#parentName, this.#joins, this.#joinType, this.#conditions, this.#selectedColumns, this.#orderByClauses, this.#limitValue, n);
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.#client, this.#parent, this.#parentName, this.#joins, this.#joinType, this.#conditions, this.#selectedColumns, this.#orderByClauses, this.#offsetValue);
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.#client.prepare(sql).all(...bind(params));
616
- const parentEntries = columnEntries(this.#parent);
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
- #client;
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(client, parent, parentName, joins, joinType, conditions, selectedColumns = null, orderByClauses = [], offsetValue = null) {
684
- this.#client = client;
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.#client, this.#parent, this.#parentName, this.#joins, this.#joinType, [...this.#conditions, condition], this.#selectedColumns, this.#orderByClauses, this.#offsetValue);
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.#client, this.#parent, this.#parentName, this.#joins, this.#joinType, this.#conditions, this.#selectedColumns, [...this.#orderByClauses, { column, direction }], this.#offsetValue);
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.#client, this.#parent, this.#parentName, this.#joins, this.#joinType, this.#conditions, this.#selectedColumns, this.#orderByClauses, n);
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 allRows = this.#client.prepare(sql).all(...bind(params));
740
- if (allRows.length === 0)
738
+ const rows = await this.#executor.all(sql, params);
739
+ const records = rows;
740
+ if (records.length === 0)
741
741
  return null;
742
- const parentEntries = columnEntries(this.#parent);
743
- const pkKey = findPKKey(this.#parent);
744
- const pkColName = getCol(this.#parent, pkKey).name;
745
- const childEntryMaps = [];
746
- for (const j of this.#joins) {
747
- childEntryMaps.push({
748
- name: j.name,
749
- entries: columnEntries(j.table),
750
- table: j.table
751
- });
752
- }
753
- const grouped = new Map;
754
- for (const r of allRows) {
755
- const pk = r[pkColName];
756
- if (!grouped.has(pk)) {
757
- const parentRow = {};
758
- for (const [key, col] of parentEntries) {
759
- parentRow[key] = r[col.name];
760
- }
761
- grouped.set(pk, {
762
- parent: parentRow,
763
- children: childEntryMaps.map(() => [])
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
- const group = grouped.get(pk);
767
- childEntryMaps.forEach((childMap, i) => {
768
- const childRow = {};
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 first = grouped.values().next().value;
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
- nested[childMap.name] = first.children[i].map((c) => decodeRow(c, childMap.table));
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
- #client;
802
+ #executor;
800
803
  #tableName;
801
804
  #table;
802
- constructor(client, tableName, table) {
803
- this.#client = client;
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.#client, this.#tableName, this.#table, rowOrRows);
811
+ return new InsertBuilder(this.#executor, this.#tableName, this.#table, rowOrRows);
809
812
  }
810
813
  }
811
814
 
812
815
  class InsertBuilder {
813
- #client;
816
+ #executor;
814
817
  #tableName;
815
818
  #table;
816
819
  #rows;
817
820
  #returning;
818
821
  #onConflict;
819
- constructor(client, tableName, table, rowOrRows, returning = false, onConflict) {
820
- this.#client = client;
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.#client, this.#tableName, this.#table, this.#rows, keys ?? true, this.#onConflict);
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.#client, this.#tableName, this.#table, this.#rows, this.#returning, { mode: "nothing" });
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.#client, this.#tableName, this.#table, this.#rows, this.#returning, {
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.#client.prepare(sql).all(...bind(params));
910
+ const rows = await this.#executor.all(sql, params);
911
+ const records = rows;
908
912
  if (Array.isArray(this.#returning)) {
909
- return rows.map((r) => decodeSelectedRow(r, this.#table, this.#returning));
913
+ return records.map((r) => decodeSelectedRow(r, this.#table, this.#returning));
910
914
  }
911
- return rows.map((r) => decodeRow(r, this.#table));
915
+ return records.map((r) => decodeRow(r, this.#table));
912
916
  }
913
- this.#client.prepare(sql).run(...bind(params));
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
- #client;
926
+ #executor;
923
927
  #tableName;
924
928
  #table;
925
- constructor(client, tableName, table) {
926
- this.#client = client;
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.#client, this.#tableName, this.#table, partial);
935
+ return new UpdateBuilder(this.#executor, this.#tableName, this.#table, partial);
932
936
  }
933
937
  }
934
938
 
935
939
  class UpdateBuilder {
936
- #client;
940
+ #executor;
937
941
  #tableName;
938
942
  #table;
939
943
  #set;
940
944
  #conditions;
941
945
  #returning;
942
- constructor(client, tableName, table, set, conditions = [], returning = false) {
943
- this.#client = client;
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.#client, this.#tableName, this.#table, { ...this.#set, ...partial }, this.#conditions, this.#returning);
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.#client, this.#tableName, this.#table, this.#set, [...this.#conditions, condition], this.#returning);
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.#client, this.#tableName, this.#table, this.#set, this.#conditions, keys ?? true);
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.#client.prepare(sql).all(...bind(params));
995
+ const rows = await this.#executor.all(sql, params);
996
+ const records = rows;
992
997
  if (Array.isArray(this.#returning)) {
993
- return rows.map((r) => decodeSelectedRow(r, this.#table, this.#returning));
998
+ return records.map((r) => decodeSelectedRow(r, this.#table, this.#returning));
994
999
  }
995
- return rows.map((r) => decodeRow(r, this.#table));
1000
+ return records.map((r) => decodeRow(r, this.#table));
996
1001
  }
997
- this.#client.prepare(sql).run(...bind(params));
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
- #client;
1011
+ #executor;
1007
1012
  #tableName;
1008
1013
  #table;
1009
1014
  #conditions;
1010
1015
  #returning;
1011
- constructor(client, tableName, table, conditions = [], returning = false) {
1012
- this.#client = client;
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.#client, this.#tableName, this.#table, [...this.#conditions, condition], this.#returning);
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.#client, this.#tableName, this.#table, this.#conditions, keys ?? true);
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.#client.prepare(sql).all(...bind(params));
1050
+ const rows = await this.#executor.all(sql, params);
1051
+ const records = rows;
1046
1052
  if (Array.isArray(this.#returning)) {
1047
- return rows.map((r) => decodeSelectedRow(r, this.#table, this.#returning));
1053
+ return records.map((r) => decodeSelectedRow(r, this.#table, this.#returning));
1048
1054
  }
1049
- return rows.map((r) => decodeRow(r, this.#table));
1055
+ return records.map((r) => decodeRow(r, this.#table));
1050
1056
  }
1051
- this.#client.prepare(sql).run(...bind(params));
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(client, table, condition) {
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 = client.prepare(sql).get(...params);
1084
+ const result = await executor.get(sql, params);
1079
1085
  return result.cnt;
1080
1086
  }
1081
- function countColumn(client, table, column, condition) {
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 = client.prepare(sql).get(...params);
1092
+ const result = await executor.get(sql, params);
1087
1093
  return result.cnt;
1088
1094
  }
1089
- function sum(client, table, column, condition) {
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 = client.prepare(sql).get(...params);
1100
+ const result = await executor.get(sql, params);
1095
1101
  return result.total;
1096
1102
  }
1097
- function avg(client, table, column, condition) {
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 = client.prepare(sql).get(...params);
1108
+ const result = await executor.get(sql, params);
1103
1109
  return result.average;
1104
1110
  }
1105
- function min(client, table, column, condition) {
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 = client.prepare(sql).get(...params);
1116
+ const result = await executor.get(sql, params);
1111
1117
  return result.minimum;
1112
1118
  }
1113
- function max(client, table, column, condition) {
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 = client.prepare(sql).get(...params);
1124
+ const result = await executor.get(sql, params);
1119
1125
  return result.maximum;
1120
1126
  }
1121
1127
 
1122
1128
  // src/flint.ts
1123
- function flint(details) {
1124
- const client = new Database(details.url);
1129
+ function createClient(executor) {
1125
1130
  return {
1126
- select: () => new SelectFromBuilder(client),
1127
- insert: (table) => new InsertValuesBuilder(client, table._.name, table),
1128
- update: (table) => new UpdateSetBuilder(client, table._.name, table),
1129
- delete: (table) => new DeleteBuilder(client, table._.name, table),
1130
- leftJoin: (parent) => new JoinStage1(client, parent, parent._.name, "left"),
1131
- innerJoin: (parent) => new JoinStage1(client, parent, parent._.name, "inner"),
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
- const tx = client.transaction(() => {
1135
- for (const { sql: query, params } of stmts) {
1136
- client.prepare(query).run(...params);
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(client, table, condition),
1142
- countColumn: (table, column, condition) => countColumn(client, table, column, condition),
1143
- sum: (table, column, condition) => sum(client, table, column, condition),
1144
- avg: (table, column, condition) => avg(client, table, column, condition),
1145
- min: (table, column, condition) => min(client, table, column, condition),
1146
- max: (table, column, condition) => max(client, table, column, condition),
1147
- $run(sql, ...params) {
1148
- return client.prepare(sql).run(...params);
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
- $client: client
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
- onUpdate() {
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 ("onUpdate" in col) {
1383
- stampedCol.onUpdate = function() {
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 ("onUpdate" in col) {
1453
- stampedCol.onUpdate = function() {
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, { referencesTable: fk.table, referencesColumn: fk.to });
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,