kysely 0.30.0-beta.0 → 0.30.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/dialect/mysql/mysql-dialect-config.d.ts +31 -6
- package/dist/dialect/mysql/mysql-dialect.d.ts +2 -2
- package/dist/dialect/mysql/mysql-dialect.js +2 -2
- package/dist/dialect/mysql/mysql-driver.js +28 -2
- package/dist/migration/file-migration-provider.d.ts +1 -1
- package/dist/migration/file-migration-provider.js +1 -1
- package/dist/migration/migrator.d.ts +48 -9
- package/dist/migration/migrator.js +40 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[](https://stand-with-ukraine.pp.ua)
|
|
2
2
|
|
|
3
3
|
[](https://github.com/kysely-org/kysely/releases/latest)
|
|
4
|
-
[](https://socket.dev/npm/package/kysely/overview/0.30.0-beta.1)
|
|
5
5
|
[](https://github.com/kysely-org/kysely)
|
|
6
6
|
[](https://github.com/kysely-org/kysely/blob/master/LICENSE)
|
|
7
7
|
[](https://github.com/kysely-org/kysely/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc)
|
|
@@ -5,23 +5,25 @@ import type { AbortableOperationOptions } from '../../util/abort.js';
|
|
|
5
5
|
*/
|
|
6
6
|
export interface MysqlDialectConfig {
|
|
7
7
|
/**
|
|
8
|
-
* A `
|
|
9
|
-
* outside of the `pool` to avoid
|
|
8
|
+
* A `createConnection` function (from either `mysql2` or `mysql2/promise`),
|
|
9
|
+
* to be used for connecting to the database outside of the `pool` to avoid
|
|
10
|
+
* waiting for an idle connection.
|
|
10
11
|
*
|
|
11
12
|
* This is useful for cancelling queries on the database side.
|
|
12
13
|
*/
|
|
13
14
|
controlConnection?: {
|
|
14
|
-
(connectionUri: string): MysqlConnection
|
|
15
|
-
(config: object): MysqlConnection
|
|
15
|
+
(connectionUri: string): MysqlConnection | Promise<MysqlPromiseConnection>;
|
|
16
|
+
(config: object): MysqlConnection | Promise<MysqlPromiseConnection>;
|
|
16
17
|
};
|
|
17
18
|
/**
|
|
18
|
-
* A mysql2 Pool instance
|
|
19
|
+
* A mysql2 Pool instance (from either `mysql2` or `mysql2/promise`) or a
|
|
20
|
+
* function that returns one.
|
|
19
21
|
*
|
|
20
22
|
* If a function is provided, it's called once when the first query is executed.
|
|
21
23
|
*
|
|
22
24
|
* https://github.com/sidorares/node-mysql2#using-connection-pools
|
|
23
25
|
*/
|
|
24
|
-
pool: MysqlPool | ((options?: AbortableOperationOptions) => Promise<MysqlPool>);
|
|
26
|
+
pool: MysqlPool | MysqlPromisePool | ((options?: AbortableOperationOptions) => Promise<MysqlPool | MysqlPromisePool>);
|
|
25
27
|
/**
|
|
26
28
|
* Called once for each created connection.
|
|
27
29
|
*/
|
|
@@ -43,6 +45,17 @@ export interface MysqlPool {
|
|
|
43
45
|
getConnection(callback: (error: unknown, connection: MysqlPoolConnection) => void): void;
|
|
44
46
|
end(callback: (error: unknown) => void): void;
|
|
45
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* This interface is the subset of `mysql2/promise`'s `Pool` class that
|
|
50
|
+
* kysely needs.
|
|
51
|
+
*
|
|
52
|
+
* It's a thin promise wrapper around the callback pool, which it exposes
|
|
53
|
+
* as its `pool` property. The dialect unwraps it and uses the callback
|
|
54
|
+
* pool directly.
|
|
55
|
+
*/
|
|
56
|
+
export interface MysqlPromisePool {
|
|
57
|
+
pool: MysqlPool;
|
|
58
|
+
}
|
|
46
59
|
export interface MysqlConnection {
|
|
47
60
|
config: object;
|
|
48
61
|
connect(callback?: (error: unknown) => void): void;
|
|
@@ -52,6 +65,18 @@ export interface MysqlConnection {
|
|
|
52
65
|
};
|
|
53
66
|
threadId: number;
|
|
54
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* This interface is the subset of `mysql2/promise`'s `Connection` class that
|
|
70
|
+
* kysely needs.
|
|
71
|
+
*
|
|
72
|
+
* It's a thin promise wrapper around the callback connection. It's already
|
|
73
|
+
* connected when the `createConnection` promise resolves, so the dialect
|
|
74
|
+
* uses its promise-based API directly.
|
|
75
|
+
*/
|
|
76
|
+
export interface MysqlPromiseConnection {
|
|
77
|
+
destroy(): void;
|
|
78
|
+
query(sql: string, values?: unknown[]): Promise<unknown>;
|
|
79
|
+
}
|
|
55
80
|
export type MysqlConectionConstructor = new (opts?: object) => MysqlConnection;
|
|
56
81
|
export interface MysqlPoolConnection extends MysqlConnection {
|
|
57
82
|
release(): void;
|
|
@@ -11,7 +11,7 @@ import type { MysqlDialectConfig } from './mysql-dialect-config.js';
|
|
|
11
11
|
* The constructor takes an instance of {@link MysqlDialectConfig}.
|
|
12
12
|
*
|
|
13
13
|
* ```ts
|
|
14
|
-
* import { createPool } from 'mysql2'
|
|
14
|
+
* import { createPool } from 'mysql2/promise' // or just 'mysql2' — both work
|
|
15
15
|
*
|
|
16
16
|
* new MysqlDialect({
|
|
17
17
|
* pool: createPool({
|
|
@@ -25,7 +25,7 @@ import type { MysqlDialectConfig } from './mysql-dialect-config.js';
|
|
|
25
25
|
* can be a function:
|
|
26
26
|
*
|
|
27
27
|
* ```ts
|
|
28
|
-
* import { createPool } from 'mysql2'
|
|
28
|
+
* import { createPool } from 'mysql2/promise' // or just 'mysql2' — both work
|
|
29
29
|
*
|
|
30
30
|
* new MysqlDialect({
|
|
31
31
|
* pool: async () => createPool({
|
|
@@ -9,7 +9,7 @@ import { MysqlAdapter } from './mysql-adapter.js';
|
|
|
9
9
|
* The constructor takes an instance of {@link MysqlDialectConfig}.
|
|
10
10
|
*
|
|
11
11
|
* ```ts
|
|
12
|
-
* import { createPool } from 'mysql2'
|
|
12
|
+
* import { createPool } from 'mysql2/promise' // or just 'mysql2' — both work
|
|
13
13
|
*
|
|
14
14
|
* new MysqlDialect({
|
|
15
15
|
* pool: createPool({
|
|
@@ -23,7 +23,7 @@ import { MysqlAdapter } from './mysql-adapter.js';
|
|
|
23
23
|
* can be a function:
|
|
24
24
|
*
|
|
25
25
|
* ```ts
|
|
26
|
-
* import { createPool } from 'mysql2'
|
|
26
|
+
* import { createPool } from 'mysql2/promise' // or just 'mysql2' — both work
|
|
27
27
|
*
|
|
28
28
|
* new MysqlDialect({
|
|
29
29
|
* pool: async () => createPool({
|
|
@@ -13,9 +13,12 @@ export class MysqlDriver {
|
|
|
13
13
|
this.#config = freeze({ ...config });
|
|
14
14
|
}
|
|
15
15
|
async init(options) {
|
|
16
|
-
|
|
16
|
+
const pool = isFunction(this.#config.pool)
|
|
17
17
|
? await this.#config.pool(options)
|
|
18
18
|
: this.#config.pool;
|
|
19
|
+
// A `mysql2/promise` pool's `getConnection` ignores the callback we pass
|
|
20
|
+
// it, hanging any query forever. Unwrap the callback pool it decorates.
|
|
21
|
+
this.#pool = isPromisePool(pool) ? pool.pool : pool;
|
|
19
22
|
}
|
|
20
23
|
async acquireConnection(options) {
|
|
21
24
|
const rawConnection = await this.#acquireConnection();
|
|
@@ -93,6 +96,12 @@ export class MysqlDriver {
|
|
|
93
96
|
});
|
|
94
97
|
}
|
|
95
98
|
}
|
|
99
|
+
function isPromisePool(pool) {
|
|
100
|
+
return ('pool' in pool && isObject(pool.pool) && isFunction(pool.pool.getConnection));
|
|
101
|
+
}
|
|
102
|
+
function isPromiseConnection(connection) {
|
|
103
|
+
return isFunction(connection.then);
|
|
104
|
+
}
|
|
96
105
|
function isOkPacket(obj) {
|
|
97
106
|
return isObject(obj) && 'insertId' in obj && 'affectedRows' in obj;
|
|
98
107
|
}
|
|
@@ -224,7 +233,24 @@ class MysqlConnection {
|
|
|
224
233
|
const {
|
|
225
234
|
// omitting these as they cause a warning and perhaps a future error when passed.
|
|
226
235
|
clientFlags: _, maxPacketSize: __, ...cfg } = config;
|
|
227
|
-
const
|
|
236
|
+
const controlConnectionOrPromise = this.#controlConnection(cfg);
|
|
237
|
+
// `mysql2/promise`'s `createConnection` returns a promise of a connection
|
|
238
|
+
// that's already connected, with a promise-based API. Use it directly.
|
|
239
|
+
if (isPromiseConnection(controlConnectionOrPromise)) {
|
|
240
|
+
const controlConnection = await controlConnectionOrPromise;
|
|
241
|
+
try {
|
|
242
|
+
// by the time we get the connection, another query might have been executed.
|
|
243
|
+
// we need to ensure we're not canceling the wrong query.
|
|
244
|
+
if (queryIdToCancel.queryId === this.#queryId?.queryId) {
|
|
245
|
+
await controlConnection.query(query, []);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
finally {
|
|
249
|
+
controlConnection.destroy();
|
|
250
|
+
}
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
const controlConnection = controlConnectionOrPromise;
|
|
228
254
|
try {
|
|
229
255
|
await new Promise((resolve, reject) => {
|
|
230
256
|
controlConnection.connect((connectError) => {
|
|
@@ -16,7 +16,7 @@ export declare const NO_MIGRATIONS: NoMigrations;
|
|
|
16
16
|
* other way.
|
|
17
17
|
*
|
|
18
18
|
* ```ts
|
|
19
|
-
* import
|
|
19
|
+
* import fs from 'node:fs/promises'
|
|
20
20
|
* import path from 'node:path'
|
|
21
21
|
* import * as Sqlite from 'better-sqlite3'
|
|
22
22
|
* import { Kysely, SqliteDialect } from 'kysely'
|
|
@@ -64,7 +64,7 @@ export declare class Migrator {
|
|
|
64
64
|
* ### Examples
|
|
65
65
|
*
|
|
66
66
|
* ```ts
|
|
67
|
-
* import
|
|
67
|
+
* import fs from 'node:fs/promises'
|
|
68
68
|
* import path from 'node:path'
|
|
69
69
|
* import * as Sqlite from 'better-sqlite3'
|
|
70
70
|
* import { FileMigrationProvider, Migrator } from 'kysely/migration'
|
|
@@ -106,7 +106,7 @@ export declare class Migrator {
|
|
|
106
106
|
* ### Examples
|
|
107
107
|
*
|
|
108
108
|
* ```ts
|
|
109
|
-
* import
|
|
109
|
+
* import fs from 'node:fs/promises'
|
|
110
110
|
* import path from 'node:path'
|
|
111
111
|
* import { FileMigrationProvider, Migrator } from 'kysely/migration'
|
|
112
112
|
*
|
|
@@ -129,7 +129,7 @@ export declare class Migrator {
|
|
|
129
129
|
* you can use a special constant `NO_MIGRATIONS`:
|
|
130
130
|
*
|
|
131
131
|
* ```ts
|
|
132
|
-
* import
|
|
132
|
+
* import fs from 'node:fs/promises'
|
|
133
133
|
* import path from 'node:path'
|
|
134
134
|
* import { FileMigrationProvider, Migrator, NO_MIGRATIONS } from 'kysely/migration'
|
|
135
135
|
*
|
|
@@ -145,8 +145,33 @@ export declare class Migrator {
|
|
|
145
145
|
*
|
|
146
146
|
* await migrator.migrateTo(NO_MIGRATIONS)
|
|
147
147
|
* ```
|
|
148
|
+
*
|
|
149
|
+
* By default, this method migrates up or down depending on which side of the
|
|
150
|
+
* current migration state the target migration is on. Pass
|
|
151
|
+
* {@link MigrateToOptions.direction} to enforce a direction — if reaching the
|
|
152
|
+
* target would require migrating the other way, nothing is executed and
|
|
153
|
+
* {@link MigrationResultSet.error} holds an error:
|
|
154
|
+
*
|
|
155
|
+
* ```ts
|
|
156
|
+
* import fs from 'node:fs/promises'
|
|
157
|
+
* import path from 'node:path'
|
|
158
|
+
* import { FileMigrationProvider, Migrator } from 'kysely/migration'
|
|
159
|
+
*
|
|
160
|
+
* const migrator = new Migrator({
|
|
161
|
+
* db,
|
|
162
|
+
* provider: new FileMigrationProvider({
|
|
163
|
+
* fs,
|
|
164
|
+
* // Path to the folder that contains all your migrations.
|
|
165
|
+
* migrationFolder: 'some/path/to/migrations',
|
|
166
|
+
* path,
|
|
167
|
+
* })
|
|
168
|
+
* })
|
|
169
|
+
*
|
|
170
|
+
* // Errors if `some_migration` is already executed.
|
|
171
|
+
* await migrator.migrateTo('some_migration', { direction: 'Up' })
|
|
172
|
+
* ```
|
|
148
173
|
*/
|
|
149
|
-
migrateTo(targetMigrationName: string | NoMigrations, options?:
|
|
174
|
+
migrateTo(targetMigrationName: string | NoMigrations, options?: MigrateToOptions): Promise<MigrationResultSet>;
|
|
150
175
|
/**
|
|
151
176
|
* Migrate one step up.
|
|
152
177
|
*
|
|
@@ -158,7 +183,7 @@ export declare class Migrator {
|
|
|
158
183
|
* ### Examples
|
|
159
184
|
*
|
|
160
185
|
* ```ts
|
|
161
|
-
* import
|
|
186
|
+
* import fs from 'node:fs/promises'
|
|
162
187
|
* import path from 'node:path'
|
|
163
188
|
* import { FileMigrationProvider, Migrator } from 'kysely/migration'
|
|
164
189
|
*
|
|
@@ -187,7 +212,7 @@ export declare class Migrator {
|
|
|
187
212
|
* ### Examples
|
|
188
213
|
*
|
|
189
214
|
* ```ts
|
|
190
|
-
* import
|
|
215
|
+
* import fs from 'node:fs/promises'
|
|
191
216
|
* import path from 'node:path'
|
|
192
217
|
* import { FileMigrationProvider, Migrator } from 'kysely/migration'
|
|
193
218
|
*
|
|
@@ -257,6 +282,21 @@ export interface MigrateOptions {
|
|
|
257
282
|
readonly transactionMode?: MigratorTransactionMode;
|
|
258
283
|
}
|
|
259
284
|
export type MigratorTransactionMode = 'per-run' | 'per-migration' | 'none';
|
|
285
|
+
export interface MigrateToOptions extends MigrateOptions {
|
|
286
|
+
/**
|
|
287
|
+
* Enforces a migration direction.
|
|
288
|
+
*
|
|
289
|
+
* When provided and reaching the target migration would require migrating
|
|
290
|
+
* the other way, nothing is executed and {@link MigrationResultSet.error}
|
|
291
|
+
* holds an error. For example, `direction: 'Up'` errors when the target
|
|
292
|
+
* migration is already executed.
|
|
293
|
+
*
|
|
294
|
+
* By default, {@link Migrator.migrateTo | migrateTo} migrates up or down
|
|
295
|
+
* depending on which side of the current migration state the target
|
|
296
|
+
* migration is on.
|
|
297
|
+
*/
|
|
298
|
+
readonly direction?: MigrationDirection;
|
|
299
|
+
}
|
|
260
300
|
export interface MigratorProps extends MigrateOptions {
|
|
261
301
|
readonly db: Kysely<any>;
|
|
262
302
|
readonly provider: MigrationProvider;
|
|
@@ -359,7 +399,7 @@ export interface MigrationResultSet {
|
|
|
359
399
|
*/
|
|
360
400
|
readonly results?: MigrationResult[];
|
|
361
401
|
}
|
|
362
|
-
type MigrationDirection = 'Up' | 'Down';
|
|
402
|
+
export type MigrationDirection = 'Up' | 'Down';
|
|
363
403
|
export interface MigrationResult {
|
|
364
404
|
readonly migrationName: string;
|
|
365
405
|
/**
|
|
@@ -422,4 +462,3 @@ export interface MigrationInfo {
|
|
|
422
462
|
*/
|
|
423
463
|
executedAt?: Date;
|
|
424
464
|
}
|
|
425
|
-
export {};
|
|
@@ -19,7 +19,7 @@ export const NO_MIGRATIONS = freeze({ __noMigrations__: true });
|
|
|
19
19
|
* other way.
|
|
20
20
|
*
|
|
21
21
|
* ```ts
|
|
22
|
-
* import
|
|
22
|
+
* import fs from 'node:fs/promises'
|
|
23
23
|
* import path from 'node:path'
|
|
24
24
|
* import * as Sqlite from 'better-sqlite3'
|
|
25
25
|
* import { Kysely, SqliteDialect } from 'kysely'
|
|
@@ -88,7 +88,7 @@ export class Migrator {
|
|
|
88
88
|
* ### Examples
|
|
89
89
|
*
|
|
90
90
|
* ```ts
|
|
91
|
-
* import
|
|
91
|
+
* import fs from 'node:fs/promises'
|
|
92
92
|
* import path from 'node:path'
|
|
93
93
|
* import * as Sqlite from 'better-sqlite3'
|
|
94
94
|
* import { FileMigrationProvider, Migrator } from 'kysely/migration'
|
|
@@ -132,7 +132,7 @@ export class Migrator {
|
|
|
132
132
|
* ### Examples
|
|
133
133
|
*
|
|
134
134
|
* ```ts
|
|
135
|
-
* import
|
|
135
|
+
* import fs from 'node:fs/promises'
|
|
136
136
|
* import path from 'node:path'
|
|
137
137
|
* import { FileMigrationProvider, Migrator } from 'kysely/migration'
|
|
138
138
|
*
|
|
@@ -155,7 +155,7 @@ export class Migrator {
|
|
|
155
155
|
* you can use a special constant `NO_MIGRATIONS`:
|
|
156
156
|
*
|
|
157
157
|
* ```ts
|
|
158
|
-
* import
|
|
158
|
+
* import fs from 'node:fs/promises'
|
|
159
159
|
* import path from 'node:path'
|
|
160
160
|
* import { FileMigrationProvider, Migrator, NO_MIGRATIONS } from 'kysely/migration'
|
|
161
161
|
*
|
|
@@ -171,11 +171,39 @@ export class Migrator {
|
|
|
171
171
|
*
|
|
172
172
|
* await migrator.migrateTo(NO_MIGRATIONS)
|
|
173
173
|
* ```
|
|
174
|
+
*
|
|
175
|
+
* By default, this method migrates up or down depending on which side of the
|
|
176
|
+
* current migration state the target migration is on. Pass
|
|
177
|
+
* {@link MigrateToOptions.direction} to enforce a direction — if reaching the
|
|
178
|
+
* target would require migrating the other way, nothing is executed and
|
|
179
|
+
* {@link MigrationResultSet.error} holds an error:
|
|
180
|
+
*
|
|
181
|
+
* ```ts
|
|
182
|
+
* import fs from 'node:fs/promises'
|
|
183
|
+
* import path from 'node:path'
|
|
184
|
+
* import { FileMigrationProvider, Migrator } from 'kysely/migration'
|
|
185
|
+
*
|
|
186
|
+
* const migrator = new Migrator({
|
|
187
|
+
* db,
|
|
188
|
+
* provider: new FileMigrationProvider({
|
|
189
|
+
* fs,
|
|
190
|
+
* // Path to the folder that contains all your migrations.
|
|
191
|
+
* migrationFolder: 'some/path/to/migrations',
|
|
192
|
+
* path,
|
|
193
|
+
* })
|
|
194
|
+
* })
|
|
195
|
+
*
|
|
196
|
+
* // Errors if `some_migration` is already executed.
|
|
197
|
+
* await migrator.migrateTo('some_migration', { direction: 'Up' })
|
|
198
|
+
* ```
|
|
174
199
|
*/
|
|
175
200
|
async migrateTo(targetMigrationName, options) {
|
|
176
201
|
return this.#migrate(({ migrations, executedMigrations, pendingMigrations, }) => {
|
|
177
202
|
if (isObject(targetMigrationName) &&
|
|
178
203
|
targetMigrationName.__noMigrations__ === true) {
|
|
204
|
+
if (options?.direction === 'Up') {
|
|
205
|
+
throw new Error(`can't migrate up to NO_MIGRATIONS`);
|
|
206
|
+
}
|
|
179
207
|
return { direction: 'Down', step: Infinity };
|
|
180
208
|
}
|
|
181
209
|
if (!migrations.find((m) => m.name === targetMigrationName)) {
|
|
@@ -184,12 +212,18 @@ export class Migrator {
|
|
|
184
212
|
const executedIndex = executedMigrations.indexOf(targetMigrationName);
|
|
185
213
|
const pendingIndex = pendingMigrations.findIndex((m) => m.name === targetMigrationName);
|
|
186
214
|
if (executedIndex !== -1) {
|
|
215
|
+
if (options?.direction === 'Up') {
|
|
216
|
+
throw new Error(`migration "${targetMigrationName}" is already executed; can't migrate up to it`);
|
|
217
|
+
}
|
|
187
218
|
return {
|
|
188
219
|
direction: 'Down',
|
|
189
220
|
step: executedMigrations.length - executedIndex - 1,
|
|
190
221
|
};
|
|
191
222
|
}
|
|
192
223
|
if (pendingIndex !== -1) {
|
|
224
|
+
if (options?.direction === 'Down') {
|
|
225
|
+
throw new Error(`migration "${targetMigrationName}" isn't executed; can't migrate down to it`);
|
|
226
|
+
}
|
|
193
227
|
return { direction: 'Up', step: pendingIndex + 1 };
|
|
194
228
|
}
|
|
195
229
|
throw new Error(`migration "${targetMigrationName}" isn't executed or pending`);
|
|
@@ -206,7 +240,7 @@ export class Migrator {
|
|
|
206
240
|
* ### Examples
|
|
207
241
|
*
|
|
208
242
|
* ```ts
|
|
209
|
-
* import
|
|
243
|
+
* import fs from 'node:fs/promises'
|
|
210
244
|
* import path from 'node:path'
|
|
211
245
|
* import { FileMigrationProvider, Migrator } from 'kysely/migration'
|
|
212
246
|
*
|
|
@@ -237,7 +271,7 @@ export class Migrator {
|
|
|
237
271
|
* ### Examples
|
|
238
272
|
*
|
|
239
273
|
* ```ts
|
|
240
|
-
* import
|
|
274
|
+
* import fs from 'node:fs/promises'
|
|
241
275
|
* import path from 'node:path'
|
|
242
276
|
* import { FileMigrationProvider, Migrator } from 'kysely/migration'
|
|
243
277
|
*
|