kysely 0.12.1 → 0.14.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.
- package/README.md +34 -10
- package/dist/cjs/{introspection → dialect}/database-introspector.d.ts +0 -0
- package/dist/cjs/{introspection → dialect}/database-introspector.js +0 -0
- package/dist/cjs/dialect/dialect.d.ts +1 -1
- package/dist/cjs/dialect/mysql/mysql-adapter.d.ts +2 -2
- package/dist/cjs/dialect/mysql/mysql-adapter.js +2 -1
- package/dist/cjs/dialect/mysql/mysql-dialect.d.ts +1 -1
- package/dist/cjs/dialect/mysql/mysql-introspector.d.ts +1 -1
- package/dist/cjs/dialect/postgres/postgres-adapter.d.ts +2 -2
- package/dist/cjs/dialect/postgres/postgres-adapter.js +2 -1
- package/dist/cjs/dialect/postgres/postgres-dialect.d.ts +1 -1
- package/dist/cjs/dialect/postgres/postgres-introspector.d.ts +1 -1
- package/dist/cjs/dialect/sqlite/sqlite-adapter.d.ts +2 -2
- package/dist/cjs/dialect/sqlite/sqlite-dialect.d.ts +1 -1
- package/dist/cjs/dialect/sqlite/sqlite-introspector.d.ts +1 -1
- package/dist/cjs/index.d.ts +5 -3
- package/dist/cjs/index.js +4 -2
- package/dist/cjs/kysely.d.ts +152 -1
- package/dist/cjs/kysely.js +37 -0
- package/dist/cjs/migration/migration.d.ts +154 -11
- package/dist/cjs/migration/migration.js +256 -135
- package/dist/cjs/operation-node/check-constraint-node.d.ts +1 -1
- package/dist/cjs/operation-node/check-constraint-node.js +2 -3
- package/dist/cjs/operation-node/column-definition-node.d.ts +8 -7
- package/dist/cjs/operation-node/column-definition-node.js +0 -4
- package/dist/cjs/operation-node/common-table-expression-name-node.d.ts +15 -0
- package/dist/cjs/operation-node/common-table-expression-name-node.js +23 -0
- package/dist/cjs/operation-node/common-table-expression-node.d.ts +3 -3
- package/dist/cjs/operation-node/data-type-node.d.ts +1 -1
- package/dist/cjs/operation-node/generated-node.d.ts +20 -0
- package/dist/cjs/operation-node/generated-node.js +31 -0
- package/dist/cjs/operation-node/on-conflict-node.d.ts +13 -2
- package/dist/cjs/operation-node/on-conflict-node.js +39 -1
- package/dist/cjs/operation-node/operation-node-transformer.d.ts +4 -2
- package/dist/cjs/operation-node/operation-node-transformer.js +22 -6
- package/dist/cjs/operation-node/operation-node-visitor.d.ts +4 -2
- package/dist/cjs/operation-node/operation-node-visitor.js +2 -1
- package/dist/cjs/operation-node/operation-node.d.ts +1 -1
- package/dist/cjs/operation-node/with-node.d.ts +3 -1
- package/dist/cjs/operation-node/with-node.js +2 -1
- package/dist/cjs/parser/reference-parser.d.ts +2 -2
- package/dist/cjs/parser/select-parser.d.ts +2 -2
- package/dist/cjs/parser/with-parser.d.ts +32 -5
- package/dist/cjs/parser/with-parser.js +13 -2
- package/dist/cjs/plugin/camel-case/camel-case-plugin.d.ts +2 -2
- package/dist/cjs/plugin/with-schema/with-schema-transformer.js +8 -0
- package/dist/cjs/query-builder/insert-query-builder.d.ts +76 -75
- package/dist/cjs/query-builder/insert-query-builder.js +150 -15
- package/dist/cjs/query-builder/on-conflict-builder.d.ts +686 -0
- package/dist/cjs/query-builder/on-conflict-builder.js +323 -0
- package/dist/cjs/query-compiler/default-query-compiler.d.ts +4 -2
- package/dist/cjs/query-compiler/default-query-compiler.js +48 -8
- package/dist/cjs/query-creator.d.ts +27 -3
- package/dist/cjs/query-creator.js +33 -1
- package/dist/cjs/query-executor/default-query-executor.d.ts +19 -0
- package/dist/cjs/query-executor/noop-query-executor.d.ts +19 -0
- package/dist/cjs/raw-builder/raw-builder.js +1 -1
- package/dist/cjs/schema/alter-table-builder.d.ts +41 -9
- package/dist/cjs/schema/alter-table-builder.js +45 -9
- package/dist/cjs/schema/column-definition-builder.d.ts +40 -8
- package/dist/cjs/schema/column-definition-builder.js +21 -8
- package/dist/cjs/schema/create-index-builder.d.ts +3 -2
- package/dist/cjs/schema/create-index-builder.js +2 -2
- package/dist/cjs/schema/create-table-builder.d.ts +3 -2
- package/dist/cjs/schema/create-table-builder.js +2 -2
- package/dist/cjs/util/type-utils.d.ts +11 -7
- package/dist/esm/{introspection → dialect}/database-introspector.d.ts +0 -0
- package/dist/esm/{introspection → dialect}/database-introspector.js +0 -0
- package/dist/esm/dialect/dialect.d.ts +1 -1
- package/dist/esm/dialect/mysql/mysql-adapter.d.ts +2 -2
- package/dist/esm/dialect/mysql/mysql-adapter.js +2 -1
- package/dist/esm/dialect/mysql/mysql-dialect.d.ts +1 -1
- package/dist/esm/dialect/mysql/mysql-introspector.d.ts +1 -1
- package/dist/esm/dialect/postgres/postgres-adapter.d.ts +2 -2
- package/dist/esm/dialect/postgres/postgres-adapter.js +2 -1
- package/dist/esm/dialect/postgres/postgres-dialect.d.ts +1 -1
- package/dist/esm/dialect/postgres/postgres-introspector.d.ts +1 -1
- package/dist/esm/dialect/sqlite/sqlite-adapter.d.ts +2 -2
- package/dist/esm/dialect/sqlite/sqlite-dialect.d.ts +1 -1
- package/dist/esm/dialect/sqlite/sqlite-introspector.d.ts +1 -1
- package/dist/esm/index.d.ts +5 -3
- package/dist/esm/index.js +4 -2
- package/dist/esm/kysely.d.ts +152 -1
- package/dist/esm/kysely.js +37 -0
- package/dist/esm/migration/migration.d.ts +154 -11
- package/dist/esm/migration/migration.js +255 -134
- package/dist/esm/operation-node/check-constraint-node.d.ts +1 -1
- package/dist/esm/operation-node/check-constraint-node.js +2 -3
- package/dist/esm/operation-node/column-definition-node.d.ts +8 -7
- package/dist/esm/operation-node/column-definition-node.js +0 -4
- package/dist/esm/operation-node/common-table-expression-name-node.d.ts +15 -0
- package/dist/esm/operation-node/common-table-expression-name-node.js +20 -0
- package/dist/esm/operation-node/common-table-expression-node.d.ts +3 -3
- package/dist/esm/operation-node/data-type-node.d.ts +1 -1
- package/dist/esm/operation-node/generated-node.d.ts +20 -0
- package/dist/esm/operation-node/generated-node.js +28 -0
- package/dist/esm/operation-node/on-conflict-node.d.ts +13 -2
- package/dist/esm/operation-node/on-conflict-node.js +39 -1
- package/dist/esm/operation-node/operation-node-transformer.d.ts +4 -2
- package/dist/esm/operation-node/operation-node-transformer.js +22 -6
- package/dist/esm/operation-node/operation-node-visitor.d.ts +4 -2
- package/dist/esm/operation-node/operation-node-visitor.js +2 -1
- package/dist/esm/operation-node/operation-node.d.ts +1 -1
- package/dist/esm/operation-node/with-node.d.ts +3 -1
- package/dist/esm/operation-node/with-node.js +2 -1
- package/dist/esm/parser/reference-parser.d.ts +2 -2
- package/dist/esm/parser/select-parser.d.ts +2 -2
- package/dist/esm/parser/with-parser.d.ts +32 -5
- package/dist/esm/parser/with-parser.js +13 -2
- package/dist/esm/plugin/camel-case/camel-case-plugin.d.ts +2 -2
- package/dist/esm/plugin/with-schema/with-schema-transformer.js +8 -0
- package/dist/esm/query-builder/insert-query-builder.d.ts +76 -75
- package/dist/esm/query-builder/insert-query-builder.js +150 -15
- package/dist/esm/query-builder/on-conflict-builder.d.ts +686 -0
- package/dist/esm/query-builder/on-conflict-builder.js +317 -0
- package/dist/esm/query-compiler/default-query-compiler.d.ts +4 -2
- package/dist/esm/query-compiler/default-query-compiler.js +48 -8
- package/dist/esm/query-creator.d.ts +27 -3
- package/dist/esm/query-creator.js +33 -1
- package/dist/esm/query-executor/default-query-executor.d.ts +19 -0
- package/dist/esm/query-executor/noop-query-executor.d.ts +19 -0
- package/dist/esm/raw-builder/raw-builder.js +1 -1
- package/dist/esm/schema/alter-table-builder.d.ts +41 -9
- package/dist/esm/schema/alter-table-builder.js +45 -9
- package/dist/esm/schema/column-definition-builder.d.ts +40 -8
- package/dist/esm/schema/column-definition-builder.js +21 -8
- package/dist/esm/schema/create-index-builder.d.ts +3 -2
- package/dist/esm/schema/create-index-builder.js +2 -2
- package/dist/esm/schema/create-table-builder.d.ts +3 -2
- package/dist/esm/schema/create-table-builder.js +2 -2
- package/dist/esm/util/type-utils.d.ts +11 -7
- package/package.json +2 -2
- package/dist/cjs/operation-node/generated-always-as-node.d.ts +0 -16
- package/dist/cjs/operation-node/generated-always-as-node.js +0 -25
- package/dist/cjs/parser/on-conflict-parser.d.ts +0 -10
- package/dist/cjs/parser/on-conflict-parser.js +0 -35
- package/dist/esm/operation-node/generated-always-as-node.d.ts +0 -16
- package/dist/esm/operation-node/generated-always-as-node.js +0 -22
- package/dist/esm/parser/on-conflict-parser.d.ts +0 -10
- package/dist/esm/parser/on-conflict-parser.js +0 -30
|
@@ -3,6 +3,73 @@ import { DialectAdapter } from '../dialect/dialect-adapter.js';
|
|
|
3
3
|
export declare const MIGRATION_TABLE = "kysely_migration";
|
|
4
4
|
export declare const MIGRATION_LOCK_TABLE = "kysely_migration_lock";
|
|
5
5
|
export declare const MIGRATION_LOCK_ID = "migration_lock";
|
|
6
|
+
export declare const NO_MIGRATIONS: NoMigrations;
|
|
7
|
+
export declare type MigrationsOrFolderPath = Record<string, Migration> | string;
|
|
8
|
+
export interface Migration {
|
|
9
|
+
up(db: Kysely<any>): Promise<void>;
|
|
10
|
+
down?(db: Kysely<any>): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Type for the NO_MIGRATIONS constant. Never create one of these.
|
|
14
|
+
*/
|
|
15
|
+
export interface NoMigrations {
|
|
16
|
+
readonly __noMigrations__: true;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* All migration methods ({@link MigrationModule.migrateTo | migrateTo},
|
|
20
|
+
* {@link MigrationModule.migrateToLatest | migrateToLatest} etc.) never
|
|
21
|
+
* throw but return this object instead.
|
|
22
|
+
*/
|
|
23
|
+
export interface MigrationResultSet {
|
|
24
|
+
/**
|
|
25
|
+
* This is defined if something went wrong.
|
|
26
|
+
*
|
|
27
|
+
* An error may have occurred in one of the migrations in which case the
|
|
28
|
+
* {@link results} list contains an item with `status === 'Error'` to
|
|
29
|
+
* indicate which migration failed.
|
|
30
|
+
*
|
|
31
|
+
* An error may also have occurred before Kysely was able to figure out
|
|
32
|
+
* which migrations should be executed, in which case the {@link results}
|
|
33
|
+
* list is undefined.
|
|
34
|
+
*/
|
|
35
|
+
readonly error?: unknown;
|
|
36
|
+
/**
|
|
37
|
+
* {@link MigrationResult} for each individual migration that was supposed
|
|
38
|
+
* to be executed by the operation.
|
|
39
|
+
*
|
|
40
|
+
* If all went well, each result's `status` is `Success`. If some migration
|
|
41
|
+
* failed, the failed migration's result's `status` is `Error` and all
|
|
42
|
+
* results after that one have `status` ´NotExecuted`.
|
|
43
|
+
*
|
|
44
|
+
* This property can be undefined if an error occurred before Kysely was
|
|
45
|
+
* able to figure out which migrations should be executed.
|
|
46
|
+
*
|
|
47
|
+
* If this list is empty, there were no migrations to execute.
|
|
48
|
+
*/
|
|
49
|
+
readonly results?: MigrationResult[];
|
|
50
|
+
}
|
|
51
|
+
export interface MigrationResult {
|
|
52
|
+
readonly migrationName: string;
|
|
53
|
+
/**
|
|
54
|
+
* The direction in which this migration was executed.
|
|
55
|
+
*/
|
|
56
|
+
readonly direction: 'Up' | 'Down';
|
|
57
|
+
/**
|
|
58
|
+
* The execution status.
|
|
59
|
+
*
|
|
60
|
+
* - `Success` means the migration was successfully executed. Note that
|
|
61
|
+
* if any of the later migrations in the {@link MigrationResult.results}
|
|
62
|
+
* list failed (have status `Error`) AND the dialect supports transactional
|
|
63
|
+
* DDL, even the successfull migrations were rolled back.
|
|
64
|
+
*
|
|
65
|
+
* - `Error` means the migration failed. In this case the
|
|
66
|
+
* {@link MigrationResult.error} contains the error.
|
|
67
|
+
*
|
|
68
|
+
* - `NotExecuted` means that the migration was supposed to be executed
|
|
69
|
+
* but wasn't because an earlier migration failed.
|
|
70
|
+
*/
|
|
71
|
+
readonly status: 'Success' | 'Error' | 'NotExecuted';
|
|
72
|
+
}
|
|
6
73
|
export declare class MigrationModule {
|
|
7
74
|
#private;
|
|
8
75
|
constructor(db: Kysely<any>, adapter: DialectAdapter);
|
|
@@ -10,26 +77,45 @@ export declare class MigrationModule {
|
|
|
10
77
|
* Runs all migrations that have not yet been run.
|
|
11
78
|
*
|
|
12
79
|
* The only argument must either be a file path to the folder that contains all migrations
|
|
13
|
-
* OR an object that contains all migrations (not just the ones that need to be
|
|
80
|
+
* OR an object that contains all migrations (not just the ones that need to be executed).
|
|
14
81
|
* The keys in the object must be the unique migration names.
|
|
15
82
|
*
|
|
83
|
+
* This method returns a {@link MigrationResultSet} instance and _never_ throws.
|
|
84
|
+
* {@link MigrationResultSet.error} holds the error if something went wrong.
|
|
85
|
+
* {@link MigrationResultSet.results} contains information about which migrations
|
|
86
|
+
* were executed and which failed. See the examples below.
|
|
87
|
+
*
|
|
16
88
|
* This method goes through all possible migrations (passed as the argument) and runs the
|
|
17
89
|
* ones whose names are alphabetically after the last migration that has been run. If the
|
|
18
|
-
* list of executed migrations doesn't match the list of possible migrations
|
|
19
|
-
* is thrown.
|
|
90
|
+
* list of executed migrations doesn't match the beginning of the list of possible migrations
|
|
91
|
+
* an error is thrown.
|
|
20
92
|
*
|
|
21
93
|
* ### Examples
|
|
22
94
|
*
|
|
23
95
|
* ```ts
|
|
24
|
-
* await db.migration.migrateToLatest(
|
|
96
|
+
* const { error, results } = await db.migration.migrateToLatest(
|
|
25
97
|
* path.join(__dirname, 'migrations')
|
|
26
98
|
* )
|
|
99
|
+
*
|
|
100
|
+
* results?.forEach((it) => {
|
|
101
|
+
* if (it.status === 'Success') {
|
|
102
|
+
* console.log(`migration "${it.migrationName}" was executed successfully`)
|
|
103
|
+
* } else if (it.status === 'Error') {
|
|
104
|
+
* console.error(`failed to execute migration "${it.migrationName}"`)
|
|
105
|
+
* }
|
|
106
|
+
* })
|
|
107
|
+
*
|
|
108
|
+
* if (error) {
|
|
109
|
+
* console.error('failed to run `migrateToLatest`')
|
|
110
|
+
* console.error(error)
|
|
111
|
+
* }
|
|
27
112
|
* ```
|
|
28
113
|
*
|
|
29
114
|
* In the next example, we use a record of migration objects instead of file folder path.
|
|
30
115
|
* The keys in the object are migration names that can be anything you want. The order of
|
|
31
116
|
* the migrations is determined based on the alphabetical order of the keys in the record.
|
|
32
|
-
* This can be useful if you are using a bundler
|
|
117
|
+
* This version of the `migrateToLatest` method can be useful if you are using a bundler
|
|
118
|
+
* like webpack or esbuild.
|
|
33
119
|
*
|
|
34
120
|
* ```ts
|
|
35
121
|
* await db.migration.migrateToLatest({
|
|
@@ -57,10 +143,67 @@ export declare class MigrationModule {
|
|
|
57
143
|
* })
|
|
58
144
|
* ```
|
|
59
145
|
*/
|
|
60
|
-
migrateToLatest(migrationsFolderPath: string): Promise<
|
|
61
|
-
migrateToLatest(allMigrations: Record<string, Migration>): Promise<
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
146
|
+
migrateToLatest(migrationsFolderPath: string): Promise<MigrationResultSet>;
|
|
147
|
+
migrateToLatest(allMigrations: Record<string, Migration>): Promise<MigrationResultSet>;
|
|
148
|
+
/**
|
|
149
|
+
* Migrate up/down to a specific migration.
|
|
150
|
+
*
|
|
151
|
+
* Otherwise works just like {@link migrateToLatest}. The first argument
|
|
152
|
+
* behaves the same, the output is the same etc.
|
|
153
|
+
*
|
|
154
|
+
* ### Examples
|
|
155
|
+
*
|
|
156
|
+
* ```ts
|
|
157
|
+
* await db.migration.migrateTo(
|
|
158
|
+
* path.join(__dirname, 'migrations'),
|
|
159
|
+
* 'some_migration'
|
|
160
|
+
* )
|
|
161
|
+
* ```
|
|
162
|
+
*
|
|
163
|
+
* If you specify the name of the first migration, this method migrates
|
|
164
|
+
* down to the first migration, but doesn't run the `down` migration for
|
|
165
|
+
* the first migration. In case you want to migrate down ALL migrations
|
|
166
|
+
* you can use a special constant `NO_MIGRATIONS`:
|
|
167
|
+
*
|
|
168
|
+
* ```ts
|
|
169
|
+
* await db.migration.migrateTo(
|
|
170
|
+
* path.join(__dirname, 'migrations'),
|
|
171
|
+
* NO_MIGRATIONS,
|
|
172
|
+
* )
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
migrateTo(migrationsFolderPath: string, targetMigrationName: string | NoMigrations): Promise<MigrationResultSet>;
|
|
176
|
+
migrateTo(allMigrations: Record<string, Migration>, targetMigrationName: string | NoMigrations): Promise<MigrationResultSet>;
|
|
177
|
+
/**
|
|
178
|
+
* Migrate one step up.
|
|
179
|
+
*
|
|
180
|
+
* Otherwise works just like {@link migrateToLatest}. The only argument
|
|
181
|
+
* behaves the same, the output is the same etc.
|
|
182
|
+
*
|
|
183
|
+
* ### Examples
|
|
184
|
+
*
|
|
185
|
+
* ```ts
|
|
186
|
+
* await db.migration.migrateUp(
|
|
187
|
+
* path.join(__dirname, 'migrations'),
|
|
188
|
+
* )
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
migrateUp(migrationsFolderPath: string): Promise<MigrationResultSet>;
|
|
192
|
+
migrateUp(allMigrations: Record<string, Migration>): Promise<MigrationResultSet>;
|
|
193
|
+
/**
|
|
194
|
+
* Migrate one step down.
|
|
195
|
+
*
|
|
196
|
+
* Otherwise works just like {@link migrateToLatest}. The only argument
|
|
197
|
+
* behaves the same, the output is the same etc.
|
|
198
|
+
*
|
|
199
|
+
* ### Examples
|
|
200
|
+
*
|
|
201
|
+
* ```ts
|
|
202
|
+
* await db.migration.migrateDown(
|
|
203
|
+
* path.join(__dirname, 'migrations'),
|
|
204
|
+
* )
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
migrateDown(migrationsFolderPath: string): Promise<MigrationResultSet>;
|
|
208
|
+
migrateDown(allMigrations: Record<string, Migration>): Promise<MigrationResultSet>;
|
|
66
209
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MigrationModule = exports.MIGRATION_LOCK_ID = exports.MIGRATION_LOCK_TABLE = exports.MIGRATION_TABLE = void 0;
|
|
3
|
+
exports.MigrationModule = exports.NO_MIGRATIONS = exports.MIGRATION_LOCK_ID = exports.MIGRATION_LOCK_TABLE = exports.MIGRATION_TABLE = void 0;
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const fs_1 = require("fs");
|
|
6
6
|
const object_utils_js_1 = require("../util/object-utils.js");
|
|
7
7
|
exports.MIGRATION_TABLE = 'kysely_migration';
|
|
8
8
|
exports.MIGRATION_LOCK_TABLE = 'kysely_migration_lock';
|
|
9
9
|
exports.MIGRATION_LOCK_ID = 'migration_lock';
|
|
10
|
+
exports.NO_MIGRATIONS = (0, object_utils_js_1.freeze)({ __noMigrations__: true });
|
|
10
11
|
class MigrationModule {
|
|
11
12
|
#db;
|
|
12
13
|
#adapter;
|
|
@@ -15,171 +16,291 @@ class MigrationModule {
|
|
|
15
16
|
this.#adapter = adapter;
|
|
16
17
|
}
|
|
17
18
|
async migrateToLatest(migrationsOrFolderPath) {
|
|
18
|
-
|
|
19
|
-
const allMigrations = await this.#getAllMigrations(migrationsOrFolderPath);
|
|
20
|
-
await this.#migrateToLatest(allMigrations);
|
|
19
|
+
return this.#migrate(migrationsOrFolderPath, ({ migrations }) => migrations.length - 1);
|
|
21
20
|
}
|
|
22
|
-
async
|
|
23
|
-
return (
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
async migrateTo(migrationsOrFolderPath, targetMigrationName) {
|
|
22
|
+
return this.#migrate(migrationsOrFolderPath, ({ migrations }) => {
|
|
23
|
+
if (targetMigrationName === exports.NO_MIGRATIONS) {
|
|
24
|
+
return -1;
|
|
25
|
+
}
|
|
26
|
+
const index = migrations.findIndex((it) => it.name === targetMigrationName);
|
|
27
|
+
if (index === -1) {
|
|
28
|
+
throw new Error(`migration "${targetMigrationName}" doesn't exist`);
|
|
29
|
+
}
|
|
30
|
+
return index;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
async migrateUp(migrationsOrFolderPath) {
|
|
34
|
+
return this.#migrate(migrationsOrFolderPath, ({ currentIndex, migrations }) => Math.min(currentIndex + 1, migrations.length - 1));
|
|
35
|
+
}
|
|
36
|
+
async migrateDown(migrationsOrFolderPath) {
|
|
37
|
+
return this.#migrate(migrationsOrFolderPath, ({ currentIndex }) => Math.max(currentIndex - 1, -1));
|
|
38
|
+
}
|
|
39
|
+
async #migrate(migrationsOrFolderPath, getTargetMigration) {
|
|
40
|
+
try {
|
|
41
|
+
await this.#ensureMigrationTablesExists();
|
|
42
|
+
return await this.#runMigrations(migrationsOrFolderPath, getTargetMigration);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
if (error instanceof MigrationResultSetError) {
|
|
46
|
+
return error.resultSet;
|
|
47
|
+
}
|
|
48
|
+
return { error };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async #ensureMigrationTablesExists() {
|
|
52
|
+
await this.#ensureMigrationTableExists();
|
|
53
|
+
await this.#ensureMigrationLockTableExists();
|
|
54
|
+
await this.#ensureLockRowExists();
|
|
26
55
|
}
|
|
27
|
-
async #
|
|
56
|
+
async #ensureMigrationTableExists() {
|
|
57
|
+
if (!(await this.#doesTableExists(exports.MIGRATION_TABLE))) {
|
|
58
|
+
try {
|
|
59
|
+
await this.#db.schema
|
|
60
|
+
.createTable(exports.MIGRATION_TABLE)
|
|
61
|
+
.ifNotExists()
|
|
62
|
+
.addColumn('name', 'varchar(255)', (col) => col.notNull().primaryKey())
|
|
63
|
+
// The migration run time as ISO string. This is not a real date type as we
|
|
64
|
+
// can't know which data type is supported by all future dialects.
|
|
65
|
+
.addColumn('timestamp', 'varchar(255)', (col) => col.notNull())
|
|
66
|
+
.execute();
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
// At least on PostgreSQL, `if not exists` doesn't guarantee the `create table`
|
|
70
|
+
// query doesn't throw if the table already exits. That's why we check if
|
|
71
|
+
// the table exist here and ignore the error if it does.
|
|
72
|
+
if (!(await this.#doesTableExists(exports.MIGRATION_TABLE))) {
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async #ensureMigrationLockTableExists() {
|
|
79
|
+
if (!(await this.#doesTableExists(exports.MIGRATION_LOCK_TABLE))) {
|
|
80
|
+
try {
|
|
81
|
+
await this.#db.schema
|
|
82
|
+
.createTable(exports.MIGRATION_LOCK_TABLE)
|
|
83
|
+
.ifNotExists()
|
|
84
|
+
.addColumn('id', 'varchar(255)', (col) => col.notNull().primaryKey())
|
|
85
|
+
.addColumn('is_locked', 'integer', (col) => col.notNull().defaultTo(0))
|
|
86
|
+
.execute();
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
// At least on PostgreSQL, `if not exists` doesn't guarantee the `create table`
|
|
90
|
+
// query doesn't throw if the table already exits. That's why we check if
|
|
91
|
+
// the table exist here and ignore the error if it does.
|
|
92
|
+
if (!(await this.#doesTableExists(exports.MIGRATION_LOCK_TABLE))) {
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async #ensureLockRowExists() {
|
|
99
|
+
if (!(await this.#doesLockRowExists())) {
|
|
100
|
+
try {
|
|
101
|
+
await this.#db
|
|
102
|
+
.insertInto(exports.MIGRATION_LOCK_TABLE)
|
|
103
|
+
.values({ id: exports.MIGRATION_LOCK_ID })
|
|
104
|
+
.execute();
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
if (!(await this.#doesLockRowExists())) {
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
async #doesTableExists(tableName) {
|
|
114
|
+
const metadata = await this.#db.introspection.getMetadata({
|
|
115
|
+
withInternalKyselyTables: true,
|
|
116
|
+
});
|
|
117
|
+
return !!metadata.tables.find((it) => it.name === tableName);
|
|
118
|
+
}
|
|
119
|
+
async #doesLockRowExists() {
|
|
120
|
+
const lockRow = await this.#db
|
|
121
|
+
.selectFrom(exports.MIGRATION_LOCK_TABLE)
|
|
122
|
+
.where('id', '=', exports.MIGRATION_LOCK_ID)
|
|
123
|
+
.select('id')
|
|
124
|
+
.executeTakeFirst();
|
|
125
|
+
return !!lockRow;
|
|
126
|
+
}
|
|
127
|
+
async #runMigrations(migrationsOrFolderPath, getTargetMigration) {
|
|
28
128
|
const run = async (db) => {
|
|
29
129
|
try {
|
|
30
130
|
await this.#adapter.acquireMigrationLock(db);
|
|
31
|
-
await
|
|
131
|
+
const state = await this.#getState(db, migrationsOrFolderPath);
|
|
132
|
+
if (state.migrations.length === 0) {
|
|
133
|
+
return { results: [] };
|
|
134
|
+
}
|
|
135
|
+
const targetIndex = getTargetMigration(state);
|
|
136
|
+
if (targetIndex === undefined) {
|
|
137
|
+
return { results: [] };
|
|
138
|
+
}
|
|
139
|
+
if (targetIndex < state.currentIndex) {
|
|
140
|
+
return await this.#migrateDown(db, state, targetIndex);
|
|
141
|
+
}
|
|
142
|
+
else if (targetIndex > state.currentIndex) {
|
|
143
|
+
return await this.#migrateUp(db, state, targetIndex);
|
|
144
|
+
}
|
|
145
|
+
return { results: [] };
|
|
32
146
|
}
|
|
33
147
|
finally {
|
|
34
148
|
await this.#adapter.releaseMigrationLock(db);
|
|
35
149
|
}
|
|
36
150
|
};
|
|
37
151
|
if (this.#adapter.supportsTransactionalDdl) {
|
|
38
|
-
|
|
152
|
+
return this.#db.transaction().execute(run);
|
|
39
153
|
}
|
|
40
154
|
else {
|
|
41
|
-
|
|
155
|
+
return this.#db.connection().execute(run);
|
|
42
156
|
}
|
|
43
157
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
158
|
+
async #getState(db, migrationsOrFolderPath) {
|
|
159
|
+
const migrations = await this.#resolveMigrations(migrationsOrFolderPath);
|
|
160
|
+
const executedMigrations = await this.#getExecutedMigrations(db);
|
|
161
|
+
this.#ensureMigrationsNotCorrupted(migrations, executedMigrations);
|
|
162
|
+
return (0, object_utils_js_1.freeze)({
|
|
163
|
+
migrations,
|
|
164
|
+
currentIndex: migrations.findIndex((it) => it.name === (0, object_utils_js_1.getLast)(executedMigrations)),
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
async #resolveMigrations(migrationsOrFolderPath) {
|
|
168
|
+
const allMigrations = (0, object_utils_js_1.isString)(migrationsOrFolderPath)
|
|
169
|
+
? await this.#readMigrationsFromFolder(migrationsOrFolderPath)
|
|
170
|
+
: migrationsOrFolderPath;
|
|
171
|
+
return Object.keys(allMigrations)
|
|
172
|
+
.sort()
|
|
173
|
+
.map((name) => ({
|
|
174
|
+
...allMigrations[name],
|
|
175
|
+
name,
|
|
176
|
+
}));
|
|
177
|
+
}
|
|
178
|
+
async #readMigrationsFromFolder(migrationsFolderPath) {
|
|
179
|
+
const files = await fs_1.promises.readdir(migrationsFolderPath);
|
|
180
|
+
const migrations = {};
|
|
181
|
+
for (const file of files) {
|
|
182
|
+
if ((file.endsWith('.js') || file.endsWith('.ts')) &&
|
|
183
|
+
!file.endsWith('.d.ts')) {
|
|
184
|
+
const migration = await Promise.resolve().then(() => require(path.join(migrationsFolderPath, file)));
|
|
185
|
+
if (isMigration(migration)) {
|
|
186
|
+
migrations[file.substring(0, file.length - 3)] = migration;
|
|
187
|
+
}
|
|
69
188
|
}
|
|
70
189
|
}
|
|
190
|
+
return migrations;
|
|
71
191
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
192
|
+
async #getExecutedMigrations(db) {
|
|
193
|
+
const executedMigrations = await db
|
|
194
|
+
.selectFrom(exports.MIGRATION_TABLE)
|
|
195
|
+
.select('name')
|
|
196
|
+
.orderBy('name')
|
|
197
|
+
.execute();
|
|
198
|
+
return executedMigrations.map((it) => it.name);
|
|
199
|
+
}
|
|
200
|
+
#ensureMigrationsNotCorrupted(migrations, executedMigrations) {
|
|
201
|
+
for (const executed of executedMigrations) {
|
|
202
|
+
if (!migrations.some((it) => it.name === executed)) {
|
|
203
|
+
throw new Error(`corrupted migrations: previously executed migration ${executed} is missing`);
|
|
204
|
+
}
|
|
82
205
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (
|
|
88
|
-
throw
|
|
206
|
+
// Now we know all executed migrations exist in the `migrations` list.
|
|
207
|
+
// Next we need to make sure that the executed migrations are the first
|
|
208
|
+
// ones in the migration list.
|
|
209
|
+
for (let i = 0; i < executedMigrations.length; ++i) {
|
|
210
|
+
if (migrations[i].name !== executedMigrations[i]) {
|
|
211
|
+
throw new Error(`corrupted migrations: expected previously executed migration ${executedMigrations[i]} to be at index ${i} but ${migrations[i].name} was found in its place. New migrations must always have a name that comes alphabetically after the last executed migration.`);
|
|
89
212
|
}
|
|
90
213
|
}
|
|
91
214
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
215
|
+
async #migrateDown(db, state, targetIndex) {
|
|
216
|
+
const results = [];
|
|
217
|
+
for (let i = state.currentIndex; i > targetIndex; --i) {
|
|
218
|
+
results.push({
|
|
219
|
+
migrationName: state.migrations[i].name,
|
|
220
|
+
direction: 'Down',
|
|
221
|
+
status: 'NotExecuted',
|
|
222
|
+
});
|
|
100
223
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
224
|
+
for (let i = 0; i < results.length; ++i) {
|
|
225
|
+
const migration = state.migrations.find((it) => it.name === results[i].migrationName);
|
|
226
|
+
try {
|
|
227
|
+
if (migration.down) {
|
|
228
|
+
await migration.down(db);
|
|
229
|
+
await db
|
|
230
|
+
.deleteFrom(exports.MIGRATION_TABLE)
|
|
231
|
+
.where('name', '=', migration.name)
|
|
232
|
+
.execute();
|
|
233
|
+
results[i] = {
|
|
234
|
+
migrationName: migration.name,
|
|
235
|
+
direction: 'Down',
|
|
236
|
+
status: 'Success',
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
results[i] = {
|
|
242
|
+
migrationName: migration.name,
|
|
243
|
+
direction: 'Down',
|
|
244
|
+
status: 'Error',
|
|
245
|
+
};
|
|
246
|
+
throw new MigrationResultSetError({
|
|
247
|
+
error,
|
|
248
|
+
results,
|
|
249
|
+
});
|
|
104
250
|
}
|
|
105
251
|
}
|
|
252
|
+
return { results };
|
|
106
253
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
254
|
+
async #migrateUp(db, state, targetIndex) {
|
|
255
|
+
const results = [];
|
|
256
|
+
for (let i = state.currentIndex + 1; i <= targetIndex; ++i) {
|
|
257
|
+
results.push({
|
|
258
|
+
migrationName: state.migrations[i].name,
|
|
259
|
+
direction: 'Up',
|
|
260
|
+
status: 'NotExecuted',
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
for (let i = 0; i < results.length; ++i) {
|
|
264
|
+
const migration = state.migrations.find((it) => it.name === results[i].migrationName);
|
|
265
|
+
try {
|
|
266
|
+
await migration.up(db);
|
|
267
|
+
await db
|
|
268
|
+
.insertInto(exports.MIGRATION_TABLE)
|
|
269
|
+
.values({
|
|
270
|
+
name: migration.name,
|
|
271
|
+
timestamp: new Date().toISOString(),
|
|
272
|
+
})
|
|
273
|
+
.execute();
|
|
274
|
+
results[i] = {
|
|
275
|
+
migrationName: migration.name,
|
|
276
|
+
direction: 'Up',
|
|
277
|
+
status: 'Success',
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
catch (error) {
|
|
281
|
+
results[i] = {
|
|
282
|
+
migrationName: migration.name,
|
|
283
|
+
direction: 'Up',
|
|
284
|
+
status: 'Error',
|
|
285
|
+
};
|
|
286
|
+
throw new MigrationResultSetError({
|
|
287
|
+
error,
|
|
288
|
+
results,
|
|
289
|
+
});
|
|
131
290
|
}
|
|
132
291
|
}
|
|
133
|
-
|
|
134
|
-
return migrations;
|
|
135
|
-
}
|
|
136
|
-
async function runNewMigrations(db, allMigrations) {
|
|
137
|
-
const sortedMigrations = Object.keys(allMigrations)
|
|
138
|
-
.sort()
|
|
139
|
-
.map((name) => ({
|
|
140
|
-
...allMigrations[name],
|
|
141
|
-
name,
|
|
142
|
-
}));
|
|
143
|
-
const executedMigrations = await db
|
|
144
|
-
.selectFrom(exports.MIGRATION_TABLE)
|
|
145
|
-
.select('name')
|
|
146
|
-
.orderBy('name')
|
|
147
|
-
.execute();
|
|
148
|
-
const lastExecuted = (0, object_utils_js_1.getLast)(executedMigrations);
|
|
149
|
-
const lastExecutedIndex = sortedMigrations.findIndex((it) => it.name === lastExecuted?.name);
|
|
150
|
-
if (lastExecuted && lastExecutedIndex === -1) {
|
|
151
|
-
throw new Error(`corrupted migrations: previously executed migration ${lastExecuted.name} is missing`);
|
|
152
|
-
}
|
|
153
|
-
const oldMigrations = lastExecuted
|
|
154
|
-
? sortedMigrations.slice(0, lastExecutedIndex + 1)
|
|
155
|
-
: [];
|
|
156
|
-
const newMigrations = lastExecuted
|
|
157
|
-
? sortedMigrations.slice(lastExecutedIndex + 1)
|
|
158
|
-
: sortedMigrations;
|
|
159
|
-
ensureMigrationsAreNotCorrupted(executedMigrations.map((it) => it.name), oldMigrations.map((it) => it.name));
|
|
160
|
-
for (const migration of newMigrations) {
|
|
161
|
-
await migration.up(db);
|
|
162
|
-
await db
|
|
163
|
-
.insertInto(exports.MIGRATION_TABLE)
|
|
164
|
-
.values({
|
|
165
|
-
name: migration.name,
|
|
166
|
-
timestamp: new Date().toISOString(),
|
|
167
|
-
})
|
|
168
|
-
.execute();
|
|
292
|
+
return { results };
|
|
169
293
|
}
|
|
170
294
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
295
|
+
exports.MigrationModule = MigrationModule;
|
|
296
|
+
class MigrationResultSetError extends Error {
|
|
297
|
+
#resultSet;
|
|
298
|
+
constructor(result) {
|
|
299
|
+
super();
|
|
300
|
+
this.#resultSet = result;
|
|
178
301
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
throw new Error(`corrupted migrations: new migration ${it} comes alphabetically before the last executed migration. New migrations must always have a name that comes alphabetically after the last executed migration.`);
|
|
182
|
-
}
|
|
302
|
+
get resultSet() {
|
|
303
|
+
return this.#resultSet;
|
|
183
304
|
}
|
|
184
305
|
}
|
|
185
306
|
function isMigration(obj) {
|
|
@@ -11,5 +11,5 @@ export interface CheckConstraintNode extends OperationNode {
|
|
|
11
11
|
*/
|
|
12
12
|
export declare const CheckConstraintNode: Readonly<{
|
|
13
13
|
is(node: OperationNode): node is CheckConstraintNode;
|
|
14
|
-
create(
|
|
14
|
+
create(expression: RawNode, constraintName?: string | undefined): CheckConstraintNode;
|
|
15
15
|
}>;
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CheckConstraintNode = void 0;
|
|
4
4
|
const object_utils_js_1 = require("../util/object-utils.js");
|
|
5
|
-
const raw_node_js_1 = require("./raw-node.js");
|
|
6
5
|
const identifier_node_js_1 = require("./identifier-node.js");
|
|
7
6
|
/**
|
|
8
7
|
* @internal
|
|
@@ -11,10 +10,10 @@ exports.CheckConstraintNode = (0, object_utils_js_1.freeze)({
|
|
|
11
10
|
is(node) {
|
|
12
11
|
return node.kind === 'CheckConstraintNode';
|
|
13
12
|
},
|
|
14
|
-
create(
|
|
13
|
+
create(expression, constraintName) {
|
|
15
14
|
return (0, object_utils_js_1.freeze)({
|
|
16
15
|
kind: 'CheckConstraintNode',
|
|
17
|
-
expression
|
|
16
|
+
expression,
|
|
18
17
|
name: constraintName ? identifier_node_js_1.IdentifierNode.create(constraintName) : undefined,
|
|
19
18
|
});
|
|
20
19
|
},
|