@balena/pinejs 15.0.0-delete-state-default-user-permissions-981931563dc47b2a8b873bc787d7dacfcc6c52e3 → 15.0.0-deprecate-node12-8a99d72ae66d7708293afc56c5d7eb19b39081cd
Sign up to get free protection for your applications and to get access to all the features.
- package/.resinci.yml +0 -1
- package/.versionbot/CHANGELOG.yml +226 -8
- package/CHANGELOG.md +85 -1
- package/out/bin/utils.js +1 -1
- package/out/bin/utils.js.map +1 -1
- package/out/config-loader/config-loader.d.ts +3 -5
- package/out/config-loader/config-loader.js +35 -31
- package/out/config-loader/config-loader.js.map +1 -1
- package/out/data-server/sbvr-server.js +8 -8
- package/out/data-server/sbvr-server.js.map +1 -1
- package/out/database-layer/db.d.ts +1 -1
- package/out/database-layer/db.js +3 -3
- package/out/database-layer/db.js.map +1 -1
- package/out/express-emulator/express.js +1 -1
- package/out/express-emulator/express.js.map +1 -1
- package/out/http-transactions/transactions.js +4 -4
- package/out/http-transactions/transactions.js.map +1 -1
- package/out/migrator/sync.d.ts +9 -0
- package/out/migrator/sync.js +121 -0
- package/out/migrator/sync.js.map +1 -0
- package/out/migrator/utils.d.ts +28 -0
- package/out/migrator/utils.js +104 -0
- package/out/migrator/utils.js.map +1 -0
- package/out/odata-metadata/odata-metadata-generator.js +6 -9
- package/out/odata-metadata/odata-metadata-generator.js.map +1 -1
- package/out/passport-pinejs/passport-pinejs.js +4 -3
- package/out/passport-pinejs/passport-pinejs.js.map +1 -1
- package/out/pinejs-session-store/pinejs-session-store.js +1 -1
- 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/abstract-sql.js.map +1 -1
- package/out/sbvr-api/control-flow.js.map +1 -1
- package/out/sbvr-api/hooks.d.ts +6 -3
- package/out/sbvr-api/hooks.js +3 -3
- package/out/sbvr-api/hooks.js.map +1 -1
- package/out/sbvr-api/odata-response.js +5 -5
- package/out/sbvr-api/odata-response.js.map +1 -1
- package/out/sbvr-api/permissions.js +25 -20
- package/out/sbvr-api/permissions.js.map +1 -1
- package/out/sbvr-api/sbvr-utils.d.ts +4 -3
- package/out/sbvr-api/sbvr-utils.js +71 -48
- package/out/sbvr-api/sbvr-utils.js.map +1 -1
- package/out/sbvr-api/uri-parser.d.ts +13 -11
- package/out/sbvr-api/uri-parser.js +4 -4
- package/out/sbvr-api/uri-parser.js.map +1 -1
- package/out/server-glue/module.d.ts +2 -2
- package/out/server-glue/module.js +2 -1
- package/out/server-glue/module.js.map +1 -1
- package/package.json +19 -19
- package/src/bin/utils.ts +1 -1
- package/src/config-loader/config-loader.ts +69 -44
- package/src/data-server/sbvr-server.js +8 -8
- package/src/database-layer/db.ts +11 -11
- package/src/express-emulator/express.js +1 -1
- package/src/http-transactions/transactions.js +4 -4
- package/src/migrator/sync.ts +169 -0
- package/src/migrator/utils.ts +154 -0
- package/src/odata-metadata/odata-metadata-generator.ts +8 -11
- package/src/passport-pinejs/passport-pinejs.ts +3 -2
- package/src/sbvr-api/abstract-sql.ts +6 -3
- package/src/sbvr-api/control-flow.ts +2 -2
- package/src/sbvr-api/hooks.ts +18 -8
- package/src/sbvr-api/odata-response.ts +4 -4
- package/src/sbvr-api/permissions.ts +42 -36
- package/src/sbvr-api/sbvr-utils.ts +121 -58
- package/src/sbvr-api/uri-parser.ts +29 -21
- package/src/server-glue/module.ts +4 -3
- package/tsconfig.json +1 -3
- package/typings/lf-to-abstract-sql.d.ts +6 -9
- package/out/migrator/migrator.d.ts +0 -17
- package/out/migrator/migrator.js +0 -185
- package/out/migrator/migrator.js.map +0 -1
- package/src/migrator/migrator.ts +0 -278
@@ -37,20 +37,22 @@ export interface UnparsedRequest {
|
|
37
37
|
_isChangeSet?: boolean;
|
38
38
|
}
|
39
39
|
|
40
|
-
export interface
|
40
|
+
export interface ParsedODataRequest {
|
41
41
|
method: SupportedMethod;
|
42
42
|
url: string;
|
43
|
+
vocabulary: string;
|
44
|
+
resourceName: string;
|
45
|
+
values: AnyObject;
|
43
46
|
odataQuery: ODataQuery;
|
44
47
|
odataBinds: OdataBinds;
|
45
|
-
|
48
|
+
custom: AnyObject;
|
49
|
+
id?: number | undefined;
|
50
|
+
_defer?: boolean;
|
51
|
+
}
|
52
|
+
export interface ODataRequest extends ParsedODataRequest {
|
46
53
|
abstractSqlModel?: AbstractSQLCompiler.AbstractSqlModel;
|
47
54
|
abstractSqlQuery?: AbstractSQLCompiler.AbstractSqlQuery;
|
48
55
|
sqlQuery?: AbstractSQLCompiler.SqlResult | AbstractSQLCompiler.SqlResult[];
|
49
|
-
resourceName: string;
|
50
|
-
vocabulary: string;
|
51
|
-
_defer?: boolean;
|
52
|
-
id?: number | undefined;
|
53
|
-
custom: AnyObject;
|
54
56
|
tx?: Tx;
|
55
57
|
modifiedFields?: ReturnType<
|
56
58
|
AbstractSQLCompiler.EngineInstance['getModifiedFields']
|
@@ -58,7 +60,7 @@ export interface ODataRequest {
|
|
58
60
|
affectedIds?: number[];
|
59
61
|
pendingAffectedIds?: Promise<number[]>;
|
60
62
|
hooks?: InstantiatedHooks;
|
61
|
-
engine
|
63
|
+
engine: AbstractSQLCompiler.Engines;
|
62
64
|
}
|
63
65
|
|
64
66
|
// Converts a value to its string representation and tries to parse is as an
|
@@ -96,12 +98,12 @@ export const memoizedParseOdata = (() => {
|
|
96
98
|
// Try to cache based on parameter aliases if there might be some
|
97
99
|
const parameterAliases = new URLSearchParams();
|
98
100
|
const queryParams = new URLSearchParams(url.slice(queryParamsIndex));
|
99
|
-
Array.from(queryParams.entries())
|
101
|
+
for (const [key, value] of Array.from(queryParams.entries())) {
|
100
102
|
if (key.startsWith('@')) {
|
101
103
|
parameterAliases.append(key, value);
|
102
104
|
queryParams.delete(key);
|
103
105
|
}
|
104
|
-
}
|
106
|
+
}
|
105
107
|
const parameterAliasesString = parameterAliases.toString();
|
106
108
|
if (parameterAliasesString !== '') {
|
107
109
|
const parsed = _.cloneDeep(
|
@@ -257,23 +259,26 @@ export const metadataEndpoints = ['$metadata', '$serviceroot'];
|
|
257
259
|
|
258
260
|
export async function parseOData(
|
259
261
|
b: UnparsedRequest & { _isChangeSet?: false },
|
260
|
-
): Promise<
|
262
|
+
): Promise<ParsedODataRequest>;
|
261
263
|
export async function parseOData(
|
262
264
|
b: UnparsedRequest & { _isChangeSet: true },
|
263
|
-
): Promise<
|
265
|
+
): Promise<ParsedODataRequest[]>;
|
264
266
|
export async function parseOData(
|
265
267
|
b: UnparsedRequest,
|
266
|
-
): Promise<
|
268
|
+
): Promise<ParsedODataRequest | ParsedODataRequest[]>;
|
267
269
|
export async function parseOData(
|
268
270
|
b: UnparsedRequest,
|
269
|
-
): Promise<
|
271
|
+
): Promise<ParsedODataRequest | ParsedODataRequest[]> {
|
270
272
|
try {
|
271
273
|
if (b._isChangeSet && b.changeSet != null) {
|
272
274
|
// We sort the CS set once, we must assure that requests which reference
|
273
275
|
// other requests in the changeset are placed last. Once they are sorted
|
274
276
|
// Map will guarantee retrival of results in insertion order
|
275
277
|
const sortedCS = _.sortBy(b.changeSet, (el) => el.url[0] !== '/');
|
276
|
-
const csReferences = new Map<
|
278
|
+
const csReferences = new Map<
|
279
|
+
ParsedODataRequest['id'],
|
280
|
+
ParsedODataRequest
|
281
|
+
>();
|
277
282
|
for (const cs of sortedCS) {
|
278
283
|
parseODataChangeset(csReferences, cs);
|
279
284
|
}
|
@@ -287,14 +292,14 @@ export async function parseOData(
|
|
287
292
|
url,
|
288
293
|
vocabulary: apiRoot,
|
289
294
|
resourceName: odata.tree.resource,
|
290
|
-
odataBinds: odata.binds,
|
291
|
-
odataQuery: odata.tree,
|
292
295
|
values: b.data ?? {},
|
296
|
+
odataQuery: odata.tree,
|
297
|
+
odataBinds: odata.binds,
|
293
298
|
custom: {},
|
294
299
|
_defer: false,
|
295
300
|
};
|
296
301
|
}
|
297
|
-
} catch (err) {
|
302
|
+
} catch (err: any) {
|
298
303
|
if (err instanceof ODataParser.SyntaxError) {
|
299
304
|
throw new BadRequestError(`Malformed url: '${b.url}'`);
|
300
305
|
}
|
@@ -307,10 +312,13 @@ export async function parseOData(
|
|
307
312
|
}
|
308
313
|
|
309
314
|
const parseODataChangeset = (
|
310
|
-
csReferences: Map<
|
315
|
+
csReferences: Map<ParsedODataRequest['id'], ParsedODataRequest>,
|
311
316
|
b: UnparsedRequest,
|
312
317
|
): void => {
|
313
|
-
const contentId:
|
318
|
+
const contentId: ParsedODataRequest['id'] = mustExtractHeader(
|
319
|
+
b,
|
320
|
+
'content-id',
|
321
|
+
);
|
314
322
|
|
315
323
|
if (csReferences.has(contentId)) {
|
316
324
|
throw new BadRequestError('Content-Id must be unique inside a changeset');
|
@@ -341,7 +349,7 @@ const parseODataChangeset = (
|
|
341
349
|
defer = true;
|
342
350
|
}
|
343
351
|
|
344
|
-
const parseResult:
|
352
|
+
const parseResult: ParsedODataRequest = {
|
345
353
|
method: b.method as SupportedMethod,
|
346
354
|
url,
|
347
355
|
vocabulary: apiRoot,
|
@@ -4,7 +4,8 @@ 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/
|
7
|
+
import * as migrator from '../migrator/sync';
|
8
|
+
import * as migratorUtils from '../migrator/utils';
|
8
9
|
|
9
10
|
import * as sbvrUtils from '../sbvr-api/sbvr-utils';
|
10
11
|
|
@@ -17,7 +18,7 @@ export * as env from '../config-loader/env';
|
|
17
18
|
export * as types from '../sbvr-api/common-types';
|
18
19
|
export * as hooks from '../sbvr-api/hooks';
|
19
20
|
export type { configLoader as ConfigLoader };
|
20
|
-
export type {
|
21
|
+
export type { migratorUtils as Migrator };
|
21
22
|
|
22
23
|
let envDatabaseOptions: dbModule.DatabaseOptions<string>;
|
23
24
|
if (dbModule.engines.websql != null) {
|
@@ -72,7 +73,7 @@ export const init = async <T extends string>(
|
|
72
73
|
await Promise.all(promises);
|
73
74
|
|
74
75
|
return cfgLoader;
|
75
|
-
} catch (err) {
|
76
|
+
} catch (err: any) {
|
76
77
|
console.error('Error initialising server', err, err.stack);
|
77
78
|
process.exit(1);
|
78
79
|
}
|
package/tsconfig.json
CHANGED
@@ -3,8 +3,6 @@
|
|
3
3
|
"module": "commonjs",
|
4
4
|
"strict": true,
|
5
5
|
"strictFunctionTypes": false,
|
6
|
-
"strictPropertyInitialization": false,
|
7
|
-
"useUnknownInCatchVariables": false,
|
8
6
|
"noImplicitThis": false,
|
9
7
|
"noUnusedParameters": true,
|
10
8
|
"noUnusedLocals": true,
|
@@ -13,7 +11,7 @@
|
|
13
11
|
"removeComments": true,
|
14
12
|
"rootDir": "src",
|
15
13
|
"sourceMap": true,
|
16
|
-
"target": "
|
14
|
+
"target": "es2019",
|
17
15
|
"declaration": true,
|
18
16
|
"skipLibCheck": true,
|
19
17
|
"resolveJsonModule": true,
|
@@ -1,22 +1,19 @@
|
|
1
1
|
declare module '@balena/lf-to-abstract-sql' {
|
2
|
+
import type sbvrTypes = require('@balena/sbvr-types');
|
3
|
+
import type { LFModel } from '@balena/sbvr-parser';
|
4
|
+
import type { AbstractSqlModel } from '@balena/abstract-sql-compiler';
|
2
5
|
export const LF2AbstractSQL: {
|
3
6
|
createInstance: () => {
|
4
|
-
match: (
|
5
|
-
lfModel: LFModel,
|
6
|
-
rule: 'Process',
|
7
|
-
) => AbstractSQLCompiler.AbstractSqlModel;
|
7
|
+
match: (lfModel: LFModel, rule: 'Process') => AbstractSqlModel;
|
8
8
|
addTypes: (types: typeof sbvrTypes) => void;
|
9
9
|
reset: () => void;
|
10
10
|
};
|
11
11
|
};
|
12
12
|
export const LF2AbstractSQLPrep: {
|
13
13
|
match: (lfModel: LFModel, rule: 'Process') => LFModel;
|
14
|
-
_extend({}): typeof
|
14
|
+
_extend({}): typeof LF2AbstractSQLPrep;
|
15
15
|
};
|
16
16
|
export const createTranslator: (
|
17
17
|
types: typeof sbvrTypes,
|
18
|
-
) => (
|
19
|
-
lfModel: LFModel,
|
20
|
-
rule: 'Process',
|
21
|
-
) => AbstractSQLCompiler.AbstractSqlModel;
|
18
|
+
) => (lfModel: LFModel, rule: 'Process') => AbstractSqlModel;
|
22
19
|
}
|
@@ -1,17 +0,0 @@
|
|
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
|
-
import { TypedError } from 'typed-error';
|
5
|
-
import * as sbvrUtils from '../sbvr-api/sbvr-utils';
|
6
|
-
declare type ApiRootModel = Model & {
|
7
|
-
apiRoot: string;
|
8
|
-
};
|
9
|
-
declare type SbvrUtils = typeof sbvrUtils;
|
10
|
-
export declare type MigrationFn = (tx: Tx, sbvrUtils: SbvrUtils) => Resolvable<void>;
|
11
|
-
export declare type Migration = string | MigrationFn;
|
12
|
-
export declare class MigrationError extends TypedError {
|
13
|
-
}
|
14
|
-
export declare const postRun: (tx: Tx, model: ApiRootModel) => Promise<void>;
|
15
|
-
export declare const run: (tx: Tx, model: ApiRootModel) => Promise<void>;
|
16
|
-
export declare const config: Config;
|
17
|
-
export {};
|
package/out/migrator/migrator.js
DELETED
@@ -1,185 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.config = exports.run = exports.postRun = exports.MigrationError = void 0;
|
4
|
-
const _ = require("lodash");
|
5
|
-
const typed_error_1 = require("typed-error");
|
6
|
-
const env_1 = require("../config-loader/env");
|
7
|
-
const sbvrUtils = require("../sbvr-api/sbvr-utils");
|
8
|
-
const control_flow_1 = require("../sbvr-api/control-flow");
|
9
|
-
const modelText = require('./migrations.sbvr');
|
10
|
-
class MigrationError extends typed_error_1.TypedError {
|
11
|
-
}
|
12
|
-
exports.MigrationError = MigrationError;
|
13
|
-
const binds = (strings, ...bindNums) => strings
|
14
|
-
.map((str, i) => {
|
15
|
-
if (i === bindNums.length) {
|
16
|
-
return str;
|
17
|
-
}
|
18
|
-
if (i + 1 !== bindNums[i]) {
|
19
|
-
throw new SyntaxError('Migration sql binds must be sequential');
|
20
|
-
}
|
21
|
-
if (sbvrUtils.db.engine === "postgres") {
|
22
|
-
return str + `$${bindNums[i]}`;
|
23
|
-
}
|
24
|
-
return str + `?`;
|
25
|
-
})
|
26
|
-
.join('');
|
27
|
-
const postRun = async (tx, model) => {
|
28
|
-
var _a, _b;
|
29
|
-
const { initSql } = model;
|
30
|
-
if (initSql == null) {
|
31
|
-
return;
|
32
|
-
}
|
33
|
-
const modelName = model.apiRoot;
|
34
|
-
const exists = await checkModelAlreadyExists(tx, modelName);
|
35
|
-
if (!exists) {
|
36
|
-
((_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');
|
37
|
-
await lockMigrations(tx, modelName, async () => {
|
38
|
-
await tx.executeSql(initSql);
|
39
|
-
});
|
40
|
-
}
|
41
|
-
};
|
42
|
-
exports.postRun = postRun;
|
43
|
-
const run = async (tx, model) => {
|
44
|
-
var _a, _b;
|
45
|
-
const { migrations } = model;
|
46
|
-
if (migrations == null || _.isEmpty(migrations)) {
|
47
|
-
return;
|
48
|
-
}
|
49
|
-
const modelName = model.apiRoot;
|
50
|
-
const exists = await checkModelAlreadyExists(tx, modelName);
|
51
|
-
if (!exists) {
|
52
|
-
((_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');
|
53
|
-
return await setExecutedMigrations(tx, modelName, Object.keys(migrations));
|
54
|
-
}
|
55
|
-
await lockMigrations(tx, modelName, async () => {
|
56
|
-
const executedMigrations = await getExecutedMigrations(tx, modelName);
|
57
|
-
const pendingMigrations = filterAndSortPendingMigrations(migrations, executedMigrations);
|
58
|
-
if (pendingMigrations.length === 0) {
|
59
|
-
return;
|
60
|
-
}
|
61
|
-
const newlyExecutedMigrations = await executeMigrations(tx, pendingMigrations);
|
62
|
-
await setExecutedMigrations(tx, modelName, [
|
63
|
-
...executedMigrations,
|
64
|
-
...newlyExecutedMigrations,
|
65
|
-
]);
|
66
|
-
});
|
67
|
-
};
|
68
|
-
exports.run = run;
|
69
|
-
const checkModelAlreadyExists = async (tx, modelName) => {
|
70
|
-
const result = await tx.tableList("name = 'migration'");
|
71
|
-
if (result.rows.length === 0) {
|
72
|
-
return false;
|
73
|
-
}
|
74
|
-
const { rows } = await tx.executeSql(binds `
|
75
|
-
SELECT 1
|
76
|
-
FROM "model"
|
77
|
-
WHERE "model"."is of-vocabulary" = ${1}
|
78
|
-
LIMIT 1`, [modelName]);
|
79
|
-
return rows.length > 0;
|
80
|
-
};
|
81
|
-
const getExecutedMigrations = async (tx, modelName) => {
|
82
|
-
const { rows } = await tx.executeSql(binds `
|
83
|
-
SELECT "migration"."executed migrations" AS "executed_migrations"
|
84
|
-
FROM "migration"
|
85
|
-
WHERE "migration"."model name" = ${1}`, [modelName]);
|
86
|
-
const data = rows[0];
|
87
|
-
if (data == null) {
|
88
|
-
return [];
|
89
|
-
}
|
90
|
-
return JSON.parse(data.executed_migrations);
|
91
|
-
};
|
92
|
-
const setExecutedMigrations = async (tx, modelName, executedMigrations) => {
|
93
|
-
const stringifiedMigrations = JSON.stringify(executedMigrations);
|
94
|
-
const result = await tx.tableList("name = 'migration'");
|
95
|
-
if (result.rows.length === 0) {
|
96
|
-
return;
|
97
|
-
}
|
98
|
-
const { rowsAffected } = await tx.executeSql(binds `
|
99
|
-
UPDATE "migration"
|
100
|
-
SET "model name" = ${1},
|
101
|
-
"executed migrations" = ${2}
|
102
|
-
WHERE "migration"."model name" = ${3}`, [modelName, stringifiedMigrations, modelName]);
|
103
|
-
if (rowsAffected === 0) {
|
104
|
-
await tx.executeSql(binds `
|
105
|
-
INSERT INTO "migration" ("model name", "executed migrations")
|
106
|
-
VALUES (${1}, ${2})`, [modelName, stringifiedMigrations]);
|
107
|
-
}
|
108
|
-
};
|
109
|
-
const filterAndSortPendingMigrations = (migrations, executedMigrations) => _(migrations).omit(executedMigrations)
|
110
|
-
.toPairs()
|
111
|
-
.sortBy(([migrationKey]) => migrationKey)
|
112
|
-
.value();
|
113
|
-
const lockMigrations = async (tx, modelName, fn) => {
|
114
|
-
try {
|
115
|
-
await tx.executeSql(binds `
|
116
|
-
DELETE FROM "migration lock"
|
117
|
-
WHERE "model name" = ${1}
|
118
|
-
AND "created at" < ${2}`, [modelName, new Date(Date.now() - env_1.migrator.lockTimeout)]);
|
119
|
-
await tx.executeSql(binds `
|
120
|
-
INSERT INTO "migration lock" ("model name")
|
121
|
-
VALUES (${1})`, [modelName]);
|
122
|
-
}
|
123
|
-
catch (err) {
|
124
|
-
await (0, control_flow_1.delay)(env_1.migrator.lockFailDelay);
|
125
|
-
throw err;
|
126
|
-
}
|
127
|
-
try {
|
128
|
-
return await fn();
|
129
|
-
}
|
130
|
-
finally {
|
131
|
-
try {
|
132
|
-
await tx.executeSql(binds `
|
133
|
-
DELETE FROM "migration lock"
|
134
|
-
WHERE "model name" = ${1}`, [modelName]);
|
135
|
-
}
|
136
|
-
catch (_a) {
|
137
|
-
}
|
138
|
-
}
|
139
|
-
};
|
140
|
-
const executeMigrations = async (tx, migrations = []) => {
|
141
|
-
var _a, _b;
|
142
|
-
try {
|
143
|
-
for (const migration of migrations) {
|
144
|
-
await executeMigration(tx, migration);
|
145
|
-
}
|
146
|
-
}
|
147
|
-
catch (err) {
|
148
|
-
((_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');
|
149
|
-
throw new MigrationError(err);
|
150
|
-
}
|
151
|
-
return migrations.map(([migrationKey]) => migrationKey);
|
152
|
-
};
|
153
|
-
const executeMigration = async (tx, [key, migration]) => {
|
154
|
-
var _a, _b;
|
155
|
-
((_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)}`);
|
156
|
-
if (typeof migration === 'function') {
|
157
|
-
await migration(tx, sbvrUtils);
|
158
|
-
}
|
159
|
-
else if (typeof migration === 'string') {
|
160
|
-
await tx.executeSql(migration);
|
161
|
-
}
|
162
|
-
else {
|
163
|
-
throw new MigrationError(`Invalid migration type: ${typeof migration}`);
|
164
|
-
}
|
165
|
-
};
|
166
|
-
exports.config = {
|
167
|
-
models: [
|
168
|
-
{
|
169
|
-
modelName: 'migrations',
|
170
|
-
apiRoot: 'migrations',
|
171
|
-
modelText,
|
172
|
-
migrations: {
|
173
|
-
'11.0.0-modified-at': `
|
174
|
-
ALTER TABLE "migration"
|
175
|
-
ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
|
176
|
-
`,
|
177
|
-
'11.0.1-modified-at': `
|
178
|
-
ALTER TABLE "migration lock"
|
179
|
-
ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
|
180
|
-
`,
|
181
|
-
},
|
182
|
-
},
|
183
|
-
],
|
184
|
-
};
|
185
|
-
//# sourceMappingURL=migrator.js.map
|
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"migrator.js","sourceRoot":"","sources":["../../src/migrator/migrator.ts"],"names":[],"mappings":"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"}
|
package/src/migrator/migrator.ts
DELETED
@@ -1,278 +0,0 @@
|
|
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
|
-
};
|