@rwillians/qx 0.1.11 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
- # qx (provisory name)
1
+ # qx
2
2
 
3
- A teeny tiny ORM for TypeScript and JavaScript inspired by Elixir's
4
- [Ecto](https://hexdocs.pm/ecto).
3
+ A teeny tiny, type-safe and dependency-free ORM for TypeScript and
4
+ JavaScript.
5
5
 
6
6
  Built for you who wants a simple, small ORM that just works.
7
7
 
@@ -10,10 +10,10 @@ import * as sqlite from '@rwillians/qx/bun-sqlite';
10
10
  import { create, from, into, table } from '@rwillians/qx';
11
11
 
12
12
  const users = table('users', t => ({
13
- id: t.integer({ primaryKey: true, autogenerate: true }),
13
+ id: t.integer().autoincrement().primaryKey(),
14
14
  name: t.string(),
15
15
  email: t.string(),
16
- createdAt: t.timestamp({ autogenerate: true }),
16
+ createdAt: t.datetime(),
17
17
  }));
18
18
 
19
19
  // ...
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.connect = void 0;
3
+ 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");
@@ -505,3 +505,10 @@ class BunSQLite {
505
505
  */
506
506
  const connect = (...args) => new BunSQLite(new bun_sqlite_1.Database(...args));
507
507
  exports.connect = connect;
508
+ /**
509
+ * @public An in-memory database connection.
510
+ * @since 0.1.12
511
+ * @version 1
512
+ */
513
+ const inmemory = connect(':memory:');
514
+ exports.inmemory = inmemory;
@@ -5,11 +5,12 @@ const node_util_1 = require("node:util");
5
5
  /**
6
6
  * @public Creates a basic console logger that logs all queries.
7
7
  * @since 0.1.0
8
- * @version 1
8
+ * @version 2
9
9
  */
10
10
  const createConsoleLogger = () => ({
11
11
  query: {
12
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'); },
13
14
  },
14
15
  });
15
16
  exports.createConsoleLogger = createConsoleLogger;
@@ -14,15 +14,16 @@ const migrations = (0, index_1.table)('schema_migrations', t => ({
14
14
  */
15
15
  const defineMigrations = (migs) => async (db) => {
16
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 }) => [[m.timestamp, 'DESC']])
19
+ .select(({ m }) => ({ mostRecentId: m.id }))
20
+ .one(db) || { mostRecentId: '' };
17
21
  for (const [id, migrate] of Object.entries(migs)) {
18
- const alreadyMigrated = await (0, index_1.from)(migrations.as('m'))
19
- .where(({ m }) => index_1.expr.eq(m.id, id))
20
- .exists(db);
21
- if (alreadyMigrated)
22
+ if (id < mostRecentId)
22
23
  continue;
23
24
  await (0, index_1.transaction)(db, async () => {
24
25
  await migrate(db);
25
- await (0, index_1.into)(migrations).insert({ id, timestamp: new Date() }).run(db);
26
+ await (0, index_1.into)(migrations).values({ id, timestamp: new Date() }).insert(db);
26
27
  });
27
28
  }
28
29
  };
package/dist/cjs/index.js CHANGED
@@ -21,7 +21,7 @@ const TABLE_ALIAS = Symbol.for('~exto.table-alias');
21
21
  /**
22
22
  * @private A builder for column properties.
23
23
  * @since 0.1.0
24
- * @version 1
24
+ * @version 2
25
25
  */
26
26
  class ColumnPropsBuilder {
27
27
  props;
@@ -39,9 +39,12 @@ class ColumnPropsBuilder {
39
39
  return new ColumnPropsBuilder({ ...this.props, autoincrement: true });
40
40
  }
41
41
  /**
42
- * @public Sets a default value for the column.
42
+ * @public Sets a default value for the column. This is not the
43
+ * table's default value for the column, but rather a
44
+ * fallback value that qx will use when inserting a new row
45
+ * where this column is nullish.
43
46
  * @since 0.1.0
44
- * @version 1
47
+ * @version 2
45
48
  */
46
49
  default(value) {
47
50
  return new ColumnPropsBuilder({ ...this.props, default: value });
@@ -49,12 +52,12 @@ class ColumnPropsBuilder {
49
52
  /**
50
53
  * @public Marks the column as nullable.
51
54
  * @since 0.1.0
52
- * @version 1
55
+ * @version 2
53
56
  * @throws {Error} if the column is a primary key.
54
57
  */
55
58
  nullable() {
56
59
  if (this.props.primaryKey)
57
- throw new Error('Cannot set nullable on a primary key column');
60
+ throw new Error('Cannot make a primary key column nullable');
58
61
  const { schema, ...props } = this.props;
59
62
  return new ColumnPropsBuilder({ ...props, nullable: true, schema: std.nullable(schema) });
60
63
  }
@@ -72,9 +75,11 @@ class ColumnPropsBuilder {
72
75
  /**
73
76
  * @public Marks the column as unique.
74
77
  * @since 0.1.0
75
- * @version 1
78
+ * @version 2
76
79
  */
77
80
  unique() {
81
+ if (this.props.primaryKey)
82
+ throw new Error('Primary key columns are already unique');
78
83
  return new ColumnPropsBuilder({ ...this.props, unique: true });
79
84
  }
80
85
  }
@@ -285,6 +290,21 @@ const expr = {
285
290
  * @version 1
286
291
  */
287
292
  not: (expr) => ({ not: expr }),
293
+ // // // // // // // // // // // // // // // // // // // // // // //
294
+ // SEMANTICS ONLY //
295
+ // // // // // // // // // // // // // // // // // // // // // // //
296
+ /**
297
+ * @public Builds an ascending order expression.
298
+ * @since 0.1.13
299
+ * @version 1
300
+ */
301
+ asc: (expr) => [expr, 'ASC'],
302
+ /**
303
+ * @public Builds a descending order expression.
304
+ * @since 0.1.13
305
+ * @version 1
306
+ */
307
+ desc: (expr) => [expr, 'DESC'],
288
308
  };
289
309
  exports.expr = expr;
290
310
  /**
@@ -538,9 +558,9 @@ class InsertBuilder {
538
558
  /**
539
559
  * @public Adds one or more rows to be inserted.
540
560
  * @since 0.1.0
541
- * @version 1
561
+ * @version 2
542
562
  */
543
- insert(rows) {
563
+ values(rows) {
544
564
  this.rows.push(...(u.wrap(rows)));
545
565
  return this;
546
566
  }
@@ -549,7 +569,7 @@ class InsertBuilder {
549
569
  * @since 0.1.0
550
570
  * @version 1
551
571
  */
552
- async run(db) {
572
+ async insert(db) {
553
573
  if (this.rows.length === 0)
554
574
  return [];
555
575
  const insertShape = getInsertShape(this.table);
@@ -501,7 +501,13 @@ class BunSQLite {
501
501
  * @version 1
502
502
  */
503
503
  const connect = (...args) => new BunSQLite(new Database(...args));
504
+ /**
505
+ * @public An in-memory database connection.
506
+ * @since 0.1.12
507
+ * @version 1
508
+ */
509
+ const inmemory = connect(':memory:');
504
510
  // // // // // // // // // // // // // // // // // // // // // // // //
505
511
  // EXPORTS //
506
512
  // // // // // // // // // // // // // // // // // // // // // // // //
507
- export { connect, };
513
+ export { connect, inmemory, };
@@ -3,10 +3,11 @@ import {} from './index';
3
3
  /**
4
4
  * @public Creates a basic console logger that logs all queries.
5
5
  * @since 0.1.0
6
- * @version 1
6
+ * @version 2
7
7
  */
8
8
  export const createConsoleLogger = () => ({
9
9
  query: {
10
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'); },
11
12
  },
12
13
  });
@@ -11,15 +11,16 @@ const migrations = table('schema_migrations', t => ({
11
11
  */
12
12
  export const defineMigrations = (migs) => async (db) => {
13
13
  await create.table(migrations, { ifNotExists: true }).onto(db);
14
+ const { mostRecentId } = await from(migrations.as('m'))
15
+ .orderBy(({ m }) => [[m.timestamp, 'DESC']])
16
+ .select(({ m }) => ({ mostRecentId: m.id }))
17
+ .one(db) || { mostRecentId: '' };
14
18
  for (const [id, migrate] of Object.entries(migs)) {
15
- const alreadyMigrated = await from(migrations.as('m'))
16
- .where(({ m }) => expr.eq(m.id, id))
17
- .exists(db);
18
- if (alreadyMigrated)
19
+ if (id < mostRecentId)
19
20
  continue;
20
21
  await transaction(db, async () => {
21
22
  await migrate(db);
22
- await into(migrations).insert({ id, timestamp: new Date() }).run(db);
23
+ await into(migrations).values({ id, timestamp: new Date() }).insert(db);
23
24
  });
24
25
  }
25
26
  };
package/dist/esm/index.js CHANGED
@@ -18,7 +18,7 @@ const TABLE_ALIAS = Symbol.for('~exto.table-alias');
18
18
  /**
19
19
  * @private A builder for column properties.
20
20
  * @since 0.1.0
21
- * @version 1
21
+ * @version 2
22
22
  */
23
23
  class ColumnPropsBuilder {
24
24
  props;
@@ -36,9 +36,12 @@ class ColumnPropsBuilder {
36
36
  return new ColumnPropsBuilder({ ...this.props, autoincrement: true });
37
37
  }
38
38
  /**
39
- * @public Sets a default value for the column.
39
+ * @public Sets a default value for the column. This is not the
40
+ * table's default value for the column, but rather a
41
+ * fallback value that qx will use when inserting a new row
42
+ * where this column is nullish.
40
43
  * @since 0.1.0
41
- * @version 1
44
+ * @version 2
42
45
  */
43
46
  default(value) {
44
47
  return new ColumnPropsBuilder({ ...this.props, default: value });
@@ -46,12 +49,12 @@ class ColumnPropsBuilder {
46
49
  /**
47
50
  * @public Marks the column as nullable.
48
51
  * @since 0.1.0
49
- * @version 1
52
+ * @version 2
50
53
  * @throws {Error} if the column is a primary key.
51
54
  */
52
55
  nullable() {
53
56
  if (this.props.primaryKey)
54
- throw new Error('Cannot set nullable on a primary key column');
57
+ throw new Error('Cannot make a primary key column nullable');
55
58
  const { schema, ...props } = this.props;
56
59
  return new ColumnPropsBuilder({ ...props, nullable: true, schema: std.nullable(schema) });
57
60
  }
@@ -69,9 +72,11 @@ class ColumnPropsBuilder {
69
72
  /**
70
73
  * @public Marks the column as unique.
71
74
  * @since 0.1.0
72
- * @version 1
75
+ * @version 2
73
76
  */
74
77
  unique() {
78
+ if (this.props.primaryKey)
79
+ throw new Error('Primary key columns are already unique');
75
80
  return new ColumnPropsBuilder({ ...this.props, unique: true });
76
81
  }
77
82
  }
@@ -280,6 +285,21 @@ const expr = {
280
285
  * @version 1
281
286
  */
282
287
  not: (expr) => ({ not: expr }),
288
+ // // // // // // // // // // // // // // // // // // // // // // //
289
+ // SEMANTICS ONLY //
290
+ // // // // // // // // // // // // // // // // // // // // // // //
291
+ /**
292
+ * @public Builds an ascending order expression.
293
+ * @since 0.1.13
294
+ * @version 1
295
+ */
296
+ asc: (expr) => [expr, 'ASC'],
297
+ /**
298
+ * @public Builds a descending order expression.
299
+ * @since 0.1.13
300
+ * @version 1
301
+ */
302
+ desc: (expr) => [expr, 'DESC'],
283
303
  };
284
304
  /**
285
305
  * @public Expression type guards.
@@ -529,9 +549,9 @@ class InsertBuilder {
529
549
  /**
530
550
  * @public Adds one or more rows to be inserted.
531
551
  * @since 0.1.0
532
- * @version 1
552
+ * @version 2
533
553
  */
534
- insert(rows) {
554
+ values(rows) {
535
555
  this.rows.push(...(u.wrap(rows)));
536
556
  return this;
537
557
  }
@@ -540,7 +560,7 @@ class InsertBuilder {
540
560
  * @since 0.1.0
541
561
  * @version 1
542
562
  */
543
- async run(db) {
563
+ async insert(db) {
544
564
  if (this.rows.length === 0)
545
565
  return [];
546
566
  const insertShape = getInsertShape(this.table);
@@ -50,4 +50,10 @@ declare class BunSQLite implements IDatabase {
50
50
  * @version 1
51
51
  */
52
52
  declare const connect: (...args: ConstructorParameters<typeof Database>) => BunSQLite;
53
- export { connect, };
53
+ /**
54
+ * @public An in-memory database connection.
55
+ * @since 0.1.12
56
+ * @version 1
57
+ */
58
+ declare const inmemory: BunSQLite;
59
+ export { connect, inmemory, };
@@ -2,6 +2,6 @@ import { type ILogger } from './index';
2
2
  /**
3
3
  * @public Creates a basic console logger that logs all queries.
4
4
  * @since 0.1.0
5
- * @version 1
5
+ * @version 2
6
6
  */
7
7
  export declare const createConsoleLogger: () => ILogger;
@@ -40,10 +40,9 @@ type ColumnProps<T extends std.Schema = std.Schema> = {
40
40
  */
41
41
  autoincrement?: true;
42
42
  /**
43
- * @public The default value for the column or a function that
44
- * returns it. If a column has no value (nullish) and
45
- * default function was provided, then it will be called
46
- * once for each row right before its insertion.
43
+ * @public The default value for the column. If a column has
44
+ * nullish value in an insert, then this value will be used
45
+ * instead.
47
46
  * @since 0.1.0
48
47
  * @version 1
49
48
  */
@@ -92,7 +91,7 @@ type ColumnProps<T extends std.Schema = std.Schema> = {
92
91
  /**
93
92
  * @public A column definition.
94
93
  * @since 0.1.0
95
- * @version 1
94
+ * @version 2
96
95
  */
97
96
  type Column<S extends string = string, T extends ColumnProps = ColumnProps> = Expand<T & {
98
97
  /**
@@ -111,15 +110,15 @@ type Column<S extends string = string, T extends ColumnProps = ColumnProps> = Ex
111
110
  /**
112
111
  * @public The column's input type, cached.
113
112
  * @since 0.1.0
114
- * @version 1
113
+ * @version 2
115
114
  */
116
- inputType: std.input<T['schema']>;
115
+ inferInput: std.input<T['schema']>;
117
116
  /**
118
117
  * @public The column's output type, cached.
119
118
  * @since 0.1.0
120
- * @version 1
119
+ * @version 2
121
120
  */
122
- outputType: std.output<T['schema']>;
121
+ inferOutput: std.output<T['schema']>;
123
122
  }>;
124
123
  /**
125
124
  * @public A table definition.
@@ -208,28 +207,28 @@ type OmitOnUpdate = {
208
207
  /**
209
208
  * @private Infers the output type of a table's row.
210
209
  * @since 0.1.0
211
- * @version 1
210
+ * @version 2
212
211
  */
213
212
  type Infer<T extends Table> = {
214
- [K in keyof T['columns']]: T['columns'][K]['outputType'];
213
+ [K in keyof T['columns']]: T['columns'][K]['inferOutput'];
215
214
  };
216
215
  /**
217
216
  * @private Infers the input type required to insert a new row.
218
217
  * @since 0.1.0
219
- * @version 1
218
+ * @version 2
220
219
  */
221
220
  type InferForInsert<T extends Table> = Expand<{
222
- [K in keyof T['columns'] as T['columns'][K] extends OmitOnInsert | OptionalOnInsert ? never : K]: T['columns'][K]['inputType'];
221
+ [K in keyof T['columns'] as T['columns'][K] extends OmitOnInsert | OptionalOnInsert ? never : K]: T['columns'][K]['inferInput'];
223
222
  } & {
224
- [K in keyof T['columns'] as T['columns'][K] extends OptionalOnInsert ? K : never]?: T['columns'][K]['inputType'];
223
+ [K in keyof T['columns'] as T['columns'][K] extends OptionalOnInsert ? K : never]?: T['columns'][K]['inferInput'];
225
224
  }>;
226
225
  /**
227
226
  * @private Infers the input type required to update an existing row.
228
227
  * @since 0.1.0
229
- * @version 1
228
+ * @version 2
230
229
  */
231
230
  type InferForUpdate<T extends Table> = {
232
- [K in keyof T['columns'] as T['columns'][K] extends OmitOnUpdate ? never : K]?: T['columns'][K]['inputType'];
231
+ [K in keyof T['columns'] as T['columns'][K] extends OmitOnUpdate ? never : K]?: T['columns'][K]['inferInput'];
233
232
  };
234
233
  /**
235
234
  * @private Adds the ability to infer types of a table.
@@ -259,7 +258,7 @@ type Inferrable<T extends Table> = T & {
259
258
  /**
260
259
  * @private A builder for column properties.
261
260
  * @since 0.1.0
262
- * @version 1
261
+ * @version 2
263
262
  */
264
263
  declare class ColumnPropsBuilder<T extends ColumnProps = ColumnProps> {
265
264
  readonly props: T;
@@ -273,17 +272,20 @@ declare class ColumnPropsBuilder<T extends ColumnProps = ColumnProps> {
273
272
  autoincrement: true;
274
273
  }>>;
275
274
  /**
276
- * @public Sets a default value for the column.
275
+ * @public Sets a default value for the column. This is not the
276
+ * table's default value for the column, but rather a
277
+ * fallback value that qx will use when inserting a new row
278
+ * where this column is nullish.
277
279
  * @since 0.1.0
278
- * @version 1
280
+ * @version 2
279
281
  */
280
- default<S extends std.output<T['schema']>, U extends S | (() => S)>(value: U): ColumnPropsBuilder<Expand<T & {
281
- default: U;
282
+ default<S extends std.output<T['schema']> | (() => std.output<T['schema']>)>(value: S): ColumnPropsBuilder<Expand<T & {
283
+ default: S;
282
284
  }>>;
283
285
  /**
284
286
  * @public Marks the column as nullable.
285
287
  * @since 0.1.0
286
- * @version 1
288
+ * @version 2
287
289
  * @throws {Error} if the column is a primary key.
288
290
  */
289
291
  nullable(): ColumnPropsBuilder<Expand<Omit<T, "schema"> & {
@@ -302,7 +304,7 @@ declare class ColumnPropsBuilder<T extends ColumnProps = ColumnProps> {
302
304
  /**
303
305
  * @public Marks the column as unique.
304
306
  * @since 0.1.0
305
- * @version 1
307
+ * @version 2
306
308
  */
307
309
  unique(): ColumnPropsBuilder<Expand<T & {
308
310
  unique: true;
@@ -648,6 +650,18 @@ declare const expr: {
648
650
  * @version 1
649
651
  */
650
652
  not: <E extends Expr>(expr: E) => ExprNot;
653
+ /**
654
+ * @public Builds an ascending order expression.
655
+ * @since 0.1.13
656
+ * @version 1
657
+ */
658
+ asc: (expr: Expr) => readonly [Expr, "ASC"];
659
+ /**
660
+ * @public Builds a descending order expression.
661
+ * @since 0.1.13
662
+ * @version 1
663
+ */
664
+ desc: (expr: Expr) => readonly [Expr, "DESC"];
651
665
  };
652
666
  /**
653
667
  * @public Expression type guards.
@@ -982,6 +996,12 @@ interface ILogger {
982
996
  * @version 1
983
997
  */
984
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;
985
1005
  };
986
1006
  }
987
1007
  /**
@@ -1064,15 +1084,15 @@ declare class InsertBuilder<T extends Table> {
1064
1084
  /**
1065
1085
  * @public Adds one or more rows to be inserted.
1066
1086
  * @since 0.1.0
1067
- * @version 1
1087
+ * @version 2
1068
1088
  */
1069
- insert(rows: InferForInsert<T> | InferForInsert<T>[]): this;
1089
+ values(rows: InferForInsert<T> | InferForInsert<T>[]): this;
1070
1090
  /**
1071
1091
  * @public Executes the insert statement onto the given database.
1072
1092
  * @since 0.1.0
1073
1093
  * @version 1
1074
1094
  */
1075
- run(db: IDatabase): Promise<Expand<Infer<T>>[]>;
1095
+ insert(db: IDatabase): Promise<Expand<Infer<T>>[]>;
1076
1096
  }
1077
1097
  /**
1078
1098
  * @public Starts an insert statement for the given table.
@@ -1150,10 +1170,10 @@ type Query<T extends Record<string, Aliased<string, Table>> = Record<string, Ali
1150
1170
  /**
1151
1171
  * @private Infers the selection output type of given query.
1152
1172
  * @since 0.1.0
1153
- * @version 1
1173
+ * @version 2
1154
1174
  */
1155
1175
  type InferSelection<T extends Query> = {
1156
- [K in keyof T['select'] & string]: T['select'][K]['outputType'];
1176
+ [K in keyof T['select'] & string]: T['select'][K]['inferOutput'];
1157
1177
  };
1158
1178
  /**
1159
1179
  * @public Select statement builder with a fluent API.
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.11",
4
+ "version": "0.1.13",
5
5
  "author": "Rafael Willians <me@rwillians.com>",
6
6
  "license": "MIT",
7
7
  "repository": {