@rwillians/qx 0.1.16 → 0.1.18

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.
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.is = exports.withLoggedQuery = void 0;
4
+ const u = require("./utils");
5
+ /**
6
+ * @public Wraps a function call that executes DDL with logging
7
+ * capabilities.
8
+ *
9
+ * A `debug` log is emitted before the function is executed,
10
+ * and an `error` log if the function throws an error. After
11
+ * logging, the error is re-thrown.
12
+ * @since 0.1.17
13
+ * @version 1
14
+ */
15
+ const withLoggedQuery = async (logger, data, fn) => {
16
+ const loggers = u.wrap(logger);
17
+ const { sql, params } = data;
18
+ loggers.forEach(logger => logger.debug(sql, params));
19
+ return Promise.resolve().then(() => fn(sql, params)).catch(error => {
20
+ loggers.forEach(logger => logger.error(sql, params, error));
21
+ return Promise.reject(error); // propagate the error without
22
+ // appending stack traces
23
+ });
24
+ };
25
+ exports.withLoggedQuery = withLoggedQuery;
26
+ var index_1 = require("./index");
27
+ Object.defineProperty(exports, "is", { enumerable: true, get: function () { return index_1.is; } });
@@ -4,7 +4,7 @@ exports.inmemory = exports.connect = void 0;
4
4
  const bun_sqlite_1 = require("bun:sqlite");
5
5
  const node_util_1 = require("node:util");
6
6
  const u = require("./utils");
7
- const index_1 = require("./index");
7
+ const adapter_1 = require("./adapter");
8
8
  /**
9
9
  * @private Mapping of qx's primitive types to SQLite native types.
10
10
  * @since 0.1.0
@@ -178,17 +178,17 @@ const render = {
178
178
  * @version 1
179
179
  */
180
180
  any: glue((value) => {
181
- if (index_1.is.binaryOp(value))
181
+ if (adapter_1.is.binaryOp(value))
182
182
  return render.expr.binaryOp(value);
183
- if (index_1.is.and(value))
183
+ if (adapter_1.is.and(value))
184
184
  return render.expr.and(value);
185
- if (index_1.is.or(value))
185
+ if (adapter_1.is.or(value))
186
186
  return render.expr.or(value);
187
- if (index_1.is.not(value))
187
+ if (adapter_1.is.not(value))
188
188
  return render.expr.not(value);
189
- if (index_1.is.column(value))
189
+ if (adapter_1.is.column(value))
190
190
  return render.expr.column(value);
191
- if (index_1.is.literal(value))
191
+ if (adapter_1.is.literal(value))
192
192
  return render.expr.literal(value);
193
193
  throw new Error(`Unsupported expression type: ${(0, node_util_1.inspect)(value)}`);
194
194
  }),
