@balena/pinejs 15.0.0-true-boolean-911aca4062d3132ad3c34712014739b6849fa13a → 15.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. package/.dockerignore +4 -0
  2. package/.github/workflows/flowzone.yml +21 -0
  3. package/.husky/pre-commit +4 -0
  4. package/.pinejs-cache.json +1 -0
  5. package/.resinci.yml +1 -0
  6. package/.versionbot/CHANGELOG.yml +9678 -2001
  7. package/CHANGELOG.md +2975 -2
  8. package/Dockerfile +14 -0
  9. package/Gruntfile.ts +3 -6
  10. package/README.md +10 -1
  11. package/VERSION +1 -0
  12. package/build/browser.ts +1 -1
  13. package/build/config.ts +0 -1
  14. package/docker-compose.npm-test.yml +11 -0
  15. package/docs/AdvancedUsage.md +77 -63
  16. package/docs/GettingStarted.md +90 -41
  17. package/docs/Migrations.md +102 -1
  18. package/docs/ProjectConfig.md +12 -21
  19. package/docs/Testing.md +7 -0
  20. package/out/bin/abstract-sql-compiler.js +17 -17
  21. package/out/bin/abstract-sql-compiler.js.map +1 -1
  22. package/out/bin/odata-compiler.js +23 -20
  23. package/out/bin/odata-compiler.js.map +1 -1
  24. package/out/bin/sbvr-compiler.js +22 -22
  25. package/out/bin/sbvr-compiler.js.map +1 -1
  26. package/out/bin/utils.d.ts +2 -2
  27. package/out/bin/utils.js +3 -3
  28. package/out/bin/utils.js.map +1 -1
  29. package/out/config-loader/config-loader.d.ts +9 -8
  30. package/out/config-loader/config-loader.js +135 -78
  31. package/out/config-loader/config-loader.js.map +1 -1
  32. package/out/config-loader/env.d.ts +41 -16
  33. package/out/config-loader/env.js +46 -2
  34. package/out/config-loader/env.js.map +1 -1
  35. package/out/data-server/sbvr-server.d.ts +2 -19
  36. package/out/data-server/sbvr-server.js +44 -38
  37. package/out/data-server/sbvr-server.js.map +1 -1
  38. package/out/database-layer/db.d.ts +32 -14
  39. package/out/database-layer/db.js +120 -41
  40. package/out/database-layer/db.js.map +1 -1
  41. package/out/express-emulator/express.js +10 -11
  42. package/out/express-emulator/express.js.map +1 -1
  43. package/out/http-transactions/transactions.d.ts +2 -18
  44. package/out/http-transactions/transactions.js +29 -21
  45. package/out/http-transactions/transactions.js.map +1 -1
  46. package/out/migrator/async.d.ts +7 -0
  47. package/out/migrator/async.js +168 -0
  48. package/out/migrator/async.js.map +1 -0
  49. package/out/migrator/migrations.sbvr +43 -0
  50. package/out/migrator/sync.d.ts +9 -0
  51. package/out/migrator/sync.js +106 -0
  52. package/out/migrator/sync.js.map +1 -0
  53. package/out/migrator/utils.d.ts +78 -0
  54. package/out/migrator/utils.js +283 -0
  55. package/out/migrator/utils.js.map +1 -0
  56. package/out/odata-metadata/odata-metadata-generator.js +10 -13
  57. package/out/odata-metadata/odata-metadata-generator.js.map +1 -1
  58. package/out/passport-pinejs/passport-pinejs.d.ts +1 -1
  59. package/out/passport-pinejs/passport-pinejs.js +8 -7
  60. package/out/passport-pinejs/passport-pinejs.js.map +1 -1
  61. package/out/pinejs-session-store/pinejs-session-store.d.ts +1 -1
  62. package/out/pinejs-session-store/pinejs-session-store.js +20 -6
  63. package/out/pinejs-session-store/pinejs-session-store.js.map +1 -1
  64. package/out/sbvr-api/abstract-sql.d.ts +3 -2
  65. package/out/sbvr-api/abstract-sql.js +9 -9
  66. package/out/sbvr-api/abstract-sql.js.map +1 -1
  67. package/out/sbvr-api/cached-compile.js +1 -1
  68. package/out/sbvr-api/cached-compile.js.map +1 -1
  69. package/out/sbvr-api/common-types.d.ts +6 -5
  70. package/out/sbvr-api/control-flow.d.ts +8 -1
  71. package/out/sbvr-api/control-flow.js +36 -9
  72. package/out/sbvr-api/control-flow.js.map +1 -1
  73. package/out/sbvr-api/errors.d.ts +47 -40
  74. package/out/sbvr-api/errors.js +78 -77
  75. package/out/sbvr-api/errors.js.map +1 -1
  76. package/out/sbvr-api/express-extension.d.ts +4 -0
  77. package/out/sbvr-api/hooks.d.ts +16 -15
  78. package/out/sbvr-api/hooks.js +74 -48
  79. package/out/sbvr-api/hooks.js.map +1 -1
  80. package/out/sbvr-api/odata-response.d.ts +2 -2
  81. package/out/sbvr-api/odata-response.js +28 -30
  82. package/out/sbvr-api/odata-response.js.map +1 -1
  83. package/out/sbvr-api/permissions.d.ts +17 -16
  84. package/out/sbvr-api/permissions.js +369 -304
  85. package/out/sbvr-api/permissions.js.map +1 -1
  86. package/out/sbvr-api/sbvr-utils.d.ts +33 -15
  87. package/out/sbvr-api/sbvr-utils.js +397 -235
  88. package/out/sbvr-api/sbvr-utils.js.map +1 -1
  89. package/out/sbvr-api/translations.d.ts +6 -0
  90. package/out/sbvr-api/translations.js +150 -0
  91. package/out/sbvr-api/translations.js.map +1 -0
  92. package/out/sbvr-api/uri-parser.d.ts +23 -17
  93. package/out/sbvr-api/uri-parser.js +33 -27
  94. package/out/sbvr-api/uri-parser.js.map +1 -1
  95. package/out/sbvr-api/user.sbvr +2 -0
  96. package/out/server-glue/module.d.ts +6 -6
  97. package/out/server-glue/module.js +4 -2
  98. package/out/server-glue/module.js.map +1 -1
  99. package/out/server-glue/server.js +5 -5
  100. package/out/server-glue/server.js.map +1 -1
  101. package/package.json +89 -73
  102. package/pinejs.png +0 -0
  103. package/repo.yml +9 -9
  104. package/src/bin/abstract-sql-compiler.ts +5 -7
  105. package/src/bin/odata-compiler.ts +11 -13
  106. package/src/bin/sbvr-compiler.ts +11 -17
  107. package/src/bin/utils.ts +3 -5
  108. package/src/config-loader/config-loader.ts +167 -53
  109. package/src/config-loader/env.ts +106 -6
  110. package/src/data-server/sbvr-server.js +44 -38
  111. package/src/database-layer/db.ts +205 -64
  112. package/src/express-emulator/express.js +10 -11
  113. package/src/http-transactions/transactions.js +29 -21
  114. package/src/migrator/async.ts +323 -0
  115. package/src/migrator/migrations.sbvr +43 -0
  116. package/src/migrator/sync.ts +152 -0
  117. package/src/migrator/utils.ts +458 -0
  118. package/src/odata-metadata/odata-metadata-generator.ts +12 -15
  119. package/src/passport-pinejs/passport-pinejs.ts +9 -7
  120. package/src/pinejs-session-store/pinejs-session-store.ts +15 -1
  121. package/src/sbvr-api/abstract-sql.ts +17 -14
  122. package/src/sbvr-api/common-types.ts +2 -1
  123. package/src/sbvr-api/control-flow.ts +45 -11
  124. package/src/sbvr-api/errors.ts +82 -77
  125. package/src/sbvr-api/express-extension.ts +6 -1
  126. package/src/sbvr-api/hooks.ts +123 -50
  127. package/src/sbvr-api/odata-response.ts +23 -28
  128. package/src/sbvr-api/permissions.ts +548 -415
  129. package/src/sbvr-api/sbvr-utils.ts +581 -259
  130. package/src/sbvr-api/translations.ts +248 -0
  131. package/src/sbvr-api/uri-parser.ts +63 -49
  132. package/src/sbvr-api/user.sbvr +2 -0
  133. package/src/server-glue/module.ts +16 -10
  134. package/src/server-glue/server.ts +5 -5
  135. package/tsconfig.dev.json +1 -0
  136. package/tsconfig.json +1 -2
  137. package/typings/lf-to-abstract-sql.d.ts +6 -9
  138. package/typings/memoizee.d.ts +1 -1
  139. package/.github/CODEOWNERS +0 -1
  140. package/circle.yml +0 -37
  141. package/docs/todo.txt +0 -22
  142. package/out/migrator/migrator.d.ts +0 -20
  143. package/out/migrator/migrator.js +0 -188
  144. package/out/migrator/migrator.js.map +0 -1
  145. package/src/migrator/migrator.ts +0 -286
