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.
Files changed (140) hide show
  1. package/README.md +34 -10
  2. package/dist/cjs/{introspection → dialect}/database-introspector.d.ts +0 -0
  3. package/dist/cjs/{introspection → dialect}/database-introspector.js +0 -0
  4. package/dist/cjs/dialect/dialect.d.ts +1 -1
  5. package/dist/cjs/dialect/mysql/mysql-adapter.d.ts +2 -2
  6. package/dist/cjs/dialect/mysql/mysql-adapter.js +2 -1
  7. package/dist/cjs/dialect/mysql/mysql-dialect.d.ts +1 -1
  8. package/dist/cjs/dialect/mysql/mysql-introspector.d.ts +1 -1
  9. package/dist/cjs/dialect/postgres/postgres-adapter.d.ts +2 -2
  10. package/dist/cjs/dialect/postgres/postgres-adapter.js +2 -1
  11. package/dist/cjs/dialect/postgres/postgres-dialect.d.ts +1 -1
  12. package/dist/cjs/dialect/postgres/postgres-introspector.d.ts +1 -1
  13. package/dist/cjs/dialect/sqlite/sqlite-adapter.d.ts +2 -2
  14. package/dist/cjs/dialect/sqlite/sqlite-dialect.d.ts +1 -1
  15. package/dist/cjs/dialect/sqlite/sqlite-introspector.d.ts +1 -1
  16. package/dist/cjs/index.d.ts +5 -3
  17. package/dist/cjs/index.js +4 -2
  18. package/dist/cjs/kysely.d.ts +152 -1
  19. package/dist/cjs/kysely.js +37 -0
  20. package/dist/cjs/migration/migration.d.ts +154 -11
  21. package/dist/cjs/migration/migration.js +256 -135
  22. package/dist/cjs/operation-node/check-constraint-node.d.ts +1 -1
  23. package/dist/cjs/operation-node/check-constraint-node.js +2 -3
  24. package/dist/cjs/operation-node/column-definition-node.d.ts +8 -7
  25. package/dist/cjs/operation-node/column-definition-node.js +0 -4
  26. package/dist/cjs/operation-node/common-table-expression-name-node.d.ts +15 -0
  27. package/dist/cjs/operation-node/common-table-expression-name-node.js +23 -0
  28. package/dist/cjs/operation-node/common-table-expression-node.d.ts +3 -3
  29. package/dist/cjs/operation-node/data-type-node.d.ts +1 -1
  30. package/dist/cjs/operation-node/generated-node.d.ts +20 -0
  31. package/dist/cjs/operation-node/generated-node.js +31 -0
  32. package/dist/cjs/operation-node/on-conflict-node.d.ts +13 -2
  33. package/dist/cjs/operation-node/on-conflict-node.js +39 -1
  34. package/dist/cjs/operation-node/operation-node-transformer.d.ts +4 -2
  35. package/dist/cjs/operation-node/operation-node-transformer.js +22 -6
  36. package/dist/cjs/operation-node/operation-node-visitor.d.ts +4 -2
  37. package/dist/cjs/operation-node/operation-node-visitor.js +2 -1
  38. package/dist/cjs/operation-node/operation-node.d.ts +1 -1
  39. package/dist/cjs/operation-node/with-node.d.ts +3 -1
  40. package/dist/cjs/operation-node/with-node.js +2 -1
  41. package/dist/cjs/parser/reference-parser.d.ts +2 -2
  42. package/dist/cjs/parser/select-parser.d.ts +2 -2
  43. package/dist/cjs/parser/with-parser.d.ts +32 -5
  44. package/dist/cjs/parser/with-parser.js +13 -2
  45. package/dist/cjs/plugin/camel-case/camel-case-plugin.d.ts +2 -2
  46. package/dist/cjs/plugin/with-schema/with-schema-transformer.js +8 -0
  47. package/dist/cjs/query-builder/insert-query-builder.d.ts +76 -75
  48. package/dist/cjs/query-builder/insert-query-builder.js +150 -15
  49. package/dist/cjs/query-builder/on-conflict-builder.d.ts +686 -0
  50. package/dist/cjs/query-builder/on-conflict-builder.js +323 -0
  51. package/dist/cjs/query-compiler/default-query-compiler.d.ts +4 -2
  52. package/dist/cjs/query-compiler/default-query-compiler.js +48 -8
  53. package/dist/cjs/query-creator.d.ts +27 -3
  54. package/dist/cjs/query-creator.js +33 -1
  55. package/dist/cjs/query-executor/default-query-executor.d.ts +19 -0
  56. package/dist/cjs/query-executor/noop-query-executor.d.ts +19 -0
  57. package/dist/cjs/raw-builder/raw-builder.js +1 -1
  58. package/dist/cjs/schema/alter-table-builder.d.ts +41 -9
  59. package/dist/cjs/schema/alter-table-builder.js +45 -9
  60. package/dist/cjs/schema/column-definition-builder.d.ts +40 -8
  61. package/dist/cjs/schema/column-definition-builder.js +21 -8
  62. package/dist/cjs/schema/create-index-builder.d.ts +3 -2
  63. package/dist/cjs/schema/create-index-builder.js +2 -2
  64. package/dist/cjs/schema/create-table-builder.d.ts +3 -2
  65. package/dist/cjs/schema/create-table-builder.js +2 -2
  66. package/dist/cjs/util/type-utils.d.ts +11 -7
  67. package/dist/esm/{introspection → dialect}/database-introspector.d.ts +0 -0
  68. package/dist/esm/{introspection → dialect}/database-introspector.js +0 -0
  69. package/dist/esm/dialect/dialect.d.ts +1 -1
  70. package/dist/esm/dialect/mysql/mysql-adapter.d.ts +2 -2
  71. package/dist/esm/dialect/mysql/mysql-adapter.js +2 -1
  72. package/dist/esm/dialect/mysql/mysql-dialect.d.ts +1 -1
  73. package/dist/esm/dialect/mysql/mysql-introspector.d.ts +1 -1
  74. package/dist/esm/dialect/postgres/postgres-adapter.d.ts +2 -2
  75. package/dist/esm/dialect/postgres/postgres-adapter.js +2 -1
  76. package/dist/esm/dialect/postgres/postgres-dialect.d.ts +1 -1
  77. package/dist/esm/dialect/postgres/postgres-introspector.d.ts +1 -1
  78. package/dist/esm/dialect/sqlite/sqlite-adapter.d.ts +2 -2
  79. package/dist/esm/dialect/sqlite/sqlite-dialect.d.ts +1 -1
  80. package/dist/esm/dialect/sqlite/sqlite-introspector.d.ts +1 -1
  81. package/dist/esm/index.d.ts +5 -3
  82. package/dist/esm/index.js +4 -2
  83. package/dist/esm/kysely.d.ts +152 -1
  84. package/dist/esm/kysely.js +37 -0
  85. package/dist/esm/migration/migration.d.ts +154 -11
  86. package/dist/esm/migration/migration.js +255 -134
  87. package/dist/esm/operation-node/check-constraint-node.d.ts +1 -1
  88. package/dist/esm/operation-node/check-constraint-node.js +2 -3
  89. package/dist/esm/operation-node/column-definition-node.d.ts +8 -7
  90. package/dist/esm/operation-node/column-definition-node.js +0 -4
  91. package/dist/esm/operation-node/common-table-expression-name-node.d.ts +15 -0
  92. package/dist/esm/operation-node/common-table-expression-name-node.js +20 -0
  93. package/dist/esm/operation-node/common-table-expression-node.d.ts +3 -3
  94. package/dist/esm/operation-node/data-type-node.d.ts +1 -1
  95. package/dist/esm/operation-node/generated-node.d.ts +20 -0
  96. package/dist/esm/operation-node/generated-node.js +28 -0
  97. package/dist/esm/operation-node/on-conflict-node.d.ts +13 -2
  98. package/dist/esm/operation-node/on-conflict-node.js +39 -1
  99. package/dist/esm/operation-node/operation-node-transformer.d.ts +4 -2
  100. package/dist/esm/operation-node/operation-node-transformer.js +22 -6
  101. package/dist/esm/operation-node/operation-node-visitor.d.ts +4 -2
  102. package/dist/esm/operation-node/operation-node-visitor.js +2 -1
  103. package/dist/esm/operation-node/operation-node.d.ts +1 -1
  104. package/dist/esm/operation-node/with-node.d.ts +3 -1
  105. package/dist/esm/operation-node/with-node.js +2 -1
  106. package/dist/esm/parser/reference-parser.d.ts +2 -2
  107. package/dist/esm/parser/select-parser.d.ts +2 -2
  108. package/dist/esm/parser/with-parser.d.ts +32 -5
  109. package/dist/esm/parser/with-parser.js +13 -2
  110. package/dist/esm/plugin/camel-case/camel-case-plugin.d.ts +2 -2
  111. package/dist/esm/plugin/with-schema/with-schema-transformer.js +8 -0
  112. package/dist/esm/query-builder/insert-query-builder.d.ts +76 -75
  113. package/dist/esm/query-builder/insert-query-builder.js +150 -15
  114. package/dist/esm/query-builder/on-conflict-builder.d.ts +686 -0
  115. package/dist/esm/query-builder/on-conflict-builder.js +317 -0
  116. package/dist/esm/query-compiler/default-query-compiler.d.ts +4 -2
  117. package/dist/esm/query-compiler/default-query-compiler.js +48 -8
  118. package/dist/esm/query-creator.d.ts +27 -3
  119. package/dist/esm/query-creator.js +33 -1
  120. package/dist/esm/query-executor/default-query-executor.d.ts +19 -0
  121. package/dist/esm/query-executor/noop-query-executor.d.ts +19 -0
  122. package/dist/esm/raw-builder/raw-builder.js +1 -1
  123. package/dist/esm/schema/alter-table-builder.d.ts +41 -9
  124. package/dist/esm/schema/alter-table-builder.js +45 -9
  125. package/dist/esm/schema/column-definition-builder.d.ts +40 -8
  126. package/dist/esm/schema/column-definition-builder.js +21 -8
  127. package/dist/esm/schema/create-index-builder.d.ts +3 -2
  128. package/dist/esm/schema/create-index-builder.js +2 -2
  129. package/dist/esm/schema/create-table-builder.d.ts +3 -2
  130. package/dist/esm/schema/create-table-builder.js +2 -2
  131. package/dist/esm/util/type-utils.d.ts +11 -7
  132. package/package.json +2 -2
  133. package/dist/cjs/operation-node/generated-always-as-node.d.ts +0 -16
  134. package/dist/cjs/operation-node/generated-always-as-node.js +0 -25
  135. package/dist/cjs/parser/on-conflict-parser.d.ts +0 -10
  136. package/dist/cjs/parser/on-conflict-parser.js +0 -35
  137. package/dist/esm/operation-node/generated-always-as-node.d.ts +0 -16
  138. package/dist/esm/operation-node/generated-always-as-node.js +0 -22
  139. package/dist/esm/parser/on-conflict-parser.d.ts +0 -10
  140. 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