@@ -260,15 +260,15 @@ const render = {
260
260
  * @version 1
261
261
  */
262
262
  literal: glue((value) => {
263
- if (index_1.is.null(value))
263
+ if (adapter_1.is.null(value))
264
264
  return render.expr.null();
265
- if (index_1.is.boolean(value))
265
+ if (adapter_1.is.boolean(value))
266
266
  return render.expr.boolean(value);
267
- if (index_1.is.date(value))
267
+ if (adapter_1.is.date(value))
268
268
  return render.expr.date(value);
269
- if (index_1.is.number(value))
269
+ if (adapter_1.is.number(value))
270
270
  return render.expr.number(value);
271
- if (index_1.is.string(value))
271
+ if (adapter_1.is.string(value))
272
272
  return render.expr.string(value);
273
273
  throw new Error(`Unsupported literal expression: ${(0, node_util_1.inspect)(value)}`);
274
274
  }),
@@ -457,9 +457,8 @@ class BunSQLite {
457
457
  * @version 1
458
458
  */
459
459
  async createTable(op) {
460
- const { sql } = ddl.createTable(op);
461
- this.loggers.forEach(logger => logger.query.debug(sql, []));
462
- this.conn.run(sql);
460
+ const { sql, params } = ddl.createTable(op);
461
+ await (0, adapter_1.withLoggedQuery)(this.loggers, { sql, params }, () => this.conn.run(sql));
463
462
  }
464
463
  /**
465
464
  * @public Executes an insert statement.
@@ -472,9 +471,9 @@ class BunSQLite {
472
471
  records: op.records.map(createEncoder(op.insertShape)),
473
472
  insertShape: u.mapKeys(op.insertShape, u.snakeCase),
474
473
  });
475
- this.loggers.forEach(logger => logger.query.debug(sql, params));
476
- const stmt = this.conn.prepare(sql);
477
- const rows = stmt.all(...params);
474
+ const rows = await (0, adapter_1.withLoggedQuery)(this.loggers, { sql, params }, () => this.conn
475
+ .prepare(sql)
476
+ .all(...params));
478
477
  return rows.map(createDecoder(op.returnShape));
479
478
  }
480
479
  /**
@@ -484,9 +483,9 @@ class BunSQLite {
484
483
  */
485
484
  async query(op) {
486
485
  const { sql, params } = ddl.select(op);
487
- this.loggers.forEach(logger => logger.query.debug(sql, params));
488
- const stmt = this.conn.prepare(sql);
489
- const rows = stmt.all(...params);
486
+ const rows = await (0, adapter_1.withLoggedQuery)(this.loggers, { sql, params }, () => this.conn
487
+ .prepare(sql)
488
+ .all(...params));
490
489
  return rows.map(createDecoder(op.select));
491
490
  }
492
491
  /**
@@ -495,7 +494,7 @@ class BunSQLite {
495
494
  * @version 1
496
495
  */
497
496
  async transaction(fn) {
498
- return await this.conn.transaction(fn)();
497
+ return this.conn.transaction(fn)();
499
498
  }
500
499
  }
501
500
  /**
@@ -506,7 +505,7 @@ class BunSQLite {
506
505
  const connect = (...args) => new BunSQLite(new bun_sqlite_1.Database(...args));
507
506
  exports.connect = connect;
508
507
  /**
509
- * @public An in-memory database connection.
508
+ * @public Creates a connection to an in-memory database.
510
509
  * @since 0.1.12
511
510
  * @version 2
512
511
  */
@@ -8,9 +8,7 @@ const node_util_1 = require("node:util");
8
8
  * @version 2
9
9
  */
10
10
  const createConsoleLogger = () => ({
11
- query: {
12
- debug: (sql, params) => { process.stdout.write(sql + ' ' + (0, node_util_1.inspect)(params, false, null, true) + '\n'); },
13
- error: (sql, params) => { process.stderr.write(sql + ' ' + (0, node_util_1.inspect)(params, false, null, true) + '\n'); },
14
- },
11
+ debug: (sql, params) => { process.stdout.write(sql + ' ' + (0, node_util_1.inspect)(params, false, null, true) + '\n'); },
12
+ error: (sql, params) => { process.stderr.write(sql + ' ' + (0, node_util_1.inspect)(params, false, null, true) + '\n'); },
15
13
  });
16
14
  exports.createConsoleLogger = createConsoleLogger;
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defineMigrations = void 0;
4
+ const index_1 = require("./index");
5
+ // // // // // // // // // // // // // // // // // // // // // // // //
6
+ // CREATE STATEMENTS //
7
+ // // // // // // // // // // // // // // // // // // // // // // // //
8
+ /**
9
+ * @public Create statement builder.
10
+ * @since 0.1.0
11
+ * @version 1
12
+ */
13
+ const create = {
14
+ /**
15
+ * @public Prepares a create table statement.
16
+ * @since 0.1.0
17
+ * @version 1
18
+ */
19
+ table: (table, options = {}) => ({
20
+ /**
21
+ * @public Executes the create table statement onto the given
22
+ * database.
23
+ * @since 0.1.0
24
+ * @version 1
25
+ */
26
+ onto: async (db) => db.createTable({
27
+ ...options,
28
+ table: table.name,
29
+ columns: Object.values(table.columns),
30
+ }),
31
+ }),
32
+ };
33
+ // // // // // // // // // // // // // // // // // // // // // // // //
34
+ // MIGRATIONS MANAGEMENT //
35
+ // // // // // // // // // // // // // // // // // // // // // // // //
36
+ /**
37
+ * @private Defines the schema migrations table.
38
+ * @since 0.1.6
39
+ * @version 1
40
+ */
41
+ const migrations = (0, index_1.table)('schema_migrations', t => ({
42
+ id: t.string({ size: 36 }).primaryKey(),
43
+ timestamp: t.datetime(),
44
+ }));
45
+ /**
46
+ * @public Defines a set of migrations to be executed against a
47
+ * database.
48
+ * @since 0.1.6
49
+ * @version 2
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * // src/db/migrations.ts
54
+ * import { create, defineMigrations } from '@rwillians/qx/experimental-migrations';
55
+ * import { users } from './users';
56
+ * import { profiles } from './profiles';
57
+ *
58
+ * export const migrate = defineMigrations({
59
+ * '0001': async (db) => {
60
+ * await create.table(users).onto(db);
61
+ * },
62
+ * '0002': async (db) => {
63
+ * await create.table(profiles).onto(db);
64
+ * },
65
+ * });
66
+ *
67
+ * // src/index.ts
68
+ * import * as sqlite from '@rwillians/qx/bun-sqlite';
69
+ * import { migrate } from './db/migrations';
70
+ *
71
+ * const db = sqlite.connect('./db.sqlite');
72
+ * await migrate(db)
73
+ * ```
74
+ */
75
+ const defineMigrations = (migs) => async (db) => {
76
+ await create.table(migrations, { ifNotExists: true }).onto(db);
77
+ const { mostRecentId } = await (0, index_1.from)(migrations.as('m'))
78
+ .orderBy(({ m }) => [index_1.expr.desc(m.timestamp)])
79
+ .select(({ m }) => ({ mostRecentId: m.id }))
80
+ .one(db) || { mostRecentId: '' };
81
+ for (const [id, migrate] of Object.entries(migs)) {
82
+ if (id <= mostRecentId)
83
+ continue;
84
+ await (0, index_1.transaction)(db, async () => {
85
+ await migrate(db);
86
+ await (0, index_1.into)(migrations).values({ id, timestamp: new Date() }).insert(db);
87
+ });
88
+ }
89
+ };
90
+ 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.transaction = 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 = void 0;
4
4
  const std = require("./standard-schema");
5
5
  const u = require("./utils");
6
6
  // // // // // // // // // // // // // // // // // // // // // // // //
@@ -471,35 +471,6 @@ exports.is = is;
471
471
  const transaction = async (db, fn) => db.transaction(fn);
472
472
  exports.transaction = transaction;
473
473
  // // // // // // // // // // // // // // // // // // // // // // // //
474
- // CREATE STATEMENTS //
475
- // // // // // // // // // // // // // // // // // // // // // // // //
476
- /**
477
- * @public Create statement builder.
478
- * @since 0.1.0
479
- * @version 1
480
- */
481
- const create = {
482
- /**
483
- * @public Prepares a create table statement.
484
- * @since 0.1.0
485
- * @version 1
486
- */
487
- table: (table, options = {}) => ({
488
- /**
489
- * @public Executes the create table statement onto the given
490
- * database.
491
- * @since 0.1.0
492
- * @version 1
493
- */
494
- onto: async (db) => db.createTable({
495
- ...options,
496
- table: table.name,
497
- columns: Object.values(table.columns),
498
- }),
499
- }),
500
- };
501
- exports.create = create;
502
- // // // // // // // // // // // // // // // // // // // // // // // //
503
474
  // INSERT STATEMENT //
504
475
  // // // // // // // // // // // // // // // // // // // // // // // //
505
476
  /**
package/dist/cjs/utils.js CHANGED
@@ -1,13 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.wrap = exports.snakeCase = exports.resolve = exports.mapValues = exports.mapKeys = exports.lte = exports.isPlainObject = exports.camelCase = void 0;
3
+ exports.wrap = exports.snakeCase = exports.resolve = exports.mapValues = exports.mapKeys = exports.lte = exports.keys = exports.isPlainObject = exports.entries = exports.camelCase = void 0;
4
4
  /**
5
5
  * @private Converts a snake_case string to camelCase.
6
6
  * @since 0.1.0
7
- * @version 1
7
+ * @version 2
8
8
  */
9
9
  const camelCase = (str) => str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
10
10
  exports.camelCase = camelCase;
11
+ /**
12
+ * @private Same as {@link Object.prototype.entries} but with better
13
+ * types.
14
+ * @since 0.1.17
15
+ * @version 1
16
+ */
17
+ const entries = (obj) => Object.entries(obj);
18
+ exports.entries = entries;
11
19
  /**
12
20
  * @private Simplified check for plain objects.
13
21
  * @since 0.1.0
@@ -22,6 +30,14 @@ const isPlainObject = (value) => {
22
30
  return proto === Object.prototype;
23
31
  };
24
32
  exports.isPlainObject = isPlainObject;
33
+ /**
34
+ * @private Same as {@link Object.prototype.keys} but with better
35
+ * types.
36
+ * @since 0.1.17
37
+ * @version 1
38
+ */
39
+ const keys = (obj) => Object.keys(obj);
40
+ exports.keys = keys;
25
41
  /**
26
42
  * @private Throws an error if the given number is greater than the
27
43
  * specified maximum.
@@ -39,14 +55,14 @@ exports.lte = lte;
39
55
  * @since 0.1.0
40
56
  * @version 1
41
57
  */
42
- const mapKeys = (obj, fn) => Object.fromEntries(Object.entries(obj).map(([key, value]) => [fn(key), value]));
58
+ const mapKeys = (obj, fn) => Object.fromEntries((0, exports.entries)(obj).map(([key, value]) => [fn(key), value]));
43
59
  exports.mapKeys = mapKeys;
44
60
  /**
45
61
  * @private Maps over the values of an object.
46
62
  * @since 0.1.0
47
63
  * @version 1
48
64
  */
49
- const mapValues = (obj, fn) => Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, fn(value, key)]));
65
+ const mapValues = (obj, fn) => Object.fromEntries((0, exports.entries)(obj).map(([key, value]) => [key, fn(value, key)]));
50
66
  exports.mapValues = mapValues;
