@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.
Files changed (52) hide show
  1. package/.versionbot/CHANGELOG.yml +126 -31
  2. package/CHANGELOG.md +63 -5
  3. package/VERSION +1 -1
  4. package/docs/Migrations.md +1 -101
  5. package/out/bin/utils.d.ts +2 -2
  6. package/out/config-loader/config-loader.d.ts +2 -2
  7. package/out/config-loader/config-loader.js +20 -29
  8. package/out/config-loader/config-loader.js.map +1 -1
  9. package/out/config-loader/env.d.ts +0 -3
  10. package/out/config-loader/env.js +0 -3
  11. package/out/config-loader/env.js.map +1 -1
  12. package/out/data-server/sbvr-server.d.ts +1 -3
  13. package/out/data-server/sbvr-server.js +1 -4
  14. package/out/data-server/sbvr-server.js.map +1 -1
  15. package/out/migrator/migrations.sbvr +0 -66
  16. package/out/migrator/migrator.d.ts +17 -0
  17. package/out/migrator/migrator.js +185 -0
  18. package/out/migrator/migrator.js.map +1 -0
  19. package/out/pinejs-session-store/pinejs-session-store.js +1 -4
  20. package/out/pinejs-session-store/pinejs-session-store.js.map +1 -1
  21. package/out/sbvr-api/abstract-sql.d.ts +1 -1
  22. package/out/sbvr-api/permissions.d.ts +5 -5
  23. package/out/sbvr-api/permissions.js +3 -6
  24. package/out/sbvr-api/permissions.js.map +1 -1
  25. package/out/sbvr-api/sbvr-utils.d.ts +4 -6
  26. package/out/sbvr-api/sbvr-utils.js +5 -17
  27. package/out/sbvr-api/sbvr-utils.js.map +1 -1
  28. package/out/server-glue/module.d.ts +3 -3
  29. package/out/server-glue/module.js +1 -2
  30. package/out/server-glue/module.js.map +1 -1
  31. package/package.json +7 -7
  32. package/src/config-loader/config-loader.ts +27 -62
  33. package/src/config-loader/env.ts +0 -3
  34. package/src/data-server/sbvr-server.js +1 -4
  35. package/src/migrator/migrations.sbvr +0 -66
  36. package/src/migrator/migrator.ts +278 -0
  37. package/src/pinejs-session-store/pinejs-session-store.ts +1 -4
  38. package/src/sbvr-api/permissions.ts +3 -6
  39. package/src/sbvr-api/sbvr-utils.ts +4 -22
  40. package/src/server-glue/module.ts +2 -3
  41. package/out/migrator/async.d.ts +0 -6
  42. package/out/migrator/async.js +0 -154
  43. package/out/migrator/async.js.map +0 -1
  44. package/out/migrator/sync.d.ts +0 -9
  45. package/out/migrator/sync.js +0 -117
  46. package/out/migrator/sync.js.map +0 -1
  47. package/out/migrator/utils.d.ts +0 -51
  48. package/out/migrator/utils.js +0 -187
  49. package/out/migrator/utils.js.map +0 -1
  50. package/src/migrator/async.ts +0 -273
  51. package/src/migrator/sync.ts +0 -167
  52. package/src/migrator/utils.ts +0 -293
