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