51
67
  /**
52
68
  * @private Resolves the given value or function to a value.
@@ -0,0 +1,23 @@
1
+ import {} from './index';
2
+ import * as u from './utils';
3
+ /**
4
+ * @public Wraps a function call that executes DDL with logging
5
+ * capabilities.
6
+ *
7
+ * A `debug` log is emitted before the function is executed,
8
+ * and an `error` log if the function throws an error. After
9
+ * logging, the error is re-thrown.
10
+ * @since 0.1.17
11
+ * @version 1
12
+ */
13
+ export const withLoggedQuery = async (logger, data, fn) => {
14
+ const loggers = u.wrap(logger);
15
+ const { sql, params } = data;
16
+ loggers.forEach(logger => logger.debug(sql, params));
17
+ return Promise.resolve().then(() => fn(sql, params)).catch(error => {
18
+ loggers.forEach(logger => logger.error(sql, params, error));
19
+ return Promise.reject(error); // propagate the error without
20
+ // appending stack traces
21
+ });
22
+ };
23
+ export { is, } from './index';
@@ -1,7 +1,7 @@
1
1
  import { Database } from 'bun:sqlite';
2
2
  import { inspect } from 'node:util';
3
3
  import * as u from './utils';
4
- import { is, } from './index';
4
+ import { is, withLoggedQuery, } from './adapter';
5
5
  /**
6
6
  * @private Mapping of qx's primitive types to SQLite native types.
7
7
  * @since 0.1.0
@@ -454,9 +454,8 @@ class BunSQLite {
454
454
  * @version 1
455
455
  */
