@balena/pinejs 14.44.0-linear-runtime-migrator-9d426d29f2b01ef0425c72333c2c691976fdc219 → 15.0.0-delete-state-default-user-permissions-57ce3dc6141cd1e8159f4c34da29d1fb113242c6
Sign up to get free protection for your applications and to get access to all the features.
- package/.versionbot/CHANGELOG.yml +126 -31
- package/CHANGELOG.md +63 -5
- package/VERSION +1 -1
- package/docs/Migrations.md +1 -101
- package/out/bin/utils.d.ts +2 -2
- package/out/config-loader/config-loader.d.ts +2 -2
- package/out/config-loader/config-loader.js +20 -29
- package/out/config-loader/config-loader.js.map +1 -1
- package/out/config-loader/env.d.ts +0 -3
- package/out/config-loader/env.js +0 -3
- package/out/config-loader/env.js.map +1 -1
- package/out/data-server/sbvr-server.d.ts +1 -3
- package/out/data-server/sbvr-server.js +1 -4
- package/out/data-server/sbvr-server.js.map +1 -1
- package/out/migrator/migrations.sbvr +0 -66
- package/out/migrator/migrator.d.ts +17 -0
- package/out/migrator/migrator.js +185 -0
- package/out/migrator/migrator.js.map +1 -0
- package/out/pinejs-session-store/pinejs-session-store.js +1 -4
- package/out/pinejs-session-store/pinejs-session-store.js.map +1 -1
- package/out/sbvr-api/abstract-sql.d.ts +1 -1
- package/out/sbvr-api/permissions.d.ts +5 -5
- package/out/sbvr-api/permissions.js +3 -6
- package/out/sbvr-api/permissions.js.map +1 -1
- package/out/sbvr-api/sbvr-utils.d.ts +4 -6
- package/out/sbvr-api/sbvr-utils.js +5 -17
- package/out/sbvr-api/sbvr-utils.js.map +1 -1
- package/out/server-glue/module.d.ts +3 -3
- package/out/server-glue/module.js +1 -2
- package/out/server-glue/module.js.map +1 -1
- package/package.json +7 -7
- package/src/config-loader/config-loader.ts +27 -62
- package/src/config-loader/env.ts +0 -3
- package/src/data-server/sbvr-server.js +1 -4
- package/src/migrator/migrations.sbvr +0 -66
- package/src/migrator/migrator.ts +278 -0
- package/src/pinejs-session-store/pinejs-session-store.ts +1 -4
- package/src/sbvr-api/permissions.ts +3 -6
- package/src/sbvr-api/sbvr-utils.ts +4 -22
- package/src/server-glue/module.ts +2 -3
- package/out/migrator/async.d.ts +0 -6
- package/out/migrator/async.js +0 -154
- package/out/migrator/async.js.map +0 -1
- package/out/migrator/sync.d.ts +0 -9
- package/out/migrator/sync.js +0 -117
- package/out/migrator/sync.js.map +0 -1
- package/out/migrator/utils.d.ts +0 -51
- package/out/migrator/utils.js +0 -187
- package/out/migrator/utils.js.map +0 -1
- package/src/migrator/async.ts +0 -273
- package/src/migrator/sync.ts +0 -167
- package/src/migrator/utils.ts +0 -293
@@ -0,0 +1,278 @@
|
|
1
|
+
import type { Tx } from '../database-layer/db';
|
2
|
+
import type { Resolvable } from '../sbvr-api/common-types';
|
3
|
+
import type { Config, Model } from '../config-loader/config-loader';
|
4
|
+
|
5
|
+
import { Engines } from '@balena/abstract-sql-compiler';
|
6
|
+
import * as _ from 'lodash';
|
7
|
+
import { TypedError } from 'typed-error';
|
8
|
+
import { migrator as migratorEnv } from '../config-loader/env';
|
9
|
+
import * as sbvrUtils from '../sbvr-api/sbvr-utils';
|
10
|
+
import { delay } from '../sbvr-api/control-flow';
|
11
|
+
|
12
|
+
// tslint:disable-next-line:no-var-requires
|
13
|
+
const modelText: string = require('./migrations.sbvr');
|
14
|
+
|
15
|
+
type ApiRootModel = Model & { apiRoot: string };
|
16
|
+
|
17
|
+
type SbvrUtils = typeof sbvrUtils;
|
18
|
+
|
19
|
+
type MigrationTuple = [string, Migration];
|
20
|
+
|
21
|
+
export type MigrationFn = (tx: Tx, sbvrUtils: SbvrUtils) => Resolvable<void>;
|
22
|
+
|
23
|
+
export type Migration = string | MigrationFn;
|
24
|
+
|
25
|
+
export class MigrationError extends TypedError {}
|
26
|
+
|
27
|
+
// Tagged template to convert binds from `?` format to the necessary output format,
|
28
|
+
// eg `$1`/`$2`/etc for postgres
|
29
|
+
const binds = (strings: TemplateStringsArray, ...bindNums: number[]) =>
|
30
|
+
strings
|
31
|
+
.map((str, i) => {
|
32
|
+
if (i === bindNums.length) {
|
33
|
+
return str;
|
34
|
+
}
|
35
|
+
if (i + 1 !== bindNums[i]) {
|
36
|
+
throw new SyntaxError('Migration sql binds must be sequential');
|
37
|
+
}
|
38
|
+
if (sbvrUtils.db.engine === Engines.postgres) {
|
39
|
+
return str + `$${bindNums[i]}`;
|
40
|
+
}
|
41
|
+
return str + `?`;
|
42
|
+
})
|
43
|
+
.join('');
|
44
|
+
|
45
|
+
export const postRun = async (tx: Tx, model: ApiRootModel): Promise<void> => {
|
46
|
+
const { initSql } = model;
|
47
|
+
if (initSql == null) {
|
48
|
+
return;
|
49
|
+
}
|
50
|
+
|
51
|
+
const modelName = model.apiRoot;
|
52
|
+
|
53
|
+
const exists = await checkModelAlreadyExists(tx, modelName);
|
54
|
+
if (!exists) {
|
55
|
+
(sbvrUtils.api.migrations?.logger.info ?? console.info)(
|
56
|
+
'First time executing, running init script',
|
57
|
+
);
|
58
|
+
await lockMigrations(tx, modelName, async () => {
|
59
|
+
await tx.executeSql(initSql);
|
60
|
+
});
|
61
|
+
}
|
62
|
+
};
|
63
|
+
|
64
|
+
export const run = async (tx: Tx, model: ApiRootModel): Promise<void> => {
|
65
|
+
const { migrations } = model;
|
66
|
+
if (migrations == null || _.isEmpty(migrations)) {
|
67
|
+
return;
|
68
|
+
}
|
69
|
+
|
70
|
+
const modelName = model.apiRoot;
|
71
|
+
|
72
|
+
// migrations only run if the model has been executed before,
|
73
|
+
// to make changes that can't be automatically applied
|
74
|
+
const exists = await checkModelAlreadyExists(tx, modelName);
|
75
|
+
if (!exists) {
|
76
|
+
(sbvrUtils.api.migrations?.logger.info ?? console.info)(
|
77
|
+
'First time model has executed, skipping migrations',
|
78
|
+
);
|
79
|
+
|
80
|
+
return await setExecutedMigrations(tx, modelName, Object.keys(migrations));
|
81
|
+
}
|
82
|
+
await lockMigrations(tx, modelName, async () => {
|
83
|
+
const executedMigrations = await getExecutedMigrations(tx, modelName);
|
84
|
+
const pendingMigrations = filterAndSortPendingMigrations(
|
85
|
+
migrations,
|
86
|
+
executedMigrations,
|
87
|
+
);
|
88
|
+
if (pendingMigrations.length === 0) {
|
89
|
+
return;
|
90
|
+
}
|
91
|
+
|
92
|
+
const newlyExecutedMigrations = await executeMigrations(
|
93
|
+
tx,
|
94
|
+
pendingMigrations,
|
95
|
+
);
|
96
|
+
await setExecutedMigrations(tx, modelName, [
|
97
|
+
...executedMigrations,
|
98
|
+
...newlyExecutedMigrations,
|
99
|
+
]);
|
100
|
+
});
|
101
|
+
};
|
102
|
+
|
103
|
+
const checkModelAlreadyExists = async (
|
104
|
+
tx: Tx,
|
105
|
+
modelName: string,
|
106
|
+
): Promise<boolean> => {
|
107
|
+
const result = await tx.tableList("name = 'migration'");
|
108
|
+
if (result.rows.length === 0) {
|
109
|
+
return false;
|
110
|
+
}
|
111
|
+
const { rows } = await tx.executeSql(
|
112
|
+
binds`
|
113
|
+
SELECT 1
|
114
|
+
FROM "model"
|
115
|
+
WHERE "model"."is of-vocabulary" = ${1}
|
116
|
+
LIMIT 1`,
|
117
|
+
[modelName],
|
118
|
+
);
|
119
|
+
|
120
|
+
return rows.length > 0;
|
121
|
+
};
|
122
|
+
|
123
|
+
const getExecutedMigrations = async (
|
124
|
+
tx: Tx,
|
125
|
+
modelName: string,
|
126
|
+
): Promise<string[]> => {
|
127
|
+
const { rows } = await tx.executeSql(
|
128
|
+
binds`
|
129
|
+
SELECT "migration"."executed migrations" AS "executed_migrations"
|
130
|
+
FROM "migration"
|
131
|
+
WHERE "migration"."model name" = ${1}`,
|
132
|
+
[modelName],
|
133
|
+
);
|
134
|
+
|
135
|
+
const data = rows[0];
|
136
|
+
if (data == null) {
|
137
|
+
return [];
|
138
|
+
}
|
139
|
+
|
140
|
+
return JSON.parse(data.executed_migrations) as string[];
|
141
|
+
};
|
142
|
+
|
143
|
+
const setExecutedMigrations = async (
|
144
|
+
tx: Tx,
|
145
|
+
modelName: string,
|
146
|
+
executedMigrations: string[],
|
147
|
+
): Promise<void> => {
|
148
|
+
const stringifiedMigrations = JSON.stringify(executedMigrations);
|
149
|
+
|
150
|
+
const result = await tx.tableList("name = 'migration'");
|
151
|
+
if (result.rows.length === 0) {
|
152
|
+
return;
|
153
|
+
}
|
154
|
+
|
155
|
+
const { rowsAffected } = await tx.executeSql(
|
156
|
+
binds`
|
157
|
+
UPDATE "migration"
|
158
|
+
SET "model name" = ${1},
|
159
|
+
"executed migrations" = ${2}
|
160
|
+
WHERE "migration"."model name" = ${3}`,
|
161
|
+
[modelName, stringifiedMigrations, modelName],
|
162
|
+
);
|
163
|
+
|
164
|
+
if (rowsAffected === 0) {
|
165
|
+
await tx.executeSql(
|
166
|
+
binds`
|
167
|
+
INSERT INTO "migration" ("model name", "executed migrations")
|
168
|
+
VALUES (${1}, ${2})`,
|
169
|
+
[modelName, stringifiedMigrations],
|
170
|
+
);
|
171
|
+
}
|
172
|
+
};
|
173
|
+
|
174
|
+
// turns {"key1": migration, "key3": migration, "key2": migration}
|
175
|
+
// into [["key1", migration], ["key2", migration], ["key3", migration]]
|
176
|
+
const filterAndSortPendingMigrations = (
|
177
|
+
migrations: NonNullable<Model['migrations']>,
|
178
|
+
executedMigrations: string[],
|
179
|
+
): MigrationTuple[] =>
|
180
|
+
(_(migrations).omit(executedMigrations) as _.Object<typeof migrations>)
|
181
|
+
.toPairs()
|
182
|
+
.sortBy(([migrationKey]) => migrationKey)
|
183
|
+
.value();
|
184
|
+
|
185
|
+
const lockMigrations = async <T>(
|
186
|
+
tx: Tx,
|
187
|
+
modelName: string,
|
188
|
+
fn: () => Promise<T>,
|
189
|
+
): Promise<T> => {
|
190
|
+
try {
|
191
|
+
await tx.executeSql(
|
192
|
+
binds`
|
193
|
+
DELETE FROM "migration lock"
|
194
|
+
WHERE "model name" = ${1}
|
195
|
+
AND "created at" < ${2}`,
|
196
|
+
[modelName, new Date(Date.now() - migratorEnv.lockTimeout)],
|
197
|
+
);
|
198
|
+
await tx.executeSql(
|
199
|
+
binds`
|
200
|
+
INSERT INTO "migration lock" ("model name")
|
201
|
+
VALUES (${1})`,
|
202
|
+
[modelName],
|
203
|
+
);
|
204
|
+
} catch (err) {
|
205
|
+
await delay(migratorEnv.lockFailDelay);
|
206
|
+
throw err;
|
207
|
+
}
|
208
|
+
try {
|
209
|
+
return await fn();
|
210
|
+
} finally {
|
211
|
+
try {
|
212
|
+
await tx.executeSql(
|
213
|
+
binds`
|
214
|
+
DELETE FROM "migration lock"
|
215
|
+
WHERE "model name" = ${1}`,
|
216
|
+
[modelName],
|
217
|
+
);
|
218
|
+
} catch {
|
219
|
+
// We ignore errors here as it's mostly likely caused by the migration failing and
|
220
|
+
// rolling back the transaction, and if we rethrow here we'll overwrite the real error
|
221
|
+
// making it much harder for users to see what went wrong and fix it
|
222
|
+
}
|
223
|
+
}
|
224
|
+
};
|
225
|
+
|
226
|
+
const executeMigrations = async (
|
227
|
+
tx: Tx,
|
228
|
+
migrations: MigrationTuple[] = [],
|
229
|
+
): Promise<string[]> => {
|
230
|
+
try {
|
231
|
+
for (const migration of migrations) {
|
232
|
+
await executeMigration(tx, migration);
|
233
|
+
}
|
234
|
+
} catch (err) {
|
235
|
+
(sbvrUtils.api.migrations?.logger.error ?? console.error)(
|
236
|
+
'Error while executing migrations, rolled back',
|
237
|
+
);
|
238
|
+
throw new MigrationError(err);
|
239
|
+
}
|
240
|
+
return migrations.map(([migrationKey]) => migrationKey); // return migration keys
|
241
|
+
};
|
242
|
+
|
243
|
+
const executeMigration = async (
|
244
|
+
tx: Tx,
|
245
|
+
[key, migration]: MigrationTuple,
|
246
|
+
): Promise<void> => {
|
247
|
+
(sbvrUtils.api.migrations?.logger.info ?? console.info)(
|
248
|
+
`Running migration ${JSON.stringify(key)}`,
|
249
|
+
);
|
250
|
+
|
251
|
+
if (typeof migration === 'function') {
|
252
|
+
await migration(tx, sbvrUtils);
|
253
|
+
} else if (typeof migration === 'string') {
|
254
|
+
await tx.executeSql(migration);
|
255
|
+
} else {
|
256
|
+
throw new MigrationError(`Invalid migration type: ${typeof migration}`);
|
257
|
+
}
|
258
|
+
};
|
259
|
+
|
260
|
+
export const config: Config = {
|
261
|
+
models: [
|
262
|
+
{
|
263
|
+
modelName: 'migrations',
|
264
|
+
apiRoot: 'migrations',
|
265
|
+
modelText,
|
266
|
+
migrations: {
|
267
|
+
'11.0.0-modified-at': `
|
268
|
+
ALTER TABLE "migration"
|
269
|
+
ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
|
270
|
+
`,
|
271
|
+
'11.0.1-modified-at': `
|
272
|
+
ALTER TABLE "migration lock"
|
273
|
+
ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
|
274
|
+
`,
|
275
|
+
},
|
276
|
+
},
|
277
|
+
],
|
278
|
+
};
|
@@ -4,7 +4,6 @@ import type { AnyObject } from '../sbvr-api/common-types';
|
|
4
4
|
import { Store } from 'express-session';
|
5
5
|
import * as permissions from '../sbvr-api/permissions';
|
6
6
|
import { api } from '../sbvr-api/sbvr-utils';
|
7
|
-
import { defaultMigrationCategory } from '../migrator/utils';
|
8
7
|
|
9
8
|
export { Store };
|
10
9
|
|
@@ -170,12 +169,10 @@ export class PinejsSessionStore extends Store {
|
|
170
169
|
error: true,
|
171
170
|
},
|
172
171
|
migrations: {
|
173
|
-
|
174
|
-
'11.0.0-modified-at': `
|
172
|
+
'11.0.0-modified-at': `
|
175
173
|
ALTER TABLE "session"
|
176
174
|
ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
|
177
175
|
`,
|
178
|
-
},
|
179
176
|
},
|
180
177
|
},
|
181
178
|
],
|
@@ -50,7 +50,6 @@ import {
|
|
50
50
|
ODataRequest,
|
51
51
|
} from './uri-parser';
|
52
52
|
import memoizeWeak = require('memoizee/weak');
|
53
|
-
import { defaultMigrationCategory } from '../migrator/utils';
|
54
53
|
|
55
54
|
// tslint:disable-next-line:no-var-requires
|
56
55
|
const userModel: string = require('./user.sbvr');
|
@@ -1680,8 +1679,7 @@ export const config = {
|
|
1680
1679
|
modelText: userModel,
|
1681
1680
|
customServerCode: exports,
|
1682
1681
|
migrations: {
|
1683
|
-
|
1684
|
-
'11.0.0-modified-at': `
|
1682
|
+
'11.0.0-modified-at': `
|
1685
1683
|
ALTER TABLE "actor"
|
1686
1684
|
ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
|
1687
1685
|
|
@@ -1705,15 +1703,14 @@ export const config = {
|
|
1705
1703
|
ALTER TABLE "user-has-permission"
|
1706
1704
|
ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
|
1707
1705
|
`,
|
1708
|
-
|
1706
|
+
'11.0.1-modified-at': `
|
1709
1707
|
ALTER TABLE "role-has-permission"
|
1710
1708
|
ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
|
1711
1709
|
`,
|
1712
|
-
|
1710
|
+
'14.42.0-api-key-expiry-date': `
|
1713
1711
|
ALTER TABLE "api key"
|
1714
1712
|
ADD COLUMN IF NOT EXISTS "expiry date" TIMESTAMP NULL;
|
1715
1713
|
`,
|
1716
|
-
},
|
1717
1714
|
},
|
1718
1715
|
},
|
1719
1716
|
] as sbvrUtils.ExecutableModel[],
|
@@ -33,9 +33,7 @@ import { PinejsClientCore, PromiseResultTypes } from 'pinejs-client-core';
|
|
33
33
|
|
34
34
|
import { ExtendedSBVRParser } from '../extended-sbvr-parser/extended-sbvr-parser';
|
35
35
|
|
36
|
-
import
|
37
|
-
import * as asyncMigrator from '../migrator/async';
|
38
|
-
import * as syncMigrator from '../migrator/sync';
|
36
|
+
import * as migrator from '../migrator/migrator';
|
39
37
|
import { generateODataMetadata } from '../odata-metadata/odata-metadata-generator';
|
40
38
|
|
41
39
|
// tslint:disable-next-line:no-var-requires
|
@@ -432,20 +430,6 @@ export const generateModels = (
|
|
432
430
|
return { vocab, se, lf, abstractSql, sql, odataMetadata };
|
433
431
|
};
|
434
432
|
|
435
|
-
export const executeAsyncModelMigration = (
|
436
|
-
model: ExecutableModel,
|
437
|
-
): Promise<void> => executeAsyncModelMigrations([model]);
|
438
|
-
|
439
|
-
export const executeAsyncModelMigrations = async (
|
440
|
-
execModels: ExecutableModel[],
|
441
|
-
): Promise<void> => {
|
442
|
-
await Promise.all(
|
443
|
-
execModels.map(async (model) => {
|
444
|
-
await asyncMigrator.run(model);
|
445
|
-
}),
|
446
|
-
);
|
447
|
-
};
|
448
|
-
|
449
433
|
export const executeModel = (
|
450
434
|
tx: Db.Tx,
|
451
435
|
model: ExecutableModel,
|
@@ -460,7 +444,7 @@ export const executeModels = async (
|
|
460
444
|
execModels.map(async (model) => {
|
461
445
|
const { apiRoot } = model;
|
462
446
|
|
463
|
-
await
|
447
|
+
await migrator.run(tx, model);
|
464
448
|
const compiledModel = generateModels(model, db.engine);
|
465
449
|
|
466
450
|
// Create tables related to terms and fact types
|
@@ -477,7 +461,7 @@ export const executeModels = async (
|
|
477
461
|
}
|
478
462
|
await promise;
|
479
463
|
}
|
480
|
-
await
|
464
|
+
await migrator.postRun(tx, model);
|
481
465
|
|
482
466
|
odataResponse.prepareModel(compiledModel.abstractSql);
|
483
467
|
deepFreeze(compiledModel.abstractSql);
|
@@ -1638,12 +1622,10 @@ export const executeStandardModels = async (tx: Db.Tx): Promise<void> => {
|
|
1638
1622
|
log: false,
|
1639
1623
|
},
|
1640
1624
|
migrations: {
|
1641
|
-
|
1642
|
-
'11.0.0-modified-at': `
|
1625
|
+
'11.0.0-modified-at': `
|
1643
1626
|
ALTER TABLE "model"
|
1644
1627
|
ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
|
1645
1628
|
`,
|
1646
|
-
},
|
1647
1629
|
},
|
1648
1630
|
});
|
1649
1631
|
await executeModels(tx, permissions.config.models);
|
@@ -4,8 +4,7 @@ import './sbvr-loader';
|
|
4
4
|
|
5
5
|
import * as dbModule from '../database-layer/db';
|
6
6
|
import * as configLoader from '../config-loader/config-loader';
|
7
|
-
import * as migrator from '../migrator/
|
8
|
-
import * as migratorUtils from '../migrator/utils';
|
7
|
+
import * as migrator from '../migrator/migrator';
|
9
8
|
|
10
9
|
import * as sbvrUtils from '../sbvr-api/sbvr-utils';
|
11
10
|
|
@@ -18,7 +17,7 @@ export * as env from '../config-loader/env';
|
|
18
17
|
export * as types from '../sbvr-api/common-types';
|
19
18
|
export * as hooks from '../sbvr-api/hooks';
|
20
19
|
export type { configLoader as ConfigLoader };
|
21
|
-
export type {
|
20
|
+
export type { migrator as Migrator };
|
22
21
|
|
23
22
|
let envDatabaseOptions: dbModule.DatabaseOptions<string>;
|
24
23
|
if (dbModule.engines.websql != null) {
|
package/out/migrator/async.d.ts
DELETED
package/out/migrator/async.js
DELETED
@@ -1,154 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.run = void 0;
|
4
|
-
const _ = require("lodash");
|
5
|
-
const sbvrUtils = require("../sbvr-api/sbvr-utils");
|
6
|
-
const utils_1 = require("./utils");
|
7
|
-
const run = async (model) => {
|
8
|
-
const { migrations } = model;
|
9
|
-
if (migrations == null ||
|
10
|
-
_.isEmpty(migrations) ||
|
11
|
-
migrations[utils_1.migrationCategories.async] === undefined) {
|
12
|
-
return;
|
13
|
-
}
|
14
|
-
await $run(model, migrations[utils_1.migrationCategories.async]);
|
15
|
-
};
|
16
|
-
exports.run = run;
|
17
|
-
const $run = async (model, migrations) => {
|
18
|
-
var _a, _b, _c, _d;
|
19
|
-
const modelName = model.apiRoot;
|
20
|
-
let exists;
|
21
|
-
await sbvrUtils.db.transaction(async (tx) => {
|
22
|
-
var _a, _b;
|
23
|
-
exists = await (0, utils_1.checkModelAlreadyExists)(tx, modelName);
|
24
|
-
if (!exists) {
|
25
|
-
((_b = (_a = sbvrUtils.api.migrations) === null || _a === void 0 ? void 0 : _a.logger.info) !== null && _b !== void 0 ? _b : console.info)('First time model has executed, skipping migrations');
|
26
|
-
return await (0, utils_1.setExecutedMigrations)(tx, modelName, Object.keys(migrations));
|
27
|
-
}
|
28
|
-
});
|
29
|
-
if (!exists) {
|
30
|
-
return;
|
31
|
-
}
|
32
|
-
let pendingMigrations = [];
|
33
|
-
await sbvrUtils.db.transaction(async (tx) => {
|
34
|
-
const executedMigrations = await (0, utils_1.getExecutedMigrations)(tx, modelName);
|
35
|
-
pendingMigrations = filterAndSortPendingAsyncMigrations(migrations, executedMigrations);
|
36
|
-
});
|
37
|
-
for (const [key, migration] of pendingMigrations) {
|
38
|
-
const initMigrationState = {
|
39
|
-
migration_key: key,
|
40
|
-
start_time: new Date(Date.now()),
|
41
|
-
last_run_time: new Date(Date.now()),
|
42
|
-
run_counter: 0,
|
43
|
-
migrated_rows: 0,
|
44
|
-
error_counter: 0,
|
45
|
-
error_threshold: utils_1.migratorEnv.asyncMigrationDefaultErrorThreshold,
|
46
|
-
delayMS: utils_1.migratorEnv.asyncMigrationDefaultDelayMS,
|
47
|
-
backoffDelayMS: utils_1.migratorEnv.asyncMigrationDefaultBackoffDelayMS,
|
48
|
-
converged_time: undefined,
|
49
|
-
last_error_message: undefined,
|
50
|
-
is_backoff: false,
|
51
|
-
should_stop: false,
|
52
|
-
};
|
53
|
-
let asyncRunnerMigratorFn;
|
54
|
-
if (typeof migration === 'object') {
|
55
|
-
if (migration.fn && typeof migration.fn === 'function') {
|
56
|
-
asyncRunnerMigratorFn = async (tx) => (await migration.fn(tx, sbvrUtils))
|
57
|
-
.rowsAffected;
|
58
|
-
}
|
59
|
-
else if (migration.sql && typeof migration.sql === 'string') {
|
60
|
-
asyncRunnerMigratorFn = async (tx) => (await tx.executeSql(migration.sql)).rowsAffected;
|
61
|
-
}
|
62
|
-
else {
|
63
|
-
((_b = (_a = sbvrUtils.api.migrations) === null || _a === void 0 ? void 0 : _a.logger.error) !== null && _b !== void 0 ? _b : console.error)(`Invalid migration object: ${JSON.stringify(migration, null, 2)}`);
|
64
|
-
continue;
|
65
|
-
}
|
66
|
-
initMigrationState.backoffDelayMS =
|
67
|
-
migration.backoffDelayMS ||
|
68
|
-
utils_1.migratorEnv.asyncMigrationDefaultBackoffDelayMS;
|
69
|
-
initMigrationState.delayMS =
|
70
|
-
migration.delayMS || utils_1.migratorEnv.asyncMigrationDefaultDelayMS;
|
71
|
-
initMigrationState.error_threshold =
|
72
|
-
migration.errorThreshold ||
|
73
|
-
utils_1.migratorEnv.asyncMigrationDefaultErrorThreshold;
|
74
|
-
}
|
75
|
-
else if (typeof migration === 'string') {
|
76
|
-
asyncRunnerMigratorFn = async (tx) => (await tx.executeSql(migration)).rowsAffected;
|
77
|
-
}
|
78
|
-
else {
|
79
|
-
((_d = (_c = sbvrUtils.api.migrations) === null || _c === void 0 ? void 0 : _c.logger.error) !== null && _d !== void 0 ? _d : console.error)(`Invalid async migration object: ${JSON.stringify(migration, null, 2)}`);
|
80
|
-
continue;
|
81
|
-
}
|
82
|
-
await sbvrUtils.db.transaction(async (tx) => (0, utils_1.initMigrationStatus)(tx, initMigrationState));
|
83
|
-
const asyncRunner = async () => {
|
84
|
-
await sbvrUtils.db.transaction(async (tx) => {
|
85
|
-
await (0, utils_1.lockMigrations)(tx, modelName, async () => {
|
86
|
-
var _a, _b, _c, _d;
|
87
|
-
const migrationState = await (0, utils_1.readMigrationStatus)(tx, key);
|
88
|
-
if (!migrationState || migrationState.should_stop === true) {
|
89
|
-
((_b = (_a = sbvrUtils.api.migrations) === null || _a === void 0 ? void 0 : _a.logger.info) !== null && _b !== void 0 ? _b : console.info)(`stopping async migration: ${key}`);
|
90
|
-
clearInterval(asyncScheduler);
|
91
|
-
return;
|
92
|
-
}
|
93
|
-
try {
|
94
|
-
clearInterval(asyncScheduler);
|
95
|
-
if (migrationState.last_run_time) {
|
96
|
-
const durationSinceLastRun = Date.now().valueOf() - migrationState.last_run_time.valueOf();
|
97
|
-
if ((migrationState.is_backoff &&
|
98
|
-
durationSinceLastRun < migrationState.backoffDelayMS) ||
|
99
|
-
(!migrationState.is_backoff &&
|
100
|
-
durationSinceLastRun < migrationState.delayMS)) {
|
101
|
-
return;
|
102
|
-
}
|
103
|
-
}
|
104
|
-
migrationState.last_run_time = new Date(Date.now());
|
105
|
-
migrationState.run_counter += 1;
|
106
|
-
let migratedRows = 0;
|
107
|
-
await sbvrUtils.db.transaction(async (migrationTx) => {
|
108
|
-
migratedRows = (await (asyncRunnerMigratorFn === null || asyncRunnerMigratorFn === void 0 ? void 0 : asyncRunnerMigratorFn(migrationTx))) || 0;
|
109
|
-
});
|
110
|
-
migrationState.migrated_rows += migratedRows;
|
111
|
-
if (migratedRows === 0) {
|
112
|
-
migrationState.is_backoff = true;
|
113
|
-
if (!migrationState.converged_time) {
|
114
|
-
migrationState.converged_time = new Date(Date.now());
|
115
|
-
}
|
116
|
-
}
|
117
|
-
else {
|
118
|
-
migrationState.is_backoff = false;
|
119
|
-
}
|
120
|
-
}
|
121
|
-
catch (err) {
|
122
|
-
migrationState.error_counter++;
|
123
|
-
if (migrationState.error_counter % migrationState.error_threshold ===
|
124
|
-
0) {
|
125
|
-
migrationState.last_error_message = `${err.name} ${err.message}`;
|
126
|
-
((_d = (_c = sbvrUtils.api.migrations) === null || _c === void 0 ? void 0 : _c.logger.error) !== null && _d !== void 0 ? _d : console.error)(`${key}: ${err.name} ${err.message}`);
|
127
|
-
migrationState.is_backoff = true;
|
128
|
-
}
|
129
|
-
}
|
130
|
-
finally {
|
131
|
-
if (migrationState.is_backoff) {
|
132
|
-
asyncScheduler = setInterval(asyncRunner, migrationState.backoffDelayMS);
|
133
|
-
}
|
134
|
-
else {
|
135
|
-
asyncScheduler = setInterval(asyncRunner, migrationState.delayMS);
|
136
|
-
}
|
137
|
-
await (0, utils_1.updateMigrationStatus)(tx, migrationState);
|
138
|
-
}
|
139
|
-
});
|
140
|
-
});
|
141
|
-
};
|
142
|
-
let asyncScheduler = setInterval(asyncRunner, initMigrationState.delayMS);
|
143
|
-
}
|
144
|
-
};
|
145
|
-
const filterAndSortPendingAsyncMigrations = (migrations, executedMigrations) => {
|
146
|
-
var _a;
|
147
|
-
const latestExecutedMigration = (_a = executedMigrations.sort().pop()) !== null && _a !== void 0 ? _a : '';
|
148
|
-
return _(migrations).omit(executedMigrations)
|
149
|
-
.toPairs()
|
150
|
-
.filter(([migrationKey]) => migrationKey > latestExecutedMigration)
|
151
|
-
.sortBy(([migrationKey]) => migrationKey)
|
152
|
-
.value();
|
153
|
-
};
|
154
|
-
//# sourceMappingURL=async.js.map
|
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"async.js","sourceRoot":"","sources":["../../src/migrator/async.ts"],"names":[],"mappings":";;;AAGA,4BAA4B;AAC5B,oDAAoD;AAIpD,mCAaiB;AAEV,MAAM,GAAG,GAAG,KAAK,EAAE,KAAmB,EAAiB,EAAE;IAC/D,MAAM,EAAE,UAAU,EAAE,GAAG,KAAK,CAAC;IAC7B,IACC,UAAU,IAAI,IAAI;QAClB,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;QACrB,UAAU,CAAC,2BAAmB,CAAC,KAAK,CAAC,KAAK,SAAS,EAClD;QACD,OAAO;KACP;IACD,MAAM,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,2BAAmB,CAAC,KAAK,CAAC,CAAC,CAAC;AAC1D,CAAC,CAAC;AAVW,QAAA,GAAG,OAUd;AAEF,MAAM,IAAI,GAAG,KAAK,EACjB,KAAmB,EACnB,UAAsB,EACN,EAAE;;IAClB,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC;IAGhC,IAAI,MAAM,CAAC;IACX,MAAM,SAAS,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;;QAC3C,MAAM,GAAG,MAAM,IAAA,+BAAuB,EAAC,EAAE,EAAE,SAAS,CAAC,CAAC;QACtD,IAAI,CAAC,MAAM,EAAE;YACZ,CAAC,MAAA,MAAA,SAAS,CAAC,GAAG,CAAC,UAAU,0CAAE,MAAM,CAAC,IAAI,mCAAI,OAAO,CAAC,IAAI,CAAC,CACtD,oDAAoD,CACpD,CAAC;YAEF,OAAO,MAAM,IAAA,6BAAqB,EACjC,EAAE,EACF,SAAS,EACT,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CACvB,CAAC;SACF;IACF,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,EAAE;QACZ,OAAO;KACP;IAyCD,IAAI,iBAAiB,GAAqB,EAAE,CAAC;IAC7C,MAAM,SAAS,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;QAC3C,MAAM,kBAAkB,GAAG,MAAM,IAAA,6BAAqB,EAAC,EAAE,EAAE,SAAS,CAAC,CAAC;QACtE,iBAAiB,GAAG,mCAAmC,CACtD,UAAU,EACV,kBAAkB,CAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAKH,KAAK,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,IAAI,iBAAiB,EAAE;QACjD,MAAM,kBAAkB,GAAG;YAC1B,aAAa,EAAE,GAAG;YAClB,UAAU,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YAChC,aAAa,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACnC,WAAW,EAAE,CAAC;YACd,aAAa,EAAE,CAAC;YAChB,aAAa,EAAE,CAAC;YAChB,eAAe,EAAE,mBAAW,CAAC,mCAAmC;YAChE,OAAO,EAAE,mBAAW,CAAC,4BAA4B;YACjD,cAAc,EAAE,mBAAW,CAAC,mCAAmC;YAC/D,cAAc,EAAE,SAAS;YACzB,kBAAkB,EAAE,SAAS;YAC7B,UAAU,EAAE,KAAK;YACjB,WAAW,EAAE,KAAK;SAClB,CAAC;QAEF,IAAI,qBAAgE,CAAC;QAErE,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE;YAClC,IAAI,SAAS,CAAC,EAAE,IAAI,OAAO,SAAS,CAAC,EAAE,KAAK,UAAU,EAAE;gBACvD,qBAAqB,GAAG,KAAK,EAAE,EAAM,EAAE,EAAE,CACxC,CAAC,MAAO,SAAS,CAAC,EAAuB,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;qBACvD,YAAY,CAAC;aAChB;iBAAM,IAAI,SAAS,CAAC,GAAG,IAAI,OAAO,SAAS,CAAC,GAAG,KAAK,QAAQ,EAAE;gBAC9D,qBAAqB,GAAG,KAAK,EAAE,EAAM,EAAE,EAAE,CACxC,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,GAAa,CAAC,CAAC,CAAC,YAAY,CAAC;aAC7D;iBAAM;gBAEN,CAAC,MAAA,MAAA,SAAS,CAAC,GAAG,CAAC,UAAU,0CAAE,MAAM,CAAC,KAAK,mCAAI,OAAO,CAAC,KAAK,CAAC,CACxD,6BAA6B,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CACjE,CAAC;gBACF,SAAS;aACT;YAED,kBAAkB,CAAC,cAAc;gBAChC,SAAS,CAAC,cAAc;oBACxB,mBAAW,CAAC,mCAAmC,CAAC;YACjD,kBAAkB,CAAC,OAAO;gBACzB,SAAS,CAAC,OAAO,IAAI,mBAAW,CAAC,4BAA4B,CAAC;YAC/D,kBAAkB,CAAC,eAAe;gBACjC,SAAS,CAAC,cAAc;oBACxB,mBAAW,CAAC,mCAAmC,CAAC;SACjD;aAAM,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE;YACzC,qBAAqB,GAAG,KAAK,EAAE,EAAM,EAAE,EAAE,CACxC,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC;SAC/C;aAAM;YACN,CAAC,MAAA,MAAA,SAAS,CAAC,GAAG,CAAC,UAAU,0CAAE,MAAM,CAAC,KAAK,mCAAI,OAAO,CAAC,KAAK,CAAC,CACxD,mCAAmC,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CACvE,CAAC;YACF,SAAS;SACT;QAED,MAAM,SAAS,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,CAC3C,IAAA,2BAAmB,EAAC,EAAE,EAAE,kBAAkB,CAAC,CAC3C,CAAC;QAEF,MAAM,WAAW,GAAG,KAAK,IAAI,EAAE;YAC9B,MAAM,SAAS,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;gBAC3C,MAAM,IAAA,sBAAc,EAAC,EAAE,EAAE,SAAS,EAAE,KAAK,IAAI,EAAE;;oBAC9C,MAAM,cAAc,GAAG,MAAM,IAAA,2BAAmB,EAAC,EAAE,EAAE,GAAG,CAAC,CAAC;oBAE1D,IAAI,CAAC,cAAc,IAAI,cAAc,CAAC,WAAW,KAAK,IAAI,EAAE;wBAG3D,CAAC,MAAA,MAAA,SAAS,CAAC,GAAG,CAAC,UAAU,0CAAE,MAAM,CAAC,IAAI,mCAAI,OAAO,CAAC,IAAI,CAAC,CACtD,6BAA6B,GAAG,EAAE,CAClC,CAAC;wBACF,aAAa,CAAC,cAAc,CAAC,CAAC;wBAC9B,OAAO;qBACP;oBACD,IAAI;wBAEH,aAAa,CAAC,cAAc,CAAC,CAAC;wBAK9B,IAAI,cAAc,CAAC,aAAa,EAAE;4BACjC,MAAM,oBAAoB,GACzB,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,GAAG,cAAc,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC;4BAC/D,IACC,CAAC,cAAc,CAAC,UAAU;gCACzB,oBAAoB,GAAG,cAAc,CAAC,cAAc,CAAC;gCACtD,CAAC,CAAC,cAAc,CAAC,UAAU;oCAC1B,oBAAoB,GAAG,cAAc,CAAC,OAAO,CAAC,EAC9C;gCAED,OAAO;6BACP;yBACD;wBAGD,cAAc,CAAC,aAAa,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;wBACpD,cAAc,CAAC,WAAW,IAAI,CAAC,CAAC;wBAEhC,IAAI,YAAY,GAAG,CAAC,CAAC;wBACrB,MAAM,SAAS,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE;4BACpD,YAAY,GAAG,CAAC,MAAM,CAAA,qBAAqB,aAArB,qBAAqB,uBAArB,qBAAqB,CAAG,WAAW,CAAC,CAAA,CAAC,IAAI,CAAC,CAAC;wBAClE,CAAC,CAAC,CAAC;wBAEH,cAAc,CAAC,aAAa,IAAI,YAAY,CAAC;wBAC7C,IAAI,YAAY,KAAK,CAAC,EAAE;4BAEvB,cAAc,CAAC,UAAU,GAAG,IAAI,CAAC;4BACjC,IAAI,CAAC,cAAc,CAAC,cAAc,EAAE;gCAEnC,cAAc,CAAC,cAAc,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;6BACrD;yBACD;6BAAM;4BAGN,cAAc,CAAC,UAAU,GAAG,KAAK,CAAC;yBAClC;qBACD;oBAAC,OAAO,GAAG,EAAE;wBACb,cAAc,CAAC,aAAa,EAAE,CAAC;wBAE/B,IACC,cAAc,CAAC,aAAa,GAAG,cAAc,CAAC,eAAe;4BAC7D,CAAC,EACA;4BACD,cAAc,CAAC,kBAAkB,GAAG,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;4BACjE,CAAC,MAAA,MAAA,SAAS,CAAC,GAAG,CAAC,UAAU,0CAAE,MAAM,CAAC,KAAK,mCAAI,OAAO,CAAC,KAAK,CAAC,CACxD,GAAG,GAAG,KAAK,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,OAAO,EAAE,CACpC,CAAC;4BACF,cAAc,CAAC,UAAU,GAAG,IAAI,CAAC;yBACjC;qBACD;4BAAS;wBACT,IAAI,cAAc,CAAC,UAAU,EAAE;4BAC9B,cAAc,GAAG,WAAW,CAC3B,WAAW,EACX,cAAc,CAAC,cAAc,CAC7B,CAAC;yBACF;6BAAM;4BACN,cAAc,GAAG,WAAW,CAAC,WAAW,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;yBAClE;wBAGD,MAAM,IAAA,6BAAqB,EAAC,EAAE,EAAE,cAAc,CAAC,CAAC;qBAChD;gBACF,CAAC,CAAC,CAAC;YACJ,CAAC,CAAC,CAAC;QACJ,CAAC,CAAC;QACF,IAAI,cAAc,GAAG,WAAW,CAAC,WAAW,EAAE,kBAAkB,CAAC,OAAO,CAAC,CAAC;KAC1E;AACF,CAAC,CAAC;AAEF,MAAM,mCAAmC,GAAG,CAC3C,UAAmC,EACnC,kBAA4B,EACT,EAAE;;IAErB,MAAM,uBAAuB,GAAG,MAAA,kBAAkB,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,mCAAI,EAAE,CAAC;IAEtE,OAAQ,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAiC;SAC5E,OAAO,EAAE;SACT,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC,YAAY,GAAG,uBAAuB,CAAC;SAClE,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC;SACxC,KAAK,EAAE,CAAC;AACX,CAAC,CAAC"}
|
package/out/migrator/sync.d.ts
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
import type { Tx } from '../database-layer/db';
|
2
|
-
import type { Config, Model } from '../config-loader/config-loader';
|
3
|
-
declare type ApiRootModel = Model & {
|
4
|
-
apiRoot: string;
|
5
|
-
};
|
6
|
-
export declare const postRun: (tx: Tx, model: ApiRootModel) => Promise<void>;
|
7
|
-
export declare const run: (tx: Tx, model: ApiRootModel) => Promise<void>;
|
8
|
-
export declare const config: Config;
|
9
|
-
export {};
|