@@ -1,117 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.config = exports.run = exports.postRun = void 0;
4
- const utils_1 = require("./utils");
5
- const _ = require("lodash");
6
- const sbvrUtils = require("../sbvr-api/sbvr-utils");
7
- const postRun = async (tx, model) => {
8
- var _a, _b;
9
- const { initSql } = model;
10
- if (initSql == null) {
11
- return;
12
- }
13
- const modelName = model.apiRoot;
14
- const exists = await (0, utils_1.checkModelAlreadyExists)(tx, modelName);
15
- if (!exists) {
16
- ((_b = (_a = sbvrUtils.api.migrations) === null || _a === void 0 ? void 0 : _a.logger.info) !== null && _b !== void 0 ? _b : console.info)('First time executing, running init script');
17
- await (0, utils_1.lockMigrations)(tx, modelName, async () => {
18
- var _a, _b;
19
- try {
20
- await tx.executeSql(initSql);
21
- }
22
- catch (err) {
23
- ((_b = (_a = sbvrUtils.api.migrations) === null || _a === void 0 ? void 0 : _a.logger.error) !== null && _b !== void 0 ? _b : console.error)(`postRun locked sql execution error ${err} `);
24
- }
25
- });
26
- }
27
- };
28
- exports.postRun = postRun;
29
- const run = async (tx, model) => {
30
- const { migrations } = model;
31
- if (migrations == null ||
32
- _.isEmpty(migrations) ||
33
- migrations[utils_1.defaultMigrationCategory] === undefined) {
34
- return;
35
- }
36
- return $run(tx, model, migrations[utils_1.defaultMigrationCategory]);
37
- };
38
- exports.run = run;
39
- const $run = async (tx, model, migrations) => {
40
- var _a, _b;
41
- const modelName = model.apiRoot;
42
- const exists = await (0, utils_1.checkModelAlreadyExists)(tx, modelName);
43
- if (!exists) {
44
- ((_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');
45
- return await (0, utils_1.setExecutedMigrations)(tx, modelName, Object.keys(migrations));
46
- }
47
- await (0, utils_1.lockMigrations)(tx, modelName, async () => {
48
- var _a, _b;
49
- try {
50
- const executedMigrations = await (0, utils_1.getExecutedMigrations)(tx, modelName);
51
- const pendingMigrations = filterAndSortPendingMigrations(migrations, executedMigrations);
52
- if (pendingMigrations.length === 0) {
53
- return;
54
- }
55
- const newlyExecutedMigrations = await executeMigrations(tx, pendingMigrations);
56
- await (0, utils_1.setExecutedMigrations)(tx, modelName, [
57
- ...executedMigrations,
58
- ...newlyExecutedMigrations,
59
- ]);
60
- }
61
- catch (err) {
62
- ((_b = (_a = sbvrUtils.api.migrations) === null || _a === void 0 ? void 0 : _a.logger.error) !== null && _b !== void 0 ? _b : console.error)(`$run executedMigrations error ${err}`);
63
- }
64
- });
65
- };
66
- const filterAndSortPendingMigrations = (migrations, executedMigrations) => _(migrations).omit(executedMigrations)
67
- .toPairs()
68
- .sortBy(([migrationKey]) => migrationKey)
69
- .value();
70
- const executeMigrations = async (tx, migrations = []) => {
71
- var _a, _b;
72
- try {
73
- for (const migration of migrations) {
74
- await executeMigration(tx, migration);
75
- }
76
- }
77
- catch (err) {
78
- ((_b = (_a = sbvrUtils.api.migrations) === null || _a === void 0 ? void 0 : _a.logger.error) !== null && _b !== void 0 ? _b : console.error)('Error while executing migrations, rolled back');
79
- throw new utils_1.MigrationError(err);
80
- }
81
- return migrations.map(([migrationKey]) => migrationKey);
82
- };
83
- const executeMigration = async (tx, [key, migration]) => {
84
- var _a, _b;
85
- ((_b = (_a = sbvrUtils.api.migrations) === null || _a === void 0 ? void 0 : _a.logger.info) !== null && _b !== void 0 ? _b : console.info)(`Running migration ${JSON.stringify(key)}`);
86
- if (typeof migration === 'function') {
87
- await migration(tx, sbvrUtils);
88
- }
89
- else if (typeof migration === 'string') {
90
- await tx.executeSql(migration);
91
- }
92
- else {
93
- throw new utils_1.MigrationError(`Invalid migration type: ${typeof migration}`);
94
- }
95
- };
96
- exports.config = {
97
- models: [
98
- {
99
- modelName: 'migrations',
100
- apiRoot: 'migrations',
101
- modelText: utils_1.modelText,
102
- migrations: {
103
- [utils_1.defaultMigrationCategory]: {
104
- '11.0.0-modified-at': `
105
- ALTER TABLE "migration"
106
- ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
107
- `,
108
- '11.0.1-modified-at': `
109
- ALTER TABLE "migration lock"
110
- ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
111
- `,
112
- },
113
- },
114
- },
115
- ],
116
- };
117
- //# sourceMappingURL=sync.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/migrator/sync.ts"],"names":[],"mappings":"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"}
@@ -1,51 +0,0 @@
1
- import type { Result, Tx } from '../database-layer/db';
2
- import type { Resolvable } from '../sbvr-api/common-types';
3
- import { TypedError } from 'typed-error';
4
- export { migrator as migratorEnv } from '../config-loader/env';
5
- export declare const modelText: any;
6
- import * as sbvrUtils from '../sbvr-api/sbvr-utils';
7
- export declare const defaultMigrationCategory = "sync";
8
- export declare enum migrationCategories {
9
- 'sync' = "sync",
10
- 'async' = "async"
11
- }
12
- declare type SbvrUtils = typeof sbvrUtils;
13
- export declare type MigrationTuple = [string, Migration];
14
- export declare type MigrationFn = (tx: Tx, sbvrUtils: SbvrUtils) => Resolvable<void>;
15
- export declare type AsyncMigrationFn = (tx: Tx, sbvrUtils: SbvrUtils) => Resolvable<Result>;
16
- export declare type AsyncMigration = {
17
- fn?: AsyncMigrationFn | undefined;
18
- sql?: string | undefined;
19
- delayMS?: number | undefined;
20
- backoffDelayMS?: number | undefined;
21
- errorThreshold?: number | undefined;
22
- };
23
- export declare type Migration = string | MigrationFn | AsyncMigration;
24
- export declare type Migrations = {
25
- [key: string]: Migration;
26
- };
27
- export declare class MigrationError extends TypedError {
28
- }
29
- export declare type MigrationStatus = {
30
- migration_key: string;
31
- start_time: Date;
32
- last_run_time: Date;
33
- run_counter: number;
34
- migrated_rows: number;
35
- error_counter: number;
36
- error_threshold: number;
37
- delayMS: number;
38
- backoffDelayMS: number;
39
- converged_time: Date | undefined;
40
- last_error_message: string | undefined;
41
- is_backoff: boolean;
42
- should_stop: boolean;
43
- };
44
- export declare const binds: (strings: TemplateStringsArray, ...bindNums: number[]) => string;
45
- export declare const lockMigrations: <T>(tx: Tx, modelName: string, fn: () => Promise<T>) => Promise<T>;
46
- export declare const checkModelAlreadyExists: (tx: Tx, modelName: string) => Promise<boolean>;
47
- export declare const setExecutedMigrations: (tx: Tx, modelName: string, executedMigrations: string[]) => Promise<void>;
48
- export declare const getExecutedMigrations: (tx: Tx, modelName: string) => Promise<string[]>;
49
- export declare const initMigrationStatus: (tx: Tx, migrationStatus: MigrationStatus) => Promise<Result | undefined>;
50
- export declare const updateMigrationStatus: (tx: Tx, migrationStatus: MigrationStatus) => Promise<Result | undefined>;
51
- export declare const readMigrationStatus: (tx: Tx, migrationKey: string) => Promise<MigrationStatus | undefined>;
@@ -1,187 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.readMigrationStatus = exports.updateMigrationStatus = exports.initMigrationStatus = exports.getExecutedMigrations = exports.setExecutedMigrations = exports.checkModelAlreadyExists = exports.lockMigrations = exports.binds = exports.MigrationError = exports.migrationCategories = exports.defaultMigrationCategory = exports.modelText = exports.migratorEnv = void 0;
4
- const typed_error_1 = require("typed-error");
5
- const env_1 = require("../config-loader/env");
6
- var env_2 = require("../config-loader/env");
7
- Object.defineProperty(exports, "migratorEnv", { enumerable: true, get: function () { return env_2.migrator; } });
8
- const control_flow_1 = require("../sbvr-api/control-flow");
9
- exports.modelText = require('./migrations.sbvr');
10
- const sbvrUtils = require("../sbvr-api/sbvr-utils");
11
- exports.defaultMigrationCategory = 'sync';
12
- var migrationCategories;
13
- (function (migrationCategories) {
14
- migrationCategories["sync"] = "sync";
15
- migrationCategories["async"] = "async";
16
- })(migrationCategories = exports.migrationCategories || (exports.migrationCategories = {}));
17
- class MigrationError extends typed_error_1.TypedError {
18
- }
19
- exports.MigrationError = MigrationError;
20
- const binds = (strings, ...bindNums) => strings
21
- .map((str, i) => {
22
- if (i === bindNums.length) {
23
- return str;
24
- }
25
- if (i + 1 !== bindNums[i]) {
26
- throw new SyntaxError('Migration sql binds must be sequential');
27
- }
28
- if (sbvrUtils.db.engine === "postgres") {
29
- return str + `$${bindNums[i]}`;
30
- }
31
- return str + `?`;
32
- })
33
- .join('');
34
- exports.binds = binds;
35
- const lockMigrations = async (tx, modelName, fn) => {
36
- try {
37
- await tx.executeSql((0, exports.binds) `
38
- DELETE FROM "migration lock"
39
- WHERE "model name" = ${1}
40
- AND "created at" < ${2}`, [modelName, new Date(Date.now() - env_1.migrator.lockTimeout)]);
41
- await tx.executeSql((0, exports.binds) `
42
- INSERT INTO "migration lock" ("model name")
43
- VALUES (${1})`, [modelName]);
44
- }
45
- catch (err) {
46
- await (0, control_flow_1.delay)(env_1.migrator.lockFailDelay);
47
- throw err;
48
- }
49
- try {
50
- return await fn();
51
- }
52
- finally {
53
- try {
54
- await tx.executeSql((0, exports.binds) `
55
- DELETE FROM "migration lock"
56
- WHERE "model name" = ${1}`, [modelName]);
57
- }
58
- catch (_a) {
59
- }
60
- }
61
- };
62
- exports.lockMigrations = lockMigrations;
63
- const checkModelAlreadyExists = async (tx, modelName) => {
64
- const result = await tx.tableList("name = 'migration'");
65
- if (result.rows.length === 0) {
66
- return false;
67
- }
68
- const { rows } = await tx.executeSql((0, exports.binds) `
69
- SELECT 1
70
- FROM "model"
71
- WHERE "model"."is of-vocabulary" = ${1}
72
- LIMIT 1`, [modelName]);
73
- return rows.length > 0;
74
- };
75
- exports.checkModelAlreadyExists = checkModelAlreadyExists;
76
- const setExecutedMigrations = async (tx, modelName, executedMigrations) => {
77
- const stringifiedMigrations = JSON.stringify(executedMigrations);
78
- const result = await tx.tableList("name = 'migration'");
79
- if (result.rows.length === 0) {
80
- return;
81
- }
82
- const { rowsAffected } = await tx.executeSql((0, exports.binds) `
83
- UPDATE "migration"
84
- SET "model name" = ${1},
85
- "executed migrations" = ${2}
86
- WHERE "migration"."model name" = ${3}`, [modelName, stringifiedMigrations, modelName]);
87
- if (rowsAffected === 0) {
88
- await tx.executeSql((0, exports.binds) `
89
- INSERT INTO "migration" ("model name", "executed migrations")
90
- VALUES (${1}, ${2})`, [modelName, stringifiedMigrations]);
91
- }
92
- };
93
- exports.setExecutedMigrations = setExecutedMigrations;
94
- const getExecutedMigrations = async (tx, modelName) => {
95
- const { rows } = await tx.executeSql((0, exports.binds) `
96
- SELECT "migration"."executed migrations" AS "executed_migrations"
97
- FROM "migration"
98
- WHERE "migration"."model name" = ${1}`, [modelName]);
99
- const data = rows[0];
100
- if (data == null) {
101
- return [];
102
- }
103
- return JSON.parse(data.executed_migrations);
104
- };
105
- exports.getExecutedMigrations = getExecutedMigrations;
106
- const initMigrationStatus = async (tx, migrationStatus) => {
107
- try {
108
- const result = await tx.executeSql((0, exports.binds) `
109
- INSERT INTO "migration status" ("migration key", "start time", "delayMS", "backoffDelayMS", "is backoff", "error threshold", "should stop")
110
- VALUES (${1}, ${2}, ${3}, ${4}, ${5}, ${6}, ${7});
111
- `, [
112
- migrationStatus['migration_key'],
113
- migrationStatus['start_time'],
114
- migrationStatus['delayMS'],
115
- migrationStatus['backoffDelayMS'],
116
- migrationStatus['is_backoff'] === true ? 1 : 0,
117
- migrationStatus['error_threshold'],
118
- migrationStatus['should_stop'] === true ? 1 : 0,
119
- ]);
120
- return result;
121
- }
122
- catch (err) {
123
- }
124
- };
125
- exports.initMigrationStatus = initMigrationStatus;
126
- const updateMigrationStatus = async (tx, migrationStatus) => {
127
- try {
128
- return await tx.executeSql((0, exports.binds) `
129
- UPDATE "migration status"
130
- SET
131
- "run counter" = ${1},
132
- "last run time" = ${2},
133
- "migrated rows" = ${3},
134
- "error counter" = ${4},
135
- "converged time" = ${5},
136
- "last error message" = ${6},
137
- "is backoff" = ${7},
138
- "should stop" = ${8}
139
- WHERE "migration status"."migration key" = ${9};`, [
140
- migrationStatus['run_counter'],
141
- migrationStatus['last_run_time'],
142
- migrationStatus['migrated_rows'],
143
- migrationStatus['error_counter'],
144
- migrationStatus['converged_time'],
145
- migrationStatus['last_error_message'],
146
- migrationStatus['is_backoff'] === true ? 1 : 0,
147
- migrationStatus['should_stop'] === true ? 1 : 0,
148
- migrationStatus['migration_key'],
149
- ]);
150
- }
151
- catch (err) {
152
- }
153
- };
154
- exports.updateMigrationStatus = updateMigrationStatus;
155
- const readMigrationStatus = async (tx, migrationKey) => {
156
- try {
157
- const { rows } = await tx.executeSql((0, exports.binds) `
158
- SELECT *
159
- FROM "migration status"
160
- WHERE "migration status"."migration key" = ${1}
161
- LIMIT 1;`, [migrationKey]);
162
- const data = rows[0];
163
- if (data == null) {
164
- return undefined;
165
- }
166
- return {
167
- migration_key: data['migration key'],
168
- start_time: data['start time'],
169
- last_run_time: data['last run time'],
170
- run_counter: data['run counter'],
171
- migrated_rows: data['migrated rows'],
172
- error_counter: data['error counter'],
173
- error_threshold: data['error threshold'],
174
- delayMS: data['delayMS'],
175
- backoffDelayMS: data['backoffDelayMS'],
176
- converged_time: data['converged_time'],
177
- last_error_message: data['last error message'],
178
- is_backoff: data['is backoff'] === 1 ? true : false,
179
- should_stop: data['should stop'] === 1 ? true : false,
180
- };
181
- }
182
- catch (err) {
183
- return undefined;
184
- }
185
- };
186
- exports.readMigrationStatus = readMigrationStatus;
187
- //# sourceMappingURL=utils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/migrator/utils.ts"],"names":[],"mappings":";;;AAKA,6CAAyC;AACzC,8CAA+D;AAC/D,4CAA+D;AAAtD,kGAAA,QAAQ,OAAe;AAChC,2DAAiD;AAGpC,QAAA,SAAS,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;AAEtD,oDAAoD;AAEvC,QAAA,wBAAwB,GAAG,MAAM,CAAC;AAC/C,IAAY,mBAGX;AAHD,WAAY,mBAAmB;IAC9B,oCAAe,CAAA;IACf,sCAAiB,CAAA;AAClB,CAAC,EAHW,mBAAmB,GAAnB,2BAAmB,KAAnB,2BAAmB,QAG9B;AAwBD,MAAa,cAAe,SAAQ,wBAAU;CAAG;AAAjD,wCAAiD;AAoB1C,MAAM,KAAK,GAAG,CAAC,OAA6B,EAAE,GAAG,QAAkB,EAAE,EAAE,CAC7E,OAAO;KACL,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;IACf,IAAI,CAAC,KAAK,QAAQ,CAAC,MAAM,EAAE;QAC1B,OAAO,GAAG,CAAC;KACX;IACD,IAAI,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE;QAC1B,MAAM,IAAI,WAAW,CAAC,wCAAwC,CAAC,CAAC;KAChE;IACD,IAAI,SAAS,CAAC,EAAE,CAAC,MAAM,eAAqB,EAAE;QAC7C,OAAO,GAAG,GAAG,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/B;IACD,OAAO,GAAG,GAAG,GAAG,CAAC;AAClB,CAAC,CAAC;KACD,IAAI,CAAC,EAAE,CAAC,CAAC;AAdC,QAAA,KAAK,SAcN;AAEL,MAAM,cAAc,GAAG,KAAK,EAClC,EAAM,EACN,SAAiB,EACjB,EAAoB,EACP,EAAE;IACf,IAAI;QACH,MAAM,EAAE,CAAC,UAAU,CAClB,IAAA,aAAK,EAAA;;yBAEiB,CAAC;uBACH,CAAC,EAAE,EACvB,CAAC,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,cAAW,CAAC,WAAW,CAAC,CAAC,CAC3D,CAAC;QACF,MAAM,EAAE,CAAC,UAAU,CAClB,IAAA,aAAK,EAAA;;YAEI,CAAC,GAAG,EACb,CAAC,SAAS,CAAC,CACX,CAAC;KACF;IAAC,OAAO,GAAG,EAAE;QACb,MAAM,IAAA,oBAAK,EAAC,cAAW,CAAC,aAAa,CAAC,CAAC;QACvC,MAAM,GAAG,CAAC;KACV;IACD,IAAI;QACH,OAAO,MAAM,EAAE,EAAE,CAAC;KAClB;YAAS;QACT,IAAI;YACH,MAAM,EAAE,CAAC,UAAU,CAClB,IAAA,aAAK,EAAA;;yBAEgB,CAAC,EAAE,EACxB,CAAC,SAAS,CAAC,CACX,CAAC;SACF;QAAC,WAAM;SAIP;KACD;AACF,CAAC,CAAC;AAvCW,QAAA,cAAc,kBAuCzB;AAEK,MAAM,uBAAuB,GAAG,KAAK,EAC3C,EAAM,EACN,SAAiB,EACE,EAAE;IACrB,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;IACxD,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE;QAC7B,OAAO,KAAK,CAAC;KACb;IACD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC,UAAU,CACnC,IAAA,aAAK,EAAA;;;6CAGsC,CAAC;gBAC9B,EACd,CAAC,SAAS,CAAC,CACX,CAAC;IAEF,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;AACxB,CAAC,CAAC;AAlBW,QAAA,uBAAuB,2BAkBlC;AAEK,MAAM,qBAAqB,GAAG,KAAK,EACzC,EAAM,EACN,SAAiB,EACjB,kBAA4B,EACZ,EAAE;IAClB,MAAM,qBAAqB,GAAG,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;IAEjE,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;IACxD,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE;QAC7B,OAAO;KACP;IAED,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,EAAE,CAAC,UAAU,CAC3C,IAAA,aAAK,EAAA;;qBAEc,CAAC;0BACI,CAAC;mCACQ,CAAC,EAAE,EACpC,CAAC,SAAS,EAAE,qBAAqB,EAAE,SAAS,CAAC,CAC7C,CAAC;IAEF,IAAI,YAAY,KAAK,CAAC,EAAE;QACvB,MAAM,EAAE,CAAC,UAAU,CAClB,IAAA,aAAK,EAAA;;UAEE,CAAC,KAAK,CAAC,GAAG,EACjB,CAAC,SAAS,EAAE,qBAAqB,CAAC,CAClC,CAAC;KACF;AACF,CAAC,CAAC;AA7BW,QAAA,qBAAqB,yBA6BhC;AAEK,MAAM,qBAAqB,GAAG,KAAK,EACzC,EAAM,EACN,SAAiB,EACG,EAAE;IACtB,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC,UAAU,CACnC,IAAA,aAAK,EAAA;;;mCAG4B,CAAC,EAAE,EACpC,CAAC,SAAS,CAAC,CACX,CAAC;IAEF,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACrB,IAAI,IAAI,IAAI,IAAI,EAAE;QACjB,OAAO,EAAE,CAAC;KACV;IAED,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAa,CAAC;AACzD,CAAC,CAAC;AAlBW,QAAA,qBAAqB,yBAkBhC;AAGK,MAAM,mBAAmB,GAAG,KAAK,EACvC,EAAM,EACN,eAAgC,EACF,EAAE;IAChC,IAAI;QACH,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,UAAU,CACjC,IAAA,aAAK,EAAA;;UAEE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC;CAC9C,EACE;YACC,eAAe,CAAC,eAAe,CAAC;YAChC,eAAe,CAAC,YAAY,CAAC;YAC7B,eAAe,CAAC,SAAS,CAAC;YAC1B,eAAe,CAAC,gBAAgB,CAAC;YACjC,eAAe,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9C,eAAe,CAAC,iBAAiB,CAAC;YAClC,eAAe,CAAC,aAAa,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SAC/C,CACD,CAAC;QACF,OAAO,MAAM,CAAC;KACd;IAAC,OAAO,GAAG,EAAE;KAEb;AACF,CAAC,CAAC;AAxBW,QAAA,mBAAmB,uBAwB9B;AAGK,MAAM,qBAAqB,GAAG,KAAK,EACzC,EAAM,EACN,eAAgC,EACF,EAAE;IAChC,IAAI;QACH,OAAO,MAAM,EAAE,CAAC,UAAU,CACzB,IAAA,aAAK,EAAA;;;kBAGU,CAAC;oBACC,CAAC;oBACD,CAAC;oBACD,CAAC;qBACA,CAAC;yBACG,CAAC;iBACT,CAAC;kBACA,CAAC;6CAC0B,CAAC,GAAG,EAC9C;YACC,eAAe,CAAC,aAAa,CAAC;YAC9B,eAAe,CAAC,eAAe,CAAC;YAChC,eAAe,CAAC,eAAe,CAAC;YAChC,eAAe,CAAC,eAAe,CAAC;YAChC,eAAe,CAAC,gBAAgB,CAAC;YACjC,eAAe,CAAC,oBAAoB,CAAC;YACrC,eAAe,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9C,eAAe,CAAC,aAAa,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/C,eAAe,CAAC,eAAe,CAAC;SAChC,CACD,CAAC;KACF;IAAC,OAAO,GAAG,EAAE;KAEb;AACF,CAAC,CAAC;AAjCW,QAAA,qBAAqB,yBAiChC;AAEK,MAAM,mBAAmB,GAAG,KAAK,EACvC,EAAM,EACN,YAAoB,EACmB,EAAE;IACzC,IAAI;QACH,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC,UAAU,CACnC,IAAA,aAAK,EAAA;;;6CAGqC,CAAC;SACrC,EACN,CAAC,YAAY,CAAC,CACd,CAAC;QAEF,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACrB,IAAI,IAAI,IAAI,IAAI,EAAE;YACjB,OAAO,SAAS,CAAC;SACjB;QAED,OAAO;YACN,aAAa,EAAE,IAAI,CAAC,eAAe,CAAC;YACpC,UAAU,EAAE,IAAI,CAAC,YAAY,CAAC;YAC9B,aAAa,EAAE,IAAI,CAAC,eAAe,CAAC;YACpC,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC;YAChC,aAAa,EAAE,IAAI,CAAC,eAAe,CAAC;YACpC,aAAa,EAAE,IAAI,CAAC,eAAe,CAAC;YACpC,eAAe,EAAE,IAAI,CAAC,iBAAiB,CAAC;YACxC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC;YACxB,cAAc,EAAE,IAAI,CAAC,gBAAgB,CAAC;YACtC,cAAc,EAAE,IAAI,CAAC,gBAAgB,CAAC;YACtC,kBAAkB,EAAE,IAAI,CAAC,oBAAoB,CAAC;YAC9C,UAAU,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK;YACnD,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK;SACrD,CAAC;KACF;IAAC,OAAO,GAAG,EAAE;QAEb,OAAO,SAAS,CAAC;KACjB;AACF,CAAC,CAAC;AAtCW,QAAA,mBAAmB,uBAsC9B"}
@@ -1,273 +0,0 @@
1
- import type { Tx } from '../database-layer/db';
2
- import type { Model } from '../config-loader/config-loader';
3
-
4
- import * as _ from 'lodash';
5
- import * as sbvrUtils from '../sbvr-api/sbvr-utils';
6
-
7
- type ApiRootModel = Model & { apiRoot: string };
8
-
9
- import {
10
- MigrationTuple,
11
- Migrations,
12
- AsyncMigrationFn,
13
- migrationCategories,
14
- checkModelAlreadyExists,
15
- setExecutedMigrations,
16
- getExecutedMigrations,
17
- migratorEnv,
18
- lockMigrations,
19
- initMigrationStatus,
20
- readMigrationStatus,
21
- updateMigrationStatus,
22
- } from './utils';
23
-
24
- export const run = async (model: ApiRootModel): Promise<void> => {
25
- const { migrations } = model;
26
- if (
27
- migrations == null ||
28
- _.isEmpty(migrations) ||
29
- migrations[migrationCategories.async] === undefined
30
- ) {
31
- return;
32
- }
33
- await $run(model, migrations[migrationCategories.async]);
34
- };
35
-
36
- const $run = async (
37
- model: ApiRootModel,
38
- migrations: Migrations,
39
- ): Promise<void> => {
40
- const modelName = model.apiRoot;
41
-
42
- // init migrations
43
- let exists;
44
- await sbvrUtils.db.transaction(async (tx) => {
45
- exists = await checkModelAlreadyExists(tx, modelName);
46
- if (!exists) {
47
- (sbvrUtils.api.migrations?.logger.info ?? console.info)(
48
- 'First time model has executed, skipping migrations',
49
- );
50
-
51
- return await setExecutedMigrations(
52
- tx,
53
- modelName,
54
- Object.keys(migrations),
55
- );
56
- }
57
- });
58
-
59
- if (!exists) {
60
- return;
61
- }
62
-
63
- /**
64
- * preflight check if there are already migrations executed before starting the async scheduler
65
- * this will impplicitly skip async migrations that have been superceeded by synchron migrations.
66
- * e.g.:
67
- *
68
- * sync migrations in repo: [001,002,004,005]
69
- * async migrations in repo: [003,006]
70
- *
71
- * executed migrations at this point should always contain all sync migrations:
72
- * executed migrations: [001,002,004,005]
73
- *
74
- * This will result in only async migration 006 being executed.
75
- *
76
- * The async migrations are ment to be used in seperate deployments to make expensive data migrations
77
- * of multiple million row update queries cheaper and with no downtime / long lasting table lock.
78
- * In the end, after each async migration, the next deploymemnt should follow up the data migration
79
- * with a final sync data migrations.
80
- * A async migration will be executed in iterations until no rows are updated anymore (keep row locks short)
81
- * then it switches into a backoff mode to check with longer delay if data needs to be migrated in the future.
82
- * Example query:
83
- * UPDATE tableA
84
- * SET columnB = columnA
85
- * WHERE id IN (SELECT id
86
- * FROM tableA
87
- * WHERE (columnA <> columnB) OR (columnA IS NOT NULL AND columnB IS NULL)
88
- * LIMIT 1000);
89
- *
90
- * The final sync data migration would look like:
91
- * UPDATE tableA
92
- * SET columnB = columnA
93
- * WHERE (columnA <> columnB) OR (columnA IS NOT NULL AND columnB IS NULL);
94
- *
95
- * And will update remaining rows, which ideally are 0 and therefore now rows are locked for the update
96
- *
97
- * In the case of a column rename the columnA could be savely dropped:
98
- * ALTER TABLE tableA
99
- * DROP COLUMN IF EXISTS columnA;
100
- */
101
-
102
- let pendingMigrations: MigrationTuple[] = [];
103
- await sbvrUtils.db.transaction(async (tx) => {
104
- const executedMigrations = await getExecutedMigrations(tx, modelName);
105
- pendingMigrations = filterAndSortPendingAsyncMigrations(
106
- migrations,
107
- executedMigrations,
108
- );
109
- });
110
-
111
- // Just schedule the migration workers and don't wait for any return of them
112
- // the migration workers run until the next deployment and may synchronise with other
113
- // instances via database tables: migration lock and migration status
114
- for (const [key, migration] of pendingMigrations) {
115
- const initMigrationState = {
116
- migration_key: key,
117
- start_time: new Date(Date.now()),
118
- last_run_time: new Date(Date.now()),
119
- run_counter: 0,
120
- migrated_rows: 0,
121
- error_counter: 0,
122
- error_threshold: migratorEnv.asyncMigrationDefaultErrorThreshold,
123
- delayMS: migratorEnv.asyncMigrationDefaultDelayMS,
124
- backoffDelayMS: migratorEnv.asyncMigrationDefaultBackoffDelayMS,
125
- converged_time: undefined,
126
- last_error_message: undefined,
127
- is_backoff: false,
128
- should_stop: false,
129
- };
130
-
131
- let asyncRunnerMigratorFn: ((tx: Tx) => Promise<number>) | undefined;
132
-
133
- if (typeof migration === 'object') {
134
- if (migration.fn && typeof migration.fn === 'function') {
135
- asyncRunnerMigratorFn = async (tx: Tx) =>
136
- (await (migration.fn as AsyncMigrationFn)(tx, sbvrUtils))
137
- .rowsAffected;
138
- } else if (migration.sql && typeof migration.sql === 'string') {
139
- asyncRunnerMigratorFn = async (tx: Tx) =>
140
- (await tx.executeSql(migration.sql as string)).rowsAffected;
141
- } else {
142
- // don't break the async migration b/c of one migration fails
143
- (sbvrUtils.api.migrations?.logger.error ?? console.error)(
144
- `Invalid migration object: ${JSON.stringify(migration, null, 2)}`,
145
- );
146
- continue;
147
- }
148
-
149
- initMigrationState.backoffDelayMS =
150
- migration.backoffDelayMS ||
151
- migratorEnv.asyncMigrationDefaultBackoffDelayMS;
152
- initMigrationState.delayMS =
153
- migration.delayMS || migratorEnv.asyncMigrationDefaultDelayMS;
154
- initMigrationState.error_threshold =
155
- migration.errorThreshold ||
156
- migratorEnv.asyncMigrationDefaultErrorThreshold;
157
- } else if (typeof migration === 'string') {
158
- asyncRunnerMigratorFn = async (tx: Tx) =>
159
- (await tx.executeSql(migration)).rowsAffected;
160
- } else {
161
- (sbvrUtils.api.migrations?.logger.error ?? console.error)(
162
- `Invalid async migration object: ${JSON.stringify(migration, null, 2)}`,
163
- );
164
- continue;
165
- }
166
-
167
- await sbvrUtils.db.transaction(async (tx) =>
168
- initMigrationStatus(tx, initMigrationState),
169
- );
170
-
171
- const asyncRunner = async () => {
172
- await sbvrUtils.db.transaction(async (tx) => {
173
- await lockMigrations(tx, modelName, async () => {
174
- const migrationState = await readMigrationStatus(tx, key);
175
-
176
- if (!migrationState || migrationState.should_stop === true) {
177
- // migration status is unclear stop the migrator
178
- // or migration should stop
179
- (sbvrUtils.api.migrations?.logger.info ?? console.info)(
180
- `stopping async migration: ${key}`,
181
- );
182
- clearInterval(asyncScheduler);
183
- return;
184
- }
185
- try {
186
- // clear the interval to avoid retriggering before finisheing this migraiton query
187
- clearInterval(asyncScheduler);
188
-
189
- // sync on the last execution time between instances
190
- // precondition: All running instances are running on the same time/block
191
- // skip execution
192
- if (migrationState.last_run_time) {
193
- const durationSinceLastRun =
194
- Date.now().valueOf() - migrationState.last_run_time.valueOf();
195
- if (
196
- (migrationState.is_backoff &&
197
- durationSinceLastRun < migrationState.backoffDelayMS) ||
198
- (!migrationState.is_backoff &&
199
- durationSinceLastRun < migrationState.delayMS)
200
- ) {
201
- // will still execute finally block where the migration lock is released.
202
- return;
203
- }
204
- }
205
- // set last run time and run counter only when backoff time sync between
206
- // competing instances is in sync
207
- migrationState.last_run_time = new Date(Date.now());
208
- migrationState.run_counter += 1;
209
-
210
- let migratedRows = 0;
211
- await sbvrUtils.db.transaction(async (migrationTx) => {
212
- migratedRows = (await asyncRunnerMigratorFn?.(migrationTx)) || 0;
213
- });
214
-
215
- migrationState.migrated_rows += migratedRows;
216
- if (migratedRows === 0) {
217
- // when all rows have been catched up once we only catch up less frequently
218
- migrationState.is_backoff = true;
219
- if (!migrationState.converged_time) {
220
- // only store the first time when migrator converged to all data migrated
221
- migrationState.converged_time = new Date(Date.now());
222
- }
223
- } else {
224
- // Only here for the case that after backoff more rows need to be catched up faster
225
- // If rows have been updated recently we start the interval again with normal frequency
226
- migrationState.is_backoff = false;
227
- }
228
- } catch (err) {
229
- migrationState.error_counter++;
230
-
231
- if (
232
- migrationState.error_counter % migrationState.error_threshold ===
233
- 0
234
- ) {
235
- migrationState.last_error_message = `${err.name} ${err.message}`;
236
- (sbvrUtils.api.migrations?.logger.error ?? console.error)(
237
- `${key}: ${err.name} ${err.message}`,
238
- );
239
- migrationState.is_backoff = true;
240
- }
241
- } finally {
242
- if (migrationState.is_backoff) {
243
- asyncScheduler = setInterval(
244
- asyncRunner,
245
- migrationState.backoffDelayMS,
246
- );
247
- } else {
248
- asyncScheduler = setInterval(asyncRunner, migrationState.delayMS);
249
- }
250
- // using finally as it will also run when return statement is called inside the try block
251
- // either success or error release the lock
252
- await updateMigrationStatus(tx, migrationState);
253
- }
254
- });
255
- });
256
- };
257
- let asyncScheduler = setInterval(asyncRunner, initMigrationState.delayMS);
258
- }
259
- };
260
-
261
- const filterAndSortPendingAsyncMigrations = (
262
- migrations: NonNullable<Migrations>,
263
- executedMigrations: string[],
264
- ): MigrationTuple[] => {
265
- // using it for string comparison, any string is greater than ''
266
- const latestExecutedMigration = executedMigrations.sort().pop() ?? '';
267
-
268
- return (_(migrations).omit(executedMigrations) as _.Object<typeof migrations>)
269
- .toPairs()
270
- .filter(([migrationKey]) => migrationKey > latestExecutedMigration)
271
- .sortBy(([migrationKey]) => migrationKey)
272
- .value();
273
- };