456
456
  async createTable(op) {
457
- const { sql } = ddl.createTable(op);
458
- this.loggers.forEach(logger => logger.query.debug(sql, []));
459
- this.conn.run(sql);
457
+ const { sql, params } = ddl.createTable(op);
458
+ await withLoggedQuery(this.loggers, { sql, params }, () => this.conn.run(sql));
460
459
  }
461
460
  /**
462
461
  * @public Executes an insert statement.
@@ -469,9 +468,9 @@ class BunSQLite {
469
468
  records: op.records.map(createEncoder(op.insertShape)),
470
469
  insertShape: u.mapKeys(op.insertShape, u.snakeCase),
471
470
  });
472
- this.loggers.forEach(logger => logger.query.debug(sql, params));
473
- const stmt = this.conn.prepare(sql);
474
- const rows = stmt.all(...params);
471
+ const rows = await withLoggedQuery(this.loggers, { sql, params }, () => this.conn
472
+ .prepare(sql)
473
+ .all(...params));
475
474
  return rows.map(createDecoder(op.returnShape));
476
475
  }
477
476
  /**
@@ -481,9 +480,9 @@ class BunSQLite {
481
480
  */
482
481
  async query(op) {
483
482
  const { sql, params } = ddl.select(op);
484
- this.loggers.forEach(logger => logger.query.debug(sql, params));
485
- const stmt = this.conn.prepare(sql);
486
- const rows = stmt.all(...params);
483
+ const rows = await withLoggedQuery(this.loggers, { sql, params }, () => this.conn
484
+ .prepare(sql)
485
+ .all(...params));
487
486
  return rows.map(createDecoder(op.select));
488
487
  }
489
488
  /**
@@ -492,7 +491,7 @@ class BunSQLite {
492
491
  * @version 1
493
492
  */
494
493
  async transaction(fn) {
495
- return await this.conn.transaction(fn)();
494
+ return this.conn.transaction(fn)();
496
495
  }
497
496
  }
498
497
  /**
@@ -502,7 +501,7 @@ class BunSQLite {
502
501
  */
503
502
  const connect = (...args) => new BunSQLite(new Database(...args));
504
503
  /**
505
- * @public An in-memory database connection.
504
+ * @public Creates a connection to an in-memory database.
506
505
  * @since 0.1.12
507
506
  * @version 2
508
507
  */
@@ -6,8 +6,6 @@ import {} from './index';
6
6
  * @version 2
7
7
  */
8
8
  export const createConsoleLogger = () => ({
9
- query: {
10
- debug: (sql, params) => { process.stdout.write(sql + ' ' + inspect(params, false, null, true) + '\n'); },
11
- error: (sql, params) => { process.stderr.write(sql + ' ' + inspect(params, false, null, true) + '\n'); },
12
- },
9
+ debug: (sql, params) => { process.stdout.write(sql + ' ' + inspect(params, false, null, true) + '\n'); },
10
+ error: (sql, params) => { process.stderr.write(sql + ' ' + inspect(params, false, null, true) + '\n'); },
13
11
  });
