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
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as path from 'path';
|
|
2
2
|
import { promises as fs } from 'fs';
|
|
3
|
-
import { getLast, isFunction, isObject, isString, } from '../util/object-utils.js';
|
|
3
|
+
import { freeze, getLast, isFunction, isObject, isString, } from '../util/object-utils.js';
|
|
4
4
|
export const MIGRATION_TABLE = 'kysely_migration';
|
|
5
5
|
export const MIGRATION_LOCK_TABLE = 'kysely_migration_lock';
|
|
6
6
|
export const MIGRATION_LOCK_ID = 'migration_lock';
|
|
7
|
+
export const NO_MIGRATIONS = freeze({ __noMigrations__: true });
|
|
7
8
|
export class MigrationModule {
|
|
8
9
|
#db;
|
|
9
10
|
#adapter;
|
|
@@ -12,170 +13,290 @@ export class MigrationModule {
|
|
|
12
13
|
this.#adapter = adapter;
|
|
13
14
|
}
|
|
14
15
|
async migrateToLatest(migrationsOrFolderPath) {
|
|
15
|
-
|
|
16
|
-
const allMigrations = await this.#getAllMigrations(migrationsOrFolderPath);
|
|
17
|
-
await this.#migrateToLatest(allMigrations);
|
|
16
|
+
return this.#migrate(migrationsOrFolderPath, ({ migrations }) => migrations.length - 1);
|
|
18
17
|
}
|
|
19
|
-
async
|
|
20
|
-
return
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
async migrateTo(migrationsOrFolderPath, targetMigrationName) {
|
|
19
|
+
return this.#migrate(migrationsOrFolderPath, ({ migrations }) => {
|
|
20
|
+
if (targetMigrationName === NO_MIGRATIONS) {
|
|
21
|
+
return -1;
|
|
22
|
+
}
|
|
23
|
+
const index = migrations.findIndex((it) => it.name === targetMigrationName);
|
|
24
|
+
if (index === -1) {
|
|
25
|
+
throw new Error(`migration "${targetMigrationName}" doesn't exist`);
|
|
26
|
+
}
|
|
27
|
+
return index;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
async migrateUp(migrationsOrFolderPath) {
|
|
31
|
+
return this.#migrate(migrationsOrFolderPath, ({ currentIndex, migrations }) => Math.min(currentIndex + 1, migrations.length - 1));
|
|
32
|
+
}
|
|
33
|
+
async migrateDown(migrationsOrFolderPath) {
|
|
34
|
+
return this.#migrate(migrationsOrFolderPath, ({ currentIndex }) => Math.max(currentIndex - 1, -1));
|
|
35
|
+
}
|
|
36
|
+
async #migrate(migrationsOrFolderPath, getTargetMigration) {
|
|
37
|
+
try {
|
|
38
|
+
await this.#ensureMigrationTablesExists();
|
|
39
|
+
return await this.#runMigrations(migrationsOrFolderPath, getTargetMigration);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (error instanceof MigrationResultSetError) {
|
|
43
|
+
return error.resultSet;
|
|
44
|
+
}
|
|
45
|
+
return { error };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async #ensureMigrationTablesExists() {
|
|
49
|
+
await this.#ensureMigrationTableExists();
|
|
50
|
+
await this.#ensureMigrationLockTableExists();
|
|
51
|
+
await this.#ensureLockRowExists();
|
|
52
|
+
}
|
|
53
|
+
async #ensureMigrationTableExists() {
|
|
54
|
+
if (!(await this.#doesTableExists(MIGRATION_TABLE))) {
|
|
55
|
+
try {
|
|
56
|
+
await this.#db.schema
|
|
57
|
+
.createTable(MIGRATION_TABLE)
|
|
58
|
+
.ifNotExists()
|
|
59
|
+
.addColumn('name', 'varchar(255)', (col) => col.notNull().primaryKey())
|
|
60
|
+
// The migration run time as ISO string. This is not a real date type as we
|
|
61
|
+
// can't know which data type is supported by all future dialects.
|
|
62
|
+
.addColumn('timestamp', 'varchar(255)', (col) => col.notNull())
|
|
63
|
+
.execute();
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
// At least on PostgreSQL, `if not exists` doesn't guarantee the `create table`
|
|
67
|
+
// query doesn't throw if the table already exits. That's why we check if
|
|
68
|
+
// the table exist here and ignore the error if it does.
|
|
69
|
+
if (!(await this.#doesTableExists(MIGRATION_TABLE))) {
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async #ensureMigrationLockTableExists() {
|
|
76
|
+
if (!(await this.#doesTableExists(MIGRATION_LOCK_TABLE))) {
|
|
77
|
+
try {
|
|
78
|
+
await this.#db.schema
|
|
79
|
+
.createTable(MIGRATION_LOCK_TABLE)
|
|
80
|
+
.ifNotExists()
|
|
81
|
+
.addColumn('id', 'varchar(255)', (col) => col.notNull().primaryKey())
|
|
82
|
+
.addColumn('is_locked', 'integer', (col) => col.notNull().defaultTo(0))
|
|
83
|
+
.execute();
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
// At least on PostgreSQL, `if not exists` doesn't guarantee the `create table`
|
|
87
|
+
// query doesn't throw if the table already exits. That's why we check if
|
|
88
|
+
// the table exist here and ignore the error if it does.
|
|
89
|
+
if (!(await this.#doesTableExists(MIGRATION_LOCK_TABLE))) {
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
23
94
|
}
|
|
24
|
-
async #
|
|
95
|
+
async #ensureLockRowExists() {
|
|
96
|
+
if (!(await this.#doesLockRowExists())) {
|
|
97
|
+
try {
|
|
98
|
+
await this.#db
|
|
99
|
+
.insertInto(MIGRATION_LOCK_TABLE)
|
|
100
|
+
.values({ id: MIGRATION_LOCK_ID })
|
|
101
|
+
.execute();
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
if (!(await this.#doesLockRowExists())) {
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async #doesTableExists(tableName) {
|
|
111
|
+
const metadata = await this.#db.introspection.getMetadata({
|
|
112
|
+
withInternalKyselyTables: true,
|
|
113
|
+
});
|
|
114
|
+
return !!metadata.tables.find((it) => it.name === tableName);
|
|
115
|
+
}
|
|
116
|
+
async #doesLockRowExists() {
|
|
117
|
+
const lockRow = await this.#db
|
|
118
|
+
.selectFrom(MIGRATION_LOCK_TABLE)
|
|
119
|
+
.where('id', '=', MIGRATION_LOCK_ID)
|
|
120
|
+
.select('id')
|
|
121
|
+
.executeTakeFirst();
|
|
122
|
+
return !!lockRow;
|
|
123
|
+
}
|
|
124
|
+
async #runMigrations(migrationsOrFolderPath, getTargetMigration) {
|
|
25
125
|
const run = async (db) => {
|
|
26
126
|
try {
|
|
27
127
|
await this.#adapter.acquireMigrationLock(db);
|
|
28
|
-
await
|
|
128
|
+
const state = await this.#getState(db, migrationsOrFolderPath);
|
|
129
|
+
if (state.migrations.length === 0) {
|
|
130
|
+
return { results: [] };
|
|
131
|
+
}
|
|
132
|
+
const targetIndex = getTargetMigration(state);
|
|
133
|
+
if (targetIndex === undefined) {
|
|
134
|
+
return { results: [] };
|
|
135
|
+
}
|
|
136
|
+
if (targetIndex < state.currentIndex) {
|
|
137
|
+
return await this.#migrateDown(db, state, targetIndex);
|
|
138
|
+
}
|
|
139
|
+
else if (targetIndex > state.currentIndex) {
|
|
140
|
+
return await this.#migrateUp(db, state, targetIndex);
|
|
141
|
+
}
|
|
142
|
+
return { results: [] };
|
|
29
143
|
}
|
|
30
144
|
finally {
|
|
31
145
|
await this.#adapter.releaseMigrationLock(db);
|
|
32
146
|
}
|
|
33
147
|
};
|
|
34
148
|
if (this.#adapter.supportsTransactionalDdl) {
|
|
35
|
-
|
|
149
|
+
return this.#db.transaction().execute(run);
|
|
36
150
|
}
|
|
37
151
|
else {
|
|
38
|
-
|
|
152
|
+
return this.#db.connection().execute(run);
|
|
39
153
|
}
|
|
40
154
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
155
|
+
async #getState(db, migrationsOrFolderPath) {
|
|
156
|
+
const migrations = await this.#resolveMigrations(migrationsOrFolderPath);
|
|
157
|
+
const executedMigrations = await this.#getExecutedMigrations(db);
|
|
158
|
+
this.#ensureMigrationsNotCorrupted(migrations, executedMigrations);
|
|
159
|
+
return freeze({
|
|
160
|
+
migrations,
|
|
161
|
+
currentIndex: migrations.findIndex((it) => it.name === getLast(executedMigrations)),
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
async #resolveMigrations(migrationsOrFolderPath) {
|
|
165
|
+
const allMigrations = isString(migrationsOrFolderPath)
|
|
166
|
+
? await this.#readMigrationsFromFolder(migrationsOrFolderPath)
|
|
167
|
+
: migrationsOrFolderPath;
|
|
168
|
+
return Object.keys(allMigrations)
|
|
169
|
+
.sort()
|
|
170
|
+
.map((name) => ({
|
|
171
|
+
...allMigrations[name],
|
|
172
|
+
name,
|
|
173
|
+
}));
|
|
174
|
+
}
|
|
175
|
+
async #readMigrationsFromFolder(migrationsFolderPath) {
|
|
176
|
+
const files = await fs.readdir(migrationsFolderPath);
|
|
177
|
+
const migrations = {};
|
|
178
|
+
for (const file of files) {
|
|
179
|
+
if ((file.endsWith('.js') || file.endsWith('.ts')) &&
|
|
180
|
+
!file.endsWith('.d.ts')) {
|
|
181
|
+
const migration = await import(path.join(migrationsFolderPath, file));
|
|
182
|
+
if (isMigration(migration)) {
|
|
183
|
+
migrations[file.substring(0, file.length - 3)] = migration;
|
|
184
|
+
}
|
|
65
185
|
}
|
|
66
186
|
}
|
|
187
|
+
return migrations;
|
|
67
188
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
189
|
+
async #getExecutedMigrations(db) {
|
|
190
|
+
const executedMigrations = await db
|
|
191
|
+
.selectFrom(MIGRATION_TABLE)
|
|
192
|
+
.select('name')
|
|
193
|
+
.orderBy('name')
|
|
194
|
+
.execute();
|
|
195
|
+
return executedMigrations.map((it) => it.name);
|
|
196
|
+
}
|
|
197
|
+
#ensureMigrationsNotCorrupted(migrations, executedMigrations) {
|
|
198
|
+
for (const executed of executedMigrations) {
|
|
199
|
+
if (!migrations.some((it) => it.name === executed)) {
|
|
200
|
+
throw new Error(`corrupted migrations: previously executed migration ${executed} is missing`);
|
|
201
|
+
}
|
|
78
202
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (
|
|
84
|
-
throw
|
|
203
|
+
// Now we know all executed migrations exist in the `migrations` list.
|
|
204
|
+
// Next we need to make sure that the executed migrations are the first
|
|
205
|
+
// ones in the migration list.
|
|
206
|
+
for (let i = 0; i < executedMigrations.length; ++i) {
|
|
207
|
+
if (migrations[i].name !== executedMigrations[i]) {
|
|
208
|
+
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.`);
|
|
85
209
|
}
|
|
86
210
|
}
|
|
87
211
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
212
|
+
async #migrateDown(db, state, targetIndex) {
|
|
213
|
+
const results = [];
|
|
214
|
+
for (let i = state.currentIndex; i > targetIndex; --i) {
|
|
215
|
+
results.push({
|
|
216
|
+
migrationName: state.migrations[i].name,
|
|
217
|
+
direction: 'Down',
|
|
218
|
+
status: 'NotExecuted',
|
|
219
|
+
});
|
|
96
220
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
221
|
+
for (let i = 0; i < results.length; ++i) {
|
|
222
|
+
const migration = state.migrations.find((it) => it.name === results[i].migrationName);
|
|
223
|
+
try {
|
|
224
|
+
if (migration.down) {
|
|
225
|
+
await migration.down(db);
|
|
226
|
+
await db
|
|
227
|
+
.deleteFrom(MIGRATION_TABLE)
|
|
228
|
+
.where('name', '=', migration.name)
|
|
229
|
+
.execute();
|
|
230
|
+
results[i] = {
|
|
231
|
+
migrationName: migration.name,
|
|
232
|
+
direction: 'Down',
|
|
233
|
+
status: 'Success',
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
results[i] = {
|
|
239
|
+
migrationName: migration.name,
|
|
240
|
+
direction: 'Down',
|
|
241
|
+
status: 'Error',
|
|
242
|
+
};
|
|
243
|
+
throw new MigrationResultSetError({
|
|
244
|
+
error,
|
|
245
|
+
results,
|
|
246
|
+
});
|
|
100
247
|
}
|
|
101
248
|
}
|
|
249
|
+
return { results };
|
|
102
250
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
251
|
+
async #migrateUp(db, state, targetIndex) {
|
|
252
|
+
const results = [];
|
|
253
|
+
for (let i = state.currentIndex + 1; i <= targetIndex; ++i) {
|
|
254
|
+
results.push({
|
|
255
|
+
migrationName: state.migrations[i].name,
|
|
256
|
+
direction: 'Up',
|
|
257
|
+
status: 'NotExecuted',
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
for (let i = 0; i < results.length; ++i) {
|
|
261
|
+
const migration = state.migrations.find((it) => it.name === results[i].migrationName);
|
|
262
|
+
try {
|
|
263
|
+
await migration.up(db);
|
|
264
|
+
await db
|
|
265
|
+
.insertInto(MIGRATION_TABLE)
|
|
266
|
+
.values({
|
|
267
|
+
name: migration.name,
|
|
268
|
+
timestamp: new Date().toISOString(),
|
|
269
|
+
})
|
|
270
|
+
.execute();
|
|
271
|
+
results[i] = {
|
|
272
|
+
migrationName: migration.name,
|
|
273
|
+
direction: 'Up',
|
|
274
|
+
status: 'Success',
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
catch (error) {
|
|
278
|
+
results[i] = {
|
|
279
|
+
migrationName: migration.name,
|
|
280
|
+
direction: 'Up',
|
|
281
|
+
status: 'Error',
|
|
282
|
+
};
|
|
283
|
+
throw new MigrationResultSetError({
|
|
284
|
+
error,
|
|
285
|
+
results,
|
|
286
|
+
});
|
|
127
287
|
}
|
|
128
288
|
}
|
|
289
|
+
return { results };
|
|
129
290
|
}
|
|
130
|
-
return migrations;
|
|
131
291
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
name,
|
|
138
|
-
}));
|
|
139
|
-
const executedMigrations = await db
|
|
140
|
-
.selectFrom(MIGRATION_TABLE)
|
|
141
|
-
.select('name')
|
|
142
|
-
.orderBy('name')
|
|
143
|
-
.execute();
|
|
144
|
-
const lastExecuted = getLast(executedMigrations);
|
|
145
|
-
const lastExecutedIndex = sortedMigrations.findIndex((it) => it.name === lastExecuted?.name);
|
|
146
|
-
if (lastExecuted && lastExecutedIndex === -1) {
|
|
147
|
-
throw new Error(`corrupted migrations: previously executed migration ${lastExecuted.name} is missing`);
|
|
148
|
-
}
|
|
149
|
-
const oldMigrations = lastExecuted
|
|
150
|
-
? sortedMigrations.slice(0, lastExecutedIndex + 1)
|
|
151
|
-
: [];
|
|
152
|
-
const newMigrations = lastExecuted
|
|
153
|
-
? sortedMigrations.slice(lastExecutedIndex + 1)
|
|
154
|
-
: sortedMigrations;
|
|
155
|
-
ensureMigrationsAreNotCorrupted(executedMigrations.map((it) => it.name), oldMigrations.map((it) => it.name));
|
|
156
|
-
for (const migration of newMigrations) {
|
|
157
|
-
await migration.up(db);
|
|
158
|
-
await db
|
|
159
|
-
.insertInto(MIGRATION_TABLE)
|
|
160
|
-
.values({
|
|
161
|
-
name: migration.name,
|
|
162
|
-
timestamp: new Date().toISOString(),
|
|
163
|
-
})
|
|
164
|
-
.execute();
|
|
292
|
+
class MigrationResultSetError extends Error {
|
|
293
|
+
#resultSet;
|
|
294
|
+
constructor(result) {
|
|
295
|
+
super();
|
|
296
|
+
this.#resultSet = result;
|
|
165
297
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const executedSet = new Set(executedMigrationNames);
|
|
169
|
-
const oldMigrationSet = new Set(oldMigrationNames);
|
|
170
|
-
for (const it of executedSet) {
|
|
171
|
-
if (!oldMigrationSet.has(it)) {
|
|
172
|
-
throw new Error(`corrupted migrations: previously executed migration ${it} is missing`);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
for (const it of oldMigrationSet) {
|
|
176
|
-
if (!executedSet.has(it)) {
|
|
177
|
-
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.`);
|
|
178
|
-
}
|
|
298
|
+
get resultSet() {
|
|
299
|
+
return this.#resultSet;
|
|
179
300
|
}
|
|
180
301
|
}
|
|
181
302
|
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
|
}>;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { freeze } from '../util/object-utils.js';
|
|
2
|
-
import { RawNode } from './raw-node.js';
|
|
3
2
|
import { IdentifierNode } from './identifier-node.js';
|
|
4
3
|
/**
|
|
5
4
|
* @internal
|
|
@@ -8,10 +7,10 @@ export const CheckConstraintNode = freeze({
|
|
|
8
7
|
is(node) {
|
|
9
8
|
return node.kind === 'CheckConstraintNode';
|
|
10
9
|
},
|
|
11
|
-
create(
|
|
10
|
+
create(expression, constraintName) {
|
|
12
11
|
return freeze({
|
|
13
12
|
kind: 'CheckConstraintNode',
|
|
14
|
-
expression
|
|
13
|
+
expression,
|
|
15
14
|
name: constraintName ? IdentifierNode.create(constraintName) : undefined,
|
|
16
15
|
});
|
|
17
16
|
},
|
|
@@ -2,24 +2,25 @@ import { CheckConstraintNode } from './check-constraint-node.js';
|
|
|
2
2
|
import { ColumnNode } from './column-node.js';
|
|
3
3
|
import { DataTypeNode } from './data-type-node.js';
|
|
4
4
|
import { DefaultValueNode } from './default-value-node.js';
|
|
5
|
-
import {
|
|
5
|
+
import { GeneratedNode } from './generated-node.js';
|
|
6
6
|
import { OperationNode } from './operation-node.js';
|
|
7
7
|
import { RawNode } from './raw-node.js';
|
|
8
8
|
import { ReferencesNode } from './references-node.js';
|
|
9
|
-
export declare type ColumnDefinitionNodeProps = Omit<Partial<ColumnDefinitionNode>, 'kind'>;
|
|
9
|
+
export declare type ColumnDefinitionNodeProps = Omit<Partial<ColumnDefinitionNode>, 'kind' | 'dataType'>;
|
|
10
10
|
export declare type ColumnDataTypeNode = DataTypeNode | RawNode;
|
|
11
11
|
export interface ColumnDefinitionNode extends OperationNode {
|
|
12
12
|
readonly kind: 'ColumnDefinitionNode';
|
|
13
13
|
readonly column: ColumnNode;
|
|
14
14
|
readonly dataType: ColumnDataTypeNode;
|
|
15
15
|
readonly references?: ReferencesNode;
|
|
16
|
-
readonly primaryKey
|
|
17
|
-
readonly autoIncrement
|
|
18
|
-
readonly unique
|
|
19
|
-
readonly
|
|
16
|
+
readonly primaryKey?: boolean;
|
|
17
|
+
readonly autoIncrement?: boolean;
|
|
18
|
+
readonly unique?: boolean;
|
|
19
|
+
readonly notNull?: boolean;
|
|
20
20
|
readonly defaultTo?: DefaultValueNode;
|
|
21
21
|
readonly check?: CheckConstraintNode;
|
|
22
|
-
readonly
|
|
22
|
+
readonly generated?: GeneratedNode;
|
|
23
|
+
readonly unsigned?: boolean;
|
|
23
24
|
}
|
|
24
25
|
/**
|
|
25
26
|
* @internal
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ColumnNode } from './column-node.js';
|
|
2
|
+
import { OperationNode } from './operation-node.js';
|
|
3
|
+
import { TableNode } from './table-node.js';
|
|
4
|
+
export interface CommonTableExpressionNameNode extends OperationNode {
|
|
5
|
+
readonly kind: 'CommonTableExpressionNameNode';
|
|
6
|
+
readonly table: TableNode;
|
|
7
|
+
readonly columns?: ReadonlyArray<ColumnNode>;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export declare const CommonTableExpressionNameNode: Readonly<{
|
|
13
|
+
is(node: OperationNode): node is CommonTableExpressionNameNode;
|
|
14
|
+
create(tableName: string, columnNames?: readonly string[] | undefined): CommonTableExpressionNameNode;
|
|
15
|
+
}>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { freeze } from '../util/object-utils.js';
|
|
2
|
+
import { ColumnNode } from './column-node.js';
|
|
3
|
+
import { TableNode } from './table-node.js';
|
|
4
|
+
/**
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export const CommonTableExpressionNameNode = freeze({
|
|
8
|
+
is(node) {
|
|
9
|
+
return node.kind === 'CommonTableExpressionNameNode';
|
|
10
|
+
},
|
|
11
|
+
create(tableName, columnNames) {
|
|
12
|
+
return freeze({
|
|
13
|
+
kind: 'CommonTableExpressionNameNode',
|
|
14
|
+
table: TableNode.create(tableName),
|
|
15
|
+
columns: columnNames
|
|
16
|
+
? freeze(columnNames.map(ColumnNode.create))
|
|
17
|
+
: undefined,
|
|
18
|
+
});
|
|
19
|
+
},
|
|
20
|
+
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CommonTableExpressionNameNode } from './common-table-expression-name-node.js';
|
|
2
2
|
import { OperationNode } from './operation-node.js';
|
|
3
3
|
import { QueryNode } from './query-node.js';
|
|
4
4
|
import { RawNode } from './raw-node.js';
|
|
5
5
|
export interface CommonTableExpressionNode extends OperationNode {
|
|
6
6
|
readonly kind: 'CommonTableExpressionNode';
|
|
7
|
-
readonly name:
|
|
7
|
+
readonly name: CommonTableExpressionNameNode;
|
|
8
8
|
readonly expression: QueryNode | RawNode;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
@@ -12,5 +12,5 @@ export interface CommonTableExpressionNode extends OperationNode {
|
|
|
12
12
|
*/
|
|
13
13
|
export declare const CommonTableExpressionNode: Readonly<{
|
|
14
14
|
is(node: OperationNode): node is CommonTableExpressionNode;
|
|
15
|
-
create(name:
|
|
15
|
+
create(name: CommonTableExpressionNameNode, expression: QueryNode | RawNode): CommonTableExpressionNode;
|
|
16
16
|
}>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { OperationNode } from './operation-node.js';
|
|
2
|
-
export declare type ColumnDataType = 'varchar' | `varchar(${number})` | 'text' | 'integer' | 'int2' | 'int4' | 'int8' | 'bigint' | 'boolean' | 'real' | 'double precision' | 'float4' | 'float8' | 'decimal' | `decimal(${number}, ${number})` | 'numeric' | `numeric(${number}, ${number})` | 'binary' | 'date' | 'datetime' | 'time' | 'timetz' | 'timestamp' | 'timestamptz' | 'serial' | 'bigserial' | 'uuid' | 'json' | 'jsonb';
|
|
2
|
+
export declare type ColumnDataType = 'varchar' | `varchar(${number})` | 'text' | 'integer' | 'int2' | 'int4' | 'int8' | 'bigint' | 'boolean' | 'real' | 'double precision' | 'float4' | 'float8' | 'decimal' | `decimal(${number}, ${number})` | 'numeric' | `numeric(${number}, ${number})` | 'binary' | 'date' | 'datetime' | 'time' | 'timetz' | 'timestamp' | 'timestamptz' | 'serial' | 'bigserial' | 'uuid' | 'json' | 'jsonb' | 'blob';
|
|
3
3
|
export declare type DataTypeParams = Omit<DataTypeNode, 'kind' | 'dataType'>;
|
|
4
4
|
export interface DataTypeNode extends OperationNode {
|
|
5
5
|
readonly kind: 'DataTypeNode';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { OperationNode } from './operation-node.js';
|
|
2
|
+
import { RawNode } from './raw-node.js';
|
|
3
|
+
export declare type GeneratedNodeParams = Omit<GeneratedNode, 'kind' | 'expression'>;
|
|
4
|
+
export interface GeneratedNode extends OperationNode {
|
|
5
|
+
readonly kind: 'GeneratedNode';
|
|
6
|
+
readonly byDefault?: boolean;
|
|
7
|
+
readonly always?: boolean;
|
|
8
|
+
readonly identity?: boolean;
|
|
9
|
+
readonly stored?: boolean;
|
|
10
|
+
readonly expression?: RawNode;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
export declare const GeneratedNode: Readonly<{
|
|
16
|
+
is(node: OperationNode): node is GeneratedNode;
|
|
17
|
+
create(params: GeneratedNodeParams): GeneratedNode;
|
|
18
|
+
createWithExpression(expression: RawNode): GeneratedNode;
|
|
19
|
+
cloneWith(node: GeneratedNode, params: GeneratedNodeParams): GeneratedNode;
|
|
20
|
+
}>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { freeze } from '../util/object-utils.js';
|
|
2
|
+
/**
|
|
3
|
+
* @internal
|
|
4
|
+
*/
|
|
5
|
+
export const GeneratedNode = freeze({
|
|
6
|
+
is(node) {
|
|
7
|
+
return node.kind === 'GeneratedNode';
|
|
8
|
+
},
|
|
9
|
+
create(params) {
|
|
10
|
+
return freeze({
|
|
11
|
+
kind: 'GeneratedNode',
|
|
12
|
+
...params,
|
|
13
|
+
});
|
|
14
|
+
},
|
|
15
|
+
createWithExpression(expression) {
|
|
16
|
+
return freeze({
|
|
17
|
+
kind: 'GeneratedNode',
|
|
18
|
+
always: true,
|
|
19
|
+
expression,
|
|
20
|
+
});
|
|
21
|
+
},
|
|
22
|
+
cloneWith(node, params) {
|
|
23
|
+
return freeze({
|
|
24
|
+
...node,
|
|
25
|
+
...params,
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
});
|