@rwillians/qx 0.1.8 → 0.1.10

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.
@@ -154,6 +154,18 @@ const render = {
154
154
  const { frags, params } = render.expr.any(expr);
155
155
  return { frags: [[...frags, dir].join(' ')], params };
156
156
  },
157
+ /**
158
+ * @private Renders a join clause.
159
+ * @since 0.1.9
160
+ * @version 1
161
+ */
162
+ join: glue((join) => {
163
+ const result = render.expr.any(join.on);
164
+ return {
165
+ frags: [' ', join.type, ' ', render.ref(join.table), ' AS ', render.ref(join.alias), ' ON ', ...result.frags],
166
+ params: result.params,
167
+ };
168
+ }),
157
169
  /**
158
170
  * @private Expression rendering functions.
159
171
  * @since 0.1.0
@@ -357,6 +369,9 @@ const ddl = {
357
369
  * @version 1
358
370
  */
359
371
  select: (op) => {
372
+ const joins = op.joins && op.joins.length > 0
373
+ ? op.joins.reduce(collect(render.join), EMPTY_RENDER_RESULT)
374
+ : EMPTY_RENDER_RESULT;
360
375
  const where = op.where
361
376
  ? render.expr.any(op.where)
362
377
  : EMPTY_RENDER_RESULT;
@@ -376,6 +391,7 @@ const ddl = {
376
391
  render.ref(op.registry[op.from]),
377
392
  ' AS ',
378
393
  render.ref(op.from),
394
+ ...joins.frags,
379
395
  (where.frags.length > 0 ? ' WHERE ' : ''),
380
396
  ...where.frags,
381
397
  (orderBy.frags.length > 0 ? ' ORDER BY ' + orderBy.frags.join(', ') : ''),
@@ -383,7 +399,7 @@ const ddl = {
383
399
  ...offset.frags,
384
400
  ';'
385
401
  ];
386
- return { sql: frags.join(''), params: [...where.params, ...limit.params, ...offset.params] };
402
+ return { sql: frags.join(''), params: [...joins.params, ...where.params, ...limit.params, ...offset.params] };
387
403
  },
388
404
  };
389
405
  /**
@@ -473,6 +489,14 @@ class BunSQLite {
473
489
  const rows = stmt.all(...params);
474
490
  return rows.map(createDecoder(op.select));
475
491
  }
492
+ /**
493
+ * @public Executes a function within a transaction.
494
+ * @since 0.1.10
495
+ * @version 1
496
+ */
497
+ async transaction(fn) {
498
+ return await this.conn.transaction(fn)();
499
+ }
476
500
  }
477
501
  /**
478
502
  * @public Creates a connection to the database.
@@ -2,28 +2,28 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.defineMigrations = void 0;
4
4
  const index_1 = require("./index");
5
- const migrations = (0, index_1.table)('migrations', t => ({
5
+ const migrations = (0, index_1.table)('schema_migrations', t => ({
6
6
  id: t.string({ size: 36 }).primaryKey(),
7
- migratedAt: t.datetime(),
7
+ timestamp: t.datetime(),
8
8
  }));
9
9
  /**
10
- * @public Defines and runs migrations against the given database.
10
+ * @public Defines a set of migrations to be executed against a
11
+ * database.
11
12
  * @since 0.1.6
12
- * @version 1
13
+ * @version 2
13
14
  */