@@ -0,0 +1,86 @@
1
+ import { expr, from, into, table, transaction, } from './index';
2
+ // // // // // // // // // // // // // // // // // // // // // // // //
3
+ // CREATE STATEMENTS //
4
+ // // // // // // // // // // // // // // // // // // // // // // // //
5
+ /**
6
+ * @public Create statement builder.
7
+ * @since 0.1.0
8
+ * @version 1
9
+ */
10
+ const create = {
11
+ /**
12
+ * @public Prepares a create table statement.
13
+ * @since 0.1.0
14
+ * @version 1
15
+ */
16
+ table: (table, options = {}) => ({
17
+ /**
18
+ * @public Executes the create table statement onto the given
19
+ * database.
20
+ * @since 0.1.0
21
+ * @version 1
22
+ */
23
+ onto: async (db) => db.createTable({
24
+ ...options,
25
+ table: table.name,
26
+ columns: Object.values(table.columns),
27
+ }),
28
+ }),
29
+ };
30
+ // // // // // // // // // // // // // // // // // // // // // // // //
31
+ // MIGRATIONS MANAGEMENT //
32
+ // // // // // // // // // // // // // // // // // // // // // // // //
33
+ /**
34
+ * @private Defines the schema migrations table.
35
+ * @since 0.1.6
36
+ * @version 1
37
+ */
38
+ const migrations = table('schema_migrations', t => ({
39
+ id: t.string({ size: 36 }).primaryKey(),
40
+ timestamp: t.datetime(),
41
+ }));
42
+ /**
43
+ * @public Defines a set of migrations to be executed against a
44
+ * database.
45
+ * @since 0.1.6
46
+ * @version 2
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * // src/db/migrations.ts
51
+ * import { create, defineMigrations } from '@rwillians/qx/experimental-migrations';
52
+ * import { users } from './users';
53
+ * import { profiles } from './profiles';
54
+ *
55
+ * export const migrate = defineMigrations({
56
+ * '0001': async (db) => {
57
+ * await create.table(users).onto(db);
58
+ * },
59
+ * '0002': async (db) => {
60
+ * await create.table(profiles).onto(db);
61
+ * },
62
+ * });
63
+ *
64
+ * // src/index.ts
65
+ * import * as sqlite from '@rwillians/qx/bun-sqlite';
66
+ * import { migrate } from './db/migrations';
67
+ *
68
+ * const db = sqlite.connect('./db.sqlite');
69
+ * await migrate(db)
70
+ * ```
71
+ */
72
+ export const defineMigrations = (migs) => async (db) => {
73
+ await create.table(migrations, { ifNotExists: true }).onto(db);
74
+ const { mostRecentId } = await from(migrations.as('m'))
75
+ .orderBy(({ m }) => [expr.desc(m.timestamp)])
76
+ .select(({ m }) => ({ mostRecentId: m.id }))
77
+ .one(db) || { mostRecentId: '' };
78
+ for (const [id, migrate] of Object.entries(migs)) {
79
+ if (id <= mostRecentId)
80
+ continue;
81
+ await transaction(db, async () => {
82
+ await migrate(db);
83
+ await into(migrations).values({ id, timestamp: new Date() }).insert(db);
84
+ });
85
+ }
86
+ };
package/dist/esm/index.js CHANGED
@@ -463,34 +463,6 @@ const is = {
463
463
  */
464
464
  const transaction = async (db, fn) => db.transaction(fn);
465
465
  // // // // // // // // // // // // // // // // // // // // // // // //
466
- // CREATE STATEMENTS //
467
- // // // // // // // // // // // // // // // // // // // // // // // //
468
- /**
469
- * @public Create statement builder.
470
- * @since 0.1.0
471
- * @version 1
472
- */
473
- const create = {
474
- /**
475
- * @public Prepares a create table statement.
476
- * @since 0.1.0
477
- * @version 1
478
- */
479
- table: (table, options = {}) => ({
480
- /**
481
- * @public Executes the create table statement onto the given
482
- * database.
483
- * @since 0.1.0
484
- * @version 1
485
- */
486
- onto: async (db) => db.createTable({
487
- ...options,
488
- table: table.name,
489
- columns: Object.values(table.columns),
490
- }),
491
- }),
492
- };
493
- // // // // // // // // // // // // // // // // // // // // // // // //
494
466
  // INSERT STATEMENT //
495
467
  // // // // // // // // // // // // // // // // // // // // // // // //
496
468
  /**
@@ -717,4 +689,4 @@ const from = (table) => new QueryBuilder({
717
689
  // // // // // // // // // // // // // // // // // // // // // // // //
718
690
  // EXPORTS //
719
691
  // // // // // // // // // // // // // // // // // // // // // // // //
720
- export { create, defineTable as table, expr, from, into, is, transaction, types as t, };
692
+ export { defineTable as table, expr, from, into, is, transaction, types as t, };
package/dist/esm/utils.js CHANGED
@@ -1,9 +1,16 @@
1
1
  /**
2
2
  * @private Converts a snake_case string to camelCase.
3
3
  * @since 0.1.0
4
- * @version 1
4
+ * @version 2
5
5
  */
6
6
  export const camelCase = (str) => str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
7
+ /**
8
+ * @private Same as {@link Object.prototype.entries} but with better
9
+ * types.
10
+ * @since 0.1.17
11
+ * @version 1
12
+ */
13
+ export const entries = (obj) => Object.entries(obj);
7
14
  /**
8
15
  * @private Simplified check for plain objects.
9
16
  * @since 0.1.0
@@ -17,6 +24,13 @@ export const isPlainObject = (value) => {
17
24
  return true;
18
25
  return proto === Object.prototype;
19
26
  };
27
+ /**
28
+ * @private Same as {@link Object.prototype.keys} but with better
29
+ * types.
30
+ * @since 0.1.17
31
+ * @version 1
32
+ */
33
+ export const keys = (obj) => Object.keys(obj);
20
34
  /**
21
35
  * @private Throws an error if the given number is greater than the
22
36
  * specified maximum.
@@ -33,13 +47,13 @@ export const lte = (n, max) => {
33
47
  * @since 0.1.0
34
48
  * @version 1
35
49
  */
36
- export const mapKeys = (obj, fn) => Object.fromEntries(Object.entries(obj).map(([key, value]) => [fn(key), value]));
50
+ export const mapKeys = (obj, fn) => Object.fromEntries(entries(obj).map(([key, value]) => [fn(key), value]));
37
51
  /**
38
52
  * @private Maps over the values of an object.
39
53
  * @since 0.1.0
40
54
  * @version 1
41
55
  */
42
- export const mapValues = (obj, fn) => Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, fn(value, key)]));
56
+ export const mapValues = (obj, fn) => Object.fromEntries(entries(obj).map(([key, value]) => [key, fn(value, key)]));
43
57
  /**
44
58
  * @private Resolves the given value or function to a value.
45
59
  * @since 0.1.0
@@ -0,0 +1,16 @@
1
+ import { type ILogger } from './index';
2
+ /**
3
+ * @public Wraps a function call that executes DDL with logging
4
+ * capabilities.
5
+ *
6
+ * A `debug` log is emitted before the function is executed,
7
+ * and an `error` log if the function throws an error. After
8
+ * logging, the error is re-thrown.
9
+ * @since 0.1.17
10
+ * @version 1
11
+ */
12
+ export declare const withLoggedQuery: <T>(logger: ILogger | ILogger[], data: {
13
+ sql: string;
14
+ params: any[];
15
+ }, fn: (sql: string, params: any[]) => Promise<T> | T) => Promise<T>;
16
+ export { type CodecsRegistry, type Column, type CreateTableStatement, type DDL, type Expr, type ExprAnd, type ExprBinaryOp, type ExprLiteral, type ExprNot, type ExprOr, type IDatabase, type ILogger, type InsertStatement, type Join, type OrderDirection, type PrimitiveToNativeTypeFactory, type SelectStatement, is, } from './index';
@@ -1,5 +1,5 @@
1
1
  import { Database } from 'bun:sqlite';
