kysely 0.18.0 → 0.18.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 (55) hide show
  1. package/dist/cjs/dialect/database-introspector.d.ts +13 -0
  2. package/dist/cjs/dialect/mysql/mysql-dialect.d.ts +9 -1
  3. package/dist/cjs/dialect/mysql/mysql-dialect.js +11 -5
  4. package/dist/cjs/dialect/mysql/mysql-driver.d.ts +25 -3
  5. package/dist/cjs/dialect/mysql/mysql-driver.js +48 -35
  6. package/dist/cjs/dialect/mysql/mysql-introspector.d.ts +11 -1
  7. package/dist/cjs/dialect/mysql/mysql-introspector.js +29 -7
  8. package/dist/cjs/dialect/postgres/postgres-dialect.d.ts +9 -1
  9. package/dist/cjs/dialect/postgres/postgres-dialect.js +11 -5
  10. package/dist/cjs/dialect/postgres/postgres-driver.d.ts +25 -3
  11. package/dist/cjs/dialect/postgres/postgres-driver.js +37 -24
  12. package/dist/cjs/dialect/postgres/postgres-introspector.d.ts +11 -1
  13. package/dist/cjs/dialect/postgres/postgres-introspector.js +15 -4
  14. package/dist/cjs/dialect/sqlite/sqlite-introspector.d.ts +11 -1
  15. package/dist/cjs/dialect/sqlite/sqlite-introspector.js +11 -4
  16. package/dist/cjs/index-nodeless.js +5 -1
  17. package/dist/cjs/index.js +5 -1
  18. package/dist/cjs/migration/migrator.d.ts +44 -2
  19. package/dist/cjs/migration/migrator.js +77 -18
  20. package/dist/cjs/plugin/noop-plugin.d.ts +42 -0
  21. package/dist/cjs/plugin/noop-plugin.js +12 -0
  22. package/dist/cjs/query-creator.d.ts +9 -0
  23. package/dist/cjs/query-creator.js +18 -0
  24. package/dist/cjs/schema/schema.d.ts +9 -0
  25. package/dist/cjs/schema/schema.js +12 -0
  26. package/dist/cjs/util/column-type.d.ts +9 -1
  27. package/dist/cjs/util/stack-trace-utils.d.ts +1 -0
  28. package/dist/cjs/util/stack-trace-utils.js +17 -0
  29. package/dist/esm/dialect/database-introspector.d.ts +13 -0
  30. package/dist/esm/dialect/mysql/mysql-dialect.d.ts +9 -1
  31. package/dist/esm/dialect/mysql/mysql-dialect.js +11 -5
  32. package/dist/esm/dialect/mysql/mysql-driver.d.ts +25 -3
  33. package/dist/esm/dialect/mysql/mysql-driver.js +48 -35
  34. package/dist/esm/dialect/mysql/mysql-introspector.d.ts +11 -1
  35. package/dist/esm/dialect/mysql/mysql-introspector.js +30 -8
  36. package/dist/esm/dialect/postgres/postgres-dialect.d.ts +9 -1
  37. package/dist/esm/dialect/postgres/postgres-dialect.js +11 -5
  38. package/dist/esm/dialect/postgres/postgres-driver.d.ts +25 -3
  39. package/dist/esm/dialect/postgres/postgres-driver.js +38 -25
  40. package/dist/esm/dialect/postgres/postgres-introspector.d.ts +11 -1
  41. package/dist/esm/dialect/postgres/postgres-introspector.js +16 -5
  42. package/dist/esm/dialect/sqlite/sqlite-introspector.d.ts +11 -1
  43. package/dist/esm/dialect/sqlite/sqlite-introspector.js +12 -5
  44. package/dist/esm/migration/migrator.d.ts +44 -2
  45. package/dist/esm/migration/migrator.js +76 -17
  46. package/dist/esm/plugin/noop-plugin.d.ts +42 -0
  47. package/dist/esm/plugin/noop-plugin.js +9 -0
  48. package/dist/esm/query-creator.d.ts +9 -0
  49. package/dist/esm/query-creator.js +18 -0
  50. package/dist/esm/schema/schema.d.ts +9 -0
  51. package/dist/esm/schema/schema.js +12 -0
  52. package/dist/esm/util/column-type.d.ts +9 -1
  53. package/dist/esm/util/stack-trace-utils.d.ts +1 -0
  54. package/dist/esm/util/stack-trace-utils.js +14 -0
  55. package/package.json +9 -9