- await ensureMigrationTablesExists(this.#db);
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 #getAllMigrations(migrationsOrFolderPath) {
20
- return isString(migrationsOrFolderPath)
21
- ? await readMigrationsFromFolder(migrationsOrFolderPath)
22
- : migrationsOrFolderPath;
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 #migrateToLatest(allMigrations) {
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 runNewMigrations(db, allMigrations);
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
- await this.#db.transaction().execute(run);
149
+ return this.#db.transaction().execute(run);
36
150
  }
37
151
  else {
38
- await this.#db.connection().execute(run);
152
+ return this.#db.connection().execute(run);
39
153
  }
40
154
  }
41
- }
42
- async function ensureMigrationTablesExists(db) {
43
- await ensureMigrationTableExists(db);
44
- await ensureMigrationLockTableExists(db);
45
- await ensureLockRowExists(db);
46
- }
47
- async function ensureMigrationTableExists(db) {
48
- if (!(await doesTableExists(db, MIGRATION_TABLE))) {
49
- try {
50
- await db.schema
51
- .createTable(MIGRATION_TABLE)
52
- .ifNotExists()
53
- .addColumn('name', 'varchar(255)', (col) => col.notNull().primaryKey())
54
- // The migration run time as ISO string. This is not a real date type as we
55
- // can't know which data type is supported by all future dialects.
56
- .addColumn('timestamp', 'varchar(255)', (col) => col.notNull())
57
- .execute();
58
- }
59
- catch (error) {
60
- // At least on PostgreSQL, `if not exists` doesn't guarantee the `create table`
61
- // query doesn't throw if the table already exits. That's why we check if
62
- // the table exist here and ignore the error if it does.
63
- if (!(await doesTableExists(db, MIGRATION_TABLE))) {
64
- throw error;
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
- async function ensureMigrationLockTableExists(db) {
70
- if (!(await doesTableExists(db, MIGRATION_LOCK_TABLE))) {
71
- try {
72
- await db.schema
73
- .createTable(MIGRATION_LOCK_TABLE)
74
- .ifNotExists()
75
- .addColumn('id', 'varchar(255)', (col) => col.notNull().primaryKey())
76
- .addColumn('is_locked', 'integer', (col) => col.notNull().defaultTo(0))
77
- .execute();
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
- catch (error) {
80
- // At least on PostgreSQL, `if not exists` doesn't guarantee the `create table`
81
- // query doesn't throw if the table already exits. That's why we check if
82
- // the table exist here and ignore the error if it does.
83
- if (!(await doesTableExists(db, MIGRATION_LOCK_TABLE))) {
84
- throw error;
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
- async function ensureLockRowExists(db) {
90
- if (!(await doesLockRowExists(db))) {
91
- try {
92
- await db
93
- .insertInto(MIGRATION_LOCK_TABLE)
94
- .values({ id: MIGRATION_LOCK_ID })
95
- .execute();
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
- catch (error) {
98
- if (!(await doesLockRowExists(db))) {
99
- throw error;
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
- async function doesTableExists(db, tableName) {
105
- const metadata = await db.introspection.getMetadata({
106
- withInternalKyselyTables: true,
107
- });
108
- return !!metadata.tables.find((it) => it.name === tableName);
109
- }
110
- async function doesLockRowExists(db) {
111
- const lockRow = await db
112
- .selectFrom(MIGRATION_LOCK_TABLE)
113
- .where('id', '=', MIGRATION_LOCK_ID)
114
- .select('id')
115
- .executeTakeFirst();
116
- return !!lockRow;
117
- }
118
- async function readMigrationsFromFolder(migrationsFolderPath) {
119
- const files = await fs.readdir(migrationsFolderPath);
120
- const migrations = {};
121
- for (const file of files) {
122
- if ((file.endsWith('.js') || file.endsWith('.ts')) &&
123
- !file.endsWith('.d.ts')) {
124
- const migration = await import(path.join(migrationsFolderPath, file));
125
- if (isMigration(migration)) {
126
- migrations[file.substring(0, file.length - 3)] = migration;
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
- async function runNewMigrations(db, allMigrations) {
133
- const sortedMigrations = Object.keys(allMigrations)
134
- .sort()
135
- .map((name) => ({
136
- ...allMigrations[name],
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
- function ensureMigrationsAreNotCorrupted(executedMigrationNames, oldMigrationNames) {
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(expressionSql: string, constraintName?: string | undefined): CheckConstraintNode;
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(expressionSql, constraintName) {
10
+ create(expression, constraintName) {
12
11
  return freeze({
13
12
  kind: 'CheckConstraintNode',
14
- expression: RawNode.createWithSql(expressionSql),
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 { GeneratedAlwaysAsNode } from './generated-always-as-node.js';
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: boolean;
17
- readonly autoIncrement: boolean;
18
- readonly unique: boolean;
19
- readonly nullable: boolean;
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 generatedAlwaysAs?: GeneratedAlwaysAsNode;
22
+ readonly generated?: GeneratedNode;
23
+ readonly unsigned?: boolean;
23
24
  }
24
25
  /**
25
26
  * @internal
@@ -12,10 +12,6 @@ export const ColumnDefinitionNode = freeze({
12
12
  kind: 'ColumnDefinitionNode',
13
13
  column: ColumnNode.create(column),
14
14
  dataType,
15
- primaryKey: false,
16
- autoIncrement: false,
17
- unique: false,
18
- nullable: true,
19
15
  });
20
16
  },
21
17
  cloneWith(node, props) {
@@ -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 { IdentifierNode } from './identifier-node.js';
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: IdentifierNode;
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: IdentifierNode, expression: QueryNode | RawNode): CommonTableExpressionNode;
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
+ });