2
- import { type CreateTableStatement, type IDatabase, type ILogger, type InsertStatement, type SelectStatement } from './index';
2
+ import { type CreateTableStatement, type IDatabase, type ILogger, type InsertStatement, type SelectStatement } from './adapter';
3
3
  /**
4
4
  * @private Bun SQLite database adapter implementation.
5
5
  * @since 0.1.0
@@ -51,7 +51,7 @@ declare class BunSQLite implements IDatabase {
51
51
  */
52
52
  declare const connect: (...args: ConstructorParameters<typeof Database>) => BunSQLite;
53
53
  /**
54
- * @public An in-memory database connection.
54
+ * @public Creates a connection to an in-memory database.
55
55
  * @since 0.1.12
56
56
  * @version 2
57
57
  */
@@ -0,0 +1,39 @@
1
+ import { type IDatabase } from './index';
2
+ /**
3
+ * @private Defines the type for a migration function.
4
+ * @since 0.1.6
5
+ * @version 1
6
+ */
7
+ type Migration = (db: IDatabase) => Promise<void>;
8
+ /**
9
+ * @public Defines a set of migrations to be executed against a
10
+ * database.
11
+ * @since 0.1.6
12
+ * @version 2
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * // src/db/migrations.ts
17
+ * import { create, defineMigrations } from '@rwillians/qx/experimental-migrations';
18
+ * import { users } from './users';
19
+ * import { profiles } from './profiles';
20
+ *
21
+ * export const migrate = defineMigrations({
22
+ * '0001': async (db) => {
23
+ * await create.table(users).onto(db);
24
+ * },
25
+ * '0002': async (db) => {
26
+ * await create.table(profiles).onto(db);
27
+ * },
28
+ * });
29
+ *
30
+ * // src/index.ts
31
+ * import * as sqlite from '@rwillians/qx/bun-sqlite';
32
+ * import { migrate } from './db/migrations';
33
+ *
34
+ * const db = sqlite.connect('./db.sqlite');
35
+ * await migrate(db)
36
+ * ```
37
+ */
38
+ export declare const defineMigrations: (migs: Record<string, Migration>) => (db: IDatabase) => Promise<void>;
39
+ export {};
@@ -802,6 +802,25 @@ declare const is: {
802
802
  */
803
803
  column: (expr: Expr) => expr is Column;
804
804
  };
805
+ /**
806
+ * @public Query logger interface.
807
+ * @since 0.1.0
808
+ * @version 2
809
+ */
810
+ interface ILogger {
811
+ /**
812
+ * @public Logs a query that has executed successfully.
813
+ * @since 0.1.17
814
+ * @version 1
815
+ */
816
+ debug(sql: string, params: any[]): void;
817
+ /**
818
+ * @public Logs a query that has failed with an error.
819
+ * @since 0.1.12
820
+ * @version 2
821
+ */
822
+ error(sql: string, params: any[], error?: Error): void;
823
+ }
805
824
  /**
806
825
  * @public Represents the direction of ordering in an ORDER BY
807
826
  * clause.
@@ -977,33 +996,6 @@ type DDL = {
977
996
  sql: string;
978
997
  params: any[];
979
998
  };
980
- /**
981
- * @public Query logger interface.
982
- * @since 0.1.0
983
- * @version 1
984
- */
985
- interface ILogger {
986
- /**
987
- * @public Query specific logging methods, so this interface plays
988
- * nice with existing logging libraries (by extending them).
989
- * @since 0.1.0
990
- * @version 1
991
- */
992
- query: {
993
- /**
994
- * @public Logs a query that has executed successfully.
995
- * @since 0.1.0
996
- * @version 1
997
- */
998
- debug(sql: string, params: any[]): void;
999
- /**
1000
- * @public Logs a query that has failed with an error.
1001
- * @since 0.1.12
1002
- * @version 1
1003
- */
1004
- error(sql: string, params: any[], error: Error): void;
1005
- };
1006
- }
1007
999
  /**
1008
1000
  * @public The interface that all database adapters must implement.
1009
1001
  * @since 0.1.0
@@ -1048,30 +1040,6 @@ interface IDatabase {
1048
1040
  * @version 1
1049
1041
  */