@@ -1,7 +1,9 @@
1
1
  /// <reference types="./migrator.d.ts" />
2
+ import { NoopPlugin } from '../plugin/noop-plugin.js';
3
+ import { WithSchemaPlugin } from '../plugin/with-schema/with-schema-plugin.js';
2
4
  import { freeze, getLast } from '../util/object-utils.js';
3
- export const MIGRATION_TABLE = 'kysely_migration';
4
- export const MIGRATION_LOCK_TABLE = 'kysely_migration_lock';
5
+ export const DEFAULT_MIGRATION_TABLE = 'kysely_migration';
6
+ export const DEFAULT_MIGRATION_LOCK_TABLE = 'kysely_migration_lock';
5
7
  export const MIGRATION_LOCK_ID = 'migration_lock';
6
8
  export const NO_MIGRATIONS = freeze({ __noMigrations__: true });
7
9
  /**
@@ -35,9 +37,10 @@ export class Migrator {
35
37
  * The returned array is sorted by migration name.
36
38
  */
37
39
  async getMigrations() {
38
- const executedMigrations = (await this.#doesTableExists(MIGRATION_TABLE))
40
+ const executedMigrations = (await this.#doesTableExists(this.#migrationTable))
39
41
  ? await this.#props.db
40
- .selectFrom(MIGRATION_TABLE)
42
+ .withPlugin(this.#schemaPlugin)
43
+ .selectFrom(this.#migrationTable)
41
44
  .select(['name', 'timestamp'])
42
45
  .execute()
43
46
  : [];
@@ -182,16 +185,61 @@ export class Migrator {
182
185
  return { error };
183
186
  }
184
187
  }
188
+ get #migrationTableSchema() {
189
+ return this.#props.migrationTableSchema;
190
+ }
191
+ get #migrationTable() {
192
+ return this.#props.migrationTableName ?? DEFAULT_MIGRATION_TABLE;
193
+ }
194
+ get #migrationLockTable() {
195
+ return this.#props.migrationLockTableName ?? DEFAULT_MIGRATION_LOCK_TABLE;
196
+ }
197
+ get #schemaPlugin() {
198
+ if (this.#migrationTableSchema) {
199
+ return new WithSchemaPlugin(this.#migrationTableSchema);
200
+ }
201
+ return new NoopPlugin();
202
+ }
185
203
  async #ensureMigrationTablesExists() {
204
+ await this.#ensureMigrationTableSchemaExists();
186
205
  await this.#ensureMigrationTableExists();
187
206
  await this.#ensureMigrationLockTableExists();
188
207
  await this.#ensureLockRowExists();
189
208
  }