package/circle.yml DELETED
@@ -1,37 +0,0 @@
1
- version: 2
2
-
3
- buildSteps: &buildSteps
4
- - checkout
5
- - run:
6
- name: Install
7
- command: npm install --loglevel warn
8
- - run:
9
- name: Test
10
- command: npm test --loglevel warn
11
-
12
- jobs:
13
- node-10:
14
- docker:
15
- - image: circleci/node:10
16
- working_directory: ~/node-10
17
- steps: *buildSteps
18
-
19
- node-12:
20
- docker:
21
- - image: circleci/node:12
22
- working_directory: ~/node-12
23
- steps: *buildSteps
24
-
25
- node-14:
26
- docker:
27
- - image: circleci/node:14
28
- working_directory: ~/node-14
29
- steps: *buildSteps
30
-
31
- workflows:
32
- version: 2
33
- build:
34
- jobs:
35
- - node-10
36
- - node-12
37
- - node-14
package/docs/todo.txt DELETED
@@ -1,22 +0,0 @@
1
- Canvas TODO:
2
- Milestone 1: SBVR Editor
3
- Chrome App
4
-
5
- Milestone 2: (Black Swan)
6
- Update Running Model (Rules only)
7
- Revise model leads to model tab (and current request URI is somehow stored in model tab URI?)
8
- Then, when model is updated, success msgbox gives link back to request.
9
-
10
- Action Items:
11
- Update button should send new model to server.
12
- Server should compare models to see if change is allowed. (eeeasy)
13
- If no, revert model (and explain)
14
- If yes, apply new model (and declare success)
15
- 'Revise Model' button should redirect to the model screen
16
- with cached request
17
- Update success should direct to return to pending request
18
- Pending request should be noted in UI with [continue] link.
19
-
20
- Milestone 3: (IAH)
21
- Logical operators (and/or)
22
- Attributes
@@ -1,20 +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 { Engines } from '@balena/abstract-sql-compiler';
5
- import { TypedError } from 'typed-error';
6
- import * as sbvrUtils from '../sbvr-api/sbvr-utils';
7
- declare type ApiRootModel = Model & {
8
- apiRoot: string;
9
- };
10
- declare type SbvrUtils = typeof sbvrUtils;
11
- export declare type MigrationFn = (tx: Tx, sbvrUtils: SbvrUtils) => Resolvable<void>;
12
- export declare type Migration = string | MigrationFn | {
13
- [dbEngine in Engines]?: string | MigrationFn;
14
- };
15
- export declare class MigrationError extends TypedError {
16
- }
17
- export declare const postRun: (tx: Tx, model: ApiRootModel) => Promise<void>;
18
- export declare const run: (tx: Tx, model: ApiRootModel) => Promise<void>;
19
- export declare const config: Config;
20
- export {};
@@ -1,188 +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 Bluebird = require("bluebird");
5
- const _ = require("lodash");
6
- const typed_error_1 = require("typed-error");
7
- const env_1 = require("../config-loader/env");
8
- const sbvrUtils = require("../sbvr-api/sbvr-utils");
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 Bluebird.using(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 Bluebird.using(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
- 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 = (tx, modelName) => Bluebird.try(async () => {
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 Bluebird.delay(env_1.migrator.lockFailDelay);
125
- throw err;
126
- }
127
- }).disposer(async () => {
128
- try {
129
- await tx.executeSql(binds `
130
- DELETE FROM "migration lock"
131
- WHERE "model name" = ${1}`, [modelName]);
132
- }
133
- catch (_a) {
134
- }
135
- });
136
- const executeMigrations = async (tx, migrations = []) => {
137
- var _a, _b;
138
- try {
139
- for (const migration of migrations) {
140
- await executeMigration(tx, migration);
141
- }
142
- }
143
- catch (err) {
144
- ((_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');
145
- throw new MigrationError(err);
146
- }
147
- return migrations.map(([migrationKey]) => migrationKey);
148
- };
149
- const executeMigration = async (tx, [key, migration]) => {
150
- var _a, _b;
151
- ((_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)}`);
152
- if (migration != null && typeof migration === 'object') {
153
- const m = migration[tx.engine];
154
- if (m == null) {
155
- throw new MigrationError(`Missing migration entry for '${key}' on db engine '${tx.engine}'`);
156
- }
157
- migration = m;
158
- }
159
- if (typeof migration === 'function') {
160
- await migration(tx, sbvrUtils);
161
- }
162
- else if (typeof migration === 'string') {
163
- await tx.executeSql(migration);
164
- }
165
- else {
166
- throw new MigrationError(`Invalid migration type: ${typeof migration}`);
167
- }
168
- };
169
- exports.config = {
170
- models: [
171
- {
172
- modelName: 'migrations',
173
- apiRoot: 'migrations',
174
- modelText,
175
- migrations: {
176
- '11.0.0-modified-at': `
177
- ALTER TABLE "migration"
178
- ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
179
- `,
180
- '11.0.1-modified-at': `
181
- ALTER TABLE "migration lock"
182
- ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
183
- `,
184
- },
185
- },
186
- ],
187
- };
188
- //# 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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"}
@@ -1,286 +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 Bluebird from 'bluebird';
7
- import * as _ from 'lodash';
8
- import { TypedError } from 'typed-error';
9
- import { migrator as migratorEnv } from '../config-loader/env';
10
- import * as sbvrUtils from '../sbvr-api/sbvr-utils';
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 =
24
- | string
25
- | MigrationFn
26
- | {
27
- [dbEngine in Engines]?: string | MigrationFn;
28
- };
29
-
30
- export class MigrationError extends TypedError {}
31
-
32
- // Tagged template to convert binds from `?` format to the necessary output format,
33
- // eg `$1`/`$2`/etc for postgres
34
- const binds = (strings: TemplateStringsArray, ...bindNums: number[]) =>
35
- strings
36
- .map((str, i) => {
37
- if (i === bindNums.length) {
38
- return str;
39
- }
40
- if (i + 1 !== bindNums[i]) {
41
- throw new SyntaxError('Migration sql binds must be sequential');
42
- }
43
- if (sbvrUtils.db.engine === Engines.postgres) {
44
- return str + `$${bindNums[i]}`;
45
- }
46
- return str + `?`;
47
- })
48
- .join('');
49
-
50
- export const postRun = async (tx: Tx, model: ApiRootModel): Promise<void> => {
51
- const { initSql } = model;
52
- if (initSql == null) {
53
- return;
54
- }
55
-
56
- const modelName = model.apiRoot;
57
-
58
- const exists = await checkModelAlreadyExists(tx, modelName);
59
- if (!exists) {
60
- (sbvrUtils.api.migrations?.logger.info ?? console.info)(
61
- 'First time executing, running init script',
62
- );
63
- await Bluebird.using(lockMigrations(tx, modelName), async () => {
64
- await tx.executeSql(initSql);
65
- });
66
- }
67
- };
68
-
69
- export const run = async (tx: Tx, model: ApiRootModel): Promise<void> => {
70
- const { migrations } = model;
71
- if (migrations == null || _.isEmpty(migrations)) {
72
- return;
73
- }
74
-
75
- const modelName = model.apiRoot;
76
-
77
- // migrations only run if the model has been executed before,
78
- // to make changes that can't be automatically applied
79
- const exists = await checkModelAlreadyExists(tx, modelName);
80
- if (!exists) {
81
- (sbvrUtils.api.migrations?.logger.info ?? console.info)(
82
- 'First time model has executed, skipping migrations',
83
- );
84
-
85
- return await setExecutedMigrations(tx, modelName, Object.keys(migrations));
86
- }
87
- await Bluebird.using(lockMigrations(tx, modelName), async () => {
88
- const executedMigrations = await getExecutedMigrations(tx, modelName);
89
- const pendingMigrations = filterAndSortPendingMigrations(
90
- migrations,
91
- executedMigrations,
92
- );
93
- if (pendingMigrations.length === 0) {
94
- return;
95
- }
96
-
97
- const newlyExecutedMigrations = await executeMigrations(
98
- tx,
99
- pendingMigrations,
100
- );
101
- await setExecutedMigrations(tx, modelName, [
102
- ...executedMigrations,
103
- ...newlyExecutedMigrations,
104
- ]);
105
- });
106
- };
107
-
108
- const checkModelAlreadyExists = async (
109
- tx: Tx,
110
- modelName: string,
111
- ): Promise<boolean> => {
112
- const result = await tx.tableList("name = 'migration'");
113
- if (result.rows.length === 0) {
114
- return false;
115
- }
116
- const { rows } = await tx.executeSql(
117
- binds`
118
- SELECT 1
119
- FROM "model"
120
- WHERE "model"."is of-vocabulary" = ${1}
121
- LIMIT 1`,
122
- [modelName],
123
- );
124
-
125
- return rows.length > 0;
126
- };
127
-
128
- const getExecutedMigrations = async (
129
- tx: Tx,
130
- modelName: string,
131
- ): Promise<string[]> => {
132
- const { rows } = await tx.executeSql(
133
- binds`
134
- SELECT "migration"."executed migrations" AS "executed_migrations"
135
- FROM "migration"
136
- WHERE "migration"."model name" = ${1}`,
137
- [modelName],
138
- );
139
-
140
- const data = rows[0];
141
- if (data == null) {
142
- return [];
143
- }
144
-
145
- return JSON.parse(data.executed_migrations) as string[];
146
- };
147
-
148
- const setExecutedMigrations = async (
149
- tx: Tx,
150
- modelName: string,
151
- executedMigrations: string[],
152
- ): Promise<void> => {
153
- const stringifiedMigrations = JSON.stringify(executedMigrations);
154
-
155
- const result = await tx.tableList("name = 'migration'");
156
- if (result.rows.length === 0) {
157
- return;
158
- }
159
-
160
- const { rowsAffected } = await tx.executeSql(
161
- binds`
162
- UPDATE "migration"
163
- SET "model name" = ${1},
164
- "executed migrations" = ${2}
165
- WHERE "migration"."model name" = ${3}`,
166
- [modelName, stringifiedMigrations, modelName],
167
- );
168
-
169
- if (rowsAffected === 0) {
170
- tx.executeSql(
171
- binds`
172
- INSERT INTO "migration" ("model name", "executed migrations")
173
- VALUES (${1}, ${2})`,
174
- [modelName, stringifiedMigrations],
175
- );
176
- }
177
- };
178
-
179
- // turns {"key1": migration, "key3": migration, "key2": migration}
180
- // into [["key1", migration], ["key2", migration], ["key3", migration]]
181
- const filterAndSortPendingMigrations = (
182
- migrations: NonNullable<Model['migrations']>,
183
- executedMigrations: string[],
184
- ): MigrationTuple[] =>
185
- (_(migrations).omit(executedMigrations) as _.Object<typeof migrations>)
186
- .toPairs()
187
- .sortBy(([migrationKey]) => migrationKey)
188
- .value();
189
-
190
- const lockMigrations = (tx: Tx, modelName: string): Bluebird.Disposer<void> =>
191
- Bluebird.try(async () => {
192
- try {
193
- await tx.executeSql(
194
- binds`
195
- DELETE FROM "migration lock"
196
- WHERE "model name" = ${1}
197
- AND "created at" < ${2}`,
198
- [modelName, new Date(Date.now() - migratorEnv.lockTimeout)],
199
- );
200
- await tx.executeSql(
201
- binds`
202
- INSERT INTO "migration lock" ("model name")
203
- VALUES (${1})`,
204
- [modelName],
205
- );
206
- } catch (err) {
207
- await Bluebird.delay(migratorEnv.lockFailDelay);
208
- throw err;
209
- }
210
- }).disposer(async () => {
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
- const executeMigrations = async (
226
- tx: Tx,
227
- migrations: MigrationTuple[] = [],
228
- ): Promise<string[]> => {
229
- try {
230
- for (const migration of migrations) {
231
- await executeMigration(tx, migration);
232
- }
233
- } catch (err) {
234
- (sbvrUtils.api.migrations?.logger.error ?? console.error)(
235
- 'Error while executing migrations, rolled back',
236
- );
237
- throw new MigrationError(err);
238
- }
239
- return migrations.map(([migrationKey]) => migrationKey); // return migration keys
240
- };
241
-
242
- const executeMigration = async (
243
- tx: Tx,
244
- [key, migration]: MigrationTuple,
245
- ): Promise<void> => {
246
- (sbvrUtils.api.migrations?.logger.info ?? console.info)(
247
- `Running migration ${JSON.stringify(key)}`,
248
- );
249
- if (migration != null && typeof migration === 'object') {
250
- const m = migration[tx.engine];
251
- if (m == null) {
252
- throw new MigrationError(
253
- `Missing migration entry for '${key}' on db engine '${tx.engine}'`,
254
- );
255
- }
256
- migration = m;
257
- }
258
-
259
- if (typeof migration === 'function') {
260
- await migration(tx, sbvrUtils);
261
- } else if (typeof migration === 'string') {
262
- await tx.executeSql(migration);
263
- } else {
264
- throw new MigrationError(`Invalid migration type: ${typeof migration}`);
265
- }
266
- };
267
-
268
- export const config: Config = {
269
- models: [
270
- {
271
- modelName: 'migrations',
272
- apiRoot: 'migrations',
273
- modelText,
274
- migrations: {
275
- '11.0.0-modified-at': `
276
- ALTER TABLE "migration"
277
- ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
278
- `,
279
- '11.0.1-modified-at': `
280
- ALTER TABLE "migration lock"
281
- ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
282
- `,
283
- },
284
- },
285
- ],
286
- };