1050
1042
  declare const transaction: <T>(db: IDatabase, fn: () => Promise<T>) => Promise<T>;
1051
- /**
1052
- * @public Create statement builder.
1053
- * @since 0.1.0
1054
- * @version 1
1055
- */
1056
- declare const create: {
1057
- /**
1058
- * @public Prepares a create table statement.
1059
- * @since 0.1.0
1060
- * @version 1
1061
- */
1062
- table: <T extends Table, S extends {
1063
- ifNotExists?: true;
1064
- unlogged?: true;
1065
- }>(table: T, options?: S) => {
1066
- /**
1067
- * @public Executes the create table statement onto the given
1068
- * database.
1069
- * @since 0.1.0
1070
- * @version 1
1071
- */
1072
- onto: (db: IDatabase) => Promise<void>;
1073
- };
1074
- };
1075
1043
  /**
1076
1044
  * @public Insert statement builder.
1077
1045
  * @since 0.1.0
@@ -1256,4 +1224,4 @@ declare class QueryBuilder<T extends Record<string, Aliased<string, Table>>, S e
1256
1224
  * @version 1
1257
1225
  */
1258
1226
  declare const from: <S extends string, T extends Aliased<S, Table>>(table: T) => QueryBuilder<{ [K in T[typeof TABLE_ALIAS]]: T; }, T>;
1259
- 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, };
1227
+ 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, defineTable as table, expr, from, into, is, transaction, types as t, };
@@ -1,15 +1,43 @@
1
+ /**
2
+ * @private Converts a snake_case string to camelCase at the type
3
+ * level.
4
+ * @since 0.1.17
5
+ * @version 1
6
+ */
7
+ type CamelCase<S extends string> = S extends `${infer T}_${infer U}` ? `${T}${Capitalize<CamelCase<U>>}` : S;
8
+ /**
9
+ * @private Converts a camelCase string to snake_case at the type
10
+ * level.
11
+ * @since 0.1.17
12
+ * @version 1
13
+ */
14
+ type SnakeCase<S extends string> = S extends `${infer T}${infer U}` ? U extends Uncapitalize<U> ? `${Lowercase<T>}${SnakeCase<U>}` : `${Lowercase<T>}_${SnakeCase<Uncapitalize<U>>}` : S;
1
15
  /**
2
16
  * @private Converts a snake_case string to camelCase.
3
17
  * @since 0.1.0
18
+ * @version 2
19
+ */
20
+ export declare const camelCase: <T extends string>(str: T) => CamelCase<T>;
21
+ /**
22
+ * @private Same as {@link Object.prototype.entries} but with better
23
+ * types.
24
+ * @since 0.1.17
4
25
  * @version 1
5
26
  */
6
- export declare const camelCase: (str: string) => string;
27
+ export declare const entries: <T extends Record<string, any>>(obj: T) => [keyof T, T[keyof T]][];
7
28
  /**
8
29
  * @private Simplified check for plain objects.
9
30
  * @since 0.1.0
10
31
  * @version 1
11
32
  */
12
33
  export declare const isPlainObject: (value: unknown) => value is Record<string, any>;
34
+ /**
35
+ * @private Same as {@link Object.prototype.keys} but with better
36
+ * types.
37
+ * @since 0.1.17
38
+ * @version 1
39
+ */
40
+ export declare const keys: <T extends Record<string, any>>(obj: T) => (keyof T)[];
13
41
  /**
14
42
  * @private Throws an error if the given number is greater than the
15
43
  * specified maximum.
@@ -40,7 +68,7 @@ export declare const resolve: <T>(value: T | (() => T)) => T;
40
68
  * @since 0.1.0
41
69
  * @version 1
42
70
  */
43
- export declare const snakeCase: (str: string) => string;
71
+ export declare const snakeCase: <T extends string>(str: T) => SnakeCase<T>;
44
72
  /**
45
73
  * @public Wraps the given value in an array, unless it's already an
46
74
  * array.
@@ -48,3 +76,4 @@ export declare const snakeCase: (str: string) => string;
48
76
  * @version 1
49
77
  */
50
78
  export declare const wrap: <T>(value: T | T[]) => T[];