14
15
  const defineMigrations = (migs) => async (db) => {
15
16
  await index_1.create.table(migrations, { ifNotExists: true }).onto(db);
16
- for (const [id, migration] of Object.entries(migs)) {
17
+ for (const [id, migrate] of Object.entries(migs)) {
17
18
  const alreadyMigrated = await (0, index_1.from)(migrations.as('m'))
18
19
  .where(({ m }) => index_1.expr.eq(m.id, id))
19
20
  .exists(db);
20
21
  if (alreadyMigrated)
21
22
  continue;
22
- // @TODO run in a transaction
23
- await migration(db);
24
- await (0, index_1.into)(migrations)
25
- .insert({ id, migratedAt: new Date() })
26
- .run(db);
23
+ await (0, index_1.transaction)(db, async () => {
24
+ await migrate(db);
25
+ await (0, index_1.into)(migrations).insert({ id, timestamp: new Date() }).run(db);
26
+ });
27
27
  }
28
28
  };
29
29
  exports.defineMigrations = defineMigrations;
package/dist/cjs/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.t = exports.is = exports.into = exports.from = exports.expr = exports.table = exports.create = void 0;
3
+ exports.t = exports.transaction = exports.is = exports.into = exports.from = exports.expr = exports.table = exports.create = void 0;
4
4
  const std = require("./standard-schema");
5
5
  const u = require("./utils");
6
6
  // // // // // // // // // // // // // // // // // // // // // // // //
@@ -441,6 +441,16 @@ const is = {
441
441
  exports.is = is;
442
442
  ;
443
443
  // // // // // // // // // // // // // // // // // // // // // // // //
444
+ // TRANSACTION //
445
+ // // // // // // // // // // // // // // // // // // // // // // // //
446
+ /**
447
+ * @public Executes the given function within a transaction.
448
+ * @since 0.1.10
449
+ * @version 1
450
+ */
451
+ const transaction = async (db, fn) => db.transaction(fn);
452
+ exports.transaction = transaction;
453
+ // // // // // // // // // // // // // // // // // // // // // // // //
444
454
  // CREATE STATEMENTS //
445
455
  // // // // // // // // // // // // // // // // // // // // // // // //
446
456
  /**
@@ -609,6 +619,20 @@ class QueryBuilder {
609
619
  const results = await db.query(toSelectStatement({ ...this.query, limit: 1, offset: 0 }));
610
620
  return results.length > 0;
611
621
  }
622
+ /**
623
+ * @public Adds an INNER JOIN clause to the query.
624
+ * @since 0.1.9
625
+ * @version 1
626
+ */
627
+ innerJoin(table, on) {
628
+ const registry = { ...this.query.registry, [table[TABLE_ALIAS]]: table };
629
+ const join = { type: 'INNER JOIN', table: table[TABLE_NAME], alias: table[TABLE_ALIAS], on: on(registry) };
630
+ return new QueryBuilder({
631
+ ...this.query,
632
+ registry,
633
+ joins: [...(this.query.joins ?? []), join],
634
+ });
635
+ }
612
636
  /**
613
637
  * @public Sets a limit on the number of rows to be returned.
614
638
  * @since 0.1.0
@@ -151,6 +151,18 @@ const render = {
151
151
  const { frags, params } = render.expr.any(expr);
152
152
  return { frags: [[...frags, dir].join(' ')], params };
153
153
  },
154
+ /**
155
+ * @private Renders a join clause.
156
+ * @since 0.1.9
157
+ * @version 1
158
+ */
159
+ join: glue((join) => {
160
+ const result = render.expr.any(join.on);
161
+ return {
162
+ frags: [' ', join.type, ' ', render.ref(join.table), ' AS ', render.ref(join.alias), ' ON ', ...result.frags],
163
+ params: result.params,
164
+ };
165
+ }),
154
166
  /**
155
167
  * @private Expression rendering functions.
156
168
  * @since 0.1.0
@@ -354,6 +366,9 @@ const ddl = {
354
366
  * @version 1
355
367
  */
356
368
  select: (op) => {
369
+ const joins = op.joins && op.joins.length > 0
370
+ ? op.joins.reduce(collect(render.join), EMPTY_RENDER_RESULT)
371
+ : EMPTY_RENDER_RESULT;
357
372
  const where = op.where
358
373
  ? render.expr.any(op.where)
359
374
  : EMPTY_RENDER_RESULT;
@@ -373,6 +388,7 @@ const ddl = {
373
388
  render.ref(op.registry[op.from]),
374
389
  ' AS ',
375
390
  render.ref(op.from),
391
+ ...joins.frags,
376
392
  (where.frags.length > 0 ? ' WHERE ' : ''),
377
393
  ...where.frags,
378
394
  (orderBy.frags.length > 0 ? ' ORDER BY ' + orderBy.frags.join(', ') : ''),
@@ -380,7 +396,7 @@ const ddl = {
380
396
  ...offset.frags,
381
397
  ';'
382
398
  ];
383
- return { sql: frags.join(''), params: [...where.params, ...limit.params, ...offset.params] };
399
+ return { sql: frags.join(''), params: [...joins.params, ...where.params, ...limit.params, ...offset.params] };
384
400
  },
385
401
  };
386
402
  /**
@@ -470,6 +486,14 @@ class BunSQLite {
470
486
  const rows = stmt.all(...params);
471
487
  return rows.map(createDecoder(op.select));
472
488
  }
489
+ /**
490
+ * @public Executes a function within a transaction.
491
+ * @since 0.1.10
492
+ * @version 1
493
+ */
494
+ async transaction(fn) {
495
+ return await this.conn.transaction(fn)();
496
+ }
473
497
  }
474
498
  /**
475
499
  * @public Creates a connection to the database.
@@ -1,25 +1,25 @@
1
- import { create, expr, from, into, table } from './index';
2
- const migrations = table('migrations', t => ({
1
+ import { create, expr, from, into, table, transaction } from './index';
2
+ const migrations = table('schema_migrations', t => ({
3
3
  id: t.string({ size: 36 }).primaryKey(),
4
- migratedAt: t.datetime(),
4
+ timestamp: t.datetime(),
5
5
  }));
6
6
  /**
7
- * @public Defines and runs migrations against the given database.
7
+ * @public Defines a set of migrations to be executed against a
8
+ * database.
8
9
  * @since 0.1.6
9
- * @version 1
10
+ * @version 2
10
11
  */
11
12
  export const defineMigrations = (migs) => async (db) => {
12
13
  await create.table(migrations, { ifNotExists: true }).onto(db);
13
- for (const [id, migration] of Object.entries(migs)) {
14
+ for (const [id, migrate] of Object.entries(migs)) {
14
15
  const alreadyMigrated = await from(migrations.as('m'))
15
16
  .where(({ m }) => expr.eq(m.id, id))
16
17
  .exists(db);
17
18
  if (alreadyMigrated)
18
19
  continue;
19
- // @TODO run in a transaction
20
- await migration(db);
21
- await into(migrations)
22
- .insert({ id, migratedAt: new Date() })
23
- .run(db);
20
+ await transaction(db, async () => {
21
+ await migrate(db);
22
+ await into(migrations).insert({ id, timestamp: new Date() }).run(db);
23
+ });
24
24
  }
25
25
  };
package/dist/esm/index.js CHANGED
@@ -434,6 +434,15 @@ const is = {
434
434
  };
435
435
  ;
436
436
  // // // // // // // // // // // // // // // // // // // // // // // //
437
+ // TRANSACTION //
438
+ // // // // // // // // // // // // // // // // // // // // // // // //
439
+ /**
440
+ * @public Executes the given function within a transaction.
441
+ * @since 0.1.10
442
+ * @version 1
443
+ */
444
+ const transaction = async (db, fn) => db.transaction(fn);
445
+ // // // // // // // // // // // // // // // // // // // // // // // //
437
446
  // CREATE STATEMENTS //
438
447
  // // // // // // // // // // // // // // // // // // // // // // // //
439
448
  /**
@@ -600,6 +609,20 @@ class QueryBuilder {
600
609
  const results = await db.query(toSelectStatement({ ...this.query, limit: 1, offset: 0 }));
601
610
  return results.length > 0;
602
611
  }
612
+ /**
613
+ * @public Adds an INNER JOIN clause to the query.
614
+ * @since 0.1.9
615
+ * @version 1
616
+ */
617
+ innerJoin(table, on) {
618
+ const registry = { ...this.query.registry, [table[TABLE_ALIAS]]: table };
619
+ const join = { type: 'INNER JOIN', table: table[TABLE_NAME], alias: table[TABLE_ALIAS], on: on(registry) };
620
+ return new QueryBuilder({
621
+ ...this.query,
622
+ registry,
623
+ joins: [...(this.query.joins ?? []), join],
624
+ });
625
+ }
603
626
  /**
604
627
  * @public Sets a limit on the number of rows to be returned.
605
628
  * @since 0.1.0
@@ -674,4 +697,4 @@ const from = (table) => new QueryBuilder({
674
697
  // // // // // // // // // // // // // // // // // // // // // // // //
675
698
  // EXPORTS //
676
699
  // // // // // // // // // // // // // // // // // // // // // // // //
677
- export { create, defineTable as table, expr, from, into, is, types as t, };
700
+ export { create, defineTable as table, expr, from, into, is, transaction, types as t, };
@@ -37,6 +37,12 @@ declare class BunSQLite implements IDatabase {
37
37
  query(op: SelectStatement): Promise<{
38
38
  [k: string]: any;
39
39
  }[]>;
40
+ /**
41
+ * @public Executes a function within a transaction.
42
+ * @since 0.1.10
43
+ * @version 1
44
+ */
45
+ transaction<T>(fn: () => Promise<T>): Promise<T>;
40
46
  }
41
47
  /**
42
48
  * @public Creates a connection to the database.
@@ -6,9 +6,10 @@ import { type IDatabase } from './index';
6
6
  */
7
7
  type Migration = (db: IDatabase) => Promise<void>;
8
8
  /**
9
- * @public Defines and runs migrations against the given database.
9
+ * @public Defines a set of migrations to be executed against a
10
+ * database.
10
11
  * @since 0.1.6
11
- * @version 1
12
+ * @version 2
12
13
  */
13
14
  export declare const defineMigrations: (migs: Record<string, Migration>) => (db: IDatabase) => Promise<void>;
14
15
  export {};
@@ -871,6 +871,12 @@ type SelectStatement = {
871
871
  * @version 1
872
872
  */
873
873
  registry: Record<string, string>;
874
+ /**
875
+ * @public The query's selection.
876
+ * @since 0.1.0
877
+ * @version 1
878
+ */
879
+ select: Record<string, Column>;
874
880
  /**
875
881
  * @public The alias of the table from which to select.
876
882
  * @since 0.1.0
@@ -878,11 +884,11 @@ type SelectStatement = {
878
884
  */
879
885
  from: string;
880
886
  /**
881
- * @public The query's selection.
882
- * @since 0.1.0
887
+ * @public The query's join clauses.
888
+ * @since 0.1.9
883
889
  * @version 1
884
890
  */
885
- select: Record<string, Column>;
891
+ joins?: Join[];
886
892
  /**
887
893
  * @public The query's where clause.
888
894
  * @since 0.1.0
@@ -1009,7 +1015,19 @@ interface IDatabase {
1009
1015
  * @version 1
1010
1016
  */
1011
1017
  query(op: SelectStatement): Promise<any[]>;
1018
+ /**
1019
+ * @public Executes a function within a transaction.
1020
+ * @since 0.1.10
1021
+ * @version 1
1022
+ */
1023
+ transaction<T>(fn: () => Promise<T>): Promise<T>;
1012
1024
  }
1025
+ /**
1026
+ * @public Executes the given function within a transaction.
1027
+ * @since 0.1.10
1028
+ * @version 1
1029
+ */
1030
+ declare const transaction: <T>(db: IDatabase, fn: () => Promise<T>) => Promise<T>;
1013
1031
  /**
1014
1032
  * @public Create statement builder.
1015
1033
  * @since 0.1.0
@@ -1062,6 +1080,17 @@ declare class InsertBuilder<T extends Table> {
1062
1080
  * @version 1
1063
1081
  */
1064
1082
  declare const into: <T extends Table>(table: T) => InsertBuilder<T>;
1083
+ /**
1084
+ * @public Represents a join clause in a select statement.
1085
+ * @since 0.1.9
1086
+ * @version 1
1087
+ */
1088
+ type Join = {
1089
+ type: 'INNER JOIN' | 'LEFT OUTER JOIN' | 'RIGHT OUTER JOIN';
1090
+ table: string;
1091
+ alias: string;
1092
+ on: Expr;
1093
+ };
1065
1094
  /**
1066
1095
  * @private It's the object type for a query being built, that will
1067
1096
  * later been transformed into a {@link SelectStatement}.
@@ -1075,6 +1104,12 @@ type Query<T extends Record<string, Aliased<string, Table>> = Record<string, Ali
1075
1104
  * @version 1
1076
1105
  */
1077
1106
  registry: T;
1107
+ /**
1108
+ * @private The query's selection.
1109
+ * @since 0.1.0
1110
+ * @version 1
1111
+ */
1112
+ select: S;
1078
1113
  /**
1079
1114
  * @private The alias of the table from which to select.
1080
1115
  * @since 0.1.0
@@ -1082,11 +1117,11 @@ type Query<T extends Record<string, Aliased<string, Table>> = Record<string, Ali
1082
1117
  */
1083
1118
  from: string;
1084
1119
  /**
1085
- * @private The query's selection.
1086
- * @since 0.1.0
1120
+ * @private The query's join clauses.
1121
+ * @since 0.1.9
1087
1122
  * @version 1
1088
1123
  */
1089
- select: S;
1124
+ joins?: Join[];
1090
1125
  /**
1091
1126
  * @private The query's where clause.
1092
1127
  * @since 0.1.0
@@ -1147,6 +1182,14 @@ declare class QueryBuilder<T extends Record<string, Aliased<string, Table>>, S e
1147
1182
  * @version 1
1148
1183
  */
1149
1184
  exists(db: IDatabase): Promise<boolean>;
1185
+ /**
1186
+ * @public Adds an INNER JOIN clause to the query.
1187
+ * @since 0.1.9
1188
+ * @version 1
1189
+ */
1190
+ innerJoin<U extends Aliased<string, Table>>(table: U, on: (registry: Expand<T & {
1191
+ [K in U[typeof TABLE_ALIAS]]: U;
1192
+ }>) => Expr): QueryBuilder<Expand<T & { [K in U[typeof TABLE_ALIAS]]: U; }>, S>;
1150
1193
  /**
1151
1194
  * @public Sets a limit on the number of rows to be returned.
1152
1195
  * @since 0.1.0
@@ -1193,4 +1236,4 @@ declare class QueryBuilder<T extends Record<string, Aliased<string, Table>>, S e
1193
1236
  * @version 1
1194
1237
  */
1195
1238
  declare const from: <S extends string, T extends Aliased<S, Table>>(table: T) => QueryBuilder<{ [K in T[typeof TABLE_ALIAS]]: T; }, T>;
1196
- export { type CodecsRegistry, type Column, type CreateTableStatement, type DDL, type Expr, type ExprAnd, type ExprBinaryOp, type ExprEq, type ExprGt, type ExprGte, type ExprIn, type ExprIs, type ExprIsNot, type ExprLike, type ExprLiteral, type ExprLt, type ExprLte, type ExprNe, type ExprNot, type ExprNotIn, type ExprNotLike, type ExprOr, type IDatabase, type ILogger, type InsertStatement, type OrderDirection, type Primitive, type PrimitiveToNativeTypeFactory, type SelectStatement, type Table, create, defineTable as table, expr, from, into, is, types as t, };
1239
+ export { type CodecsRegistry, type Column, type CreateTableStatement, type DDL, type Expr, type ExprAnd, type ExprBinaryOp, type ExprEq, type ExprGt, type ExprGte, type ExprIn, type ExprIs, type ExprIsNot, type ExprLike, type ExprLiteral, type ExprLt, type ExprLte, type ExprNe, type ExprNot, type ExprNotIn, type ExprNotLike, type ExprOr, type IDatabase, type ILogger, type Join, type InsertStatement, type OrderDirection, type Primitive, type PrimitiveToNativeTypeFactory, type SelectStatement, type Table, create, defineTable as table, expr, from, into, is, transaction, types as t, };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rwillians/qx",
3
3
  "description": "A teeny tiny ORM for SQLite.",
4
- "version": "0.1.8",
4
+ "version": "0.1.10",
5
5
  "author": "Rafael Willians <me@rwillians.com>",
6
6
  "license": "MIT",
7
7
  "repository": {