@balena/pinejs 20.0.2-build-compile-in-as-eq-any-cdd3d0c80b63550d7316739dc6050ed1382f8009-1 → 20.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,15 +1,15 @@
|
|
1
1
|
- commits:
|
2
|
-
- subject:
|
3
|
-
hash:
|
2
|
+
- subject: "Migrations.md: Update the rollbackable migrations guide"
|
3
|
+
hash: 192216f3f07fa8637bc024bb634227d1b09b26d8
|
4
4
|
body: ""
|
5
5
|
footer:
|
6
6
|
Change-type: patch
|
7
7
|
change-type: patch
|
8
|
-
author:
|
8
|
+
author: Thodoris Greasidis
|
9
9
|
nested: []
|
10
10
|
version: 20.0.2
|
11
11
|
title: ""
|
12
|
-
date: 2025-02-
|
12
|
+
date: 2025-02-04T08:58:30.428Z
|
13
13
|
- commits:
|
14
14
|
- subject: Update postgres Docker tag to v17
|
15
15
|
hash: cfd7adeb986bad2fa6bfdf266ffd36c50c30a9f9
|
package/CHANGELOG.md
CHANGED
@@ -7,7 +7,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
7
7
|
# v20.0.2
|
8
8
|
## (2025-02-04)
|
9
9
|
|
10
|
-
*
|
10
|
+
* Migrations.md: Update the rollbackable migrations guide [Thodoris Greasidis]
|
11
11
|
|
12
12
|
# v20.0.1
|
13
13
|
## (2025-01-21)
|
package/docs/Migrations.md
CHANGED
@@ -65,23 +65,6 @@ Async migrations are stored in the migrations folder, alongside synchronous migr
|
|
65
65
|
The async migration query must have a `LIMIT` statement to limit the maximum number of affected rows per batch.
|
66
66
|
|
67
67
|
|
68
|
-
### Async migration procedure
|
69
|
-
* Deployment 1
|
70
|
-
- Add new column (with independent sync migration) to contain new data and add code accessing the new column.
|
71
|
-
- Update the service's implementation to set both the old & new column on each write.
|
72
|
-
- The service's implementation should only read the old column since the async migration still migrates data from old column to new column.
|
73
|
-
- Async migrator runs forever.
|
74
|
-
* Deployment 2
|
75
|
-
- Finalize async migration => only sync migration part gets executed.
|
76
|
-
- Sync migration migrates all left over data from old column to new column.
|
77
|
-
- Update the service's implementation to only read the new column, but still write the old one as well.
|
78
|
-
- Mark the old field as optional in the sbvr if it isn't, or set a default value for it.
|
79
|
-
* Deployment 3
|
80
|
-
- Update the service's implementation to stop settings the old column and remove it from the sbvr.
|
81
|
-
- Make the old field NULLable if it isn't.
|
82
|
-
* Deployment 4
|
83
|
-
- Delete the old column with a sync migration.
|
84
|
-
|
85
68
|
### TS migration file format with SQL query string
|
86
69
|
|
87
70
|
The placeholder `%%ASYNC_BATCH_SIZE%%` will be replaced with the value specified by asyncBatchSize parameter
|
@@ -147,4 +130,35 @@ export = {
|
|
147
130
|
|
148
131
|
```
|
149
132
|
### SQL query file (plain text)
|
150
|
-
Plain SQL files are not supported as they cannot bundle async and sync migration statements in one file. Moreover they cannot carry migration metadata.
|
133
|
+
Plain SQL files are not supported as they cannot bundle async and sync migration statements in one file. Moreover they cannot carry migration metadata.
|
134
|
+
|
135
|
+
## Rollbackable no-down-time suggested migration procedure
|
136
|
+
|
137
|
+
* Deployment 1
|
138
|
+
- Add the new column with an independent sync migration.
|
139
|
+
- Add an Async migrator that starts migrating data from the old column to new column (optional optimization for big tables).
|
140
|
+
- Update the service's implementation to set both the old & new column on each write.
|
141
|
+
The service's implementation should only read the old column, since not all data has been migrated to the new column yet.
|
142
|
+
* Deployment 2
|
143
|
+
- Complete the data migration from the old to the new column:
|
144
|
+
- Either finalize the async migration from deployment 1 if you are using one.
|
145
|
+
This causes the sync part of the migration to execute.
|
146
|
+
- Or write a sync migration otherwise.
|
147
|
+
- Mark the new column as non-NULL if applicable as part of the above migration.
|
148
|
+
- Update the service's implementation to only read the new column, but still write to the old one as well.
|
149
|
+
- Test that the implementation works even if we keep the old column as NOT NULLable.
|
150
|
+
This makes sure that older service instances can still work during the deployment.
|
151
|
+
- Only then mark the old field as NULLable if it isn't.
|
152
|
+
* Deployment 3
|
153
|
+
- Update the service's implementation to stop writing to the old column.
|
154
|
+
- Remove the old column from the SBVR, and add it in the `initSql`/`initSqlPath` of the model
|
155
|
+
(so that the SBVR & DB stay in sync) with a TODO to DROP it from the DB in a follow-up.
|
156
|
+
The old column needs to stay in the DB so that older service instances can still work during the deployment.
|
157
|
+
* Deployment 4
|
158
|
+
- DROP the old column with a sync migration.
|
159
|
+
|
160
|
+
### Testing rollbacks
|
161
|
+
For each step, be sure and utilize testing to ensure you can safely rollback to previous versions of your service even with the updated database schemas (with data) deployed.
|
162
|
+
Before merging each step, try rolling back your development environment to the previous deployment and make sure that everything still works without issues.
|
163
|
+
The old deployment should be able to operate with DB records created by the new deployment and leave the DB in a valid state.
|
164
|
+
Eg: While testing the PR for deployment 2 on your development environment, make sure that if you push deplpoyment 1 everything still works without issues.
|
@@ -46,7 +46,7 @@ export const getAndCheckBindValues = async (request, bindings) => {
|
|
46
46
|
const sqlModelTables = sbvrUtils.getAbstractSqlModel(request).tables;
|
47
47
|
return await Promise.all(bindings.map(async (binding) => {
|
48
48
|
let fieldName = '';
|
49
|
-
let
|
49
|
+
let field;
|
50
50
|
let value;
|
51
51
|
if (binding[0] === 'Bind') {
|
52
52
|
const bindValue = binding[1];
|
@@ -66,56 +66,46 @@ export const getAndCheckBindValues = async (request, bindings) => {
|
|
66
66
|
if (maybeField == null) {
|
67
67
|
throw new Error(`Could not find field '${fieldName}'`);
|
68
68
|
}
|
69
|
-
|
69
|
+
field = maybeField;
|
70
70
|
}
|
71
71
|
else if (Number.isInteger(bindValue)) {
|
72
72
|
if (bindValue >= odataBinds.length) {
|
73
73
|
console.error(`Invalid binding number '${bindValue}' for binds: `, odataBinds);
|
74
74
|
throw new Error('Invalid binding');
|
75
75
|
}
|
76
|
+
let dataType;
|
76
77
|
[dataType, value] = odataBinds[bindValue];
|
78
|
+
field = { dataType };
|
77
79
|
}
|
78
80
|
else if (typeof bindValue === 'string') {
|
79
81
|
if (!Object.hasOwn(odataBinds, bindValue)) {
|
80
82
|
console.error(`Invalid binding '${bindValue}' for binds: `, odataBinds);
|
81
83
|
throw new Error('Invalid binding');
|
82
84
|
}
|
85
|
+
let dataType;
|
83
86
|
[dataType, value] = odataBinds[bindValue];
|
87
|
+
field = { dataType };
|
84
88
|
}
|
85
89
|
else {
|
86
90
|
throw new Error(`Unknown binding: ${binding}`);
|
87
91
|
}
|
88
92
|
}
|
89
93
|
else {
|
94
|
+
let dataType;
|
90
95
|
[dataType, value] = binding;
|
96
|
+
field = { dataType };
|
91
97
|
}
|
92
98
|
if (value === undefined) {
|
93
99
|
throw new Error(`Bind value cannot be undefined: ${binding}`);
|
94
100
|
}
|
95
101
|
try {
|
96
|
-
return await
|
102
|
+
return await AbstractSQLCompiler[engine].dataTypeValidate(value, field);
|
97
103
|
}
|
98
104
|
catch (err) {
|
99
105
|
throw new BadRequestError(`"${fieldName}" ${err.message}`);
|
100
106
|
}
|
101
107
|
}));
|
102
108
|
};
|
103
|
-
const validateBindingType = async (engine, $value, $dataType) => {
|
104
|
-
if ($dataType === 'List') {
|
105
|
-
if (!Array.isArray($value)) {
|
106
|
-
throw new Error('List value binding must be an array');
|
107
|
-
}
|
108
|
-
return await Promise.all($value.map(async ([dataType, value]) => {
|
109
|
-
if (dataType === 'Null') {
|
110
|
-
return null;
|
111
|
-
}
|
112
|
-
return await validateBindingType(engine, value, dataType);
|
113
|
-
}));
|
114
|
-
}
|
115
|
-
return await AbstractSQLCompiler[engine].dataTypeValidate($value, {
|
116
|
-
dataType: $dataType,
|
117
|
-
});
|
118
|
-
};
|
119
109
|
const checkModifiedFields = (ruleReferencedFields, modifiedFields) => {
|
120
110
|
const refs = ruleReferencedFields[modifiedFields.table];
|
121
111
|
if (refs == null) {
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"abstract-sql.js","sourceRoot":"","sources":["../../src/sbvr-api/abstract-sql.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,QAAQ,CAAC;
|
1
|
+
{"version":3,"file":"abstract-sql.js","sourceRoot":"","sources":["../../src/sbvr-api/abstract-sql.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@balena/pinejs",
|
3
|
-
"version": "20.0.2
|
3
|
+
"version": "20.0.2",
|
4
4
|
"main": "out/server-glue/module.js",
|
5
5
|
"type": "module",
|
6
6
|
"repository": "git@github.com:balena-io/pinejs.git",
|
@@ -26,12 +26,12 @@
|
|
26
26
|
"generate-types": "node ./bin/sbvr-compiler.js generate-types ./src/sbvr-api/user.sbvr ./src/sbvr-api/user.ts && node ./bin/sbvr-compiler.js generate-types ./src/migrator/migrations.sbvr ./src/migrator/migrations.ts && node ./bin/sbvr-compiler.js generate-types ./src/sbvr-api/dev.sbvr ./src/sbvr-api/dev.ts && node ./bin/sbvr-compiler.js generate-types ./src/tasks/tasks.sbvr ./src/tasks/tasks.ts && balena-lint -t tsconfig.dev.json --fix ./src/sbvr-api/user.ts ./src/migrator/migrations.ts ./src/sbvr-api/dev.ts"
|
27
27
|
},
|
28
28
|
"dependencies": {
|
29
|
-
"@balena/abstract-sql-compiler": "^10.
|
29
|
+
"@balena/abstract-sql-compiler": "^10.1.0",
|
30
30
|
"@balena/abstract-sql-to-typescript": "^5.1.0",
|
31
31
|
"@balena/env-parsing": "^1.2.0",
|
32
32
|
"@balena/lf-to-abstract-sql": "^5.0.3",
|
33
|
-
"@balena/odata-parser": "
|
34
|
-
"@balena/odata-to-abstract-sql": "7.
|
33
|
+
"@balena/odata-parser": "^3.1.2",
|
34
|
+
"@balena/odata-to-abstract-sql": "^7.0.1",
|
35
35
|
"@balena/sbvr-parser": "^1.4.6",
|
36
36
|
"@balena/sbvr-types": "^9.1.0",
|
37
37
|
"@types/body-parser": "^1.19.5",
|
@@ -148,6 +148,6 @@
|
|
148
148
|
"recursive": true
|
149
149
|
},
|
150
150
|
"versionist": {
|
151
|
-
"publishedAt": "2025-02-
|
151
|
+
"publishedAt": "2025-02-04T08:58:31.332Z"
|
152
152
|
}
|
153
153
|
}
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import _ from 'lodash';
|
2
2
|
|
3
|
-
import type { Engines } from '@balena/abstract-sql-compiler';
|
4
3
|
import AbstractSQLCompiler from '@balena/abstract-sql-compiler';
|
5
4
|
import type { BindKey } from '@balena/odata-parser';
|
6
5
|
import {
|
@@ -79,7 +78,7 @@ export const getAndCheckBindValues = async (
|
|
79
78
|
return await Promise.all(
|
80
79
|
bindings.map(async (binding) => {
|
81
80
|
let fieldName = '';
|
82
|
-
let dataType: string;
|
81
|
+
let field: { dataType: string };
|
83
82
|
let value: any;
|
84
83
|
if (binding[0] === 'Bind') {
|
85
84
|
const bindValue = binding[1];
|
@@ -104,7 +103,7 @@ export const getAndCheckBindValues = async (
|
|
104
103
|
if (maybeField == null) {
|
105
104
|
throw new Error(`Could not find field '${fieldName}'`);
|
106
105
|
}
|
107
|
-
|
106
|
+
field = maybeField;
|
108
107
|
} else if (Number.isInteger(bindValue)) {
|
109
108
|
if (bindValue >= odataBinds.length) {
|
110
109
|
console.error(
|
@@ -113,7 +112,9 @@ export const getAndCheckBindValues = async (
|
|
113
112
|
);
|
114
113
|
throw new Error('Invalid binding');
|
115
114
|
}
|
115
|
+
let dataType;
|
116
116
|
[dataType, value] = odataBinds[bindValue];
|
117
|
+
field = { dataType };
|
117
118
|
} else if (typeof bindValue === 'string') {
|
118
119
|
if (!Object.hasOwn(odataBinds, bindValue)) {
|
119
120
|
console.error(
|
@@ -122,12 +123,16 @@ export const getAndCheckBindValues = async (
|
|
122
123
|
);
|
123
124
|
throw new Error('Invalid binding');
|
124
125
|
}
|
126
|
+
let dataType;
|
125
127
|
[dataType, value] = odataBinds[bindValue as BindKey];
|
128
|
+
field = { dataType };
|
126
129
|
} else {
|
127
130
|
throw new Error(`Unknown binding: ${binding}`);
|
128
131
|
}
|
129
132
|
} else {
|
133
|
+
let dataType;
|
130
134
|
[dataType, value] = binding;
|
135
|
+
field = { dataType };
|
131
136
|
}
|
132
137
|
|
133
138
|
if (value === undefined) {
|
@@ -135,7 +140,7 @@ export const getAndCheckBindValues = async (
|
|
135
140
|
}
|
136
141
|
|
137
142
|
try {
|
138
|
-
return await
|
143
|
+
return await AbstractSQLCompiler[engine].dataTypeValidate(value, field);
|
139
144
|
} catch (err: any) {
|
140
145
|
throw new BadRequestError(`"${fieldName}" ${err.message}`);
|
141
146
|
}
|
@@ -143,30 +148,6 @@ export const getAndCheckBindValues = async (
|
|
143
148
|
);
|
144
149
|
};
|
145
150
|
|
146
|
-
const validateBindingType = async (
|
147
|
-
engine: Engines,
|
148
|
-
$value: any,
|
149
|
-
$dataType: string,
|
150
|
-
): Promise<any> => {
|
151
|
-
if ($dataType === 'List') {
|
152
|
-
if (!Array.isArray($value)) {
|
153
|
-
throw new Error('List value binding must be an array');
|
154
|
-
}
|
155
|
-
return await Promise.all(
|
156
|
-
$value.map(async ([dataType, value]: [string, any]) => {
|
157
|
-
// Null is a special case for list values
|
158
|
-
if (dataType === 'Null') {
|
159
|
-
return null;
|
160
|
-
}
|
161
|
-
return await validateBindingType(engine, value, dataType);
|
162
|
-
}),
|
163
|
-
);
|
164
|
-
}
|
165
|
-
return await AbstractSQLCompiler[engine].dataTypeValidate($value, {
|
166
|
-
dataType: $dataType,
|
167
|
-
});
|
168
|
-
};
|
169
|
-
|
170
151
|
const checkModifiedFields = (
|
171
152
|
ruleReferencedFields: AbstractSQLCompiler.RuleReferencedFields,
|
172
153
|
modifiedFields: AbstractSQLCompiler.ModifiedFields,
|