79
+ export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rwillians/qx",
3
- "description": "A teeny tiny ORM for SQLite.",
4
- "version": "0.1.16",
3
+ "description": "A zero-dependencies teeny tiny ORM for SQLite.",
4
+ "version": "0.1.18",
5
5
  "author": "Rafael Willians <me@rwillians.com>",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -21,7 +21,8 @@
21
21
  "bun"
22
22
  ],
23
23
  "type": "module",
24
- "module": "dist/index.js",
24
+ "module": "dist/esm/index.js",
25
+ "main": "dist/cjs/index.js",
25
26
  "files": ["dist/", "LICENSE"],
26
27
  "exports": {
27
28
  ".": {
@@ -30,6 +31,12 @@
30
31
  "require": "./dist/cjs/index.js",
31
32
  "default": "./dist/cjs/index.js"
32
33
  },
34
+ "./adapter": {
35
+ "types": "./dist/types/adapter.d.ts",
36
+ "import": "./dist/esm/adapter.js",
37
+ "require": "./dist/cjs/adapter.js",
38
+ "default": "./dist/cjs/adapter.js"
39
+ },
33
40
  "./bun-sqlite": {
34
41
  "types": "./dist/types/bun-sqlite.d.ts",
35
42
  "import": "./dist/esm/bun-sqlite.js",
@@ -42,11 +49,11 @@
42
49
  "require": "./dist/cjs/console-logger.js",
43
50
  "default": "./dist/cjs/console-logger.js"
44
51
  },
45
- "./experimental-migration": {
46
- "types": "./dist/types/experimental-migration.d.ts",
47
- "import": "./dist/esm/experimental-migration.js",
48
- "require": "./dist/cjs/experimental-migration.js",
49
- "default": "./dist/cjs/experimental-migration.js"
52
+ "./experimental-migrations": {
53
+ "types": "./dist/types/experimental-migrations.d.ts",
54
+ "import": "./dist/esm/experimental-migrations.js",
55
+ "require": "./dist/cjs/experimental-migrations.js",
56
+ "default": "./dist/cjs/experimental-migrations.js"
50
57
  }
51
58
  },
52
59
  "scripts": {
@@ -1,30 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.defineMigrations = void 0;
4
- const index_1 = require("./index");
5
- const migrations = (0, index_1.table)('schema_migrations', t => ({
6
- id: t.string({ size: 36 }).primaryKey(),
7
- timestamp: t.datetime(),
8
- }));
9
- /**
10
- * @public Defines a set of migrations to be executed against a
11
- * database.
12
- * @since 0.1.6
13
- * @version 2
14
- */
15
- const defineMigrations = (migs) => async (db) => {
16
- await index_1.create.table(migrations, { ifNotExists: true }).onto(db);
17
- const { mostRecentId } = await (0, index_1.from)(migrations.as('m'))
18
- .orderBy(({ m }) => [index_1.expr.desc(m.timestamp)])
19
- .select(({ m }) => ({ mostRecentId: m.id }))
20
- .one(db) || { mostRecentId: '' };
21
- for (const [id, migrate] of Object.entries(migs)) {
22
- if (id <= mostRecentId)
23
- continue;
24
- await (0, index_1.transaction)(db, async () => {
25
- await migrate(db);
26
- await (0, index_1.into)(migrations).values({ id, timestamp: new Date() }).insert(db);
27
- });
28
- }
29
- };
30
- exports.defineMigrations = defineMigrations;
@@ -1,26 +0,0 @@
1
- import { create, expr, from, into, table, transaction } from './index';
2
- const migrations = table('schema_migrations', t => ({
3
- id: t.string({ size: 36 }).primaryKey(),
4
- timestamp: t.datetime(),
5
- }));
6
- /**
7
- * @public Defines a set of migrations to be executed against a
8
- * database.
9
- * @since 0.1.6
10
- * @version 2
11
- */
12
- export const defineMigrations = (migs) => async (db) => {
13
- await create.table(migrations, { ifNotExists: true }).onto(db);
14
- const { mostRecentId } = await from(migrations.as('m'))
15
- .orderBy(({ m }) => [expr.desc(m.timestamp)])
16
- .select(({ m }) => ({ mostRecentId: m.id }))
17
- .one(db) || { mostRecentId: '' };
18
- for (const [id, migrate] of Object.entries(migs)) {
19
- if (id <= mostRecentId)
20
- continue;
21
- await transaction(db, async () => {
22
- await migrate(db);
23
- await into(migrations).values({ id, timestamp: new Date() }).insert(db);
24
- });
25
- }
26
- };
@@ -1,15 +0,0 @@
1
- import { type IDatabase } from './index';
2
- /**
3
- * @private Defines the type for a migration function.
4
- * @since 0.1.6
5
- * @version 1
6
- */
7
- type Migration = (db: IDatabase) => Promise<void>;
8
- /**
9
- * @public Defines a set of migrations to be executed against a
10
- * database.
11
- * @since 0.1.6
12
- * @version 2
13
- */
14
- export declare const defineMigrations: (migs: Record<string, Migration>) => (db: IDatabase) => Promise<void>;
15
- export {};