kysely 0.12.2 → 0.15.0

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 (156) hide show
  1. package/README.md +115 -31
  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/mysql/mysql-introspector.js +3 -3
  10. package/dist/cjs/dialect/postgres/postgres-adapter.d.ts +2 -2
  11. package/dist/cjs/dialect/postgres/postgres-adapter.js +2 -1
  12. package/dist/cjs/dialect/postgres/postgres-dialect.d.ts +1 -1
  13. package/dist/cjs/dialect/postgres/postgres-introspector.d.ts +1 -1
  14. package/dist/cjs/dialect/postgres/postgres-introspector.js +3 -3
  15. package/dist/cjs/dialect/sqlite/sqlite-adapter.d.ts +2 -2
  16. package/dist/cjs/dialect/sqlite/sqlite-dialect.d.ts +1 -1
  17. package/dist/cjs/dialect/sqlite/sqlite-introspector.d.ts +1 -1
  18. package/dist/cjs/dialect/sqlite/sqlite-introspector.js +3 -3
  19. package/dist/cjs/index.d.ts +7 -4
  20. package/dist/cjs/index.js +6 -3
  21. package/dist/cjs/kysely.d.ts +8 -40
  22. package/dist/cjs/kysely.js +8 -40
  23. package/dist/cjs/migration/file-migration-provider.d.ts +52 -0
  24. package/dist/cjs/migration/file-migration-provider.js +52 -0
  25. package/dist/cjs/migration/migrator.d.ts +234 -0
  26. package/dist/cjs/migration/migrator.js +417 -0
  27. package/dist/cjs/operation-node/check-constraint-node.d.ts +1 -1
  28. package/dist/cjs/operation-node/check-constraint-node.js +2 -3
  29. package/dist/cjs/operation-node/column-definition-node.d.ts +8 -7
  30. package/dist/cjs/operation-node/column-definition-node.js +0 -4
  31. package/dist/cjs/operation-node/data-type-node.d.ts +1 -1
  32. package/dist/cjs/operation-node/generated-node.d.ts +20 -0
  33. package/dist/cjs/operation-node/generated-node.js +31 -0
  34. package/dist/cjs/operation-node/on-conflict-node.d.ts +13 -2
  35. package/dist/cjs/operation-node/on-conflict-node.js +39 -1
  36. package/dist/cjs/operation-node/operation-node-transformer.d.ts +2 -2
  37. package/dist/cjs/operation-node/operation-node-transformer.js +13 -6
  38. package/dist/cjs/operation-node/operation-node-visitor.d.ts +2 -2
  39. package/dist/cjs/operation-node/operation-node-visitor.js +1 -1
  40. package/dist/cjs/operation-node/operation-node.d.ts +1 -1
  41. package/dist/cjs/parser/insert-values-parser.d.ts +4 -4
  42. package/dist/cjs/parser/insert-values-parser.js +2 -3
  43. package/dist/cjs/parser/reference-parser.d.ts +4 -3
  44. package/dist/cjs/parser/select-parser.d.ts +10 -4
  45. package/dist/cjs/parser/update-set-parser.d.ts +2 -1
  46. package/dist/cjs/plugin/camel-case/camel-case-plugin.d.ts +2 -2
  47. package/dist/cjs/query-builder/delete-query-builder.d.ts +0 -3
  48. package/dist/cjs/query-builder/insert-query-builder.d.ts +78 -94
  49. package/dist/cjs/query-builder/insert-query-builder.js +145 -15
  50. package/dist/cjs/query-builder/on-conflict-builder.d.ts +686 -0
  51. package/dist/cjs/query-builder/on-conflict-builder.js +323 -0
  52. package/dist/cjs/query-builder/returning-interface.d.ts +0 -3
  53. package/dist/cjs/query-builder/update-query-builder.d.ts +0 -3
  54. package/dist/cjs/query-compiler/default-query-compiler.d.ts +2 -2
  55. package/dist/cjs/query-compiler/default-query-compiler.js +37 -8
  56. package/dist/cjs/query-creator.d.ts +0 -2
  57. package/dist/cjs/query-creator.js +0 -2
  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/column-type.d.ts +165 -0
  67. package/dist/cjs/util/column-type.js +2 -0
  68. package/dist/cjs/util/private-symbols.d.ts +5 -0
  69. package/dist/cjs/util/private-symbols.js +8 -0
  70. package/dist/cjs/util/type-utils.d.ts +6 -42
  71. package/dist/esm/{introspection → dialect}/database-introspector.d.ts +0 -0
  72. package/dist/esm/{introspection → dialect}/database-introspector.js +0 -0
  73. package/dist/esm/dialect/dialect.d.ts +1 -1
  74. package/dist/esm/dialect/mysql/mysql-adapter.d.ts +2 -2
  75. package/dist/esm/dialect/mysql/mysql-adapter.js +2 -1
  76. package/dist/esm/dialect/mysql/mysql-dialect.d.ts +1 -1
  77. package/dist/esm/dialect/mysql/mysql-introspector.d.ts +1 -1
  78. package/dist/esm/dialect/mysql/mysql-introspector.js +1 -1
  79. package/dist/esm/dialect/postgres/postgres-adapter.d.ts +2 -2
  80. package/dist/esm/dialect/postgres/postgres-adapter.js +2 -1
  81. package/dist/esm/dialect/postgres/postgres-dialect.d.ts +1 -1
  82. package/dist/esm/dialect/postgres/postgres-introspector.d.ts +1 -1
  83. package/dist/esm/dialect/postgres/postgres-introspector.js +1 -1
  84. package/dist/esm/dialect/sqlite/sqlite-adapter.d.ts +2 -2
  85. package/dist/esm/dialect/sqlite/sqlite-dialect.d.ts +1 -1
  86. package/dist/esm/dialect/sqlite/sqlite-introspector.d.ts +1 -1
  87. package/dist/esm/dialect/sqlite/sqlite-introspector.js +1 -1
  88. package/dist/esm/index.d.ts +7 -4
  89. package/dist/esm/index.js +6 -3
  90. package/dist/esm/kysely.d.ts +8 -40
  91. package/dist/esm/kysely.js +8 -40
  92. package/dist/esm/migration/file-migration-provider.d.ts +52 -0
  93. package/dist/esm/migration/file-migration-provider.js +48 -0
  94. package/dist/esm/migration/migrator.d.ts +234 -0
  95. package/dist/esm/migration/migrator.js +413 -0
  96. package/dist/esm/operation-node/check-constraint-node.d.ts +1 -1
  97. package/dist/esm/operation-node/check-constraint-node.js +2 -3
  98. package/dist/esm/operation-node/column-definition-node.d.ts +8 -7
  99. package/dist/esm/operation-node/column-definition-node.js +0 -4
  100. package/dist/esm/operation-node/data-type-node.d.ts +1 -1
  101. package/dist/esm/operation-node/generated-node.d.ts +20 -0
  102. package/dist/esm/operation-node/generated-node.js +28 -0
  103. package/dist/esm/operation-node/on-conflict-node.d.ts +13 -2
  104. package/dist/esm/operation-node/on-conflict-node.js +39 -1
  105. package/dist/esm/operation-node/operation-node-transformer.d.ts +2 -2
  106. package/dist/esm/operation-node/operation-node-transformer.js +13 -6
  107. package/dist/esm/operation-node/operation-node-visitor.d.ts +2 -2
  108. package/dist/esm/operation-node/operation-node-visitor.js +1 -1
  109. package/dist/esm/operation-node/operation-node.d.ts +1 -1
  110. package/dist/esm/parser/insert-values-parser.d.ts +4 -4
  111. package/dist/esm/parser/insert-values-parser.js +2 -3
  112. package/dist/esm/parser/reference-parser.d.ts +4 -3
  113. package/dist/esm/parser/select-parser.d.ts +10 -4
  114. package/dist/esm/parser/update-set-parser.d.ts +2 -1
  115. package/dist/esm/plugin/camel-case/camel-case-plugin.d.ts +2 -2
  116. package/dist/esm/query-builder/delete-query-builder.d.ts +0 -3
  117. package/dist/esm/query-builder/insert-query-builder.d.ts +78 -94
  118. package/dist/esm/query-builder/insert-query-builder.js +145 -15
  119. package/dist/esm/query-builder/on-conflict-builder.d.ts +686 -0
  120. package/dist/esm/query-builder/on-conflict-builder.js +317 -0
  121. package/dist/esm/query-builder/returning-interface.d.ts +0 -3
  122. package/dist/esm/query-builder/update-query-builder.d.ts +0 -3
  123. package/dist/esm/query-compiler/default-query-compiler.d.ts +2 -2
  124. package/dist/esm/query-compiler/default-query-compiler.js +37 -8
  125. package/dist/esm/query-creator.d.ts +0 -2
  126. package/dist/esm/query-creator.js +0 -2
  127. package/dist/esm/schema/alter-table-builder.d.ts +41 -9
  128. package/dist/esm/schema/alter-table-builder.js +45 -9
  129. package/dist/esm/schema/column-definition-builder.d.ts +40 -8
  130. package/dist/esm/schema/column-definition-builder.js +21 -8
  131. package/dist/esm/schema/create-index-builder.d.ts +3 -2
  132. package/dist/esm/schema/create-index-builder.js +2 -2
  133. package/dist/esm/schema/create-table-builder.d.ts +3 -2
  134. package/dist/esm/schema/create-table-builder.js +2 -2
  135. package/dist/esm/util/column-type.d.ts +165 -0
  136. package/dist/esm/util/column-type.js +1 -0
  137. package/dist/esm/util/private-symbols.d.ts +5 -0
  138. package/dist/esm/util/private-symbols.js +5 -0
  139. package/dist/esm/util/type-utils.d.ts +6 -42
  140. package/package.json +1 -1
  141. package/dist/cjs/migration/migration.d.ts +0 -66
  142. package/dist/cjs/migration/migration.js +0 -187
  143. package/dist/cjs/operation-node/generated-always-as-node.d.ts +0 -16
  144. package/dist/cjs/operation-node/generated-always-as-node.js +0 -25
  145. package/dist/cjs/parser/on-conflict-parser.d.ts +0 -10
  146. package/dist/cjs/parser/on-conflict-parser.js +0 -35
  147. package/dist/cjs/util/generated-placeholder.d.ts +0 -3
  148. package/dist/cjs/util/generated-placeholder.js +0 -11
  149. package/dist/esm/migration/migration.d.ts +0 -66
  150. package/dist/esm/migration/migration.js +0 -183
  151. package/dist/esm/operation-node/generated-always-as-node.d.ts +0 -16
  152. package/dist/esm/operation-node/generated-always-as-node.js +0 -22
  153. package/dist/esm/parser/on-conflict-parser.d.ts +0 -10
  154. package/dist/esm/parser/on-conflict-parser.js +0 -30
  155. package/dist/esm/util/generated-placeholder.d.ts +0 -3
  156. package/dist/esm/util/generated-placeholder.js +0 -7
