@dungarees/datasource 0.11.4
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/fake.d.ts +35 -0
- package/fake.js +51 -0
- package/fake.test.d.ts +1 -0
- package/fake.test.js +558 -0
- package/helpers.d.ts +2 -0
- package/helpers.js +4 -0
- package/migration/inmemory-migrator.d.ts +2 -0
- package/migration/inmemory-migrator.js +126 -0
- package/migration/kysely-migrator.d.ts +2 -0
- package/migration/kysely-migrator.js +6 -0
- package/migration/migration.d.ts +4 -0
- package/migration/migration.js +5 -0
- package/migration/provider.d.ts +5 -0
- package/migration/provider.js +39 -0
- package/migration/service.d.ts +2 -0
- package/migration/service.js +24 -0
- package/migration/type.d.ts +48 -0
- package/migration/type.js +1 -0
- package/package.json +510 -0
- package/postgres/fake.d.ts +2 -0
- package/postgres/fake.js +45 -0
- package/postgres/service.d.ts +11 -0
- package/postgres/service.js +23 -0
- package/service.d.ts +2 -0
- package/service.js +1 -0
- package/service.test.d.ts +1 -0
- package/service.test.js +37 -0
- package/test-migrations/001-test-migration.d.ts +2 -0
- package/test-migrations/001-test-migration.js +13 -0
- package/test-migrations/002-test-migration.d.ts +2 -0
- package/test-migrations/002-test-migration.js +9 -0
- package/test-migrations/003-test-migration.d.ts +2 -0
- package/test-migrations/003-test-migration.js +9 -0
- package/test-migrations-with-error/001-test-migration.d.ts +2 -0
- package/test-migrations-with-error/001-test-migration.js +13 -0
- package/test-migrations-with-error/002-test-migration.d.ts +2 -0
- package/test-migrations-with-error/002-test-migration.js +10 -0
- package/type.d.ts +5 -0
- package/type.js +1 -0
package/fake.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { MigrationSource, Migrator } from './migration/type.ts';
|
|
2
|
+
import type { ConnectionBuilder, Datasource, Generated } from './type.ts';
|
|
3
|
+
export type FakeDbConnectionBuilder = {
|
|
4
|
+
connectionBuilder: ConnectionBuilder;
|
|
5
|
+
queries: string[];
|
|
6
|
+
};
|
|
7
|
+
export declare const createFakeDbConnectionBuilder: () => FakeDbConnectionBuilder;
|
|
8
|
+
export type DbFixture<SCHEMA, CONTEXT = undefined> = (datasource: Datasource<SCHEMA>) => Promise<CONTEXT>;
|
|
9
|
+
export type TestDatasourceAndMigrator<SCHEMA> = {
|
|
10
|
+
datasource: Datasource<SCHEMA>;
|
|
11
|
+
migrator: Migrator;
|
|
12
|
+
[Symbol.asyncDispose]: () => Promise<void>;
|
|
13
|
+
};
|
|
14
|
+
export type TestDatasourceWithContext<SCHEMA, CONTEXT> = TestDatasourceAndMigrator<SCHEMA> & {
|
|
15
|
+
context: CONTEXT;
|
|
16
|
+
};
|
|
17
|
+
export type TestDatasourceAndMigratorArgs<SCHEMA> = MigrationSource & {
|
|
18
|
+
datasource?: Datasource<SCHEMA>;
|
|
19
|
+
};
|
|
20
|
+
export type TestMigratedDatasourceArgs<SCHEMA, CONTEXT> = TestDatasourceAndMigratorArgs<SCHEMA> & {
|
|
21
|
+
dbFixture: DbFixture<SCHEMA, CONTEXT>;
|
|
22
|
+
};
|
|
23
|
+
export declare const createTestDatasource: <SCHEMA>() => Datasource<SCHEMA>;
|
|
24
|
+
export declare const createTestDatasourceAndMigrator: <SCHEMA>({ datasource, ...source }: TestDatasourceAndMigratorArgs<SCHEMA>) => Promise<TestDatasourceAndMigrator<SCHEMA>>;
|
|
25
|
+
export declare const createTestMigratedDatasource: <SCHEMA, CONTEXT>({ dbFixture, ...args }: TestMigratedDatasourceArgs<SCHEMA, CONTEXT>) => Promise<TestDatasourceWithContext<SCHEMA, CONTEXT>>;
|
|
26
|
+
export type TestSchema = {
|
|
27
|
+
table1: {
|
|
28
|
+
id: Generated<string>;
|
|
29
|
+
name: string;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
export declare const testMigrationsFolder: any;
|
|
33
|
+
export declare const testErrorMigrationsFolder: any;
|
|
34
|
+
export declare const createTestDatasourceAndMigratorWithTestMigrations: () => Promise<TestDatasourceAndMigrator<TestSchema>>;
|
|
35
|
+
export declare const createTestDatasourceAndMigratorWithTestErrorMigrations: () => Promise<TestDatasourceAndMigrator<TestSchema>>;
|
package/fake.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createInMemoryMigrator } from './migration/inmemory-migrator.js';
|
|
2
|
+
import { createMigrator } from './migration/service.js';
|
|
3
|
+
import { createInMemoryPostgresConnectionBuilder } from './postgres/fake.js';
|
|
4
|
+
import { createDatasource } from './service.js';
|
|
5
|
+
import { createCausedError } from '@dungarees/core/error.ts';
|
|
6
|
+
import { dirname, join } from 'node:path';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
// Prefer createTestDatasource for anything that asserts on data: that one runs the real SQL.
|
|
9
|
+
export const createFakeDbConnectionBuilder = () => {
|
|
10
|
+
const queries = [];
|
|
11
|
+
return {
|
|
12
|
+
connectionBuilder: () =>
|
|
13
|
+
// Only the one method is implemented, so this cannot be built as a real Datasource.
|
|
14
|
+
({
|
|
15
|
+
selectFrom: (table) => queries.push(table),
|
|
16
|
+
}),
|
|
17
|
+
queries,
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export const createTestDatasource = () => createDatasource(createInMemoryPostgresConnectionBuilder());
|
|
21
|
+
export const createTestDatasourceAndMigrator = async ({ datasource, ...source }) => {
|
|
22
|
+
const datasourceToUse = datasource ?? createTestDatasource();
|
|
23
|
+
return await Promise.resolve({
|
|
24
|
+
datasource: datasourceToUse,
|
|
25
|
+
migrator: createMigrator(createInMemoryMigrator({ datasource: datasourceToUse, ...source })),
|
|
26
|
+
[Symbol.asyncDispose]: async () => {
|
|
27
|
+
await datasourceToUse.destroy();
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
export const createTestMigratedDatasource = async ({ dbFixture, ...args }) => {
|
|
32
|
+
const db = await createTestDatasourceAndMigrator(args);
|
|
33
|
+
const { error, results } = await db.migrator.migrateToLatest();
|
|
34
|
+
if (error !== undefined) {
|
|
35
|
+
throw createCausedError({
|
|
36
|
+
message: `Failed to migrate: ${describeResults(results)}`,
|
|
37
|
+
cause: error,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return { ...db, context: await dbFixture(db.datasource) };
|
|
41
|
+
};
|
|
42
|
+
// Named in the message rather than logged, so the failure says which migration stopped it without
|
|
43
|
+
// this library writing to the console.
|
|
44
|
+
const describeResults = (results) => results.map(({ migrationName, status }) => `${migrationName}=${status}`).join(', ');
|
|
45
|
+
const packageFolder = dirname(fileURLToPath(import.meta.url));
|
|
46
|
+
export const testMigrationsFolder = join(packageFolder, 'test-migrations');
|
|
47
|
+
export const testErrorMigrationsFolder = join(packageFolder, 'test-migrations-with-error');
|
|
48
|
+
export const createTestDatasourceAndMigratorWithTestMigrations = async () => await createTestDatasourceAndMigrator({ migrationsFolder: testMigrationsFolder });
|
|
49
|
+
export const createTestDatasourceAndMigratorWithTestErrorMigrations = async () => await createTestDatasourceAndMigrator({
|
|
50
|
+
migrationsFolder: testErrorMigrationsFolder,
|
|
51
|
+
});
|
package/fake.test.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/fake.test.js
ADDED
|
@@ -0,0 +1,558 @@
|
|
|
1
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
2
|
+
if (value !== null && value !== void 0) {
|
|
3
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
4
|
+
var dispose, inner;
|
|
5
|
+
if (async) {
|
|
6
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
7
|
+
dispose = value[Symbol.asyncDispose];
|
|
8
|
+
}
|
|
9
|
+
if (dispose === void 0) {
|
|
10
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
11
|
+
dispose = value[Symbol.dispose];
|
|
12
|
+
if (async) inner = dispose;
|
|
13
|
+
}
|
|
14
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
15
|
+
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
16
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
17
|
+
}
|
|
18
|
+
else if (async) {
|
|
19
|
+
env.stack.push({ async: true });
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
};
|
|
23
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
24
|
+
return function (env) {
|
|
25
|
+
function fail(e) {
|
|
26
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
27
|
+
env.hasError = true;
|
|
28
|
+
}
|
|
29
|
+
var r, s = 0;
|
|
30
|
+
function next() {
|
|
31
|
+
while (r = env.stack.pop()) {
|
|
32
|
+
try {
|
|
33
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
34
|
+
if (r.dispose) {
|
|
35
|
+
var result = r.dispose.call(r.value);
|
|
36
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
37
|
+
}
|
|
38
|
+
else s |= 1;
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
fail(e);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
45
|
+
if (env.hasError) throw env.error;
|
|
46
|
+
}
|
|
47
|
+
return next();
|
|
48
|
+
};
|
|
49
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
50
|
+
var e = new Error(message);
|
|
51
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
|
+
});
|
|
53
|
+
import { createTestDatasourceAndMigrator, createTestDatasourceAndMigratorWithTestErrorMigrations, createTestDatasourceAndMigratorWithTestMigrations, createTestMigratedDatasource, testErrorMigrationsFolder, testMigrationsFolder, } from './fake.js';
|
|
54
|
+
import { createInMemoryPostgresConnectionBuilder } from './postgres/fake.js';
|
|
55
|
+
import { createDatasource } from './service.js';
|
|
56
|
+
import { expect, test } from 'vitest';
|
|
57
|
+
const migrationsFolder = testMigrationsFolder;
|
|
58
|
+
const dbFixture = async (datasource) => {
|
|
59
|
+
await datasource.insertInto('table1').values({ name: 'test3' }).execute();
|
|
60
|
+
};
|
|
61
|
+
const dbFixtureWithContext = async (datasource) => {
|
|
62
|
+
await datasource.insertInto('table1').values({ name: 'test3' }).execute();
|
|
63
|
+
return { value: 3 };
|
|
64
|
+
};
|
|
65
|
+
const MIGRATED_ROWS = [
|
|
66
|
+
{ id: 1, name: 'test1' },
|
|
67
|
+
{ id: 2, name: 'test2' },
|
|
68
|
+
];
|
|
69
|
+
test('a migrated test datasource has run every migration and the fixture', async () => {
|
|
70
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
71
|
+
try {
|
|
72
|
+
const db = __addDisposableResource(env_1, await createTestMigratedDatasource({ dbFixture, migrationsFolder }), true);
|
|
73
|
+
expect(await db.datasource.selectFrom('table1').selectAll().execute()).toEqual([
|
|
74
|
+
...MIGRATED_ROWS,
|
|
75
|
+
{ id: 3, name: 'test3' },
|
|
76
|
+
]);
|
|
77
|
+
}
|
|
78
|
+
catch (e_1) {
|
|
79
|
+
env_1.error = e_1;
|
|
80
|
+
env_1.hasError = true;
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
const result_1 = __disposeResources(env_1);
|
|
84
|
+
if (result_1)
|
|
85
|
+
await result_1;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
test('a migrated test datasource is destroyed when it goes out of scope', async () => {
|
|
89
|
+
const destroyed = [];
|
|
90
|
+
{
|
|
91
|
+
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
92
|
+
try {
|
|
93
|
+
const db = __addDisposableResource(env_2, await createTestMigratedDatasource({ dbFixture, migrationsFolder }), true);
|
|
94
|
+
db.datasource.destroy = async () => {
|
|
95
|
+
destroyed.push(true);
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
catch (e_2) {
|
|
99
|
+
env_2.error = e_2;
|
|
100
|
+
env_2.hasError = true;
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
const result_2 = __disposeResources(env_2);
|
|
104
|
+
if (result_2)
|
|
105
|
+
await result_2;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
expect(destroyed).toEqual([true]);
|
|
109
|
+
});
|
|
110
|
+
test('a fixture can hand back a context alongside the datasource', async () => {
|
|
111
|
+
const env_3 = { stack: [], error: void 0, hasError: false };
|
|
112
|
+
try {
|
|
113
|
+
const db = __addDisposableResource(env_3, await createTestMigratedDatasource({
|
|
114
|
+
dbFixture: dbFixtureWithContext,
|
|
115
|
+
migrationsFolder,
|
|
116
|
+
}), true);
|
|
117
|
+
expect(db.context).toEqual({ value: 3 });
|
|
118
|
+
}
|
|
119
|
+
catch (e_3) {
|
|
120
|
+
env_3.error = e_3;
|
|
121
|
+
env_3.hasError = true;
|
|
122
|
+
}
|
|
123
|
+
finally {
|
|
124
|
+
const result_3 = __disposeResources(env_3);
|
|
125
|
+
if (result_3)
|
|
126
|
+
await result_3;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
test('a migrated test datasource can be given a datasource to use', async () => {
|
|
130
|
+
const datasource = createDatasource(createInMemoryPostgresConnectionBuilder());
|
|
131
|
+
await createTestMigratedDatasource({ dbFixture, migrationsFolder, datasource });
|
|
132
|
+
expect(await datasource.selectFrom('table1').selectAll().execute()).toEqual([
|
|
133
|
+
...MIGRATED_ROWS,
|
|
134
|
+
{ id: 3, name: 'test3' },
|
|
135
|
+
]);
|
|
136
|
+
});
|
|
137
|
+
test('a migrated test datasource still exposes its migrator', async () => {
|
|
138
|
+
const env_4 = { stack: [], error: void 0, hasError: false };
|
|
139
|
+
try {
|
|
140
|
+
const db = __addDisposableResource(env_4, await createTestMigratedDatasource({ dbFixture, migrationsFolder }), true);
|
|
141
|
+
await db.migrator.migrateDownStep();
|
|
142
|
+
expect(await db.datasource.selectFrom('table1').selectAll().execute()).toEqual([
|
|
143
|
+
{ id: 1, name: 'test1' },
|
|
144
|
+
{ id: 3, name: 'test3' },
|
|
145
|
+
]);
|
|
146
|
+
}
|
|
147
|
+
catch (e_4) {
|
|
148
|
+
env_4.error = e_4;
|
|
149
|
+
env_4.hasError = true;
|
|
150
|
+
}
|
|
151
|
+
finally {
|
|
152
|
+
const result_4 = __disposeResources(env_4);
|
|
153
|
+
if (result_4)
|
|
154
|
+
await result_4;
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
test('a migrated test datasource reports which migration failed', async () => {
|
|
158
|
+
await expect(createTestMigratedDatasource({ dbFixture, migrationsFolder: testErrorMigrationsFolder })).rejects.toThrow('002-test-migration=Error');
|
|
159
|
+
});
|
|
160
|
+
test('a test datasource and migrator has not run any migration yet', async () => {
|
|
161
|
+
const env_5 = { stack: [], error: void 0, hasError: false };
|
|
162
|
+
try {
|
|
163
|
+
const db = __addDisposableResource(env_5, await createTestDatasourceAndMigrator({ migrationsFolder }), true);
|
|
164
|
+
await expect(db.datasource.selectFrom('table1').selectAll().execute()).rejects.toThrow();
|
|
165
|
+
}
|
|
166
|
+
catch (e_5) {
|
|
167
|
+
env_5.error = e_5;
|
|
168
|
+
env_5.hasError = true;
|
|
169
|
+
}
|
|
170
|
+
finally {
|
|
171
|
+
const result_5 = __disposeResources(env_5);
|
|
172
|
+
if (result_5)
|
|
173
|
+
await result_5;
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
test('a test datasource and migrator is destroyed when it goes out of scope', async () => {
|
|
177
|
+
const destroyed = [];
|
|
178
|
+
{
|
|
179
|
+
const env_6 = { stack: [], error: void 0, hasError: false };
|
|
180
|
+
try {
|
|
181
|
+
const db = __addDisposableResource(env_6, await createTestDatasourceAndMigrator({ migrationsFolder }), true);
|
|
182
|
+
db.datasource.destroy = async () => {
|
|
183
|
+
destroyed.push(true);
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
catch (e_6) {
|
|
187
|
+
env_6.error = e_6;
|
|
188
|
+
env_6.hasError = true;
|
|
189
|
+
}
|
|
190
|
+
finally {
|
|
191
|
+
const result_6 = __disposeResources(env_6);
|
|
192
|
+
if (result_6)
|
|
193
|
+
await result_6;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
expect(destroyed).toEqual([true]);
|
|
197
|
+
});
|
|
198
|
+
test('a test datasource and migrator can be given a datasource to use', async () => {
|
|
199
|
+
const env_7 = { stack: [], error: void 0, hasError: false };
|
|
200
|
+
try {
|
|
201
|
+
const datasource = createDatasource(createInMemoryPostgresConnectionBuilder());
|
|
202
|
+
const db = __addDisposableResource(env_7, await createTestDatasourceAndMigrator({ migrationsFolder, datasource }), true);
|
|
203
|
+
await db.migrator.migrateToLatest();
|
|
204
|
+
expect(await datasource.selectFrom('table1').selectAll().execute()).toEqual(MIGRATED_ROWS);
|
|
205
|
+
}
|
|
206
|
+
catch (e_7) {
|
|
207
|
+
env_7.error = e_7;
|
|
208
|
+
env_7.hasError = true;
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
const result_7 = __disposeResources(env_7);
|
|
212
|
+
if (result_7)
|
|
213
|
+
await result_7;
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
test('migrateToLatest runs every migration', async () => {
|
|
217
|
+
const env_8 = { stack: [], error: void 0, hasError: false };
|
|
218
|
+
try {
|
|
219
|
+
const db = __addDisposableResource(env_8, await createTestDatasourceAndMigrator({ migrationsFolder }), true);
|
|
220
|
+
await db.migrator.migrateToLatest();
|
|
221
|
+
expect(await db.datasource.selectFrom('table1').selectAll().execute()).toEqual(MIGRATED_ROWS);
|
|
222
|
+
}
|
|
223
|
+
catch (e_8) {
|
|
224
|
+
env_8.error = e_8;
|
|
225
|
+
env_8.hasError = true;
|
|
226
|
+
}
|
|
227
|
+
finally {
|
|
228
|
+
const result_8 = __disposeResources(env_8);
|
|
229
|
+
if (result_8)
|
|
230
|
+
await result_8;
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
test('migrateUpStep runs only the next migration', async () => {
|
|
234
|
+
const env_9 = { stack: [], error: void 0, hasError: false };
|
|
235
|
+
try {
|
|
236
|
+
const db = __addDisposableResource(env_9, await createTestDatasourceAndMigrator({ migrationsFolder }), true);
|
|
237
|
+
await db.migrator.migrateUpStep();
|
|
238
|
+
expect(await db.datasource.selectFrom('table1').selectAll().execute()).toEqual([]);
|
|
239
|
+
}
|
|
240
|
+
catch (e_9) {
|
|
241
|
+
env_9.error = e_9;
|
|
242
|
+
env_9.hasError = true;
|
|
243
|
+
}
|
|
244
|
+
finally {
|
|
245
|
+
const result_9 = __disposeResources(env_9);
|
|
246
|
+
if (result_9)
|
|
247
|
+
await result_9;
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
test('migrateUpStep run twice runs the second migration as well', async () => {
|
|
251
|
+
const env_10 = { stack: [], error: void 0, hasError: false };
|
|
252
|
+
try {
|
|
253
|
+
const db = __addDisposableResource(env_10, await createTestDatasourceAndMigrator({ migrationsFolder }), true);
|
|
254
|
+
await db.migrator.migrateUpStep();
|
|
255
|
+
await db.migrator.migrateUpStep();
|
|
256
|
+
expect(await db.datasource.selectFrom('table1').selectAll().execute()).toEqual([
|
|
257
|
+
{ id: 1, name: 'test1' },
|
|
258
|
+
]);
|
|
259
|
+
}
|
|
260
|
+
catch (e_10) {
|
|
261
|
+
env_10.error = e_10;
|
|
262
|
+
env_10.hasError = true;
|
|
263
|
+
}
|
|
264
|
+
finally {
|
|
265
|
+
const result_10 = __disposeResources(env_10);
|
|
266
|
+
if (result_10)
|
|
267
|
+
await result_10;
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
test('migrateUpStep past the last migration does nothing', async () => {
|
|
271
|
+
const env_11 = { stack: [], error: void 0, hasError: false };
|
|
272
|
+
try {
|
|
273
|
+
const db = __addDisposableResource(env_11, await createTestDatasourceAndMigrator({ migrationsFolder }), true);
|
|
274
|
+
await db.migrator.migrateToLatest();
|
|
275
|
+
expect(await db.migrator.migrateUpStep()).toEqual({ error: undefined, results: [] });
|
|
276
|
+
}
|
|
277
|
+
catch (e_11) {
|
|
278
|
+
env_11.error = e_11;
|
|
279
|
+
env_11.hasError = true;
|
|
280
|
+
}
|
|
281
|
+
finally {
|
|
282
|
+
const result_11 = __disposeResources(env_11);
|
|
283
|
+
if (result_11)
|
|
284
|
+
await result_11;
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
test('migrateDownStep undoes the last migration', async () => {
|
|
288
|
+
const env_12 = { stack: [], error: void 0, hasError: false };
|
|
289
|
+
try {
|
|
290
|
+
const db = __addDisposableResource(env_12, await createTestDatasourceAndMigrator({ migrationsFolder }), true);
|
|
291
|
+
await db.migrator.migrateToLatest();
|
|
292
|
+
await db.migrator.migrateDownStep();
|
|
293
|
+
expect(await db.datasource.selectFrom('table1').selectAll().execute()).toEqual([
|
|
294
|
+
{ id: 1, name: 'test1' },
|
|
295
|
+
]);
|
|
296
|
+
}
|
|
297
|
+
catch (e_12) {
|
|
298
|
+
env_12.error = e_12;
|
|
299
|
+
env_12.hasError = true;
|
|
300
|
+
}
|
|
301
|
+
finally {
|
|
302
|
+
const result_12 = __disposeResources(env_12);
|
|
303
|
+
if (result_12)
|
|
304
|
+
await result_12;
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
test('migrateDownStep with nothing applied does nothing', async () => {
|
|
308
|
+
const env_13 = { stack: [], error: void 0, hasError: false };
|
|
309
|
+
try {
|
|
310
|
+
const db = __addDisposableResource(env_13, await createTestDatasourceAndMigrator({ migrationsFolder }), true);
|
|
311
|
+
expect(await db.migrator.migrateDownStep()).toEqual({ error: undefined, results: [] });
|
|
312
|
+
}
|
|
313
|
+
catch (e_13) {
|
|
314
|
+
env_13.error = e_13;
|
|
315
|
+
env_13.hasError = true;
|
|
316
|
+
}
|
|
317
|
+
finally {
|
|
318
|
+
const result_13 = __disposeResources(env_13);
|
|
319
|
+
if (result_13)
|
|
320
|
+
await result_13;
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
test('getMigrations lists every migration as not yet executed', async () => {
|
|
324
|
+
const env_14 = { stack: [], error: void 0, hasError: false };
|
|
325
|
+
try {
|
|
326
|
+
const db = __addDisposableResource(env_14, await createTestDatasourceAndMigrator({ migrationsFolder }), true);
|
|
327
|
+
expect(await db.migrator.getMigrations()).toEqual([
|
|
328
|
+
{ name: '001-test-migration', executedAt: undefined },
|
|
329
|
+
{ name: '002-test-migration', executedAt: undefined },
|
|
330
|
+
{ name: '003-test-migration', executedAt: undefined },
|
|
331
|
+
]);
|
|
332
|
+
}
|
|
333
|
+
catch (e_14) {
|
|
334
|
+
env_14.error = e_14;
|
|
335
|
+
env_14.hasError = true;
|
|
336
|
+
}
|
|
337
|
+
finally {
|
|
338
|
+
const result_14 = __disposeResources(env_14);
|
|
339
|
+
if (result_14)
|
|
340
|
+
await result_14;
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
test('getMigrations stamps the migrations that have run', async () => {
|
|
344
|
+
const env_15 = { stack: [], error: void 0, hasError: false };
|
|
345
|
+
try {
|
|
346
|
+
const db = __addDisposableResource(env_15, await createTestDatasourceAndMigrator({ migrationsFolder }), true);
|
|
347
|
+
await db.migrator.migrateToLatest();
|
|
348
|
+
const executed = (await db.migrator.getMigrations()).map(({ name, executedAt }) => ({
|
|
349
|
+
name,
|
|
350
|
+
hasRun: executedAt !== undefined,
|
|
351
|
+
}));
|
|
352
|
+
expect(executed).toEqual([
|
|
353
|
+
{ name: '001-test-migration', hasRun: true },
|
|
354
|
+
{ name: '002-test-migration', hasRun: true },
|
|
355
|
+
{ name: '003-test-migration', hasRun: true },
|
|
356
|
+
]);
|
|
357
|
+
}
|
|
358
|
+
catch (e_15) {
|
|
359
|
+
env_15.error = e_15;
|
|
360
|
+
env_15.hasError = true;
|
|
361
|
+
}
|
|
362
|
+
finally {
|
|
363
|
+
const result_15 = __disposeResources(env_15);
|
|
364
|
+
if (result_15)
|
|
365
|
+
await result_15;
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
test('migrateTo runs up to the named migration and skips the rest', async () => {
|
|
369
|
+
const env_16 = { stack: [], error: void 0, hasError: false };
|
|
370
|
+
try {
|
|
371
|
+
const db = __addDisposableResource(env_16, await createTestDatasourceAndMigrator({ migrationsFolder }), true);
|
|
372
|
+
const { results } = await db.migrator.migrateTo('002-test-migration');
|
|
373
|
+
expect(await db.datasource.selectFrom('table1').selectAll().execute()).toEqual([
|
|
374
|
+
{ id: 1, name: 'test1' },
|
|
375
|
+
]);
|
|
376
|
+
expect(results).toEqual([
|
|
377
|
+
{ migrationName: '001-test-migration', status: 'Success', direction: 'Up' },
|
|
378
|
+
{ migrationName: '002-test-migration', status: 'Success', direction: 'Up' },
|
|
379
|
+
{ migrationName: '003-test-migration', status: 'NotExecuted', direction: 'Up' },
|
|
380
|
+
]);
|
|
381
|
+
}
|
|
382
|
+
catch (e_16) {
|
|
383
|
+
env_16.error = e_16;
|
|
384
|
+
env_16.hasError = true;
|
|
385
|
+
}
|
|
386
|
+
finally {
|
|
387
|
+
const result_16 = __disposeResources(env_16);
|
|
388
|
+
if (result_16)
|
|
389
|
+
await result_16;
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
test('migrateTo walks back down to the named migration', async () => {
|
|
393
|
+
const env_17 = { stack: [], error: void 0, hasError: false };
|
|
394
|
+
try {
|
|
395
|
+
const db = __addDisposableResource(env_17, await createTestDatasourceAndMigrator({ migrationsFolder }), true);
|
|
396
|
+
await db.migrator.migrateToLatest();
|
|
397
|
+
const { results } = await db.migrator.migrateTo('001-test-migration');
|
|
398
|
+
expect(await db.datasource.selectFrom('table1').selectAll().execute()).toEqual([]);
|
|
399
|
+
expect(results).toEqual([
|
|
400
|
+
{ migrationName: '001-test-migration', status: 'NotExecuted', direction: 'Down' },
|
|
401
|
+
{ migrationName: '002-test-migration', status: 'Success', direction: 'Down' },
|
|
402
|
+
{ migrationName: '003-test-migration', status: 'Success', direction: 'Down' },
|
|
403
|
+
]);
|
|
404
|
+
}
|
|
405
|
+
catch (e_17) {
|
|
406
|
+
env_17.error = e_17;
|
|
407
|
+
env_17.hasError = true;
|
|
408
|
+
}
|
|
409
|
+
finally {
|
|
410
|
+
const result_17 = __disposeResources(env_17);
|
|
411
|
+
if (result_17)
|
|
412
|
+
await result_17;
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
test('migrateTo walks back down from the middle', async () => {
|
|
416
|
+
const env_18 = { stack: [], error: void 0, hasError: false };
|
|
417
|
+
try {
|
|
418
|
+
const db = __addDisposableResource(env_18, await createTestDatasourceAndMigrator({ migrationsFolder }), true);
|
|
419
|
+
await db.migrator.migrateTo('002-test-migration');
|
|
420
|
+
const { results } = await db.migrator.migrateTo('001-test-migration');
|
|
421
|
+
expect(await db.datasource.selectFrom('table1').selectAll().execute()).toEqual([]);
|
|
422
|
+
expect(results).toEqual([
|
|
423
|
+
{ migrationName: '001-test-migration', status: 'NotExecuted', direction: 'Down' },
|
|
424
|
+
{ migrationName: '002-test-migration', status: 'Success', direction: 'Down' },
|
|
425
|
+
{ migrationName: '003-test-migration', status: 'NotExecuted', direction: 'Down' },
|
|
426
|
+
]);
|
|
427
|
+
}
|
|
428
|
+
catch (e_18) {
|
|
429
|
+
env_18.error = e_18;
|
|
430
|
+
env_18.hasError = true;
|
|
431
|
+
}
|
|
432
|
+
finally {
|
|
433
|
+
const result_18 = __disposeResources(env_18);
|
|
434
|
+
if (result_18)
|
|
435
|
+
await result_18;
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
test('migrateTo refuses a migration name that does not exist', async () => {
|
|
439
|
+
const env_19 = { stack: [], error: void 0, hasError: false };
|
|
440
|
+
try {
|
|
441
|
+
const db = __addDisposableResource(env_19, await createTestDatasourceAndMigrator({ migrationsFolder }), true);
|
|
442
|
+
await expect(db.migrator.migrateTo('009-nope')).rejects.toThrow('Migration 009-nope not found');
|
|
443
|
+
}
|
|
444
|
+
catch (e_19) {
|
|
445
|
+
env_19.error = e_19;
|
|
446
|
+
env_19.hasError = true;
|
|
447
|
+
}
|
|
448
|
+
finally {
|
|
449
|
+
const result_19 = __disposeResources(env_19);
|
|
450
|
+
if (result_19)
|
|
451
|
+
await result_19;
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
test('migrateToEmpty leaves nothing behind', async () => {
|
|
455
|
+
const env_20 = { stack: [], error: void 0, hasError: false };
|
|
456
|
+
try {
|
|
457
|
+
const db = __addDisposableResource(env_20, await createTestDatasourceAndMigrator({ migrationsFolder }), true);
|
|
458
|
+
await db.migrator.migrateToLatest();
|
|
459
|
+
await db.migrator.migrateToEmpty();
|
|
460
|
+
await expect(db.datasource.selectFrom('table1').selectAll().execute()).rejects.toThrow();
|
|
461
|
+
}
|
|
462
|
+
catch (e_20) {
|
|
463
|
+
env_20.error = e_20;
|
|
464
|
+
env_20.hasError = true;
|
|
465
|
+
}
|
|
466
|
+
finally {
|
|
467
|
+
const result_20 = __disposeResources(env_20);
|
|
468
|
+
if (result_20)
|
|
469
|
+
await result_20;
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
test('migrateToEmpty on a datasource that was never migrated leaves it empty', async () => {
|
|
473
|
+
const env_21 = { stack: [], error: void 0, hasError: false };
|
|
474
|
+
try {
|
|
475
|
+
const db = __addDisposableResource(env_21, await createTestDatasourceAndMigrator({ migrationsFolder }), true);
|
|
476
|
+
await db.migrator.migrateToEmpty();
|
|
477
|
+
await expect(db.datasource.selectFrom('table1').selectAll().execute()).rejects.toThrow();
|
|
478
|
+
}
|
|
479
|
+
catch (e_21) {
|
|
480
|
+
env_21.error = e_21;
|
|
481
|
+
env_21.hasError = true;
|
|
482
|
+
}
|
|
483
|
+
finally {
|
|
484
|
+
const result_21 = __disposeResources(env_21);
|
|
485
|
+
if (result_21)
|
|
486
|
+
await result_21;
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
test('the packaged test migrations helper migrates to latest', async () => {
|
|
490
|
+
const env_22 = { stack: [], error: void 0, hasError: false };
|
|
491
|
+
try {
|
|
492
|
+
const db = __addDisposableResource(env_22, await createTestDatasourceAndMigratorWithTestMigrations(), true);
|
|
493
|
+
await db.migrator.migrateToLatest();
|
|
494
|
+
expect(await db.datasource.selectFrom('table1').selectAll().execute()).toEqual(MIGRATED_ROWS);
|
|
495
|
+
}
|
|
496
|
+
catch (e_22) {
|
|
497
|
+
env_22.error = e_22;
|
|
498
|
+
env_22.hasError = true;
|
|
499
|
+
}
|
|
500
|
+
finally {
|
|
501
|
+
const result_22 = __disposeResources(env_22);
|
|
502
|
+
if (result_22)
|
|
503
|
+
await result_22;
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
test('a failing migration is reported as an error rather than thrown', async () => {
|
|
507
|
+
const env_23 = { stack: [], error: void 0, hasError: false };
|
|
508
|
+
try {
|
|
509
|
+
const db = __addDisposableResource(env_23, await createTestDatasourceAndMigratorWithTestErrorMigrations(), true);
|
|
510
|
+
const { error, results } = await db.migrator.migrateToLatest();
|
|
511
|
+
expect(error).toBeInstanceOf(Error);
|
|
512
|
+
expect(results).toEqual([
|
|
513
|
+
{ migrationName: '001-test-migration', status: 'Success', direction: 'Up' },
|
|
514
|
+
{ migrationName: '002-test-migration', status: 'Error', direction: 'Up' },
|
|
515
|
+
]);
|
|
516
|
+
}
|
|
517
|
+
catch (e_23) {
|
|
518
|
+
env_23.error = e_23;
|
|
519
|
+
env_23.hasError = true;
|
|
520
|
+
}
|
|
521
|
+
finally {
|
|
522
|
+
const result_23 = __disposeResources(env_23);
|
|
523
|
+
if (result_23)
|
|
524
|
+
await result_23;
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
test('migrations can be handed over directly instead of read from a folder', async () => {
|
|
528
|
+
const env_24 = { stack: [], error: void 0, hasError: false };
|
|
529
|
+
try {
|
|
530
|
+
const created = [];
|
|
531
|
+
const db = __addDisposableResource(env_24, await createTestDatasourceAndMigrator({
|
|
532
|
+
migrations: {
|
|
533
|
+
'001-inline': {
|
|
534
|
+
up: async (datasource) => {
|
|
535
|
+
created.push('001-inline');
|
|
536
|
+
await datasource.schema
|
|
537
|
+
.createTable('table1')
|
|
538
|
+
.addColumn('id', 'serial', (col) => col.primaryKey())
|
|
539
|
+
.addColumn('name', 'varchar', (col) => col.notNull())
|
|
540
|
+
.execute();
|
|
541
|
+
},
|
|
542
|
+
},
|
|
543
|
+
},
|
|
544
|
+
}), true);
|
|
545
|
+
await db.migrator.migrateToLatest();
|
|
546
|
+
expect(created).toEqual(['001-inline']);
|
|
547
|
+
expect(await db.datasource.selectFrom('table1').selectAll().execute()).toEqual([]);
|
|
548
|
+
}
|
|
549
|
+
catch (e_24) {
|
|
550
|
+
env_24.error = e_24;
|
|
551
|
+
env_24.hasError = true;
|
|
552
|
+
}
|
|
553
|
+
finally {
|
|
554
|
+
const result_24 = __disposeResources(env_24);
|
|
555
|
+
if (result_24)
|
|
556
|
+
await result_24;
|
|
557
|
+
}
|
|
558
|
+
});
|
package/helpers.d.ts
ADDED
package/helpers.js
ADDED