remult 0.25.8 → 0.26.0
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.
- package/README.md +194 -129
- package/esm/graphql.js +131 -59
- package/esm/index.js +1 -1
- package/esm/migrations/compare-migration-snapshots.js +61 -0
- package/esm/migrations/generate-migrations.js +68 -0
- package/esm/migrations/index.js +2 -0
- package/esm/migrations/migrate.js +90 -0
- package/esm/migrations/migration-types.js +36 -0
- package/esm/migrations/update-migrations-ts-file.js +115 -0
- package/esm/postgres/postgres-data-provider.js +24 -3
- package/esm/postgres/schema-builder.js +35 -26
- package/esm/remult-better-sqlite3.js +47 -0
- package/esm/remult-bun-sqlite.js +41 -0
- package/esm/remult-knex/index.js +180 -51
- package/esm/remult-mongo.js +2 -2
- package/esm/remult-sql-js.js +3 -78
- package/esm/remult-sqlite-core.js +104 -0
- package/esm/server/expressBridge.js +130 -29
- package/esm/server/initAsyncHooks.js +75 -1
- package/esm/src/CompoundIdField.js +8 -2
- package/esm/src/context.js +20 -24
- package/esm/src/data-api.js +71 -30
- package/esm/src/data-providers/rest-data-provider.js +17 -15
- package/esm/src/data-providers/sql-database.js +32 -7
- package/esm/src/data-providers/web-sql-data-provider.js +1 -9
- package/esm/src/filter/filter-consumer-bridge-to-sql-request.js +37 -11
- package/esm/src/filter/filter-interfaces.js +229 -17
- package/esm/src/isOfType.js +9 -0
- package/esm/src/remult3/Fields.js +70 -18
- package/esm/src/remult3/RepositoryImplementation.js +47 -21
- package/esm/src/remult3/addValidator.js +15 -0
- package/esm/src/remult3/remult3.js +28 -57
- package/esm/src/server-action.js +4 -4
- package/esm/src/validators.js +6 -3
- package/esm/src/valueConverters.js +1 -1
- package/graphql.js +156 -71
- package/index.d.ts +4 -4
- package/index.js +2 -1
- package/migrations/compare-migration-snapshots.d.ts +27 -0
- package/migrations/compare-migration-snapshots.js +165 -0
- package/migrations/generate-migrations.d.ts +21 -0
- package/migrations/generate-migrations.js +104 -0
- package/migrations/index.d.ts +3 -0
- package/migrations/index.js +7 -0
- package/migrations/migrate.d.ts +27 -0
- package/migrations/migrate.js +175 -0
- package/migrations/migration-types.d.ts +48 -0
- package/migrations/migration-types.js +88 -0
- package/migrations/update-migrations-ts-file.d.ts +1 -0
- package/migrations/update-migrations-ts-file.js +141 -0
- package/package.json +21 -1
- package/postgres/postgres-data-provider.d.ts +8 -3
- package/postgres/postgres-data-provider.js +46 -3
- package/postgres/schema-builder.js +81 -48
- package/remult-better-sqlite3.d.ts +12 -0
- package/remult-better-sqlite3.js +64 -0
- package/remult-bun-sqlite.d.ts +11 -0
- package/remult-bun-sqlite.js +56 -0
- package/remult-knex/index.d.ts +12 -5
- package/remult-knex/index.js +257 -90
- package/remult-mongo.d.ts +2 -2
- package/remult-mongo.js +2 -2
- package/remult-sql-js.d.ts +2 -15
- package/remult-sql-js.js +11 -152
- package/remult-sqlite-core.d.ts +21 -0
- package/remult-sqlite-core.js +217 -0
- package/server/expressBridge.d.ts +30 -1
- package/server/expressBridge.js +140 -32
- package/server/initAsyncHooks.d.ts +16 -0
- package/server/initAsyncHooks.js +128 -2
- package/src/CompoundIdField.js +8 -2
- package/src/column-interfaces.d.ts +9 -3
- package/src/context.d.ts +8 -6
- package/src/context.js +27 -36
- package/src/data-api.d.ts +13 -9
- package/src/data-api.js +184 -135
- package/src/data-providers/rest-data-provider.js +26 -15
- package/src/data-providers/sql-database.d.ts +17 -5
- package/src/data-providers/sql-database.js +31 -7
- package/src/data-providers/web-sql-data-provider.d.ts +1 -2
- package/src/data-providers/web-sql-data-provider.js +4 -8
- package/src/entity.d.ts +64 -6
- package/src/filter/filter-consumer-bridge-to-sql-request.d.ts +31 -7
- package/src/filter/filter-consumer-bridge-to-sql-request.js +46 -21
- package/src/filter/filter-interfaces.d.ts +106 -39
- package/src/filter/filter-interfaces.js +312 -32
- package/src/isOfType.d.ts +2 -0
- package/src/isOfType.js +14 -0
- package/src/remult3/Fields.d.ts +36 -0
- package/src/remult3/Fields.js +81 -19
- package/src/remult3/RepositoryImplementation.d.ts +7 -3
- package/src/remult3/RepositoryImplementation.js +106 -71
- package/src/remult3/addValidator.d.ts +2 -0
- package/src/remult3/addValidator.js +20 -0
- package/src/remult3/remult3.d.ts +6 -2
- package/src/remult3/remult3.js +28 -57
- package/src/server-action.d.ts +1 -1
- package/src/server-action.js +5 -4
- package/src/sql-command.d.ts +6 -1
- package/src/validators.d.ts +1 -0
- package/src/validators.js +10 -4
- package/src/valueConverters.js +1 -1
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.emptySnapshot = exports.compareMigrationSnapshot = void 0;
|
|
4
|
+
var tslib_1 = require("tslib");
|
|
5
|
+
var index_js_1 = require("../index.js");
|
|
6
|
+
var filter_consumer_bridge_to_sql_request_js_1 = require("../src/filter/filter-consumer-bridge-to-sql-request.js");
|
|
7
|
+
function compareMigrationSnapshot(_a) {
|
|
8
|
+
var entities = _a.entities, snapshot = _a.snapshot, migrationBuilder = _a.migrationBuilder, reporter = _a.reporter;
|
|
9
|
+
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
10
|
+
var processedEntities, entities_1, entities_1_1, entity, meta, e, entitySnapshot, createColumns, processedColumns, _b, _c, field, columnDbName, column, e_1_1, _d, _e, columnDbName, e_2_1, e_3_1, _f, _g, entityDbName, e_4_1;
|
|
11
|
+
var e_3, _h, e_1, _j, e_2, _k, e_4, _l;
|
|
12
|
+
return tslib_1.__generator(this, function (_m) {
|
|
13
|
+
switch (_m.label) {
|
|
14
|
+
case 0:
|
|
15
|
+
snapshot = JSON.parse(JSON.stringify(snapshot));
|
|
16
|
+
processedEntities = new Set();
|
|
17
|
+
_m.label = 1;
|
|
18
|
+
case 1:
|
|
19
|
+
_m.trys.push([1, 23, 24, 25]);
|
|
20
|
+
entities_1 = tslib_1.__values(entities), entities_1_1 = entities_1.next();
|
|
21
|
+
_m.label = 2;
|
|
22
|
+
case 2:
|
|
23
|
+
if (!!entities_1_1.done) return [3 /*break*/, 22];
|
|
24
|
+
entity = entities_1_1.value;
|
|
25
|
+
meta = (0, index_js_1.repo)(entity).metadata;
|
|
26
|
+
return [4 /*yield*/, (0, filter_consumer_bridge_to_sql_request_js_1.dbNamesOf)(meta, function (x) { return x; })];
|
|
27
|
+
case 3:
|
|
28
|
+
e = _m.sent();
|
|
29
|
+
processedEntities.add(e.$entityName);
|
|
30
|
+
if (!(0, filter_consumer_bridge_to_sql_request_js_1.shouldCreateEntity)(meta, e)) return [3 /*break*/, 21];
|
|
31
|
+
entitySnapshot = snapshot.entities[e.$entityName];
|
|
32
|
+
createColumns = true;
|
|
33
|
+
if (!!entitySnapshot) return [3 /*break*/, 5];
|
|
34
|
+
createColumns = false;
|
|
35
|
+
reporter('create table ' + e.$entityName);
|
|
36
|
+
return [4 /*yield*/, migrationBuilder.createTable(meta)];
|
|
37
|
+
case 4:
|
|
38
|
+
_m.sent();
|
|
39
|
+
entitySnapshot = snapshot.entities[e.$entityName] = {
|
|
40
|
+
key: meta.key,
|
|
41
|
+
className: meta.entityType.name,
|
|
42
|
+
columns: {},
|
|
43
|
+
};
|
|
44
|
+
_m.label = 5;
|
|
45
|
+
case 5:
|
|
46
|
+
processedColumns = new Set();
|
|
47
|
+
_m.label = 6;
|
|
48
|
+
case 6:
|
|
49
|
+
_m.trys.push([6, 12, 13, 14]);
|
|
50
|
+
_b = (e_1 = void 0, tslib_1.__values(meta.fields)), _c = _b.next();
|
|
51
|
+
_m.label = 7;
|
|
52
|
+
case 7:
|
|
53
|
+
if (!!_c.done) return [3 /*break*/, 11];
|
|
54
|
+
field = _c.value;
|
|
55
|
+
if (!!(0, filter_consumer_bridge_to_sql_request_js_1.shouldNotCreateField)(field, e)) return [3 /*break*/, 10];
|
|
56
|
+
columnDbName = e.$dbNameOf(field);
|
|
57
|
+
processedColumns.add(columnDbName);
|
|
58
|
+
column = entitySnapshot.columns[columnDbName];
|
|
59
|
+
if (!!column) return [3 /*break*/, 10];
|
|
60
|
+
if (!createColumns) return [3 /*break*/, 9];
|
|
61
|
+
reporter('add column ' + e.$entityName + '.' + columnDbName);
|
|
62
|
+
return [4 /*yield*/, migrationBuilder.addColumn(meta, field)];
|
|
63
|
+
case 8:
|
|
64
|
+
_m.sent();
|
|
65
|
+
_m.label = 9;
|
|
66
|
+
case 9:
|
|
67
|
+
entitySnapshot.columns[columnDbName] = { key: field.key };
|
|
68
|
+
_m.label = 10;
|
|
69
|
+
case 10:
|
|
70
|
+
_c = _b.next();
|
|
71
|
+
return [3 /*break*/, 7];
|
|
72
|
+
case 11: return [3 /*break*/, 14];
|
|
73
|
+
case 12:
|
|
74
|
+
e_1_1 = _m.sent();
|
|
75
|
+
e_1 = { error: e_1_1 };
|
|
76
|
+
return [3 /*break*/, 14];
|
|
77
|
+
case 13:
|
|
78
|
+
try {
|
|
79
|
+
if (_c && !_c.done && (_j = _b.return)) _j.call(_b);
|
|
80
|
+
}
|
|
81
|
+
finally { if (e_1) throw e_1.error; }
|
|
82
|
+
return [7 /*endfinally*/];
|
|
83
|
+
case 14:
|
|
84
|
+
_m.trys.push([14, 19, 20, 21]);
|
|
85
|
+
_d = (e_2 = void 0, tslib_1.__values(Object.keys(entitySnapshot.columns))), _e = _d.next();
|
|
86
|
+
_m.label = 15;
|
|
87
|
+
case 15:
|
|
88
|
+
if (!!_e.done) return [3 /*break*/, 18];
|
|
89
|
+
columnDbName = _e.value;
|
|
90
|
+
if (!!processedColumns.has(columnDbName)) return [3 /*break*/, 17];
|
|
91
|
+
reporter('remove column ' + e.$entityName + '.' + columnDbName);
|
|
92
|
+
return [4 /*yield*/, migrationBuilder.removeColumn(e.$entityName, columnDbName)];
|
|
93
|
+
case 16:
|
|
94
|
+
_m.sent();
|
|
95
|
+
delete entitySnapshot.columns[columnDbName];
|
|
96
|
+
_m.label = 17;
|
|
97
|
+
case 17:
|
|
98
|
+
_e = _d.next();
|
|
99
|
+
return [3 /*break*/, 15];
|
|
100
|
+
case 18: return [3 /*break*/, 21];
|
|
101
|
+
case 19:
|
|
102
|
+
e_2_1 = _m.sent();
|
|
103
|
+
e_2 = { error: e_2_1 };
|
|
104
|
+
return [3 /*break*/, 21];
|
|
105
|
+
case 20:
|
|
106
|
+
try {
|
|
107
|
+
if (_e && !_e.done && (_k = _d.return)) _k.call(_d);
|
|
108
|
+
}
|
|
109
|
+
finally { if (e_2) throw e_2.error; }
|
|
110
|
+
return [7 /*endfinally*/];
|
|
111
|
+
case 21:
|
|
112
|
+
entities_1_1 = entities_1.next();
|
|
113
|
+
return [3 /*break*/, 2];
|
|
114
|
+
case 22: return [3 /*break*/, 25];
|
|
115
|
+
case 23:
|
|
116
|
+
e_3_1 = _m.sent();
|
|
117
|
+
e_3 = { error: e_3_1 };
|
|
118
|
+
return [3 /*break*/, 25];
|
|
119
|
+
case 24:
|
|
120
|
+
try {
|
|
121
|
+
if (entities_1_1 && !entities_1_1.done && (_h = entities_1.return)) _h.call(entities_1);
|
|
122
|
+
}
|
|
123
|
+
finally { if (e_3) throw e_3.error; }
|
|
124
|
+
return [7 /*endfinally*/];
|
|
125
|
+
case 25:
|
|
126
|
+
_m.trys.push([25, 30, 31, 32]);
|
|
127
|
+
_f = tslib_1.__values(Object.keys(snapshot.entities)), _g = _f.next();
|
|
128
|
+
_m.label = 26;
|
|
129
|
+
case 26:
|
|
130
|
+
if (!!_g.done) return [3 /*break*/, 29];
|
|
131
|
+
entityDbName = _g.value;
|
|
132
|
+
if (!!processedEntities.has(entityDbName)) return [3 /*break*/, 28];
|
|
133
|
+
reporter('remove table ' + entityDbName);
|
|
134
|
+
return [4 /*yield*/, migrationBuilder.removeTable(entityDbName)];
|
|
135
|
+
case 27:
|
|
136
|
+
_m.sent();
|
|
137
|
+
delete snapshot.entities[entityDbName];
|
|
138
|
+
_m.label = 28;
|
|
139
|
+
case 28:
|
|
140
|
+
_g = _f.next();
|
|
141
|
+
return [3 /*break*/, 26];
|
|
142
|
+
case 29: return [3 /*break*/, 32];
|
|
143
|
+
case 30:
|
|
144
|
+
e_4_1 = _m.sent();
|
|
145
|
+
e_4 = { error: e_4_1 };
|
|
146
|
+
return [3 /*break*/, 32];
|
|
147
|
+
case 31:
|
|
148
|
+
try {
|
|
149
|
+
if (_g && !_g.done && (_l = _f.return)) _l.call(_f);
|
|
150
|
+
}
|
|
151
|
+
finally { if (e_4) throw e_4.error; }
|
|
152
|
+
return [7 /*endfinally*/];
|
|
153
|
+
case 32: return [2 /*return*/, snapshot];
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
exports.compareMigrationSnapshot = compareMigrationSnapshot;
|
|
159
|
+
function emptySnapshot() {
|
|
160
|
+
return {
|
|
161
|
+
version: 1,
|
|
162
|
+
entities: {},
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
exports.emptySnapshot = emptySnapshot;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { DataProvider } from '../index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generates migration scripts based on changes in entities.
|
|
4
|
+
*
|
|
5
|
+
* @param options - Configuration options for generating migrations.
|
|
6
|
+
* @param options.entities - An array of entity classes whose changes will be included in the migration.
|
|
7
|
+
* @param options.dataProvider - The data provider instance or a function returning a promise of the data provider.
|
|
8
|
+
* @param options.migrationsFolder - (Optional) The path to the folder where migration scripts will be stored. Default is 'src/migrations'.
|
|
9
|
+
* @param options.snapshotFile - (Optional) The path to the file where the snapshot of the last known state will be stored. Default is 'migrations-snapshot.json' in the `migrationsFolder`.
|
|
10
|
+
* @param options.migrationsTSFile - (Optional) The path to the TypeScript file where the generated migrations will be written. Default is 'migrations.ts' in the `migrationsFolder`.
|
|
11
|
+
* @param options.endConnection - (Optional) Determines whether to close the database connection after generating migrations. Default is false.
|
|
12
|
+
* @see [Migrations](https://remult.dev/docs/migrations.html)
|
|
13
|
+
*/
|
|
14
|
+
export declare function generateMigrations(options: {
|
|
15
|
+
entities: any[];
|
|
16
|
+
dataProvider: DataProvider | Promise<DataProvider> | (() => Promise<DataProvider | undefined>);
|
|
17
|
+
migrationsFolder?: string;
|
|
18
|
+
snapshotFile?: string;
|
|
19
|
+
migrationsTSFile?: string;
|
|
20
|
+
endConnection?: boolean;
|
|
21
|
+
}): Promise<boolean>;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateMigrations = void 0;
|
|
4
|
+
var tslib_1 = require("tslib");
|
|
5
|
+
var path_1 = tslib_1.__importDefault(require("path"));
|
|
6
|
+
var fs_1 = tslib_1.__importDefault(require("fs"));
|
|
7
|
+
var compare_migration_snapshots_js_1 = require("./compare-migration-snapshots.js");
|
|
8
|
+
var update_migrations_ts_file_js_1 = require("./update-migrations-ts-file.js");
|
|
9
|
+
var migration_types_js_1 = require("./migration-types.js");
|
|
10
|
+
var isOfType_js_1 = require("../src/isOfType.js");
|
|
11
|
+
var initDataProvider_js_1 = require("../server/initDataProvider.js");
|
|
12
|
+
/**
|
|
13
|
+
* Generates migration scripts based on changes in entities.
|
|
14
|
+
*
|
|
15
|
+
* @param options - Configuration options for generating migrations.
|
|
16
|
+
* @param options.entities - An array of entity classes whose changes will be included in the migration.
|
|
17
|
+
* @param options.dataProvider - The data provider instance or a function returning a promise of the data provider.
|
|
18
|
+
* @param options.migrationsFolder - (Optional) The path to the folder where migration scripts will be stored. Default is 'src/migrations'.
|
|
19
|
+
* @param options.snapshotFile - (Optional) The path to the file where the snapshot of the last known state will be stored. Default is 'migrations-snapshot.json' in the `migrationsFolder`.
|
|
20
|
+
* @param options.migrationsTSFile - (Optional) The path to the TypeScript file where the generated migrations will be written. Default is 'migrations.ts' in the `migrationsFolder`.
|
|
21
|
+
* @param options.endConnection - (Optional) Determines whether to close the database connection after generating migrations. Default is false.
|
|
22
|
+
* @see [Migrations](https://remult.dev/docs/migrations.html)
|
|
23
|
+
*/
|
|
24
|
+
function generateMigrations(options) {
|
|
25
|
+
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
26
|
+
var migrationDir, snapshotFileName, migrationsTSFilename, dataProvider, _a, _b, p, snapshot, hasSql, steps, code, migrationBuilder, reporter;
|
|
27
|
+
var e_1, _c;
|
|
28
|
+
return tslib_1.__generator(this, function (_d) {
|
|
29
|
+
switch (_d.label) {
|
|
30
|
+
case 0:
|
|
31
|
+
migrationDir = options.migrationsFolder || path_1.default.join(process.cwd(), 'src/migrations');
|
|
32
|
+
snapshotFileName = options.snapshotFile || path_1.default.join(migrationDir, 'migrations-snapshot.json');
|
|
33
|
+
migrationsTSFilename = options.migrationsTSFile || path_1.default.join(migrationDir, 'migrations.ts');
|
|
34
|
+
return [4 /*yield*/, (0, initDataProvider_js_1.initDataProvider)(options.dataProvider)];
|
|
35
|
+
case 1:
|
|
36
|
+
dataProvider = _d.sent();
|
|
37
|
+
try {
|
|
38
|
+
for (_a = tslib_1.__values([snapshotFileName, migrationsTSFilename]), _b = _a.next(); !_b.done; _b = _a.next()) {
|
|
39
|
+
p = _b.value;
|
|
40
|
+
if (!fs_1.default.existsSync(path_1.default.dirname(p))) {
|
|
41
|
+
fs_1.default.mkdirSync(path_1.default.dirname(p), { recursive: true });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
46
|
+
finally {
|
|
47
|
+
try {
|
|
48
|
+
if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
|
|
49
|
+
}
|
|
50
|
+
finally { if (e_1) throw e_1.error; }
|
|
51
|
+
}
|
|
52
|
+
snapshot = (0, compare_migration_snapshots_js_1.emptySnapshot)();
|
|
53
|
+
if (fs_1.default.existsSync(snapshotFileName)) {
|
|
54
|
+
snapshot = JSON.parse(fs_1.default.readFileSync(snapshotFileName).toString());
|
|
55
|
+
}
|
|
56
|
+
hasSql = false;
|
|
57
|
+
steps = [];
|
|
58
|
+
code = {
|
|
59
|
+
//https://marketplace.visualstudio.com/items?itemName=qufiwefefwoyn.inline-sql-syntax
|
|
60
|
+
addSql: function (sql) {
|
|
61
|
+
steps.push('await sql(`--sql\n' + sql + '`)');
|
|
62
|
+
hasSql = true;
|
|
63
|
+
},
|
|
64
|
+
addTypescriptCode: function (code) { return steps.push(code); },
|
|
65
|
+
addComment: function (comment) {
|
|
66
|
+
return steps.push(comment.indexOf('\n') >= 0 ? "/*".concat(comment, "*/") : "// ".concat(comment));
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
migrationBuilder = new migration_types_js_1.DefaultMigrationBuilder(code);
|
|
70
|
+
if ((0, isOfType_js_1.isOfType)(dataProvider, 'provideMigrationBuilder')) {
|
|
71
|
+
migrationBuilder = new migration_types_js_1.DefaultMigrationBuilder(code, dataProvider.provideMigrationBuilder(code));
|
|
72
|
+
}
|
|
73
|
+
reporter = function (what) { return console.log('[generateMigrations] ' + what); };
|
|
74
|
+
return [4 /*yield*/, (0, compare_migration_snapshots_js_1.compareMigrationSnapshot)({
|
|
75
|
+
entities: options.entities,
|
|
76
|
+
snapshot: snapshot,
|
|
77
|
+
reporter: reporter,
|
|
78
|
+
migrationBuilder: migrationBuilder,
|
|
79
|
+
})];
|
|
80
|
+
case 2:
|
|
81
|
+
snapshot = _d.sent();
|
|
82
|
+
if (!steps.length) return [3 /*break*/, 4];
|
|
83
|
+
return [4 /*yield*/, (0, update_migrations_ts_file_js_1.updateMigrationsFile)(migrationsTSFilename, [
|
|
84
|
+
"async (".concat(hasSql ? '{sql}' : '', ")=>{\n").concat(steps.join('\n'), "\n}"),
|
|
85
|
+
])];
|
|
86
|
+
case 3:
|
|
87
|
+
_d.sent();
|
|
88
|
+
return [3 /*break*/, 5];
|
|
89
|
+
case 4:
|
|
90
|
+
reporter('No changes detected');
|
|
91
|
+
_d.label = 5;
|
|
92
|
+
case 5:
|
|
93
|
+
fs_1.default.writeFileSync(snapshotFileName, JSON.stringify(snapshot, null, 2));
|
|
94
|
+
if (!(options.endConnection && (0, isOfType_js_1.isOfType)(dataProvider, 'end'))) return [3 /*break*/, 7];
|
|
95
|
+
return [4 /*yield*/, dataProvider.end()];
|
|
96
|
+
case 6:
|
|
97
|
+
_d.sent();
|
|
98
|
+
_d.label = 7;
|
|
99
|
+
case 7: return [2 /*return*/, steps.length > 0];
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
exports.generateMigrations = generateMigrations;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.migrate = exports.generateMigrations = void 0;
|
|
4
|
+
var generate_migrations_js_1 = require("./generate-migrations.js");
|
|
5
|
+
Object.defineProperty(exports, "generateMigrations", { enumerable: true, get: function () { return generate_migrations_js_1.generateMigrations; } });
|
|
6
|
+
var migrate_js_1 = require("./migrate.js");
|
|
7
|
+
Object.defineProperty(exports, "migrate", { enumerable: true, get: function () { return migrate_js_1.migrate; } });
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type DataProvider } from '../index.js';
|
|
2
|
+
import type { Migrations } from './migration-types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Applies migration scripts to update the database schema.
|
|
5
|
+
*
|
|
6
|
+
* @param options - Configuration options for applying migrations.
|
|
7
|
+
* @param options.migrations - An object containing the migration scripts, each keyed by a unique identifier.
|
|
8
|
+
* @param options.dataProvider - The data provider instance or a function returning a promise of the data provider.
|
|
9
|
+
* @param options.migrationsTable - (Optional) The name of the table that tracks applied migrations. Default is '__remult_migrations_version'.
|
|
10
|
+
* @param options.endConnection - (Optional) Determines whether to close the database connection after applying migrations. Default is false.
|
|
11
|
+
* @param options.beforeMigration - (Optional) A callback function that is called before each migration is applied. Receives an object with the migration index.
|
|
12
|
+
* @param options.afterMigration - (Optional) A callback function that is called after each migration is applied. Receives an object with the migration index and the duration of the migration.
|
|
13
|
+
* @see [Migrations](https://remult.dev/docs/migrations.html)
|
|
14
|
+
*/
|
|
15
|
+
export declare function migrate(options: {
|
|
16
|
+
migrations: Migrations;
|
|
17
|
+
dataProvider: DataProvider | Promise<DataProvider> | (() => Promise<DataProvider | undefined>);
|
|
18
|
+
migrationsTable?: string;
|
|
19
|
+
endConnection?: boolean;
|
|
20
|
+
beforeMigration?: (info: {
|
|
21
|
+
index: number;
|
|
22
|
+
}) => void | Promise<void>;
|
|
23
|
+
afterMigration?: (info: {
|
|
24
|
+
index: number;
|
|
25
|
+
duration: number;
|
|
26
|
+
}) => void | Promise<void>;
|
|
27
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.migrate = void 0;
|
|
4
|
+
var tslib_1 = require("tslib");
|
|
5
|
+
var index_js_1 = require("../index.js");
|
|
6
|
+
var initDataProvider_js_1 = require("../server/initDataProvider.js");
|
|
7
|
+
var context_js_1 = require("../src/context.js");
|
|
8
|
+
var isOfType_js_1 = require("../src/isOfType.js");
|
|
9
|
+
/**
|
|
10
|
+
* Applies migration scripts to update the database schema.
|
|
11
|
+
*
|
|
12
|
+
* @param options - Configuration options for applying migrations.
|
|
13
|
+
* @param options.migrations - An object containing the migration scripts, each keyed by a unique identifier.
|
|
14
|
+
* @param options.dataProvider - The data provider instance or a function returning a promise of the data provider.
|
|
15
|
+
* @param options.migrationsTable - (Optional) The name of the table that tracks applied migrations. Default is '__remult_migrations_version'.
|
|
16
|
+
* @param options.endConnection - (Optional) Determines whether to close the database connection after applying migrations. Default is false.
|
|
17
|
+
* @param options.beforeMigration - (Optional) A callback function that is called before each migration is applied. Receives an object with the migration index.
|
|
18
|
+
* @param options.afterMigration - (Optional) A callback function that is called after each migration is applied. Receives an object with the migration index and the duration of the migration.
|
|
19
|
+
* @see [Migrations](https://remult.dev/docs/migrations.html)
|
|
20
|
+
*/
|
|
21
|
+
function migrate(options) {
|
|
22
|
+
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
23
|
+
var migrationTableName, dataProvider, prev, VersionInfo_1, steps_1;
|
|
24
|
+
var _this = this;
|
|
25
|
+
return tslib_1.__generator(this, function (_a) {
|
|
26
|
+
switch (_a.label) {
|
|
27
|
+
case 0:
|
|
28
|
+
migrationTableName = options.migrationsTable || '__remult_migrations_version';
|
|
29
|
+
return [4 /*yield*/, (0, initDataProvider_js_1.initDataProvider)(options.dataProvider)];
|
|
30
|
+
case 1:
|
|
31
|
+
dataProvider = _a.sent();
|
|
32
|
+
prev = index_js_1.remult.dataProvider;
|
|
33
|
+
index_js_1.remult.dataProvider = dataProvider;
|
|
34
|
+
_a.label = 2;
|
|
35
|
+
case 2:
|
|
36
|
+
_a.trys.push([2, , 6, 7]);
|
|
37
|
+
VersionInfo_1 = /** @class */ (function (_super) {
|
|
38
|
+
tslib_1.__extends(VersionInfo, _super);
|
|
39
|
+
function VersionInfo() {
|
|
40
|
+
var _this = _super !== null && _super.apply(this, arguments) || this;
|
|
41
|
+
_this.version = -1;
|
|
42
|
+
return _this;
|
|
43
|
+
}
|
|
44
|
+
tslib_1.__decorate([
|
|
45
|
+
index_js_1.Fields.number(),
|
|
46
|
+
tslib_1.__metadata("design:type", Object)
|
|
47
|
+
], VersionInfo_1.prototype, "version", void 0);
|
|
48
|
+
VersionInfo = tslib_1.__decorate([
|
|
49
|
+
(0, index_js_1.Entity)(migrationTableName)
|
|
50
|
+
], VersionInfo);
|
|
51
|
+
return VersionInfo;
|
|
52
|
+
}(index_js_1.IdEntity));
|
|
53
|
+
steps_1 = Object.entries(options.migrations).sort(function (_a, _b) {
|
|
54
|
+
var _c = tslib_1.__read(_a, 1), a = _c[0];
|
|
55
|
+
var _d = tslib_1.__read(_b, 1), b = _d[0];
|
|
56
|
+
return parseInt(a) - parseInt(b);
|
|
57
|
+
});
|
|
58
|
+
if (!dataProvider.ensureSchema) return [3 /*break*/, 4];
|
|
59
|
+
return [4 /*yield*/, dataProvider.ensureSchema([
|
|
60
|
+
new index_js_1.Remult(dataProvider).repo(VersionInfo_1).metadata,
|
|
61
|
+
])];
|
|
62
|
+
case 3:
|
|
63
|
+
_a.sent();
|
|
64
|
+
_a.label = 4;
|
|
65
|
+
case 4: return [4 /*yield*/, (0, context_js_1.doTransaction)(index_js_1.remult, function (dp) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
66
|
+
var repo, v, steps_2, steps_2_1, _a, stepText, action, step, startTime, utils, err_1, e_1_1;
|
|
67
|
+
var e_1, _b;
|
|
68
|
+
var _this = this;
|
|
69
|
+
return tslib_1.__generator(this, function (_c) {
|
|
70
|
+
switch (_c.label) {
|
|
71
|
+
case 0:
|
|
72
|
+
repo = new index_js_1.Remult(dataProvider).repo(VersionInfo_1, dp);
|
|
73
|
+
return [4 /*yield*/, repo.findFirst()];
|
|
74
|
+
case 1:
|
|
75
|
+
v = _c.sent();
|
|
76
|
+
if (!v) {
|
|
77
|
+
v = repo.create();
|
|
78
|
+
v.version = -1;
|
|
79
|
+
}
|
|
80
|
+
_c.label = 2;
|
|
81
|
+
case 2:
|
|
82
|
+
_c.trys.push([2, 15, 16, 17]);
|
|
83
|
+
steps_2 = tslib_1.__values(steps_1), steps_2_1 = steps_2.next();
|
|
84
|
+
_c.label = 3;
|
|
85
|
+
case 3:
|
|
86
|
+
if (!!steps_2_1.done) return [3 /*break*/, 14];
|
|
87
|
+
_a = tslib_1.__read(steps_2_1.value, 2), stepText = _a[0], action = _a[1];
|
|
88
|
+
step = parseInt(stepText);
|
|
89
|
+
if (step < 0)
|
|
90
|
+
throw new Error('Migration step number must be a non-negative integer');
|
|
91
|
+
if (v.version >= step)
|
|
92
|
+
return [3 /*break*/, 13];
|
|
93
|
+
if (!options.beforeMigration) return [3 /*break*/, 5];
|
|
94
|
+
return [4 /*yield*/, options.beforeMigration({ index: step })];
|
|
95
|
+
case 4:
|
|
96
|
+
_c.sent();
|
|
97
|
+
_c.label = 5;
|
|
98
|
+
case 5:
|
|
99
|
+
startTime = Date.now();
|
|
100
|
+
console.info('Executing migration step ' + step);
|
|
101
|
+
console.time('Completed migration step ' + step);
|
|
102
|
+
_c.label = 6;
|
|
103
|
+
case 6:
|
|
104
|
+
_c.trys.push([6, 10, , 11]);
|
|
105
|
+
utils = {
|
|
106
|
+
sql: function (sql) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
107
|
+
return tslib_1.__generator(this, function (_a) {
|
|
108
|
+
switch (_a.label) {
|
|
109
|
+
case 0: return [4 /*yield*/, (0, isOfType_js_1.cast)(dp, 'execute').execute(sql)];
|
|
110
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}); },
|
|
114
|
+
};
|
|
115
|
+
return [4 /*yield*/, action(utils)];
|
|
116
|
+
case 7:
|
|
117
|
+
_c.sent();
|
|
118
|
+
if (!options.afterMigration) return [3 /*break*/, 9];
|
|
119
|
+
return [4 /*yield*/, options.afterMigration({
|
|
120
|
+
index: step,
|
|
121
|
+
duration: Date.now() - startTime,
|
|
122
|
+
})];
|
|
123
|
+
case 8:
|
|
124
|
+
_c.sent();
|
|
125
|
+
_c.label = 9;
|
|
126
|
+
case 9:
|
|
127
|
+
console.timeEnd('Completed migration step ' + step);
|
|
128
|
+
return [3 /*break*/, 11];
|
|
129
|
+
case 10:
|
|
130
|
+
err_1 = _c.sent();
|
|
131
|
+
console.error('Failed to execute migration step ' + step);
|
|
132
|
+
console.error(err_1);
|
|
133
|
+
throw err_1;
|
|
134
|
+
case 11:
|
|
135
|
+
v.version = step;
|
|
136
|
+
return [4 /*yield*/, v.save()];
|
|
137
|
+
case 12:
|
|
138
|
+
_c.sent();
|
|
139
|
+
_c.label = 13;
|
|
140
|
+
case 13:
|
|
141
|
+
steps_2_1 = steps_2.next();
|
|
142
|
+
return [3 /*break*/, 3];
|
|
143
|
+
case 14: return [3 /*break*/, 17];
|
|
144
|
+
case 15:
|
|
145
|
+
e_1_1 = _c.sent();
|
|
146
|
+
e_1 = { error: e_1_1 };
|
|
147
|
+
return [3 /*break*/, 17];
|
|
148
|
+
case 16:
|
|
149
|
+
try {
|
|
150
|
+
if (steps_2_1 && !steps_2_1.done && (_b = steps_2.return)) _b.call(steps_2);
|
|
151
|
+
}
|
|
152
|
+
finally { if (e_1) throw e_1.error; }
|
|
153
|
+
return [7 /*endfinally*/];
|
|
154
|
+
case 17: return [2 /*return*/];
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}); })];
|
|
158
|
+
case 5:
|
|
159
|
+
_a.sent();
|
|
160
|
+
return [3 /*break*/, 7];
|
|
161
|
+
case 6:
|
|
162
|
+
index_js_1.remult.dataProvider = prev;
|
|
163
|
+
return [7 /*endfinally*/];
|
|
164
|
+
case 7:
|
|
165
|
+
if (!(options.endConnection && (0, isOfType_js_1.isOfType)(dataProvider, 'end'))) return [3 /*break*/, 9];
|
|
166
|
+
return [4 /*yield*/, dataProvider.end()];
|
|
167
|
+
case 8:
|
|
168
|
+
_a.sent();
|
|
169
|
+
_a.label = 9;
|
|
170
|
+
case 9: return [2 /*return*/];
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
exports.migrate = migrate;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { EntityMetadata, FieldMetadata } from '../index.js';
|
|
2
|
+
export interface CanBuildMigrations {
|
|
3
|
+
provideMigrationBuilder(builder: MigrationCode): MigrationBuilder;
|
|
4
|
+
}
|
|
5
|
+
export interface MigrationBuilder {
|
|
6
|
+
createTable(meta: EntityMetadata): Promise<void>;
|
|
7
|
+
addColumn(meta: EntityMetadata, field: FieldMetadata): Promise<void>;
|
|
8
|
+
removeTable?(entityDbName: string): unknown;
|
|
9
|
+
removeColumn?($entityName: string, columnDbName: string): unknown;
|
|
10
|
+
}
|
|
11
|
+
export interface MigrationCode {
|
|
12
|
+
addSql(sql: string): void;
|
|
13
|
+
addComment(comment: string): void;
|
|
14
|
+
addTypescriptCode(code: string): void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Represents a set of migrations, each identified by a unique number.
|
|
18
|
+
*
|
|
19
|
+
* Each migration function takes a `MigrationUtils` object as a parameter, which provides utility methods for executing SQL statements and other migration-related operations.
|
|
20
|
+
*
|
|
21
|
+
* Migrations are executed in a transaction, meaning that all changes within a single migration are either fully applied or fully rolled back in case of an error. This ensures the consistency of the database state.
|
|
22
|
+
*
|
|
23
|
+
* Note: Some databases, like MySQL, do not support rolling back structural changes (e.g., table creation or alteration) as part of a transaction. Developers should be aware of this when designing migrations for such databases.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* export const migrations: Migrations = {
|
|
27
|
+
* 1: async ({ sql }) => {
|
|
28
|
+
* await sql(`CREATE TABLE example (id SERIAL PRIMARY KEY, name VARCHAR(255))`);
|
|
29
|
+
* },
|
|
30
|
+
* 2: async ({ sql }) => {
|
|
31
|
+
* await sql(`ALTER TABLE example ADD COLUMN description TEXT`);
|
|
32
|
+
* },
|
|
33
|
+
* };
|
|
34
|
+
* @see [Migrations](http://remult.dev/docs/migrations.html)
|
|
35
|
+
*/
|
|
36
|
+
export type Migrations = Record<number, (utils: MigrationUtils) => Promise<unknown>>;
|
|
37
|
+
export type MigrationUtils = {
|
|
38
|
+
sql(sql: string): Promise<unknown>;
|
|
39
|
+
};
|
|
40
|
+
export declare class DefaultMigrationBuilder implements Required<MigrationBuilder> {
|
|
41
|
+
code: MigrationCode;
|
|
42
|
+
private wrapped?;
|
|
43
|
+
constructor(code: MigrationCode, wrapped?: MigrationBuilder);
|
|
44
|
+
createTable(meta: EntityMetadata): Promise<void>;
|
|
45
|
+
addColumn(meta: EntityMetadata, field: FieldMetadata): Promise<void>;
|
|
46
|
+
removeTable(entityDbName: string): Promise<void>;
|
|
47
|
+
removeColumn(entityName: string, columnDbName: string): Promise<void>;
|
|
48
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DefaultMigrationBuilder = void 0;
|
|
4
|
+
var tslib_1 = require("tslib");
|
|
5
|
+
var DefaultMigrationBuilder = /** @class */ (function () {
|
|
6
|
+
function DefaultMigrationBuilder(code, wrapped) {
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.wrapped = wrapped;
|
|
9
|
+
}
|
|
10
|
+
DefaultMigrationBuilder.prototype.createTable = function (meta) {
|
|
11
|
+
var _a;
|
|
12
|
+
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
13
|
+
return tslib_1.__generator(this, function (_b) {
|
|
14
|
+
switch (_b.label) {
|
|
15
|
+
case 0:
|
|
16
|
+
if (!((_a = this.wrapped) === null || _a === void 0 ? void 0 : _a.createTable)) return [3 /*break*/, 2];
|
|
17
|
+
return [4 /*yield*/, this.wrapped.createTable(meta)];
|
|
18
|
+
case 1:
|
|
19
|
+
_b.sent();
|
|
20
|
+
return [3 /*break*/, 3];
|
|
21
|
+
case 2:
|
|
22
|
+
this.code.addComment('TODO: implement create table ' + meta.dbName);
|
|
23
|
+
_b.label = 3;
|
|
24
|
+
case 3: return [2 /*return*/];
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
DefaultMigrationBuilder.prototype.addColumn = function (meta, field) {
|
|
30
|
+
var _a;
|
|
31
|
+
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
32
|
+
return tslib_1.__generator(this, function (_b) {
|
|
33
|
+
switch (_b.label) {
|
|
34
|
+
case 0:
|
|
35
|
+
if (!((_a = this.wrapped) === null || _a === void 0 ? void 0 : _a.addColumn)) return [3 /*break*/, 2];
|
|
36
|
+
return [4 /*yield*/, this.wrapped.addColumn(meta, field)];
|
|
37
|
+
case 1:
|
|
38
|
+
_b.sent();
|
|
39
|
+
return [3 /*break*/, 3];
|
|
40
|
+
case 2:
|
|
41
|
+
this.code.addComment('TODO: implement add column ' + meta.dbName + '.' + field.dbName);
|
|
42
|
+
_b.label = 3;
|
|
43
|
+
case 3: return [2 /*return*/];
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
DefaultMigrationBuilder.prototype.removeTable = function (entityDbName) {
|
|
49
|
+
var _a;
|
|
50
|
+
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
51
|
+
return tslib_1.__generator(this, function (_b) {
|
|
52
|
+
switch (_b.label) {
|
|
53
|
+
case 0:
|
|
54
|
+
if (!((_a = this.wrapped) === null || _a === void 0 ? void 0 : _a.removeTable)) return [3 /*break*/, 2];
|
|
55
|
+
return [4 /*yield*/, this.wrapped.removeTable(entityDbName)];
|
|
56
|
+
case 1:
|
|
57
|
+
_b.sent();
|
|
58
|
+
return [3 /*break*/, 3];
|
|
59
|
+
case 2:
|
|
60
|
+
this.code.addComment('TODO: implement remove table ' + entityDbName);
|
|
61
|
+
_b.label = 3;
|
|
62
|
+
case 3: return [2 /*return*/];
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
DefaultMigrationBuilder.prototype.removeColumn = function (entityName, columnDbName) {
|
|
68
|
+
var _a;
|
|
69
|
+
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
70
|
+
return tslib_1.__generator(this, function (_b) {
|
|
71
|
+
switch (_b.label) {
|
|
72
|
+
case 0:
|
|
73
|
+
if (!((_a = this.wrapped) === null || _a === void 0 ? void 0 : _a.removeColumn)) return [3 /*break*/, 2];
|
|
74
|
+
return [4 /*yield*/, this.wrapped.removeColumn(entityName, columnDbName)];
|
|
75
|
+
case 1:
|
|
76
|
+
_b.sent();
|
|
77
|
+
return [3 /*break*/, 3];
|
|
78
|
+
case 2:
|
|
79
|
+
this.code.addComment('TODO: implement remove column ' + entityName + '.' + columnDbName);
|
|
80
|
+
_b.label = 3;
|
|
81
|
+
case 3: return [2 /*return*/];
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
return DefaultMigrationBuilder;
|
|
87
|
+
}());
|
|
88
|
+
exports.DefaultMigrationBuilder = DefaultMigrationBuilder;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function updateMigrationsFile(filePath: string, steps: string[]): Promise<void>;
|