@@ -0,0 +1,234 @@
1
+ import { Kysely } from '../kysely.js';
2
+ export declare const MIGRATION_TABLE = "kysely_migration";
3
+ export declare const MIGRATION_LOCK_TABLE = "kysely_migration_lock";
4
+ export declare const MIGRATION_LOCK_ID = "migration_lock";
5
+ export declare const NO_MIGRATIONS: NoMigrations;
6
+ export interface Migration {
7
+ up(db: Kysely<any>): Promise<void>;
8
+ /**
9
+ * An optional down method.
10
+ *
11
+ * If you don't provide a down method, the migration is skipped when
12
+ * migrating down.
13
+ */
14
+ down?(db: Kysely<any>): Promise<void>;
15
+ }
16
+ /**
17
+ * A class for running migrations.
18
+ *
19
+ * ### Example
20
+ *
21
+ * This example uses the {@link FileMigrationProvider} that reads migrations
22
+ * files from a single folder. You can easily implement your own
23
+ * {@link MigrationProvider} if you want to provide migrations some
24
+ * other way.
25
+ *
26
+ * ```ts
27
+ * const migrator = new Migrator({
28
+ * db,
29
+ * // The constructor signature of FileMigrationProvider is a
30
+ * // bit weird to keep Kysely independent of node.js or any
31
+ * // other environment.
32
+ * provider: new FileMigrationProvider(
33
+ * fs.readdir,
34
+ * path.join,
35
+ * // Path to the folder that contains all your migrations.
36
+ * 'migrations'
37
+ * )
38
+ * })
39
+ * ```
40
+ */
41
+ export declare class Migrator {
42
+ #private;
43
+ constructor(props: MigratorProps);
44
+ /**
45
+ * Runs all migrations that have not yet been run.
46
+ *
47
+ * This method returns a {@link MigrationResultSet} instance and _never_ throws.
48
+ * {@link MigrationResultSet.error} holds the error if something went wrong.
49
+ * {@link MigrationResultSet.results} contains information about which migrations
50
+ * were executed and which failed. See the examples below.
51
+ *
52
+ * This method goes through all possible migrations provided by the provider and runs the
53
+ * ones whose names come alphabetically after the last migration that has been run. If the
54
+ * list of executed migrations doesn't match the beginning of the list of possible migrations
55
+ * an error is thrown.
56
+ *
57
+ * ### Examples
58
+ *
59
+ * ```ts
60
+ * import * as path from 'path'
61
+ * import * as fs from 'fs/promises'
62
+ *
63
+ * const db = new Kysely<Database>({
64
+ * dialect: new PostgresDialect({
65
+ * host: 'localhost',
66
+ * database: 'kysely_test',
67
+ * }),
68
+ * })
69
+ *
70
+ * const migrator = new Migrator({
71
+ * db,
72
+ * // The constructor signature of FileMigrationProvider is a
73
+ * // bit weird to keep Kysely independent of node.js or any
74
+ * // other environment.
75
+ * provider: new FileMigrationProvider(
76
+ * fs.readdir,
77
+ * path.join,
78
+ * // Path to the folder that contains all your migrations.
79
+ * 'migrations'
80
+ * )
81
+ * })
82
+ *
83
+ * const { error, results } = await migrator.migrateToLatest()
84
+ *
85
+ * results?.forEach((it) => {
86
+ * if (it.status === 'Success') {
87
+ * console.log(`migration "${it.migrationName}" was executed successfully`)
88
+ * } else if (it.status === 'Error') {
89
+ * console.error(`failed to execute migration "${it.migrationName}"`)
90
+ * }
91
+ * })
92
+ *
93
+ * if (error) {
94
+ * console.error('failed to run `migrateToLatest`')
95
+ * console.error(error)
96
+ * }
97
+ * ```
98
+ */
99
+ migrateToLatest(): Promise<MigrationResultSet>;
100
+ /**
101
+ * Migrate up/down to a specific migration.
102
+ *
103
+ * This method returns a {@link MigrationResultSet} instance and _never_ throws.
104
+ * {@link MigrationResultSet.error} holds the error if something went wrong.
105
+ * {@link MigrationResultSet.results} contains information about which migrations
106
+ * were executed and which failed.
107
+ *
108
+ * ### Examples
109
+ *
110
+ * ```ts
111
+ * await migrator.migrateTo('some_migration')
112
+ * ```
113
+ *
114
+ * If you specify the name of the first migration, this method migrates
115
+ * down to the first migration, but doesn't run the `down` method of
116
+ * the first migration. In case you want to migrate all the way down,
117
+ * you can use a special constant `NO_MIGRATIONS`:
118
+ *
119
+ * ```ts
120
+ * await migrator.migrateTo(NO_MIGRATIONS)
121
+ * ```
122
+ */
123
+ migrateTo(targetMigrationName: string | NoMigrations): Promise<MigrationResultSet>;
124
+ /**
125
+ * Migrate one step up.
126
+ *
127
+ * This method returns a {@link MigrationResultSet} instance and _never_ throws.
128
+ * {@link MigrationResultSet.error} holds the error if something went wrong.
129
+ * {@link MigrationResultSet.results} contains information about which migrations
130
+ * were executed and which failed.
131
+ *
132
+ * ### Examples
133
+ *
134
+ * ```ts
135
+ * await migrator.migrateUp()
136
+ * ```
137
+ */
138
+ migrateUp(): Promise<MigrationResultSet>;
139
+ /**
140
+ * Migrate one step down.
141
+ *
142
+ * This method returns a {@link MigrationResultSet} instance and _never_ throws.
143
+ * {@link MigrationResultSet.error} holds the error if something went wrong.
144
+ * {@link MigrationResultSet.results} contains information about which migrations
145
+ * were executed and which failed.
146
+ *
147
+ * ### Examples
148
+ *
149
+ * ```ts
150
+ * await migrator.migrateDown()
151
+ * ```
152
+ */
153
+ migrateDown(): Promise<MigrationResultSet>;
154
+ }
155
+ export interface MigratorProps {
156
+ readonly db: Kysely<any>;
157
+ readonly provider: MigrationProvider;
158
+ }
159
+ /**
160
+ * All migration methods ({@link MigrationModule.migrateTo | migrateTo},
161
+ * {@link MigrationModule.migrateToLatest | migrateToLatest} etc.) never
162
+ * throw but return this object instead.
163
+ */
164
+ export interface MigrationResultSet {
165
+ /**
166
+ * This is defined if something went wrong.
167
+ *
168
+ * An error may have occurred in one of the migrations in which case the
169
+ * {@link results} list contains an item with `status === 'Error'` to
170
+ * indicate which migration failed.
171
+ *
172
+ * An error may also have occurred before Kysely was able to figure out
173
+ * which migrations should be executed, in which case the {@link results}
174
+ * list is undefined.
175
+ */
176
+ readonly error?: unknown;
177
+ /**
178
+ * {@link MigrationResult} for each individual migration that was supposed
179
+ * to be executed by the operation.
180
+ *
181
+ * If all went well, each result's `status` is `Success`. If some migration
182
+ * failed, the failed migration's result's `status` is `Error` and all
183
+ * results after that one have `status` ´NotExecuted`.
184
+ *
185
+ * This property can be undefined if an error occurred before Kysely was
186
+ * able to figure out which migrations should be executed.
187
+ *
188
+ * If this list is empty, there were no migrations to execute.
189
+ */
190
+ readonly results?: MigrationResult[];
191
+ }
192
+ export interface MigrationResult {
193
+ readonly migrationName: string;
194
+ /**
195
+ * The direction in which this migration was executed.
196
+ */
197
+ readonly direction: 'Up' | 'Down';
198
+ /**
199
+ * The execution status.
200
+ *
201
+ * - `Success` means the migration was successfully executed. Note that
202
+ * if any of the later migrations in the {@link MigrationResult.results}
203
+ * list failed (have status `Error`) AND the dialect supports transactional
204
+ * DDL, even the successfull migrations were rolled back.
205
+ *
206
+ * - `Error` means the migration failed. In this case the
207
+ * {@link MigrationResult.error} contains the error.
208
+ *
209
+ * - `NotExecuted` means that the migration was supposed to be executed
210
+ * but wasn't because an earlier migration failed.
211
+ */
212
+ readonly status: 'Success' | 'Error' | 'NotExecuted';
213
+ }
214
+ export interface MigrationProvider {
215
+ /**
216
+ * Returns all migrations, old and new.
217
+ *
218
+ * For example if you have your migrations in a folder as separate files,
219
+ * you can use the {@link FileMigrationProvider} that implements this
220
+ * method to return all migrations in a folder.
221
+ *
222
+ * The keys of the returned object are migration names and values are the
223
+ * migrations. The order of the migrations is determined by the alphabetical
224
+ * order of the migration names. The items in the object don't need to be
225
+ * sorted, they are sorted by Kysely.
226
+ */
227
+ getMigrations(): Promise<Record<string, Migration>>;
228
+ }
229
+ /**
230
+ * Type for the {@link NO_MIGRATIONS} constant. Never create one of these.
231
+ */
232
+ export interface NoMigrations {
233
+ readonly __noMigrations__: true;
234
+ }
@@ -0,0 +1,413 @@
1
+ import { freeze, getLast } from '../util/object-utils.js';
2
+ import { PRIVATE_ADAPTER } from '../util/private-symbols.js';
3
+ export const MIGRATION_TABLE = 'kysely_migration';
4
+ export const MIGRATION_LOCK_TABLE = 'kysely_migration_lock';
5
+ export const MIGRATION_LOCK_ID = 'migration_lock';
6
+ export const NO_MIGRATIONS = freeze({ __noMigrations__: true });
7
+ /**
8
+ * A class for running migrations.
9
+ *
10
+ * ### Example
11
+ *
12
+ * This example uses the {@link FileMigrationProvider} that reads migrations
13
+ * files from a single folder. You can easily implement your own
14
+ * {@link MigrationProvider} if you want to provide migrations some
15
+ * other way.
16
+ *
17
+ * ```ts
18
+ * const migrator = new Migrator({
19
+ * db,
20
+ * // The constructor signature of FileMigrationProvider is a
21
+ * // bit weird to keep Kysely independent of node.js or any
22
+ * // other environment.
23
+ * provider: new FileMigrationProvider(
24
+ * fs.readdir,
25
+ * path.join,
26
+ * // Path to the folder that contains all your migrations.
27
+ * 'migrations'
28
+ * )
29
+ * })
30
+ * ```
31
+ */
32
+ export class Migrator {
33
+ #props;
34
+ constructor(props) {
35
+ this.#props = freeze(props);
36
+ }
37
+ /**
38
+ * Runs all migrations that have not yet been run.
39
+ *
40
+ * This method returns a {@link MigrationResultSet} instance and _never_ throws.
41
+ * {@link MigrationResultSet.error} holds the error if something went wrong.
42
+ * {@link MigrationResultSet.results} contains information about which migrations
43
+ * were executed and which failed. See the examples below.
44
+ *
45
+ * This method goes through all possible migrations provided by the provider and runs the
46
+ * ones whose names come alphabetically after the last migration that has been run. If the
47
+ * list of executed migrations doesn't match the beginning of the list of possible migrations
48
+ * an error is thrown.
49
+ *
50
+ * ### Examples
51
+ *
52
+ * ```ts
53
+ * import * as path from 'path'
54
+ * import * as fs from 'fs/promises'
55
+ *
56
+ * const db = new Kysely<Database>({
57
+ * dialect: new PostgresDialect({
58
+ * host: 'localhost',
59
+ * database: 'kysely_test',
60
+ * }),
61
+ * })
62
+ *
63
+ * const migrator = new Migrator({
64
+ * db,
65
+ * // The constructor signature of FileMigrationProvider is a
66
+ * // bit weird to keep Kysely independent of node.js or any
67
+ * // other environment.
68
+ * provider: new FileMigrationProvider(
69
+ * fs.readdir,
70
+ * path.join,
71
+ * // Path to the folder that contains all your migrations.
72
+ * 'migrations'
73
+ * )
74
+ * })
75
+ *
76
+ * const { error, results } = await migrator.migrateToLatest()
77
+ *
78
+ * results?.forEach((it) => {
79
+ * if (it.status === 'Success') {
80
+ * console.log(`migration "${it.migrationName}" was executed successfully`)
81
+ * } else if (it.status === 'Error') {
82
+ * console.error(`failed to execute migration "${it.migrationName}"`)
83
+ * }
84
+ * })
85
+ *
86
+ * if (error) {
87
+ * console.error('failed to run `migrateToLatest`')
88
+ * console.error(error)
89
+ * }
90
+ * ```
91
+ */
92
+ async migrateToLatest() {
93
+ return this.#migrate(({ migrations }) => migrations.length - 1);
94
+ }
95
+ /**
96
+ * Migrate up/down to a specific migration.
97
+ *
98
+ * This method returns a {@link MigrationResultSet} instance and _never_ throws.
99
+ * {@link MigrationResultSet.error} holds the error if something went wrong.
100
+ * {@link MigrationResultSet.results} contains information about which migrations
101
+ * were executed and which failed.
102
+ *
103
+ * ### Examples
104
+ *
105
+ * ```ts
106
+ * await migrator.migrateTo('some_migration')
107
+ * ```
108
+ *
109
+ * If you specify the name of the first migration, this method migrates
110
+ * down to the first migration, but doesn't run the `down` method of
111
+ * the first migration. In case you want to migrate all the way down,
112
+ * you can use a special constant `NO_MIGRATIONS`:
113
+ *
114
+ * ```ts
115
+ * await migrator.migrateTo(NO_MIGRATIONS)
116
+ * ```
117
+ */
118
+ async migrateTo(targetMigrationName) {
119
+ return this.#migrate(({ migrations }) => {
120
+ if (targetMigrationName === NO_MIGRATIONS) {
121
+ return -1;
122
+ }
123
+ const index = migrations.findIndex((it) => it.name === targetMigrationName);
124
+ if (index === -1) {
125
+ throw new Error(`migration "${targetMigrationName}" doesn't exist`);
126
+ }
127
+ return index;
128
+ });
129
+ }
130
+ /**
131
+ * Migrate one step up.
132
+ *
133
+ * This method returns a {@link MigrationResultSet} instance and _never_ throws.
134
+ * {@link MigrationResultSet.error} holds the error if something went wrong.
135
+ * {@link MigrationResultSet.results} contains information about which migrations
136
+ * were executed and which failed.
137
+ *
138
+ * ### Examples
139
+ *
140
+ * ```ts
141
+ * await migrator.migrateUp()
142
+ * ```
143
+ */
144
+ async migrateUp() {
145
+ return this.#migrate(({ currentIndex, migrations }) => Math.min(currentIndex + 1, migrations.length - 1));
146
+ }
147
+ /**
148
+ * Migrate one step down.
149
+ *
150
+ * This method returns a {@link MigrationResultSet} instance and _never_ throws.
151
+ * {@link MigrationResultSet.error} holds the error if something went wrong.
152
+ * {@link MigrationResultSet.results} contains information about which migrations
153
+ * were executed and which failed.
154
+ *
155
+ * ### Examples
156
+ *
157
+ * ```ts
158
+ * await migrator.migrateDown()
159
+ * ```
160
+ */
161
+ async migrateDown() {
162
+ return this.#migrate(({ currentIndex }) => Math.max(currentIndex - 1, -1));
163
+ }
164
+ async #migrate(getTargetMigrationIndex) {
165
+ try {
166
+ await this.#ensureMigrationTablesExists();
167
+ return await this.#runMigrations(getTargetMigrationIndex);
168
+ }
169
+ catch (error) {
170
+ if (error instanceof MigrationResultSetError) {
171
+ return error.resultSet;
172
+ }
173
+ return { error };
174
+ }
175
+ }
176
+ async #ensureMigrationTablesExists() {
177
+ await this.#ensureMigrationTableExists();
178
+ await this.#ensureMigrationLockTableExists();
179
+ await this.#ensureLockRowExists();
180
+ }
181
+ async #ensureMigrationTableExists() {
182
+ if (!(await this.#doesTableExists(MIGRATION_TABLE))) {
183
+ try {
184
+ await this.#props.db.schema
185
+ .createTable(MIGRATION_TABLE)
186
+ .ifNotExists()
187
+ .addColumn('name', 'varchar(255)', (col) => col.notNull().primaryKey())
188
+ // The migration run time as ISO string. This is not a real date type as we
189
+ // can't know which data type is supported by all future dialects.
190
+ .addColumn('timestamp', 'varchar(255)', (col) => col.notNull())
191
+ .execute();
192
+ }
193
+ catch (error) {
194
+ // At least on PostgreSQL, `if not exists` doesn't guarantee the `create table`
195
+ // query doesn't throw if the table already exits. That's why we check if
196
+ // the table exist here and ignore the error if it does.
197
+ if (!(await this.#doesTableExists(MIGRATION_TABLE))) {
198
+ throw error;
199
+ }
200
+ }
201
+ }
202
+ }
203
+ async #ensureMigrationLockTableExists() {
204
+ if (!(await this.#doesTableExists(MIGRATION_LOCK_TABLE))) {
205
+ try {
206
+ await this.#props.db.schema
207
+ .createTable(MIGRATION_LOCK_TABLE)
208
+ .ifNotExists()
209
+ .addColumn('id', 'varchar(255)', (col) => col.notNull().primaryKey())
210
+ .addColumn('is_locked', 'integer', (col) => col.notNull().defaultTo(0))
211
+ .execute();
212
+ }
213
+ catch (error) {
214
+ // At least on PostgreSQL, `if not exists` doesn't guarantee the `create table`
215
+ // query doesn't throw if the table already exits. That's why we check if
216
+ // the table exist here and ignore the error if it does.
217
+ if (!(await this.#doesTableExists(MIGRATION_LOCK_TABLE))) {
218
+ throw error;
219
+ }
220
+ }
221
+ }
222
+ }
223
+ async #ensureLockRowExists() {
224
+ if (!(await this.#doesLockRowExists())) {
225
+ try {
226
+ await this.#props.db
227
+ .insertInto(MIGRATION_LOCK_TABLE)
228
+ .values({ id: MIGRATION_LOCK_ID })
229
+ .execute();
230
+ }
231
+ catch (error) {
232
+ if (!(await this.#doesLockRowExists())) {
233
+ throw error;
234
+ }
235
+ }
236
+ }
237
+ }
238
+ async #doesTableExists(tableName) {
239
+ const metadata = await this.#props.db.introspection.getMetadata({
240
+ withInternalKyselyTables: true,
241
+ });
242
+ return !!metadata.tables.find((it) => it.name === tableName);
243
+ }
244
+ async #doesLockRowExists() {
245
+ const lockRow = await this.#props.db
246
+ .selectFrom(MIGRATION_LOCK_TABLE)
247
+ .where('id', '=', MIGRATION_LOCK_ID)
248
+ .select('id')
249
+ .executeTakeFirst();
250
+ return !!lockRow;
251
+ }
252
+ async #runMigrations(getTargetMigrationIndex) {
253
+ const run = async (db) => {
254
+ try {
255
+ await this.#props.db[PRIVATE_ADAPTER].acquireMigrationLock(db);
256
+ const state = await this.#getState(db);
257
+ if (state.migrations.length === 0) {
258
+ return { results: [] };
259
+ }
260
+ const targetIndex = getTargetMigrationIndex(state);
261
+ if (targetIndex === undefined) {
262
+ return { results: [] };
263
+ }
264
+ if (targetIndex < state.currentIndex) {
265
+ return await this.#migrateDown(db, state, targetIndex);
266
+ }
267
+ else if (targetIndex > state.currentIndex) {
268
+ return await this.#migrateUp(db, state, targetIndex);
269
+ }
270
+ return { results: [] };
271
+ }
272
+ finally {
273
+ await this.#props.db[PRIVATE_ADAPTER].releaseMigrationLock(db);
274
+ }
275
+ };
276
+ if (this.#props.db[PRIVATE_ADAPTER].supportsTransactionalDdl) {
277
+ return this.#props.db.transaction().execute(run);
278
+ }
279
+ else {
280
+ return this.#props.db.connection().execute(run);
281
+ }
282
+ }
283
+ async #getState(db) {
284
+ const migrations = await this.#resolveMigrations();
285
+ const executedMigrations = await this.#getExecutedMigrations(db);
286
+ this.#ensureMigrationsNotCorrupted(migrations, executedMigrations);
287
+ return freeze({
288
+ migrations,
289
+ currentIndex: migrations.findIndex((it) => it.name === getLast(executedMigrations)),
290
+ });
291
+ }
292
+ async #resolveMigrations() {
293
+ const allMigrations = await this.#props.provider.getMigrations();
294
+ return Object.keys(allMigrations)
295
+ .sort()
296
+ .map((name) => ({
297
+ ...allMigrations[name],
298
+ name,
299
+ }));
300
+ }
301
+ async #getExecutedMigrations(db) {
302
+ const executedMigrations = await db
303
+ .selectFrom(MIGRATION_TABLE)
304
+ .select('name')
305
+ .orderBy('name')
306
+ .execute();
307
+ return executedMigrations.map((it) => it.name);
308
+ }
309
+ #ensureMigrationsNotCorrupted(migrations, executedMigrations) {
310
+ for (const executed of executedMigrations) {
311
+ if (!migrations.some((it) => it.name === executed)) {
312
+ throw new Error(`corrupted migrations: previously executed migration ${executed} is missing`);
313
+ }
314
+ }
315
+ // Now we know all executed migrations exist in the `migrations` list.
316
+ // Next we need to make sure that the executed migratiosns are the first
317
+ // ones in the migration list.
318
+ for (let i = 0; i < executedMigrations.length; ++i) {
319
+ if (migrations[i].name !== executedMigrations[i]) {
320
+ 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.`);
321
+ }
322
+ }
323
+ }
324
+ async #migrateDown(db, state, targetIndex) {
325
+ const results = [];
326
+ for (let i = state.currentIndex; i > targetIndex; --i) {
327
+ results.push({
328
+ migrationName: state.migrations[i].name,
329
+ direction: 'Down',
330
+ status: 'NotExecuted',
331
+ });
332
+ }
333
+ for (let i = 0; i < results.length; ++i) {
334
+ const migration = state.migrations.find((it) => it.name === results[i].migrationName);
335
+ try {
336
+ if (migration.down) {
337
+ await migration.down(db);
338
+ await db
339
+ .deleteFrom(MIGRATION_TABLE)
340
+ .where('name', '=', migration.name)
341
+ .execute();
342
+ results[i] = {
343
+ migrationName: migration.name,
344
+ direction: 'Down',
345
+ status: 'Success',
346
+ };
347
+ }
348
+ }
349
+ catch (error) {
350
+ results[i] = {
351
+ migrationName: migration.name,
352
+ direction: 'Down',
353
+ status: 'Error',
354
+ };
355
+ throw new MigrationResultSetError({
356
+ error,
357
+ results,
358
+ });
359
+ }
360
+ }
361
+ return { results };
362
+ }
363
+ async #migrateUp(db, state, targetIndex) {
364
+ const results = [];
365
+ for (let i = state.currentIndex + 1; i <= targetIndex; ++i) {
366
+ results.push({
367
+ migrationName: state.migrations[i].name,
368
+ direction: 'Up',
369
+ status: 'NotExecuted',
370
+ });
371
+ }
372
+ for (let i = 0; i < results.length; ++i) {
373
+ const migration = state.migrations.find((it) => it.name === results[i].migrationName);
374
+ try {
375
+ await migration.up(db);
376
+ await db
377
+ .insertInto(MIGRATION_TABLE)
378
+ .values({
379
+ name: migration.name,
380
+ timestamp: new Date().toISOString(),
381
+ })
382
+ .execute();
383
+ results[i] = {
384
+ migrationName: migration.name,
385
+ direction: 'Up',
386
+ status: 'Success',
387
+ };
388
+ }
389
+ catch (error) {
390
+ results[i] = {
391
+ migrationName: migration.name,
392
+ direction: 'Up',
393
+ status: 'Error',
394
+ };
395
+ throw new MigrationResultSetError({
396
+ error,
397
+ results,
398
+ });
399
+ }
400
+ }
401
+ return { results };
402
+ }
403
+ }
404
+ class MigrationResultSetError extends Error {
405
+ #resultSet;
406
+ constructor(result) {
407
+ super();
408
+ this.#resultSet = result;
409
+ }
410
+ get resultSet() {
411
+ return this.#resultSet;
412
+ }
413
+ }
@@ -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
  },