remult 0.25.8-exp.13 → 0.25.8-exp.15
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/esm/migrations/compare-migration-snapshots.js +26 -4
- package/esm/migrations/generate-migrations.js +13 -8
- package/esm/migrations/migrate.js +47 -33
- package/esm/migrations/migration-types.js +27 -3
- package/esm/migrations/update-migrations-ts-file.js +4 -1
- package/esm/src/filter/filter-interfaces.js +21 -1
- package/esm/src/remult3/remult3.js +14 -10
- package/migrations/compare-migration-snapshots.d.ts +3 -2
- package/migrations/compare-migration-snapshots.js +107 -42
- package/migrations/generate-migrations.d.ts +5 -5
- package/migrations/generate-migrations.js +17 -13
- package/migrations/migrate.d.ts +12 -3
- package/migrations/migrate.js +104 -98
- package/migrations/migration-types.d.ts +7 -2
- package/migrations/migration-types.js +68 -7
- package/migrations/update-migrations-ts-file.js +3 -0
- package/package.json +1 -1
- package/src/filter/filter-interfaces.d.ts +18 -0
- package/src/filter/filter-interfaces.js +31 -1
- package/src/remult3/remult3.d.ts +1 -1
- package/src/remult3/remult3.js +14 -10
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { repo } from '../index.js';
|
|
2
2
|
import { dbNamesOf, shouldCreateEntity, shouldNotCreateField, } from '../src/filter/filter-consumer-bridge-to-sql-request.js';
|
|
3
|
-
export async function compareMigrationSnapshot({ entities, snapshot, migrationBuilder
|
|
3
|
+
export async function compareMigrationSnapshot({ entities, snapshot, migrationBuilder, reporter, }) {
|
|
4
4
|
snapshot = JSON.parse(JSON.stringify(snapshot));
|
|
5
|
+
let processedEntities = new Set();
|
|
5
6
|
for (const entity of entities) {
|
|
6
7
|
const meta = repo(entity).metadata;
|
|
7
8
|
const e = await dbNamesOf(meta, (x) => x);
|
|
9
|
+
processedEntities.add(e.$entityName);
|
|
8
10
|
if (shouldCreateEntity(meta, e)) {
|
|
9
11
|
let entitySnapshot = snapshot.entities[e.$entityName];
|
|
10
12
|
let createColumns = true;
|
|
11
13
|
if (!entitySnapshot) {
|
|
12
14
|
createColumns = false;
|
|
15
|
+
reporter('create table ' + e.$entityName);
|
|
13
16
|
await migrationBuilder.createTable(meta);
|
|
14
17
|
entitySnapshot = snapshot.entities[e.$entityName] = {
|
|
15
18
|
key: meta.key,
|
|
@@ -17,16 +20,35 @@ export async function compareMigrationSnapshot({ entities, snapshot, migrationBu
|
|
|
17
20
|
columns: {},
|
|
18
21
|
};
|
|
19
22
|
}
|
|
23
|
+
const processedColumns = new Set();
|
|
20
24
|
for (const field of meta.fields) {
|
|
21
25
|
if (!shouldNotCreateField(field, e)) {
|
|
22
|
-
const
|
|
26
|
+
const columnDbName = e.$dbNameOf(field);
|
|
27
|
+
processedColumns.add(columnDbName);
|
|
28
|
+
const column = entitySnapshot.columns[columnDbName];
|
|
23
29
|
if (!column) {
|
|
24
|
-
if (createColumns)
|
|
30
|
+
if (createColumns) {
|
|
31
|
+
reporter('add column ' + e.$entityName + '.' + columnDbName);
|
|
25
32
|
await migrationBuilder.addColumn(meta, field);
|
|
26
|
-
|
|
33
|
+
}
|
|
34
|
+
entitySnapshot.columns[columnDbName] = { key: field.key };
|
|
27
35
|
}
|
|
28
36
|
}
|
|
29
37
|
}
|
|
38
|
+
for (const columnDbName of Object.keys(entitySnapshot.columns)) {
|
|
39
|
+
if (!processedColumns.has(columnDbName)) {
|
|
40
|
+
reporter('remove column ' + e.$entityName + '.' + columnDbName);
|
|
41
|
+
await migrationBuilder.removeColumn(e.$entityName, columnDbName);
|
|
42
|
+
delete entitySnapshot.columns[columnDbName];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
for (const entityDbName of Object.keys(snapshot.entities)) {
|
|
48
|
+
if (!processedEntities.has(entityDbName)) {
|
|
49
|
+
reporter('remove table ' + entityDbName);
|
|
50
|
+
await migrationBuilder.removeTable(entityDbName);
|
|
51
|
+
delete snapshot.entities[entityDbName];
|
|
30
52
|
}
|
|
31
53
|
}
|
|
32
54
|
return snapshot;
|
|
@@ -9,17 +9,16 @@ import { initDataProvider } from '../server/initDataProvider.js';
|
|
|
9
9
|
* Generates migration scripts based on changes in entities.
|
|
10
10
|
*
|
|
11
11
|
* @param options - Configuration options for generating migrations.
|
|
12
|
-
* @param options.entities - An array of entity classes
|
|
12
|
+
* @param options.entities - An array of entity classes whose changes will be included in the migration.
|
|
13
13
|
* @param options.dataProvider - The data provider instance or a function returning a promise of the data provider.
|
|
14
|
-
* @param options.migrationsFolder - (Optional) The path to the folder where migration scripts will be stored. Default is 'src/
|
|
14
|
+
* @param options.migrationsFolder - (Optional) The path to the folder where migration scripts will be stored. Default is 'src/migrations'.
|
|
15
15
|
* @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`.
|
|
16
16
|
* @param options.migrationsTSFile - (Optional) The path to the TypeScript file where the generated migrations will be written. Default is 'migrations.ts' in the `migrationsFolder`.
|
|
17
|
-
* @param options.endConnection - (Optional) Determines whether to close the database connection after generating migrations. Default is
|
|
18
|
-
* @see [Migrations](
|
|
17
|
+
* @param options.endConnection - (Optional) Determines whether to close the database connection after generating migrations. Default is false.
|
|
18
|
+
* @see [Migrations](https://remult.dev/docs/migrations.html)
|
|
19
19
|
*/
|
|
20
20
|
export async function generateMigrations(options) {
|
|
21
|
-
const migrationDir = options.migrationsFolder ||
|
|
22
|
-
path.join(process.cwd(), 'src/server/migrations');
|
|
21
|
+
const migrationDir = options.migrationsFolder || path.join(process.cwd(), 'src/migrations');
|
|
23
22
|
const snapshotFileName = options.snapshotFile || path.join(migrationDir, 'migrations-snapshot.json');
|
|
24
23
|
const migrationsTSFilename = options.migrationsTSFile || path.join(migrationDir, 'migrations.ts');
|
|
25
24
|
const dataProvider = await initDataProvider(options.dataProvider);
|
|
@@ -45,19 +44,25 @@ export async function generateMigrations(options) {
|
|
|
45
44
|
};
|
|
46
45
|
let migrationBuilder = new DefaultMigrationBuilder(code);
|
|
47
46
|
if (isOfType(dataProvider, 'provideMigrationBuilder')) {
|
|
48
|
-
migrationBuilder = dataProvider.provideMigrationBuilder(code);
|
|
47
|
+
migrationBuilder = new DefaultMigrationBuilder(code, dataProvider.provideMigrationBuilder(code));
|
|
49
48
|
}
|
|
49
|
+
let reporter = (what) => console.log('[generateMigrations] ' + what);
|
|
50
50
|
snapshot = await compareMigrationSnapshot({
|
|
51
51
|
entities: options.entities,
|
|
52
52
|
snapshot,
|
|
53
|
+
reporter,
|
|
53
54
|
migrationBuilder,
|
|
54
55
|
});
|
|
55
56
|
if (steps.length)
|
|
56
57
|
await updateMigrationsFile(migrationsTSFilename, [
|
|
57
58
|
`async (${hasSql ? '{sql}' : ''})=>{\n${steps.join('\n')}\n}`,
|
|
58
59
|
]);
|
|
60
|
+
else {
|
|
61
|
+
reporter('No changes detected');
|
|
62
|
+
}
|
|
59
63
|
fs.writeFileSync(snapshotFileName, JSON.stringify(snapshot, null, 2));
|
|
60
|
-
if (options.endConnection
|
|
64
|
+
if (options.endConnection && isOfType(dataProvider, 'end')) {
|
|
61
65
|
await dataProvider.end();
|
|
62
66
|
}
|
|
67
|
+
return steps.length > 0;
|
|
63
68
|
}
|
|
@@ -10,9 +10,11 @@ import { cast, isOfType } from '../src/isOfType.js';
|
|
|
10
10
|
* @param options.migrations - An object containing the migration scripts, each keyed by a unique identifier.
|
|
11
11
|
* @param options.dataProvider - The data provider instance or a function returning a promise of the data provider.
|
|
12
12
|
* @param options.migrationsTable - (Optional) The name of the table that tracks applied migrations. Default is '__remult_migrations_version'.
|
|
13
|
-
* @param options.endConnection - (Optional) Determines whether to close the database connection after applying migrations. Default is
|
|
14
|
-
* @
|
|
15
|
-
|
|
13
|
+
* @param options.endConnection - (Optional) Determines whether to close the database connection after applying migrations. Default is false.
|
|
14
|
+
* @param options.beforeMigration - (Optional) A callback function that is called before each migration is applied. Receives an object with the migration index.
|
|
15
|
+
* @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.
|
|
16
|
+
* @see [Migrations](https://remult.dev/docs/migrations.html)
|
|
17
|
+
*/
|
|
16
18
|
export async function migrate(options) {
|
|
17
19
|
let migrationTableName = options.migrationsTable || '__remult_migrations_version';
|
|
18
20
|
const dataProvider = await initDataProvider(options.dataProvider);
|
|
@@ -29,48 +31,60 @@ export async function migrate(options) {
|
|
|
29
31
|
VersionInfo = __decorate([
|
|
30
32
|
Entity(migrationTableName)
|
|
31
33
|
], VersionInfo);
|
|
32
|
-
const
|
|
34
|
+
const steps = Object.entries(options.migrations).sort(([a], [b]) => parseInt(a) - parseInt(b));
|
|
33
35
|
if (dataProvider.ensureSchema) {
|
|
34
|
-
await dataProvider.ensureSchema([
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (!v) {
|
|
38
|
-
v = repo.create();
|
|
39
|
-
v.version = -1;
|
|
36
|
+
await dataProvider.ensureSchema([
|
|
37
|
+
new Remult(dataProvider).repo(VersionInfo).metadata,
|
|
38
|
+
]);
|
|
40
39
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
40
|
+
await doTransaction(remult, async (dp) => {
|
|
41
|
+
const repo = new Remult(dataProvider).repo(VersionInfo, dp);
|
|
42
|
+
let v = await repo.findFirst();
|
|
43
|
+
if (!v) {
|
|
44
|
+
v = repo.create();
|
|
45
|
+
v.version = -1;
|
|
46
|
+
}
|
|
47
|
+
for (const [stepText, action] of steps) {
|
|
48
|
+
const step = parseInt(stepText);
|
|
49
|
+
if (step < 0)
|
|
50
|
+
throw new Error('Migration step number must be a non-negative integer');
|
|
51
|
+
if (v.version >= step)
|
|
52
|
+
continue;
|
|
53
|
+
if (options.beforeMigration) {
|
|
54
|
+
await options.beforeMigration({ index: step });
|
|
55
|
+
}
|
|
56
|
+
const startTime = Date.now();
|
|
57
|
+
console.info('Executing migration step ' + step);
|
|
58
|
+
console.time('Completed migration step ' + step);
|
|
59
|
+
try {
|
|
52
60
|
const utils = {
|
|
53
61
|
sql: async (sql) => {
|
|
54
|
-
await cast(dp, 'execute').execute(sql);
|
|
62
|
+
return await cast(dp, 'execute').execute(sql);
|
|
55
63
|
},
|
|
56
64
|
};
|
|
57
65
|
await action(utils);
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
if (options.afterMigration) {
|
|
67
|
+
await options.afterMigration({
|
|
68
|
+
index: step,
|
|
69
|
+
duration: Date.now() - startTime,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
console.timeEnd('Completed migration step ' + step);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
console.error('Failed to execute migration step ' + step);
|
|
76
|
+
console.error(err);
|
|
77
|
+
throw err;
|
|
78
|
+
}
|
|
79
|
+
v.version = step;
|
|
80
|
+
await v.save();
|
|
65
81
|
}
|
|
66
|
-
|
|
67
|
-
await v.save();
|
|
68
|
-
}
|
|
82
|
+
});
|
|
69
83
|
}
|
|
70
84
|
finally {
|
|
71
85
|
remult.dataProvider = prev;
|
|
72
86
|
}
|
|
73
|
-
if (options.endConnection
|
|
87
|
+
if (options.endConnection && isOfType(dataProvider, 'end')) {
|
|
74
88
|
await dataProvider.end();
|
|
75
89
|
}
|
|
76
90
|
}
|
|
@@ -1,12 +1,36 @@
|
|
|
1
1
|
export class DefaultMigrationBuilder {
|
|
2
2
|
code;
|
|
3
|
-
|
|
3
|
+
wrapped;
|
|
4
|
+
constructor(code, wrapped) {
|
|
4
5
|
this.code = code;
|
|
6
|
+
this.wrapped = wrapped;
|
|
5
7
|
}
|
|
6
8
|
async createTable(meta) {
|
|
7
|
-
this.
|
|
9
|
+
if (this.wrapped?.createTable) {
|
|
10
|
+
await this.wrapped.createTable(meta);
|
|
11
|
+
}
|
|
12
|
+
else
|
|
13
|
+
this.code.addComment('TODO: implement create table ' + meta.dbName);
|
|
8
14
|
}
|
|
9
15
|
async addColumn(meta, field) {
|
|
10
|
-
this.
|
|
16
|
+
if (this.wrapped?.addColumn) {
|
|
17
|
+
await this.wrapped.addColumn(meta, field);
|
|
18
|
+
}
|
|
19
|
+
else
|
|
20
|
+
this.code.addComment('TODO: implement add column ' + meta.dbName + '.' + field.dbName);
|
|
21
|
+
}
|
|
22
|
+
async removeTable(entityDbName) {
|
|
23
|
+
if (this.wrapped?.removeTable) {
|
|
24
|
+
await this.wrapped.removeTable(entityDbName);
|
|
25
|
+
}
|
|
26
|
+
else
|
|
27
|
+
this.code.addComment('TODO: implement remove table ' + entityDbName);
|
|
28
|
+
}
|
|
29
|
+
async removeColumn(entityName, columnDbName) {
|
|
30
|
+
if (this.wrapped?.removeColumn) {
|
|
31
|
+
await this.wrapped.removeColumn(entityName, columnDbName);
|
|
32
|
+
}
|
|
33
|
+
else
|
|
34
|
+
this.code.addComment('TODO: implement remove column ' + entityName + '.' + columnDbName);
|
|
11
35
|
}
|
|
12
36
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
// consider replacing with https://www.npmjs.com/package/ts-morph
|
|
2
2
|
export async function updateMigrationsFile(filePath, steps) {
|
|
3
|
-
|
|
3
|
+
let ts = await import('typescript');
|
|
4
|
+
//@ts-ignore
|
|
5
|
+
if (ts.default)
|
|
6
|
+
ts = ts.default;
|
|
4
7
|
const fs = await import('fs');
|
|
5
8
|
let maxStep = -1;
|
|
6
9
|
function buildSteps() {
|
|
@@ -64,6 +64,27 @@ export class Filter {
|
|
|
64
64
|
await Filter.fromEntityFilter(metadata, filter).__applyToConsumer(result);
|
|
65
65
|
return result;
|
|
66
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Retrieves information about a filter, including precise values for each property.
|
|
69
|
+
* @template entityType The type of the entity being filtered.
|
|
70
|
+
* @param metadata The metadata of the entity being filtered.
|
|
71
|
+
* @param filter The filter to analyze.
|
|
72
|
+
* @returns A promise that resolves to a FilterInfo object containing the filter information.
|
|
73
|
+
* @example
|
|
74
|
+
* const info = await where.getInfo();
|
|
75
|
+
* console.log(info.preciseValues);
|
|
76
|
+
* // Output:
|
|
77
|
+
* // {
|
|
78
|
+
* // "customerId": ["1", "2", "3"], // Precise values inferred from the filter
|
|
79
|
+
* // "status": undefined, // Cannot infer precise values for 'status'
|
|
80
|
+
* // }
|
|
81
|
+
|
|
82
|
+
*/
|
|
83
|
+
async getInfo() {
|
|
84
|
+
const result = new preciseValuesCollector();
|
|
85
|
+
await this.__applyToConsumer(result);
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
67
88
|
static createCustom(rawFilterTranslator, key = '') {
|
|
68
89
|
let rawFilterInfo = { key: key, rawFilterTranslator };
|
|
69
90
|
return Object.assign((x) => {
|
|
@@ -248,7 +269,6 @@ export class Filter {
|
|
|
248
269
|
return await filter();
|
|
249
270
|
return filter;
|
|
250
271
|
}
|
|
251
|
-
//@internal
|
|
252
272
|
toJson() {
|
|
253
273
|
let r = new FilterSerializer();
|
|
254
274
|
this.__applyToConsumer(r);
|
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
export {};
|
|
2
|
-
//p1 - It's good that there is no migrations added. (I also don't like automatic deletion), and it can be done manually if needed.
|
|
3
|
-
//p1 - Maybe migrations-snapshots.json should have fields deleted to have a one to one representation of the db?
|
|
2
|
+
//p1 DOC DONE - It's good that there is no migrations added. (I also don't like automatic deletion), and it can be done manually if needed.
|
|
3
|
+
//p1 DOC DONE - Maybe migrations-snapshots.json should have fields deleted to have a one to one representation of the db?
|
|
4
|
+
//p1 DOC DONE - @JYT - should I write to console on generate migrations, what are the changes that I've found / the migration step id / not changes found
|
|
5
|
+
//p1 DOC DONE - re-discuss endConnection - default false - explain in docs
|
|
6
|
+
//p1 DONE - JYC log the migration request - beforeMigration. afterMigration
|
|
7
|
+
//p1 DONE - migration default folder should be source/migrations (also docs?)
|
|
8
|
+
//p1 DONE - @JYT run all migrations in a single transaction? or transaction per step?
|
|
9
|
+
//p1 Done - Filter.toJson should be public
|
|
4
10
|
//p1 - I needed to modify the changes Field of changeLog entity to @Fields.json() to be nvarchar(max) too. Why is @Fields.object() only nvarchar(255) ? Or is it default size and can be adjusted?
|
|
5
|
-
//p1 -
|
|
6
|
-
//p1 -
|
|
7
|
-
//y1 - JY build issue
|
|
8
|
-
//p1 -
|
|
9
|
-
//y1 - migration default folder should be source/migrations (also docs?)
|
|
10
|
-
//y1 - discuss the typing issue with relations in this case vs the ValueListFieldTypes
|
|
11
|
-
//y1 - JYC log the migration request
|
|
12
|
-
//y1 - JYC health check approach
|
|
11
|
+
//p1 - improve type augmentation doc with specific of the file and with the export trick - fix code samples to init reqiest error
|
|
12
|
+
//p1 - document custom filter without sql
|
|
13
|
+
//y1!! - JY build issue
|
|
14
|
+
//p1 - discuss the typing issue with relations in this case vs the ValueListFieldTypes - return partial with id values.
|
|
13
15
|
//p1 - admin url1 - pocketbase use /_ for the admin //{allowed?:Allowed,url?:string}
|
|
14
16
|
//p1 - document new sqlite providers
|
|
15
17
|
//p1 - article auth.js with express
|
|
16
18
|
//p1 - document offline support
|
|
17
19
|
//p1 - fix getting started article with using your own database connection
|
|
20
|
+
//p1 - create foreign key constraints in user code
|
|
21
|
+
//p1 - https://github.com/vuejs/vitepress/issues/3154#issuecomment-1784612839
|
|
18
22
|
//y2 - should we validate relations
|
|
19
23
|
//y1 - dependency of live query tables
|
|
20
24
|
//y1 - consider replacing all errors with error classes that extend the base Error class
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { MigrationBuilder } from './migration-types.js';
|
|
2
|
-
export declare function compareMigrationSnapshot({ entities, snapshot, migrationBuilder
|
|
2
|
+
export declare function compareMigrationSnapshot({ entities, snapshot, migrationBuilder, reporter, }: {
|
|
3
3
|
entities: any[];
|
|
4
4
|
snapshot: EntitiesSnapshot;
|
|
5
|
-
migrationBuilder: MigrationBuilder
|
|
5
|
+
migrationBuilder: Required<MigrationBuilder>;
|
|
6
|
+
reporter: (what: string) => void;
|
|
6
7
|
}): Promise<{
|
|
7
8
|
version: number;
|
|
8
9
|
entities: Record<string, {
|
|
@@ -5,87 +5,152 @@ var tslib_1 = require("tslib");
|
|
|
5
5
|
var index_js_1 = require("../index.js");
|
|
6
6
|
var filter_consumer_bridge_to_sql_request_js_1 = require("../src/filter/filter-consumer-bridge-to-sql-request.js");
|
|
7
7
|
function compareMigrationSnapshot(_a) {
|
|
8
|
-
var entities = _a.entities, snapshot = _a.snapshot, migrationBuilder = _a.migrationBuilder;
|
|
8
|
+
var entities = _a.entities, snapshot = _a.snapshot, migrationBuilder = _a.migrationBuilder, reporter = _a.reporter;
|
|
9
9
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
10
|
-
var entities_1, entities_1_1, entity, meta, e, entitySnapshot, createColumns, _b, _c, field, column, e_1_1, e_2_1;
|
|
11
|
-
var
|
|
12
|
-
return tslib_1.__generator(this, function (
|
|
13
|
-
switch (
|
|
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
14
|
case 0:
|
|
15
15
|
snapshot = JSON.parse(JSON.stringify(snapshot));
|
|
16
|
-
|
|
16
|
+
processedEntities = new Set();
|
|
17
|
+
_m.label = 1;
|
|
17
18
|
case 1:
|
|
18
|
-
|
|
19
|
+
_m.trys.push([1, 23, 24, 25]);
|
|
19
20
|
entities_1 = tslib_1.__values(entities), entities_1_1 = entities_1.next();
|
|
20
|
-
|
|
21
|
+
_m.label = 2;
|
|
21
22
|
case 2:
|
|
22
|
-
if (!!entities_1_1.done) return [3 /*break*/,
|
|
23
|
+
if (!!entities_1_1.done) return [3 /*break*/, 22];
|
|
23
24
|
entity = entities_1_1.value;
|
|
24
25
|
meta = (0, index_js_1.repo)(entity).metadata;
|
|
25
26
|
return [4 /*yield*/, (0, filter_consumer_bridge_to_sql_request_js_1.dbNamesOf)(meta, function (x) { return x; })];
|
|
26
27
|
case 3:
|
|
27
|
-
e =
|
|
28
|
-
|
|
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];
|
|
29
31
|
entitySnapshot = snapshot.entities[e.$entityName];
|
|
30
32
|
createColumns = true;
|
|
31
33
|
if (!!entitySnapshot) return [3 /*break*/, 5];
|
|
32
34
|
createColumns = false;
|
|
35
|
+
reporter('create table ' + e.$entityName);
|
|
33
36
|
return [4 /*yield*/, migrationBuilder.createTable(meta)];
|
|
34
37
|
case 4:
|
|
35
|
-
|
|
38
|
+
_m.sent();
|
|
36
39
|
entitySnapshot = snapshot.entities[e.$entityName] = {
|
|
37
40
|
key: meta.key,
|
|
38
41
|
className: meta.entityType.name,
|
|
39
42
|
columns: {},
|
|
40
43
|
};
|
|
41
|
-
|
|
44
|
+
_m.label = 5;
|
|
42
45
|
case 5:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
_f.label = 6;
|
|
46
|
+
processedColumns = new Set();
|
|
47
|
+
_m.label = 6;
|
|
46
48
|
case 6:
|
|
47
|
-
|
|
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];
|
|
48
54
|
field = _c.value;
|
|
49
|
-
if (!!(0, filter_consumer_bridge_to_sql_request_js_1.shouldNotCreateField)(field, e)) return [3 /*break*/,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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);
|
|
53
62
|
return [4 /*yield*/, migrationBuilder.addColumn(meta, field)];
|
|
54
|
-
case 7:
|
|
55
|
-
_f.sent();
|
|
56
|
-
_f.label = 8;
|
|
57
63
|
case 8:
|
|
58
|
-
|
|
59
|
-
|
|
64
|
+
_m.sent();
|
|
65
|
+
_m.label = 9;
|
|
60
66
|
case 9:
|
|
67
|
+
entitySnapshot.columns[columnDbName] = { key: field.key };
|
|
68
|
+
_m.label = 10;
|
|
69
|
+
case 10:
|
|
61
70
|
_c = _b.next();
|
|
62
|
-
return [3 /*break*/,
|
|
63
|
-
case
|
|
64
|
-
case 11:
|
|
65
|
-
e_1_1 = _f.sent();
|
|
66
|
-
e_1 = { error: e_1_1 };
|
|
67
|
-
return [3 /*break*/, 13];
|
|
71
|
+
return [3 /*break*/, 7];
|
|
72
|
+
case 11: return [3 /*break*/, 14];
|
|
68
73
|
case 12:
|
|
74
|
+
e_1_1 = _m.sent();
|
|
75
|
+
e_1 = { error: e_1_1 };
|
|
76
|
+
return [3 /*break*/, 14];
|
|
77
|
+
case 13:
|
|
69
78
|
try {
|
|
70
|
-
if (_c && !_c.done && (
|
|
79
|
+
if (_c && !_c.done && (_j = _b.return)) _j.call(_b);
|
|
71
80
|
}
|
|
72
81
|
finally { if (e_1) throw e_1.error; }
|
|
73
82
|
return [7 /*endfinally*/];
|
|
74
|
-
case
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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;
|
|
78
87
|
case 15:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return [3 /*break*/, 17];
|
|
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)];
|
|
82
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:
|
|
83
106
|
try {
|
|
84
|
-
if (
|
|
107
|
+
if (_e && !_e.done && (_k = _d.return)) _k.call(_d);
|
|
85
108
|
}
|
|
86
109
|
finally { if (e_2) throw e_2.error; }
|
|
87
110
|
return [7 /*endfinally*/];
|
|
88
|
-
case
|
|
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];
|
|
89
154
|
}
|
|
90
155
|
});
|
|
91
156
|
});
|
|
@@ -3,13 +3,13 @@ import type { DataProvider } from '../index.js';
|
|
|
3
3
|
* Generates migration scripts based on changes in entities.
|
|
4
4
|
*
|
|
5
5
|
* @param options - Configuration options for generating migrations.
|
|
6
|
-
* @param options.entities - An array of entity classes
|
|
6
|
+
* @param options.entities - An array of entity classes whose changes will be included in the migration.
|
|
7
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/
|
|
8
|
+
* @param options.migrationsFolder - (Optional) The path to the folder where migration scripts will be stored. Default is 'src/migrations'.
|
|
9
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
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
|
|
12
|
-
* @see [Migrations](
|
|
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
13
|
*/
|
|
14
14
|
export declare function generateMigrations(options: {
|
|
15
15
|
entities: any[];
|
|
@@ -18,4 +18,4 @@ export declare function generateMigrations(options: {
|
|
|
18
18
|
snapshotFile?: string;
|
|
19
19
|
migrationsTSFile?: string;
|
|
20
20
|
endConnection?: boolean;
|
|
21
|
-
}): Promise<
|
|
21
|
+
}): Promise<boolean>;
|
|
@@ -13,23 +13,22 @@ var initDataProvider_js_1 = require("../server/initDataProvider.js");
|
|
|
13
13
|
* Generates migration scripts based on changes in entities.
|
|
14
14
|
*
|
|
15
15
|
* @param options - Configuration options for generating migrations.
|
|
16
|
-
* @param options.entities - An array of entity classes
|
|
16
|
+
* @param options.entities - An array of entity classes whose changes will be included in the migration.
|
|
17
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/
|
|
18
|
+
* @param options.migrationsFolder - (Optional) The path to the folder where migration scripts will be stored. Default is 'src/migrations'.
|
|
19
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
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
|
|
22
|
-
* @see [Migrations](
|
|
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
23
|
*/
|
|
24
24
|
function generateMigrations(options) {
|
|
25
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;
|
|
26
|
+
var migrationDir, snapshotFileName, migrationsTSFilename, dataProvider, _a, _b, p, snapshot, hasSql, steps, code, migrationBuilder, reporter;
|
|
27
27
|
var e_1, _c;
|
|
28
28
|
return tslib_1.__generator(this, function (_d) {
|
|
29
29
|
switch (_d.label) {
|
|
30
30
|
case 0:
|
|
31
|
-
migrationDir = options.migrationsFolder ||
|
|
32
|
-
path_1.default.join(process.cwd(), 'src/server/migrations');
|
|
31
|
+
migrationDir = options.migrationsFolder || path_1.default.join(process.cwd(), 'src/migrations');
|
|
33
32
|
snapshotFileName = options.snapshotFile || path_1.default.join(migrationDir, 'migrations-snapshot.json');
|
|
34
33
|
migrationsTSFilename = options.migrationsTSFile || path_1.default.join(migrationDir, 'migrations.ts');
|
|
35
34
|
return [4 /*yield*/, (0, initDataProvider_js_1.initDataProvider)(options.dataProvider)];
|
|
@@ -69,11 +68,13 @@ function generateMigrations(options) {
|
|
|
69
68
|
};
|
|
70
69
|
migrationBuilder = new migration_types_js_1.DefaultMigrationBuilder(code);
|
|
71
70
|
if ((0, isOfType_js_1.isOfType)(dataProvider, 'provideMigrationBuilder')) {
|
|
72
|
-
migrationBuilder = dataProvider.provideMigrationBuilder(code);
|
|
71
|
+
migrationBuilder = new migration_types_js_1.DefaultMigrationBuilder(code, dataProvider.provideMigrationBuilder(code));
|
|
73
72
|
}
|
|
73
|
+
reporter = function (what) { return console.log('[generateMigrations] ' + what); };
|
|
74
74
|
return [4 /*yield*/, (0, compare_migration_snapshots_js_1.compareMigrationSnapshot)({
|
|
75
75
|
entities: options.entities,
|
|
76
76
|
snapshot: snapshot,
|
|
77
|
+
reporter: reporter,
|
|
77
78
|
migrationBuilder: migrationBuilder,
|
|
78
79
|
})];
|
|
79
80
|
case 2:
|
|
@@ -84,15 +85,18 @@ function generateMigrations(options) {
|
|
|
84
85
|
])];
|
|
85
86
|
case 3:
|
|
86
87
|
_d.sent();
|
|
87
|
-
|
|
88
|
+
return [3 /*break*/, 5];
|
|
88
89
|
case 4:
|
|
90
|
+
reporter('No changes detected');
|
|
91
|
+
_d.label = 5;
|
|
92
|
+
case 5:
|
|
89
93
|
fs_1.default.writeFileSync(snapshotFileName, JSON.stringify(snapshot, null, 2));
|
|
90
|
-
if (!(options.endConnection
|
|
94
|
+
if (!(options.endConnection && (0, isOfType_js_1.isOfType)(dataProvider, 'end'))) return [3 /*break*/, 7];
|
|
91
95
|
return [4 /*yield*/, dataProvider.end()];
|
|
92
|
-
case
|
|
96
|
+
case 6:
|
|
93
97
|
_d.sent();
|
|
94
|
-
_d.label =
|
|
95
|
-
case
|
|
98
|
+
_d.label = 7;
|
|
99
|
+
case 7: return [2 /*return*/, steps.length > 0];
|
|
96
100
|
}
|
|
97
101
|
});
|
|
98
102
|
});
|
package/migrations/migrate.d.ts
CHANGED
|
@@ -7,12 +7,21 @@ import type { Migrations } from './migration-types.js';
|
|
|
7
7
|
* @param options.migrations - An object containing the migration scripts, each keyed by a unique identifier.
|
|
8
8
|
* @param options.dataProvider - The data provider instance or a function returning a promise of the data provider.
|
|
9
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
|
|
11
|
-
* @
|
|
12
|
-
|
|
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
|
+
*/
|
|
13
15
|
export declare function migrate(options: {
|
|
14
16
|
migrations: Migrations;
|
|
15
17
|
dataProvider: DataProvider | Promise<DataProvider> | (() => Promise<DataProvider | undefined>);
|
|
16
18
|
migrationsTable?: string;
|
|
17
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>;
|
|
18
27
|
}): Promise<void>;
|
package/migrations/migrate.js
CHANGED
|
@@ -13,27 +13,28 @@ var isOfType_js_1 = require("../src/isOfType.js");
|
|
|
13
13
|
* @param options.migrations - An object containing the migration scripts, each keyed by a unique identifier.
|
|
14
14
|
* @param options.dataProvider - The data provider instance or a function returning a promise of the data provider.
|
|
15
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
|
|
17
|
-
* @
|
|
18
|
-
|
|
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
|
+
*/
|
|
19
21
|
function migrate(options) {
|
|
20
22
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
21
|
-
var migrationTableName, dataProvider, prev,
|
|
22
|
-
var e_1, _b;
|
|
23
|
+
var migrationTableName, dataProvider, prev, VersionInfo_1, steps_1;
|
|
23
24
|
var _this = this;
|
|
24
|
-
return tslib_1.__generator(this, function (
|
|
25
|
-
switch (
|
|
25
|
+
return tslib_1.__generator(this, function (_a) {
|
|
26
|
+
switch (_a.label) {
|
|
26
27
|
case 0:
|
|
27
28
|
migrationTableName = options.migrationsTable || '__remult_migrations_version';
|
|
28
29
|
return [4 /*yield*/, (0, initDataProvider_js_1.initDataProvider)(options.dataProvider)];
|
|
29
30
|
case 1:
|
|
30
|
-
dataProvider =
|
|
31
|
+
dataProvider = _a.sent();
|
|
31
32
|
prev = index_js_1.remult.dataProvider;
|
|
32
33
|
index_js_1.remult.dataProvider = dataProvider;
|
|
33
|
-
|
|
34
|
+
_a.label = 2;
|
|
34
35
|
case 2:
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
_a.trys.push([2, , 6, 7]);
|
|
37
|
+
VersionInfo_1 = /** @class */ (function (_super) {
|
|
37
38
|
tslib_1.__extends(VersionInfo, _super);
|
|
38
39
|
function VersionInfo() {
|
|
39
40
|
var _this = _super !== null && _super.apply(this, arguments) || this;
|
|
@@ -43,125 +44,130 @@ function migrate(options) {
|
|
|
43
44
|
tslib_1.__decorate([
|
|
44
45
|
index_js_1.Fields.number(),
|
|
45
46
|
tslib_1.__metadata("design:type", Object)
|
|
46
|
-
],
|
|
47
|
+
], VersionInfo_1.prototype, "version", void 0);
|
|
47
48
|
VersionInfo = tslib_1.__decorate([
|
|
48
49
|
(0, index_js_1.Entity)(migrationTableName)
|
|
49
50
|
], VersionInfo);
|
|
50
51
|
return VersionInfo;
|
|
51
52
|
}(index_js_1.IdEntity));
|
|
52
|
-
|
|
53
|
-
if (!dataProvider.ensureSchema) return [3 /*break*/, 4];
|
|
54
|
-
return [4 /*yield*/, dataProvider.ensureSchema([repo.metadata])];
|
|
55
|
-
case 3:
|
|
56
|
-
_c.sent();
|
|
57
|
-
_c.label = 4;
|
|
58
|
-
case 4: return [4 /*yield*/, repo.findFirst()];
|
|
59
|
-
case 5:
|
|
60
|
-
v = _c.sent();
|
|
61
|
-
if (!v) {
|
|
62
|
-
v = repo.create();
|
|
63
|
-
v.version = -1;
|
|
64
|
-
}
|
|
65
|
-
steps = Object.entries(options.migrations).sort(function (_a, _b) {
|
|
53
|
+
steps_1 = Object.entries(options.migrations).sort(function (_a, _b) {
|
|
66
54
|
var _c = tslib_1.__read(_a, 1), a = _c[0];
|
|
67
55
|
var _d = tslib_1.__read(_b, 1), b = _d[0];
|
|
68
56
|
return parseInt(a) - parseInt(b);
|
|
69
57
|
});
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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) {
|
|
74
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];
|
|
75
88
|
step = parseInt(stepText);
|
|
76
89
|
if (step < 0)
|
|
77
90
|
throw new Error('Migration step number must be a non-negative integer');
|
|
78
91
|
if (v.version >= step)
|
|
79
|
-
return [
|
|
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();
|
|
80
100
|
console.info('Executing migration step ' + step);
|
|
81
101
|
console.time('Completed migration step ' + step);
|
|
82
|
-
|
|
83
|
-
case
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
var _this = this;
|
|
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 () {
|
|
88
107
|
return tslib_1.__generator(this, function (_a) {
|
|
89
108
|
switch (_a.label) {
|
|
90
|
-
case 0:
|
|
91
|
-
|
|
92
|
-
sql: function (sql) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
93
|
-
return tslib_1.__generator(this, function (_a) {
|
|
94
|
-
switch (_a.label) {
|
|
95
|
-
case 0: return [4 /*yield*/, (0, isOfType_js_1.cast)(dp, 'execute').execute(sql)];
|
|
96
|
-
case 1:
|
|
97
|
-
_a.sent();
|
|
98
|
-
return [2 /*return*/];
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
}); },
|
|
102
|
-
};
|
|
103
|
-
return [4 /*yield*/, action(utils)];
|
|
104
|
-
case 1:
|
|
105
|
-
_a.sent();
|
|
106
|
-
return [2 /*return*/];
|
|
109
|
+
case 0: return [4 /*yield*/, (0, isOfType_js_1.cast)(dp, 'execute').execute(sql)];
|
|
110
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
107
111
|
}
|
|
108
112
|
});
|
|
109
|
-
}); }
|
|
110
|
-
|
|
111
|
-
|
|
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:
|
|
112
127
|
console.timeEnd('Completed migration step ' + step);
|
|
113
|
-
return [3 /*break*/,
|
|
114
|
-
case
|
|
115
|
-
err_1 =
|
|
128
|
+
return [3 /*break*/, 11];
|
|
129
|
+
case 10:
|
|
130
|
+
err_1 = _c.sent();
|
|
116
131
|
console.error('Failed to execute migration step ' + step);
|
|
117
132
|
console.error(err_1);
|
|
118
133
|
throw err_1;
|
|
119
|
-
case
|
|
134
|
+
case 11:
|
|
120
135
|
v.version = step;
|
|
121
136
|
return [4 /*yield*/, v.save()];
|
|
122
|
-
case
|
|
123
|
-
|
|
124
|
-
|
|
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*/];
|
|
125
155
|
}
|
|
126
156
|
});
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
_c.trys.push([6, 11, 12, 13]);
|
|
131
|
-
steps_1 = tslib_1.__values(steps), steps_1_1 = steps_1.next();
|
|
132
|
-
_c.label = 7;
|
|
133
|
-
case 7:
|
|
134
|
-
if (!!steps_1_1.done) return [3 /*break*/, 10];
|
|
135
|
-
_a = tslib_1.__read(steps_1_1.value, 2), stepText = _a[0], action = _a[1];
|
|
136
|
-
return [5 /*yield**/, _loop_1(stepText, action)];
|
|
137
|
-
case 8:
|
|
138
|
-
_c.sent();
|
|
139
|
-
_c.label = 9;
|
|
140
|
-
case 9:
|
|
141
|
-
steps_1_1 = steps_1.next();
|
|
157
|
+
}); })];
|
|
158
|
+
case 5:
|
|
159
|
+
_a.sent();
|
|
142
160
|
return [3 /*break*/, 7];
|
|
143
|
-
case
|
|
144
|
-
case 11:
|
|
145
|
-
e_1_1 = _c.sent();
|
|
146
|
-
e_1 = { error: e_1_1 };
|
|
147
|
-
return [3 /*break*/, 13];
|
|
148
|
-
case 12:
|
|
149
|
-
try {
|
|
150
|
-
if (steps_1_1 && !steps_1_1.done && (_b = steps_1.return)) _b.call(steps_1);
|
|
151
|
-
}
|
|
152
|
-
finally { if (e_1) throw e_1.error; }
|
|
153
|
-
return [7 /*endfinally*/];
|
|
154
|
-
case 13: return [3 /*break*/, 15];
|
|
155
|
-
case 14:
|
|
161
|
+
case 6:
|
|
156
162
|
index_js_1.remult.dataProvider = prev;
|
|
157
163
|
return [7 /*endfinally*/];
|
|
158
|
-
case
|
|
159
|
-
if (!(options.endConnection
|
|
164
|
+
case 7:
|
|
165
|
+
if (!(options.endConnection && (0, isOfType_js_1.isOfType)(dataProvider, 'end'))) return [3 /*break*/, 9];
|
|
160
166
|
return [4 /*yield*/, dataProvider.end()];
|
|
161
|
-
case
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
case
|
|
167
|
+
case 8:
|
|
168
|
+
_a.sent();
|
|
169
|
+
_a.label = 9;
|
|
170
|
+
case 9: return [2 /*return*/];
|
|
165
171
|
}
|
|
166
172
|
});
|
|
167
173
|
});
|
|
@@ -5,6 +5,8 @@ export interface CanBuildMigrations {
|
|
|
5
5
|
export interface MigrationBuilder {
|
|
6
6
|
createTable(meta: EntityMetadata): Promise<void>;
|
|
7
7
|
addColumn(meta: EntityMetadata, field: FieldMetadata): Promise<void>;
|
|
8
|
+
removeTable?(entityDbName: string): unknown;
|
|
9
|
+
removeColumn?($entityName: string, columnDbName: string): unknown;
|
|
8
10
|
}
|
|
9
11
|
export interface MigrationCode {
|
|
10
12
|
addSql(sql: string): void;
|
|
@@ -35,9 +37,12 @@ export type Migrations = Record<number, (utils: MigrationUtils) => Promise<unkno
|
|
|
35
37
|
export type MigrationUtils = {
|
|
36
38
|
sql(sql: string): Promise<unknown>;
|
|
37
39
|
};
|
|
38
|
-
export declare class DefaultMigrationBuilder implements MigrationBuilder {
|
|
40
|
+
export declare class DefaultMigrationBuilder implements Required<MigrationBuilder> {
|
|
39
41
|
code: MigrationCode;
|
|
40
|
-
|
|
42
|
+
private wrapped?;
|
|
43
|
+
constructor(code: MigrationCode, wrapped?: MigrationBuilder);
|
|
41
44
|
createTable(meta: EntityMetadata): Promise<void>;
|
|
42
45
|
addColumn(meta: EntityMetadata, field: FieldMetadata): Promise<void>;
|
|
46
|
+
removeTable(entityDbName: string): Promise<void>;
|
|
47
|
+
removeColumn(entityName: string, columnDbName: string): Promise<void>;
|
|
43
48
|
}
|
|
@@ -3,22 +3,83 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.DefaultMigrationBuilder = void 0;
|
|
4
4
|
var tslib_1 = require("tslib");
|
|
5
5
|
var DefaultMigrationBuilder = /** @class */ (function () {
|
|
6
|
-
function DefaultMigrationBuilder(code) {
|
|
6
|
+
function DefaultMigrationBuilder(code, wrapped) {
|
|
7
7
|
this.code = code;
|
|
8
|
+
this.wrapped = wrapped;
|
|
8
9
|
}
|
|
9
10
|
DefaultMigrationBuilder.prototype.createTable = function (meta) {
|
|
11
|
+
var _a;
|
|
10
12
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
11
|
-
return tslib_1.__generator(this, function (
|
|
12
|
-
|
|
13
|
-
|
|
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
|
+
}
|
|
14
26
|
});
|
|
15
27
|
});
|
|
16
28
|
};
|
|
17
29
|
DefaultMigrationBuilder.prototype.addColumn = function (meta, field) {
|
|
30
|
+
var _a;
|
|
18
31
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
19
|
-
return tslib_1.__generator(this, function (
|
|
20
|
-
|
|
21
|
-
|
|
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
|
+
}
|
|
22
83
|
});
|
|
23
84
|
});
|
|
24
85
|
};
|
|
@@ -16,6 +16,9 @@ function updateMigrationsFile(filePath, steps) {
|
|
|
16
16
|
case 0: return [4 /*yield*/, Promise.resolve().then(function () { return tslib_1.__importStar(require('typescript')); })];
|
|
17
17
|
case 1:
|
|
18
18
|
ts = _a.sent();
|
|
19
|
+
//@ts-ignore
|
|
20
|
+
if (ts.default)
|
|
21
|
+
ts = ts.default;
|
|
19
22
|
return [4 /*yield*/, Promise.resolve().then(function () { return tslib_1.__importStar(require('fs')); })];
|
|
20
23
|
case 2:
|
|
21
24
|
fs = _a.sent();
|
package/package.json
CHANGED
|
@@ -30,6 +30,23 @@ export declare class Filter {
|
|
|
30
30
|
|
|
31
31
|
*/
|
|
32
32
|
static getInfo<entityType>(metadata: EntityMetadata<entityType>, filter: EntityFilter<entityType>): Promise<FilterInfo<entityType>>;
|
|
33
|
+
/**
|
|
34
|
+
* Retrieves information about a filter, including precise values for each property.
|
|
35
|
+
* @template entityType The type of the entity being filtered.
|
|
36
|
+
* @param metadata The metadata of the entity being filtered.
|
|
37
|
+
* @param filter The filter to analyze.
|
|
38
|
+
* @returns A promise that resolves to a FilterInfo object containing the filter information.
|
|
39
|
+
* @example
|
|
40
|
+
* const info = await where.getInfo();
|
|
41
|
+
* console.log(info.preciseValues);
|
|
42
|
+
* // Output:
|
|
43
|
+
* // {
|
|
44
|
+
* // "customerId": ["1", "2", "3"], // Precise values inferred from the filter
|
|
45
|
+
* // "status": undefined, // Cannot infer precise values for 'status'
|
|
46
|
+
* // }
|
|
47
|
+
|
|
48
|
+
*/
|
|
49
|
+
getInfo<entityType>(): Promise<FilterInfo<entityType>>;
|
|
33
50
|
/**
|
|
34
51
|
* Creates a custom filter. Custom filters are evaluated on the backend, ensuring security and efficiency.
|
|
35
52
|
* When the filter is used in the frontend, only its name is sent to the backend via the API,
|
|
@@ -158,6 +175,7 @@ export declare class Filter {
|
|
|
158
175
|
* @returns {Promise<EntityFilter<entityType>>} The resolved entity filter.
|
|
159
176
|
*/
|
|
160
177
|
static resolve<entityType>(filter: EntityFilter<entityType> | (() => EntityFilter<entityType> | Promise<EntityFilter<entityType>>)): Promise<EntityFilter<entityType>>;
|
|
178
|
+
toJson(): any;
|
|
161
179
|
}
|
|
162
180
|
export interface FilterConsumer {
|
|
163
181
|
or(orElements: Filter[]): any;
|
|
@@ -101,6 +101,37 @@ var Filter = /** @class */ (function () {
|
|
|
101
101
|
});
|
|
102
102
|
});
|
|
103
103
|
};
|
|
104
|
+
/**
|
|
105
|
+
* Retrieves information about a filter, including precise values for each property.
|
|
106
|
+
* @template entityType The type of the entity being filtered.
|
|
107
|
+
* @param metadata The metadata of the entity being filtered.
|
|
108
|
+
* @param filter The filter to analyze.
|
|
109
|
+
* @returns A promise that resolves to a FilterInfo object containing the filter information.
|
|
110
|
+
* @example
|
|
111
|
+
* const info = await where.getInfo();
|
|
112
|
+
* console.log(info.preciseValues);
|
|
113
|
+
* // Output:
|
|
114
|
+
* // {
|
|
115
|
+
* // "customerId": ["1", "2", "3"], // Precise values inferred from the filter
|
|
116
|
+
* // "status": undefined, // Cannot infer precise values for 'status'
|
|
117
|
+
* // }
|
|
118
|
+
|
|
119
|
+
*/
|
|
120
|
+
Filter.prototype.getInfo = function () {
|
|
121
|
+
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
122
|
+
var result;
|
|
123
|
+
return tslib_1.__generator(this, function (_a) {
|
|
124
|
+
switch (_a.label) {
|
|
125
|
+
case 0:
|
|
126
|
+
result = new preciseValuesCollector();
|
|
127
|
+
return [4 /*yield*/, this.__applyToConsumer(result)];
|
|
128
|
+
case 1:
|
|
129
|
+
_a.sent();
|
|
130
|
+
return [2 /*return*/, result];
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
};
|
|
104
135
|
Filter.createCustom = function (rawFilterTranslator, key) {
|
|
105
136
|
if (key === void 0) { key = ''; }
|
|
106
137
|
var rawFilterInfo = { key: key, rawFilterTranslator: rawFilterTranslator };
|
|
@@ -295,7 +326,6 @@ var Filter = /** @class */ (function () {
|
|
|
295
326
|
});
|
|
296
327
|
});
|
|
297
328
|
};
|
|
298
|
-
//@internal
|
|
299
329
|
Filter.prototype.toJson = function () {
|
|
300
330
|
var r = new FilterSerializer();
|
|
301
331
|
this.__applyToConsumer(r);
|
package/src/remult3/remult3.d.ts
CHANGED
|
@@ -240,7 +240,7 @@ export declare type MembersOnly<T> = {
|
|
|
240
240
|
};
|
|
241
241
|
export declare type idType<entityType> = entityType extends {
|
|
242
242
|
id?: infer U;
|
|
243
|
-
} ? U : string | number;
|
|
243
|
+
} ? U extends string ? string : U extends number ? number : string | number : string | number;
|
|
244
244
|
/**used to perform CRUD operations on an `entityType` */
|
|
245
245
|
export interface Repository<entityType> {
|
|
246
246
|
/** returns a result array based on the provided options */
|
package/src/remult3/remult3.js
CHANGED
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
//p1 - It's good that there is no migrations added. (I also don't like automatic deletion), and it can be done manually if needed.
|
|
4
|
-
//p1 - Maybe migrations-snapshots.json should have fields deleted to have a one to one representation of the db?
|
|
3
|
+
//p1 DOC DONE - It's good that there is no migrations added. (I also don't like automatic deletion), and it can be done manually if needed.
|
|
4
|
+
//p1 DOC DONE - Maybe migrations-snapshots.json should have fields deleted to have a one to one representation of the db?
|
|
5
|
+
//p1 DOC DONE - @JYT - should I write to console on generate migrations, what are the changes that I've found / the migration step id / not changes found
|
|
6
|
+
//p1 DOC DONE - re-discuss endConnection - default false - explain in docs
|
|
7
|
+
//p1 DONE - JYC log the migration request - beforeMigration. afterMigration
|
|
8
|
+
//p1 DONE - migration default folder should be source/migrations (also docs?)
|
|
9
|
+
//p1 DONE - @JYT run all migrations in a single transaction? or transaction per step?
|
|
10
|
+
//p1 Done - Filter.toJson should be public
|
|
5
11
|
//p1 - I needed to modify the changes Field of changeLog entity to @Fields.json() to be nvarchar(max) too. Why is @Fields.object() only nvarchar(255) ? Or is it default size and can be adjusted?
|
|
6
|
-
//p1 -
|
|
7
|
-
//p1 -
|
|
8
|
-
//y1 - JY build issue
|
|
9
|
-
//p1 -
|
|
10
|
-
//y1 - migration default folder should be source/migrations (also docs?)
|
|
11
|
-
//y1 - discuss the typing issue with relations in this case vs the ValueListFieldTypes
|
|
12
|
-
//y1 - JYC log the migration request
|
|
13
|
-
//y1 - JYC health check approach
|
|
12
|
+
//p1 - improve type augmentation doc with specific of the file and with the export trick - fix code samples to init reqiest error
|
|
13
|
+
//p1 - document custom filter without sql
|
|
14
|
+
//y1!! - JY build issue
|
|
15
|
+
//p1 - discuss the typing issue with relations in this case vs the ValueListFieldTypes - return partial with id values.
|
|
14
16
|
//p1 - admin url1 - pocketbase use /_ for the admin //{allowed?:Allowed,url?:string}
|
|
15
17
|
//p1 - document new sqlite providers
|
|
16
18
|
//p1 - article auth.js with express
|
|
17
19
|
//p1 - document offline support
|
|
18
20
|
//p1 - fix getting started article with using your own database connection
|
|
21
|
+
//p1 - create foreign key constraints in user code
|
|
22
|
+
//p1 - https://github.com/vuejs/vitepress/issues/3154#issuecomment-1784612839
|
|
19
23
|
//y2 - should we validate relations
|
|
20
24
|
//y1 - dependency of live query tables
|
|
21
25
|
//y1 - consider replacing all errors with error classes that extend the base Error class
|