209
+ async #ensureMigrationTableSchemaExists() {
210
+ if (!this.#migrationTableSchema) {
211
+ // Use default schema. Nothing to do.
212
+ return;
213
+ }
214
+ if (!(await this.#doesSchemaExists())) {
215
+ try {
216
+ await this.#props.db.schema
217
+ .createSchema(this.#migrationTableSchema)
218
+ .ifNotExists()
219
+ .execute();
220
+ }
221
+ catch (error) {
222
+ // At least on PostgreSQL, `if not exists` doesn't guarantee the `create schema`
223
+ // query doesn't throw if the schema already exits. That's why we check if
224
+ // the schema exist here and ignore the error if it does.
225
+ if (!(await this.#doesSchemaExists())) {
226
+ throw error;
227
+ }
228
+ }
229
+ }
230
+ }
190
231
  async #ensureMigrationTableExists() {
191
- if (!(await this.#doesTableExists(MIGRATION_TABLE))) {
232
+ if (!(await this.#doesTableExists(this.#migrationTable))) {
192
233
  try {
234
+ if (this.#migrationTableSchema) {
235
+ await this.#props.db.schema
236
+ .createSchema(this.#migrationTableSchema)
237
+ .ifNotExists()
238
+ .execute();
239
+ }
193
240
  await this.#props.db.schema
194
- .createTable(MIGRATION_TABLE)
241
+ .withPlugin(this.#schemaPlugin)
242
+ .createTable(this.#migrationTable)
195
243
  .ifNotExists()
196
244
  .addColumn('name', 'varchar(255)', (col) => col.notNull().primaryKey())
197
245
  // The migration run time as ISO string. This is not a real date type as we
@@ -203,17 +251,18 @@ export class Migrator {
203
251
  // At least on PostgreSQL, `if not exists` doesn't guarantee the `create table`
204
252
  // query doesn't throw if the table already exits. That's why we check if
205
253
  // the table exist here and ignore the error if it does.
206
- if (!(await this.#doesTableExists(MIGRATION_TABLE))) {
254
+ if (!(await this.#doesTableExists(this.#migrationTable))) {
207
255
  throw error;
208
256
  }
209
257
  }
210
258
  }
211
259
  }
212
260
  async #ensureMigrationLockTableExists() {
213
- if (!(await this.#doesTableExists(MIGRATION_LOCK_TABLE))) {
261
+ if (!(await this.#doesTableExists(this.#migrationLockTable))) {
214
262
  try {
215
263
  await this.#props.db.schema
216
- .createTable(MIGRATION_LOCK_TABLE)
264
+ .withPlugin(this.#schemaPlugin)
265
+ .createTable(this.#migrationLockTable)
217
266
  .ifNotExists()
218
267
  .addColumn('id', 'varchar(255)', (col) => col.notNull().primaryKey())
219
268
  .addColumn('is_locked', 'integer', (col) => col.notNull().defaultTo(0))
@@ -223,7 +272,7 @@ export class Migrator {
223
272
  // At least on PostgreSQL, `if not exists` doesn't guarantee the `create table`
224
273
  // query doesn't throw if the table already exits. That's why we check if
225
274
  // the table exist here and ignore the error if it does.
226
- if (!(await this.#doesTableExists(MIGRATION_LOCK_TABLE))) {
275
+ if (!(await this.#doesTableExists(this.#migrationLockTable))) {
227
276
  throw error;
228
277
  }
229
278
  }
@@ -233,7 +282,8 @@ export class Migrator {
233
282
  if (!(await this.#doesLockRowExists())) {
234
283
  try {
235
284
  await this.#props.db
236
- .insertInto(MIGRATION_LOCK_TABLE)
285
+ .withPlugin(this.#schemaPlugin)
286
+ .insertInto(this.#migrationLockTable)
237
287
  .values({ id: MIGRATION_LOCK_ID, is_locked: 0 })
238
288
  .execute();
239
289
  }
@@ -244,15 +294,21 @@ export class Migrator {
244
294
  }
245
295
  }
246
296
  }
297
+ async #doesSchemaExists() {
298
+ const schemas = await this.#props.db.introspection.getSchemas();
299
+ return schemas.some((it) => it.name === this.#migrationTableSchema);
300
+ }
247
301
  async #doesTableExists(tableName) {
248
- const metadata = await this.#props.db.introspection.getMetadata({
302
+ const schema = this.#migrationTableSchema;
303
+ const tables = await this.#props.db.introspection.getTables({
249
304
  withInternalKyselyTables: true,
250
305
  });
251
- return !!metadata.tables.find((it) => it.name === tableName);
306
+ return tables.some((it) => it.name === tableName && (!schema || it.schema === schema));
252
307
  }
253
308
  async #doesLockRowExists() {
254
309
  const lockRow = await this.#props.db
255
- .selectFrom(MIGRATION_LOCK_TABLE)
310
+ .withPlugin(this.#schemaPlugin)
311
+ .selectFrom(this.#migrationLockTable)
256
312
  .where('id', '=', MIGRATION_LOCK_ID)
257
313
  .select('id')
258
314
  .executeTakeFirst();
@@ -310,7 +366,8 @@ export class Migrator {
310
366
  }
311
367
  async #getExecutedMigrations(db) {
312
368
  const executedMigrations = await db
313
- .selectFrom(MIGRATION_TABLE)
369
+ .withPlugin(this.#schemaPlugin)
370
+ .selectFrom(this.#migrationTable)
314
371
  .select('name')
315
372
  .orderBy('name')
316
373
  .execute();
@@ -346,7 +403,8 @@ export class Migrator {
346
403
  if (migration.down) {
347
404
  await migration.down(db);
348
405
  await db
349
- .deleteFrom(MIGRATION_TABLE)
406
+ .withPlugin(this.#schemaPlugin)
407
+ .deleteFrom(this.#migrationTable)
350
408
  .where('name', '=', migration.name)
351
409
  .execute();
352
410
  results[i] = {
@@ -384,7 +442,8 @@ export class Migrator {
384
442
  try {
385
443
  await migration.up(db);
386
444
  await db
387
- .insertInto(MIGRATION_TABLE)
445
+ .withPlugin(this.#schemaPlugin)
446
+ .insertInto(this.#migrationTable)
388
447
  .values({
389
448
  name: migration.name,
390
449
  timestamp: new Date().toISOString(),
@@ -0,0 +1,42 @@
1
+ import { QueryResult } from '../driver/database-connection.js';
2
+ import { UnknownRow } from '../index-nodeless.js';
3
+ import { RootOperationNode } from '../query-compiler/query-compiler.js';
4
+ import { KyselyPlugin, PluginTransformQueryArgs, PluginTransformResultArgs } from './kysely-plugin.js';
5
+ export declare class NoopPlugin implements KyselyPlugin {
6
+ /**
7
+ * This is called for each query before it is executed. You can modify the query by
8
+ * transforming its {@link OperationNode} tree provided in {@link PluginTransformQueryArgs.node | args.node}
9
+ * and returning the transformed tree. You'd usually want to use an {@link OperationNodeTransformer}
10
+ * for this.
11
+ *
12
+ * If you need to pass some query-related data between this method and `transformResult` you
13
+ * can use a `WeakMap` with {@link PluginTransformQueryArgs.queryId | args.queryId} as the key:
14
+ *
15
+ * ```ts
16
+ * const plugin = {
17
+ * data: new WeakMap<QueryId, SomeData>(),
18
+ *
19
+ * transformQuery(args: PluginTransformQueryArgs): RootOperationNode {
20
+ * this.data.set(args.queryId, something)
21
+ * return args.node
22
+ * },
23
+ *
24
+ * transformResult(args: PluginTransformResultArgs): QueryResult<UnknownRow> {
25
+ * const data = this.data.get(args.queryId)
26
+ * return args.result
27
+ * }
28
+ * }
29
+ * ```
30
+ *
31
+ * You should use a `WeakMap` instead of a `Map` or some other strong references because `transformQuery`
32
+ * is not always matched by a call to `transformResult` which would leave orphaned items in the map
33
+ * and cause a memory leak.
34
+ */
35
+ transformQuery(args: PluginTransformQueryArgs): RootOperationNode;
36
+ /**
37
+ * This method is called for each query after it has been executed. The result
38
+ * of the query can be accessed through {@link PluginTransformResultArgs.result | args.result}.
39
+ * You can modify the result and return the modifier result.
40
+ */
41
+ transformResult(args: PluginTransformResultArgs): Promise<QueryResult<UnknownRow>>;
42
+ }
@@ -0,0 +1,9 @@
1
+ /// <reference types="./noop-plugin.d.ts" />
2
+ export class NoopPlugin {
3
+ transformQuery(args) {
4
+ return args.node;
5
+ }
6
+ async transformResult(args) {
7
+ return args.result;
8
+ }
9
+ }
@@ -9,6 +9,7 @@ import { WithNode } from './operation-node/with-node.js';
9
9
  import { InsertResult } from './query-builder/insert-result.js';
10
10
  import { DeleteResult } from './query-builder/delete-result.js';
11
11
  import { UpdateResult } from './query-builder/update-result.js';
12
+ import { KyselyPlugin } from './plugin/kysely-plugin.js';
12
13
  export declare class QueryCreator<DB> {
13
14
  #private;
14
15
  constructor(props: QueryCreatorProps);
@@ -252,6 +253,14 @@ export declare class QueryCreator<DB> {
252
253
  * See the {@link with} method for examples and more documentation.
253
254
  */
254
255
  withRecursive<N extends string, E extends RecursiveCommonTableExpression<DB, N>>(name: N, expression: E): QueryCreatorWithCommonTableExpression<DB, N, E>;
256
+ /**
257
+ * Returns a copy of this query creator instance with the given plugin installed.
258
+ */
259
+ withPlugin(plugin: KyselyPlugin): QueryCreator<DB>;
260
+ /**
261
+ * Returns a copy of this query creator instance without any plugins.
262
+ */
263
+ withoutPlugins(): QueryCreator<DB>;
255
264
  /**
256
265
  * Sets the schema to be used for all table references that don't explicitly
257
266
  * specify a schema.
@@ -190,6 +190,24 @@ export class QueryCreator {
190
190
  : WithNode.create(cte, { recursive: true }),
191
191
  });
192
192
  }
193
+ /**
194
+ * Returns a copy of this query creator instance with the given plugin installed.
195
+ */
196
+ withPlugin(plugin) {
197
+ return new QueryCreator({
198
+ ...this.#props,
199
+ executor: this.#props.executor.withPlugin(plugin),
200
+ });
201
+ }
202
+ /**
203
+ * Returns a copy of this query creator instance without any plugins.
204
+ */
205
+ withoutPlugins() {
206
+ return new QueryCreator({
207
+ ...this.#props,
208
+ executor: this.#props.executor.withoutPlugins(),
209
+ });
210
+ }
193
211
  /**
194
212
  * Sets the schema to be used for all table references that don't explicitly
195
213
  * specify a schema.
@@ -8,6 +8,7 @@ import { DropSchemaBuilder } from './drop-schema-builder.js';
8
8
  import { DropTableBuilder } from './drop-table-builder.js';
9
9
  import { CreateViewBuilder } from './create-view-builder.js';
10
10
  import { DropViewBuilder } from './drop-view-builder.js';
11
+ import { KyselyPlugin } from '../plugin/kysely-plugin.js';
11
12
  /**
12
13
  * Provides methods for building database schema.
13
14
  */
@@ -169,6 +170,14 @@ export declare class SchemaModule {
169
170
  * ```
170
171
  */
171
172
  dropView(viewName: string): DropViewBuilder;
173
+ /**
174
+ * Returns a copy of this schema module with the given plugin installed.
175
+ */
176
+ withPlugin(plugin: KyselyPlugin): SchemaModule;
177
+ /**
178
+ * Returns a copy of this schema module without any plugins.
179
+ */
180
+ withoutPlugins(): SchemaModule;
172
181
  /**
173
182
  * See {@link QueryCreator.withSchema}
174
183
  */
@@ -237,6 +237,18 @@ export class SchemaModule {
237
237
  dropViewNode: DropViewNode.create(viewName),
238
238
  });
239
239
  }
240
+ /**
241
+ * Returns a copy of this schema module with the given plugin installed.
242
+ */
243
+ withPlugin(plugin) {
244
+ return new SchemaModule(this.#executor.withPlugin(plugin));
245
+ }
246
+ /**
247
+ * Returns a copy of this schema module without any plugins.
248
+ */
249
+ withoutPlugins() {
250
+ return new SchemaModule(this.#executor.withoutPlugins());
251
+ }
240
252
  /**
241
253
  * See {@link QueryCreator.withSchema}
242
254
  */
@@ -43,13 +43,21 @@ export declare type ColumnType<SelectType, InsertType = SelectType, UpdateType =
43
43
  * is the same for all selects, inserts and updates but the
44
44
  * column is optional for inserts and updates.
45
45
  *
46
- * This is implemented using {@link ColumnType} like this:
46
+ * The implementation:
47
47
  *
48
48
  * ```ts
49
+ * // The update type is `S` instead of `S | undefined` because
50
+ * // updates are always optional --> no need to specify optionality.
49
51
  * type Generated<S> = ColumnType<S, S | undefined, S>
50
52
  * ```
51
53
  */
52
54
  export declare type Generated<S> = ColumnType<S, S | undefined, S>;
55
+ /**
56
+ * A shortcut for defining columns that are only database-generated
57
+ * (like postgres GENERATED ALWAYS AS IDENTITY). No insert/update
58
+ * is allowed.
59
+ */
60
+ export declare type GeneratedAlways<S> = ColumnType<S, never, never>;
53
61
  /**
54
62
  * Evaluates to `K` if `T` can be `null` or `undefined`.
55
63
  */
@@ -0,0 +1 @@
1
+ export declare function extendStackTrace(err: unknown, stackError: Error): unknown;
@@ -0,0 +1,14 @@
1
+ /// <reference types="./stack-trace-utils.d.ts" />
2
+ import { isObject, isString } from './object-utils.js';
3
+ export function extendStackTrace(err, stackError) {
4
+ if (isStackHolder(err) && stackError.stack) {
5
+ // Remove the first line that just says `Error`.
6
+ const stackExtension = stackError.stack.split('\n').slice(1).join('\n');
7
+ err.stack += `\n${stackExtension}`;
8
+ return err;
9
+ }
10
+ return err;
11
+ }
12
+ function isStackHolder(obj) {
13
+ return isObject(obj) && isString(obj.stack);
14
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kysely",
3
- "version": "0.18.0",
3
+ "version": "0.18.1",
4
4
  "description": "Type safe SQL query builder",
5
5
  "repository": {
6
6
  "type": "git",
@@ -48,21 +48,21 @@
48
48
  },
49
49
  "devDependencies": {
50
50
  "@types/better-sqlite3": "^7.5.0",
51
- "@types/chai": "^4.3.0",
51
+ "@types/chai": "^4.3.1",
52
52
  "@types/chai-subset": "^1.3.3",
53
53
  "@types/mocha": "^9.1.0",
54
54
  "@types/pg": "^8.6.5",
55
- "better-sqlite3": "^7.5.0",
55
+ "better-sqlite3": "^7.5.1",
56
56
  "chai": "^4.3.6",
57
57
  "chai-subset": "^1.6.0",
58
- "esbuild": "^0.14.27",
58
+ "esbuild": "^0.14.36",
59
59
  "mocha": "^9.2.2",
60
60
  "mysql2": "^2.3.3",
61
61
  "pg": "^8.7.3",
62
- "playwright": "^1.20.0",
63
- "prettier": "^2.6.0",
64
- "tsd": "^0.19.1",
65
- "typedoc": "^0.22.13",
66
- "typescript": "4.6.2"
62
+ "playwright": "^1.21.0",
63
+ "prettier": "^2.6.2",
64
+ "tsd": "^0.20.0",
65
+ "typedoc": "^0.22.15",
66
+ "typescript": "4.6.3"
67
67
  }
68
68
  }