@oliasoft-open-source/node-json-migrator 3.1.0-beta-1 → 3.1.0-beta-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +211 -0
- package/dist/index.d.cts +44 -2
- package/dist/index.d.mts +44 -2
- package/dist/index.mjs +211 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -9027,6 +9027,77 @@ const getVersions = async (db, entity) => {
|
|
|
9027
9027
|
};
|
|
9028
9028
|
return db.any(query, params);
|
|
9029
9029
|
};
|
|
9030
|
+
const getRecordList = async (db, entity, entityColumnNames, latestVersion, latestVersionPlanLength) => {
|
|
9031
|
+
const query = `
|
|
9032
|
+
SELECT
|
|
9033
|
+
$(entityIdColumn:name) AS id,
|
|
9034
|
+
name,
|
|
9035
|
+
$(entityCreatedColumn:name) AS created,
|
|
9036
|
+
version
|
|
9037
|
+
FROM $(entityTable:name)
|
|
9038
|
+
WHERE (
|
|
9039
|
+
version IS NULL
|
|
9040
|
+
OR (
|
|
9041
|
+
version <> $(latestVersion)
|
|
9042
|
+
AND (
|
|
9043
|
+
SELECT
|
|
9044
|
+
CASE
|
|
9045
|
+
WHEN IS_JSON(plan) THEN JSON_ARRAY_LENGTH(plan::json)
|
|
9046
|
+
ELSE 0
|
|
9047
|
+
END AS length
|
|
9048
|
+
FROM $(entityVersionsTable:name)
|
|
9049
|
+
WHERE $(entityVersionsTable:name).version = version
|
|
9050
|
+
LIMIT 1
|
|
9051
|
+
)::integer <= $(latestVersionPlanLength)
|
|
9052
|
+
)
|
|
9053
|
+
)
|
|
9054
|
+
`;
|
|
9055
|
+
const params = {
|
|
9056
|
+
entityTable: entity,
|
|
9057
|
+
entityVersionsTable: `${entity}_versions`,
|
|
9058
|
+
entityIdColumn: entityColumnNames.id,
|
|
9059
|
+
entityCreatedColumn: entityColumnNames.created,
|
|
9060
|
+
latestVersion,
|
|
9061
|
+
latestVersionPlanLength
|
|
9062
|
+
};
|
|
9063
|
+
return db.any(query, params);
|
|
9064
|
+
};
|
|
9065
|
+
const getRecord = async (t, entity, entityColumnNames, entityId) => {
|
|
9066
|
+
const query = `
|
|
9067
|
+
SELECT *
|
|
9068
|
+
FROM $(entityTable:name)
|
|
9069
|
+
WHERE $(entityIdColumn:name) = $(entityId)
|
|
9070
|
+
`;
|
|
9071
|
+
const params = {
|
|
9072
|
+
entityTable: entity,
|
|
9073
|
+
entityId,
|
|
9074
|
+
entityIdColumn: entityColumnNames.id
|
|
9075
|
+
};
|
|
9076
|
+
return t.one(query, params);
|
|
9077
|
+
};
|
|
9078
|
+
const updateRecord = async (t, entity, entityColumnNames, entityId, currentVersion, nextData, nextVersion, etag) => {
|
|
9079
|
+
const useEtag = typeof etag === "number";
|
|
9080
|
+
const query = `
|
|
9081
|
+
UPDATE $(entityTable:name)
|
|
9082
|
+
SET data = $(nextData),
|
|
9083
|
+
version = $(nextVersion)
|
|
9084
|
+
${useEtag ? ", etag = etag + 1" : ""}
|
|
9085
|
+
WHERE $(entityIdColumn:name) = $(entityId)
|
|
9086
|
+
AND version = $(currentVersion)
|
|
9087
|
+
${useEtag ? "AND etag = $(etag)" : ""}
|
|
9088
|
+
RETURNING *
|
|
9089
|
+
`;
|
|
9090
|
+
const params = {
|
|
9091
|
+
entityTable: entity,
|
|
9092
|
+
entityId,
|
|
9093
|
+
entityIdColumn: entityColumnNames.id,
|
|
9094
|
+
currentVersion,
|
|
9095
|
+
nextData,
|
|
9096
|
+
nextVersion,
|
|
9097
|
+
etag
|
|
9098
|
+
};
|
|
9099
|
+
return t.oneOrNone(query, params);
|
|
9100
|
+
};
|
|
9030
9101
|
|
|
9031
9102
|
let cachedPlannedVersion = null;
|
|
9032
9103
|
let cachedMigratorFunctions = [];
|
|
@@ -9589,6 +9660,145 @@ const migrate = async ({
|
|
|
9589
9660
|
};
|
|
9590
9661
|
};
|
|
9591
9662
|
|
|
9663
|
+
const migrateRecord = async ({
|
|
9664
|
+
record,
|
|
9665
|
+
config,
|
|
9666
|
+
beforeMigrateRecord,
|
|
9667
|
+
afterMigrateRecord
|
|
9668
|
+
}) => {
|
|
9669
|
+
const { dry } = config;
|
|
9670
|
+
console.log(chalk.gray(` ${record.name}`));
|
|
9671
|
+
try {
|
|
9672
|
+
await config.database.tx(async (transaction) => {
|
|
9673
|
+
const currentRecord = await getRecord(
|
|
9674
|
+
transaction,
|
|
9675
|
+
config.entity,
|
|
9676
|
+
config.entityColumnNames,
|
|
9677
|
+
record.id
|
|
9678
|
+
);
|
|
9679
|
+
const { data, etag, version: currentVersion } = currentRecord;
|
|
9680
|
+
await beforeMigrateRecord({
|
|
9681
|
+
currentRecord,
|
|
9682
|
+
dry
|
|
9683
|
+
});
|
|
9684
|
+
const { nextPayload: nextData, nextVersion } = await migrate({
|
|
9685
|
+
payload: data,
|
|
9686
|
+
config: {
|
|
9687
|
+
...config,
|
|
9688
|
+
version: currentVersion,
|
|
9689
|
+
printPendingFileNames: true
|
|
9690
|
+
}
|
|
9691
|
+
});
|
|
9692
|
+
if (!dry) {
|
|
9693
|
+
const nextRecord = await updateRecord(
|
|
9694
|
+
transaction,
|
|
9695
|
+
config?.entity,
|
|
9696
|
+
config.entityColumnNames,
|
|
9697
|
+
record.id,
|
|
9698
|
+
currentVersion,
|
|
9699
|
+
nextData,
|
|
9700
|
+
nextVersion,
|
|
9701
|
+
etag
|
|
9702
|
+
);
|
|
9703
|
+
if (!nextRecord) {
|
|
9704
|
+
throw new Error(
|
|
9705
|
+
"Failed to patch record with newest migration - The record was probably updated while migrating..."
|
|
9706
|
+
);
|
|
9707
|
+
}
|
|
9708
|
+
await afterMigrateRecord({
|
|
9709
|
+
currentRecord,
|
|
9710
|
+
nextRecord,
|
|
9711
|
+
transaction,
|
|
9712
|
+
dry
|
|
9713
|
+
});
|
|
9714
|
+
}
|
|
9715
|
+
});
|
|
9716
|
+
return null;
|
|
9717
|
+
} catch (error) {
|
|
9718
|
+
const migrationErrorPayload = {
|
|
9719
|
+
id: record.id,
|
|
9720
|
+
name: record.name,
|
|
9721
|
+
created: record.created,
|
|
9722
|
+
error,
|
|
9723
|
+
stackTrace: error.stack
|
|
9724
|
+
};
|
|
9725
|
+
console.log(
|
|
9726
|
+
chalk.red(
|
|
9727
|
+
` Dataset migration with id ${record.id} failed:
|
|
9728
|
+
${error.stack}`
|
|
9729
|
+
)
|
|
9730
|
+
);
|
|
9731
|
+
return migrationErrorPayload;
|
|
9732
|
+
}
|
|
9733
|
+
};
|
|
9734
|
+
const migrateRecords = async ({
|
|
9735
|
+
recordList,
|
|
9736
|
+
config,
|
|
9737
|
+
beforeMigrateRecord,
|
|
9738
|
+
afterMigrateRecord,
|
|
9739
|
+
onMigrationErrors
|
|
9740
|
+
}) => {
|
|
9741
|
+
const { dry } = config;
|
|
9742
|
+
const migrationErrors = [];
|
|
9743
|
+
if (recordList.length) {
|
|
9744
|
+
console.log(chalk.gray("Executing record migration scripts..."));
|
|
9745
|
+
for await (const record of recordList) {
|
|
9746
|
+
const migrationErrorPayload = await migrateRecord({
|
|
9747
|
+
record,
|
|
9748
|
+
config,
|
|
9749
|
+
beforeMigrateRecord,
|
|
9750
|
+
afterMigrateRecord
|
|
9751
|
+
});
|
|
9752
|
+
if (migrationErrorPayload) {
|
|
9753
|
+
migrationErrors.push(migrationErrorPayload);
|
|
9754
|
+
}
|
|
9755
|
+
}
|
|
9756
|
+
}
|
|
9757
|
+
if (migrationErrors.length) {
|
|
9758
|
+
console.log(
|
|
9759
|
+
chalk.yellow(
|
|
9760
|
+
`Completed ${config?.entity ?? "entity"} migrations (some failed)${config?.dry ? " [dry-run, no output written]" : ""} \u2713`
|
|
9761
|
+
)
|
|
9762
|
+
);
|
|
9763
|
+
await onMigrationErrors({
|
|
9764
|
+
migrationErrors,
|
|
9765
|
+
dry
|
|
9766
|
+
});
|
|
9767
|
+
} else {
|
|
9768
|
+
console.log(
|
|
9769
|
+
chalk.green(
|
|
9770
|
+
`Completed ${config?.entity ?? "entity"} migrations (success)${config?.dry ? " [dry-run, no output written]" : ""} \u2713`
|
|
9771
|
+
)
|
|
9772
|
+
);
|
|
9773
|
+
}
|
|
9774
|
+
};
|
|
9775
|
+
const migrateAll = async ({
|
|
9776
|
+
config,
|
|
9777
|
+
beforeMigrateRecord,
|
|
9778
|
+
afterMigrateRecord,
|
|
9779
|
+
onMigrationErrors
|
|
9780
|
+
}) => {
|
|
9781
|
+
const plan = await getPlannedMigrations({
|
|
9782
|
+
config
|
|
9783
|
+
});
|
|
9784
|
+
const latestVersion = plan.nextVersion;
|
|
9785
|
+
const latestVersionPlanLength = plan.plannedMigrations.length;
|
|
9786
|
+
const recordList = await getRecordList(
|
|
9787
|
+
config?.database,
|
|
9788
|
+
config?.entity,
|
|
9789
|
+
config?.entityColumnNames,
|
|
9790
|
+
latestVersion,
|
|
9791
|
+
latestVersionPlanLength
|
|
9792
|
+
);
|
|
9793
|
+
await migrateRecords({
|
|
9794
|
+
config,
|
|
9795
|
+
recordList,
|
|
9796
|
+
beforeMigrateRecord,
|
|
9797
|
+
afterMigrateRecord,
|
|
9798
|
+
onMigrationErrors
|
|
9799
|
+
});
|
|
9800
|
+
};
|
|
9801
|
+
|
|
9592
9802
|
const parsePlan = (plan) => {
|
|
9593
9803
|
return (() => {
|
|
9594
9804
|
try {
|
|
@@ -9642,5 +9852,6 @@ exports.getPlannedMigrations = getPlannedMigrations;
|
|
|
9642
9852
|
exports.getPlannedVersion = getPlannedVersion;
|
|
9643
9853
|
exports.getVersions = getVersions;
|
|
9644
9854
|
exports.migrate = migrate;
|
|
9855
|
+
exports.migrateAll = migrateAll;
|
|
9645
9856
|
exports.pipe = pipe;
|
|
9646
9857
|
exports.printVersionHistory = printVersionHistory;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IDatabase, IHelpers } from 'pg-promise';
|
|
1
|
+
import { IDatabase, IHelpers, ITask } from 'pg-promise';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Generate a new dataset migration
|
|
@@ -21,6 +21,14 @@ type TEntityColumnNames = {
|
|
|
21
21
|
id: string;
|
|
22
22
|
created: string;
|
|
23
23
|
};
|
|
24
|
+
type TRecord<T extends TEntityColumnNames = TEntityColumnNames> = {
|
|
25
|
+
name: string;
|
|
26
|
+
version: string;
|
|
27
|
+
} & {
|
|
28
|
+
[K in T['id']]: number | string;
|
|
29
|
+
} & {
|
|
30
|
+
[K in T['created']]: string | Date;
|
|
31
|
+
};
|
|
24
32
|
type TConfig = {
|
|
25
33
|
directory: string;
|
|
26
34
|
database?: IDatabase<unknown>;
|
|
@@ -35,6 +43,30 @@ type TConfig = {
|
|
|
35
43
|
importModule?: boolean;
|
|
36
44
|
autoInitializeTable?: boolean;
|
|
37
45
|
};
|
|
46
|
+
type TBeforeMigrateRecordPayload = {
|
|
47
|
+
currentRecord: TRecord;
|
|
48
|
+
dry: boolean;
|
|
49
|
+
};
|
|
50
|
+
type TBeforeMigrateRecord = (params: TBeforeMigrateRecordPayload) => Promise<void>;
|
|
51
|
+
type TAfterMigrateRecordPayload = {
|
|
52
|
+
currentRecord: TRecord;
|
|
53
|
+
nextRecord: TRecord;
|
|
54
|
+
transaction?: ITask<unknown>;
|
|
55
|
+
dry: boolean;
|
|
56
|
+
};
|
|
57
|
+
type TAfterMigrateRecord = (params: TAfterMigrateRecordPayload) => Promise<void>;
|
|
58
|
+
type TMigrationErrorPayload = {
|
|
59
|
+
id: string;
|
|
60
|
+
name: string;
|
|
61
|
+
created: string | Date;
|
|
62
|
+
error: unknown;
|
|
63
|
+
stackTrace?: string;
|
|
64
|
+
};
|
|
65
|
+
type TOnMigrationErrorsPayload = {
|
|
66
|
+
migrationErrors: TMigrationErrorPayload[];
|
|
67
|
+
dry: boolean;
|
|
68
|
+
};
|
|
69
|
+
type TOnMigrationErrors = (params: TOnMigrationErrorsPayload) => Promise<void>;
|
|
38
70
|
|
|
39
71
|
declare const getPlannedMigrations: ({ config }: {
|
|
40
72
|
config: TConfig;
|
|
@@ -62,6 +94,16 @@ declare const migrate: ({ payload, config, }: {
|
|
|
62
94
|
nextVersion: string;
|
|
63
95
|
}>;
|
|
64
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Migrate all records (only use via command line interface)
|
|
99
|
+
*/
|
|
100
|
+
declare const migrateAll: ({ config, beforeMigrateRecord, afterMigrateRecord, onMigrationErrors, }: {
|
|
101
|
+
config: TConfig;
|
|
102
|
+
beforeMigrateRecord: TBeforeMigrateRecord;
|
|
103
|
+
afterMigrateRecord: TAfterMigrateRecord;
|
|
104
|
+
onMigrationErrors: TOnMigrationErrors;
|
|
105
|
+
}) => Promise<void>;
|
|
106
|
+
|
|
65
107
|
/**
|
|
66
108
|
* Executes the pending migrators on a payload, returns modified payload
|
|
67
109
|
*
|
|
@@ -84,4 +126,4 @@ declare const printVersionHistory: ({ config }: {
|
|
|
84
126
|
config: TConfig;
|
|
85
127
|
}) => Promise<void>;
|
|
86
128
|
|
|
87
|
-
export { createMigration, getPlannedMigrations, getPlannedVersion, getVersions, migrate, pipe, printVersionHistory };
|
|
129
|
+
export { type TAfterMigrateRecord, type TAfterMigrateRecordPayload, type TBeforeMigrateRecord, type TBeforeMigrateRecordPayload, type TConfig, type TEntityColumnNames, type TMigration, type TMigrationErrorPayload, type TOnMigrationErrors, type TOnMigrationErrorsPayload, type TRecord, createMigration, getPlannedMigrations, getPlannedVersion, getVersions, migrate, migrateAll, pipe, printVersionHistory };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IDatabase, IHelpers } from 'pg-promise';
|
|
1
|
+
import { IDatabase, IHelpers, ITask } from 'pg-promise';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Generate a new dataset migration
|
|
@@ -21,6 +21,14 @@ type TEntityColumnNames = {
|
|
|
21
21
|
id: string;
|
|
22
22
|
created: string;
|
|
23
23
|
};
|
|
24
|
+
type TRecord<T extends TEntityColumnNames = TEntityColumnNames> = {
|
|
25
|
+
name: string;
|
|
26
|
+
version: string;
|
|
27
|
+
} & {
|
|
28
|
+
[K in T['id']]: number | string;
|
|
29
|
+
} & {
|
|
30
|
+
[K in T['created']]: string | Date;
|
|
31
|
+
};
|
|
24
32
|
type TConfig = {
|
|
25
33
|
directory: string;
|
|
26
34
|
database?: IDatabase<unknown>;
|
|
@@ -35,6 +43,30 @@ type TConfig = {
|
|
|
35
43
|
importModule?: boolean;
|
|
36
44
|
autoInitializeTable?: boolean;
|
|
37
45
|
};
|
|
46
|
+
type TBeforeMigrateRecordPayload = {
|
|
47
|
+
currentRecord: TRecord;
|
|
48
|
+
dry: boolean;
|
|
49
|
+
};
|
|
50
|
+
type TBeforeMigrateRecord = (params: TBeforeMigrateRecordPayload) => Promise<void>;
|
|
51
|
+
type TAfterMigrateRecordPayload = {
|
|
52
|
+
currentRecord: TRecord;
|
|
53
|
+
nextRecord: TRecord;
|
|
54
|
+
transaction?: ITask<unknown>;
|
|
55
|
+
dry: boolean;
|
|
56
|
+
};
|
|
57
|
+
type TAfterMigrateRecord = (params: TAfterMigrateRecordPayload) => Promise<void>;
|
|
58
|
+
type TMigrationErrorPayload = {
|
|
59
|
+
id: string;
|
|
60
|
+
name: string;
|
|
61
|
+
created: string | Date;
|
|
62
|
+
error: unknown;
|
|
63
|
+
stackTrace?: string;
|
|
64
|
+
};
|
|
65
|
+
type TOnMigrationErrorsPayload = {
|
|
66
|
+
migrationErrors: TMigrationErrorPayload[];
|
|
67
|
+
dry: boolean;
|
|
68
|
+
};
|
|
69
|
+
type TOnMigrationErrors = (params: TOnMigrationErrorsPayload) => Promise<void>;
|
|
38
70
|
|
|
39
71
|
declare const getPlannedMigrations: ({ config }: {
|
|
40
72
|
config: TConfig;
|
|
@@ -62,6 +94,16 @@ declare const migrate: ({ payload, config, }: {
|
|
|
62
94
|
nextVersion: string;
|
|
63
95
|
}>;
|
|
64
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Migrate all records (only use via command line interface)
|
|
99
|
+
*/
|
|
100
|
+
declare const migrateAll: ({ config, beforeMigrateRecord, afterMigrateRecord, onMigrationErrors, }: {
|
|
101
|
+
config: TConfig;
|
|
102
|
+
beforeMigrateRecord: TBeforeMigrateRecord;
|
|
103
|
+
afterMigrateRecord: TAfterMigrateRecord;
|
|
104
|
+
onMigrationErrors: TOnMigrationErrors;
|
|
105
|
+
}) => Promise<void>;
|
|
106
|
+
|
|
65
107
|
/**
|
|
66
108
|
* Executes the pending migrators on a payload, returns modified payload
|
|
67
109
|
*
|
|
@@ -84,4 +126,4 @@ declare const printVersionHistory: ({ config }: {
|
|
|
84
126
|
config: TConfig;
|
|
85
127
|
}) => Promise<void>;
|
|
86
128
|
|
|
87
|
-
export { createMigration, getPlannedMigrations, getPlannedVersion, getVersions, migrate, pipe, printVersionHistory };
|
|
129
|
+
export { type TAfterMigrateRecord, type TAfterMigrateRecordPayload, type TBeforeMigrateRecord, type TBeforeMigrateRecordPayload, type TConfig, type TEntityColumnNames, type TMigration, type TMigrationErrorPayload, type TOnMigrationErrors, type TOnMigrationErrorsPayload, type TRecord, createMigration, getPlannedMigrations, getPlannedVersion, getVersions, migrate, migrateAll, pipe, printVersionHistory };
|
package/dist/index.mjs
CHANGED
|
@@ -9006,6 +9006,77 @@ const getVersions = async (db, entity) => {
|
|
|
9006
9006
|
};
|
|
9007
9007
|
return db.any(query, params);
|
|
9008
9008
|
};
|
|
9009
|
+
const getRecordList = async (db, entity, entityColumnNames, latestVersion, latestVersionPlanLength) => {
|
|
9010
|
+
const query = `
|
|
9011
|
+
SELECT
|
|
9012
|
+
$(entityIdColumn:name) AS id,
|
|
9013
|
+
name,
|
|
9014
|
+
$(entityCreatedColumn:name) AS created,
|
|
9015
|
+
version
|
|
9016
|
+
FROM $(entityTable:name)
|
|
9017
|
+
WHERE (
|
|
9018
|
+
version IS NULL
|
|
9019
|
+
OR (
|
|
9020
|
+
version <> $(latestVersion)
|
|
9021
|
+
AND (
|
|
9022
|
+
SELECT
|
|
9023
|
+
CASE
|
|
9024
|
+
WHEN IS_JSON(plan) THEN JSON_ARRAY_LENGTH(plan::json)
|
|
9025
|
+
ELSE 0
|
|
9026
|
+
END AS length
|
|
9027
|
+
FROM $(entityVersionsTable:name)
|
|
9028
|
+
WHERE $(entityVersionsTable:name).version = version
|
|
9029
|
+
LIMIT 1
|
|
9030
|
+
)::integer <= $(latestVersionPlanLength)
|
|
9031
|
+
)
|
|
9032
|
+
)
|
|
9033
|
+
`;
|
|
9034
|
+
const params = {
|
|
9035
|
+
entityTable: entity,
|
|
9036
|
+
entityVersionsTable: `${entity}_versions`,
|
|
9037
|
+
entityIdColumn: entityColumnNames.id,
|
|
9038
|
+
entityCreatedColumn: entityColumnNames.created,
|
|
9039
|
+
latestVersion,
|
|
9040
|
+
latestVersionPlanLength
|
|
9041
|
+
};
|
|
9042
|
+
return db.any(query, params);
|
|
9043
|
+
};
|
|
9044
|
+
const getRecord = async (t, entity, entityColumnNames, entityId) => {
|
|
9045
|
+
const query = `
|
|
9046
|
+
SELECT *
|
|
9047
|
+
FROM $(entityTable:name)
|
|
9048
|
+
WHERE $(entityIdColumn:name) = $(entityId)
|
|
9049
|
+
`;
|
|
9050
|
+
const params = {
|
|
9051
|
+
entityTable: entity,
|
|
9052
|
+
entityId,
|
|
9053
|
+
entityIdColumn: entityColumnNames.id
|
|
9054
|
+
};
|
|
9055
|
+
return t.one(query, params);
|
|
9056
|
+
};
|
|
9057
|
+
const updateRecord = async (t, entity, entityColumnNames, entityId, currentVersion, nextData, nextVersion, etag) => {
|
|
9058
|
+
const useEtag = typeof etag === "number";
|
|
9059
|
+
const query = `
|
|
9060
|
+
UPDATE $(entityTable:name)
|
|
9061
|
+
SET data = $(nextData),
|
|
9062
|
+
version = $(nextVersion)
|
|
9063
|
+
${useEtag ? ", etag = etag + 1" : ""}
|
|
9064
|
+
WHERE $(entityIdColumn:name) = $(entityId)
|
|
9065
|
+
AND version = $(currentVersion)
|
|
9066
|
+
${useEtag ? "AND etag = $(etag)" : ""}
|
|
9067
|
+
RETURNING *
|
|
9068
|
+
`;
|
|
9069
|
+
const params = {
|
|
9070
|
+
entityTable: entity,
|
|
9071
|
+
entityId,
|
|
9072
|
+
entityIdColumn: entityColumnNames.id,
|
|
9073
|
+
currentVersion,
|
|
9074
|
+
nextData,
|
|
9075
|
+
nextVersion,
|
|
9076
|
+
etag
|
|
9077
|
+
};
|
|
9078
|
+
return t.oneOrNone(query, params);
|
|
9079
|
+
};
|
|
9009
9080
|
|
|
9010
9081
|
let cachedPlannedVersion = null;
|
|
9011
9082
|
let cachedMigratorFunctions = [];
|
|
@@ -9568,6 +9639,145 @@ const migrate = async ({
|
|
|
9568
9639
|
};
|
|
9569
9640
|
};
|
|
9570
9641
|
|
|
9642
|
+
const migrateRecord = async ({
|
|
9643
|
+
record,
|
|
9644
|
+
config,
|
|
9645
|
+
beforeMigrateRecord,
|
|
9646
|
+
afterMigrateRecord
|
|
9647
|
+
}) => {
|
|
9648
|
+
const { dry } = config;
|
|
9649
|
+
console.log(chalk.gray(` ${record.name}`));
|
|
9650
|
+
try {
|
|
9651
|
+
await config.database.tx(async (transaction) => {
|
|
9652
|
+
const currentRecord = await getRecord(
|
|
9653
|
+
transaction,
|
|
9654
|
+
config.entity,
|
|
9655
|
+
config.entityColumnNames,
|
|
9656
|
+
record.id
|
|
9657
|
+
);
|
|
9658
|
+
const { data, etag, version: currentVersion } = currentRecord;
|
|
9659
|
+
await beforeMigrateRecord({
|
|
9660
|
+
currentRecord,
|
|
9661
|
+
dry
|
|
9662
|
+
});
|
|
9663
|
+
const { nextPayload: nextData, nextVersion } = await migrate({
|
|
9664
|
+
payload: data,
|
|
9665
|
+
config: {
|
|
9666
|
+
...config,
|
|
9667
|
+
version: currentVersion,
|
|
9668
|
+
printPendingFileNames: true
|
|
9669
|
+
}
|
|
9670
|
+
});
|
|
9671
|
+
if (!dry) {
|
|
9672
|
+
const nextRecord = await updateRecord(
|
|
9673
|
+
transaction,
|
|
9674
|
+
config?.entity,
|
|
9675
|
+
config.entityColumnNames,
|
|
9676
|
+
record.id,
|
|
9677
|
+
currentVersion,
|
|
9678
|
+
nextData,
|
|
9679
|
+
nextVersion,
|
|
9680
|
+
etag
|
|
9681
|
+
);
|
|
9682
|
+
if (!nextRecord) {
|
|
9683
|
+
throw new Error(
|
|
9684
|
+
"Failed to patch record with newest migration - The record was probably updated while migrating..."
|
|
9685
|
+
);
|
|
9686
|
+
}
|
|
9687
|
+
await afterMigrateRecord({
|
|
9688
|
+
currentRecord,
|
|
9689
|
+
nextRecord,
|
|
9690
|
+
transaction,
|
|
9691
|
+
dry
|
|
9692
|
+
});
|
|
9693
|
+
}
|
|
9694
|
+
});
|
|
9695
|
+
return null;
|
|
9696
|
+
} catch (error) {
|
|
9697
|
+
const migrationErrorPayload = {
|
|
9698
|
+
id: record.id,
|
|
9699
|
+
name: record.name,
|
|
9700
|
+
created: record.created,
|
|
9701
|
+
error,
|
|
9702
|
+
stackTrace: error.stack
|
|
9703
|
+
};
|
|
9704
|
+
console.log(
|
|
9705
|
+
chalk.red(
|
|
9706
|
+
` Dataset migration with id ${record.id} failed:
|
|
9707
|
+
${error.stack}`
|
|
9708
|
+
)
|
|
9709
|
+
);
|
|
9710
|
+
return migrationErrorPayload;
|
|
9711
|
+
}
|
|
9712
|
+
};
|
|
9713
|
+
const migrateRecords = async ({
|
|
9714
|
+
recordList,
|
|
9715
|
+
config,
|
|
9716
|
+
beforeMigrateRecord,
|
|
9717
|
+
afterMigrateRecord,
|
|
9718
|
+
onMigrationErrors
|
|
9719
|
+
}) => {
|
|
9720
|
+
const { dry } = config;
|
|
9721
|
+
const migrationErrors = [];
|
|
9722
|
+
if (recordList.length) {
|
|
9723
|
+
console.log(chalk.gray("Executing record migration scripts..."));
|
|
9724
|
+
for await (const record of recordList) {
|
|
9725
|
+
const migrationErrorPayload = await migrateRecord({
|
|
9726
|
+
record,
|
|
9727
|
+
config,
|
|
9728
|
+
beforeMigrateRecord,
|
|
9729
|
+
afterMigrateRecord
|
|
9730
|
+
});
|
|
9731
|
+
if (migrationErrorPayload) {
|
|
9732
|
+
migrationErrors.push(migrationErrorPayload);
|
|
9733
|
+
}
|
|
9734
|
+
}
|
|
9735
|
+
}
|
|
9736
|
+
if (migrationErrors.length) {
|
|
9737
|
+
console.log(
|
|
9738
|
+
chalk.yellow(
|
|
9739
|
+
`Completed ${config?.entity ?? "entity"} migrations (some failed)${config?.dry ? " [dry-run, no output written]" : ""} \u2713`
|
|
9740
|
+
)
|
|
9741
|
+
);
|
|
9742
|
+
await onMigrationErrors({
|
|
9743
|
+
migrationErrors,
|
|
9744
|
+
dry
|
|
9745
|
+
});
|
|
9746
|
+
} else {
|
|
9747
|
+
console.log(
|
|
9748
|
+
chalk.green(
|
|
9749
|
+
`Completed ${config?.entity ?? "entity"} migrations (success)${config?.dry ? " [dry-run, no output written]" : ""} \u2713`
|
|
9750
|
+
)
|
|
9751
|
+
);
|
|
9752
|
+
}
|
|
9753
|
+
};
|
|
9754
|
+
const migrateAll = async ({
|
|
9755
|
+
config,
|
|
9756
|
+
beforeMigrateRecord,
|
|
9757
|
+
afterMigrateRecord,
|
|
9758
|
+
onMigrationErrors
|
|
9759
|
+
}) => {
|
|
9760
|
+
const plan = await getPlannedMigrations({
|
|
9761
|
+
config
|
|
9762
|
+
});
|
|
9763
|
+
const latestVersion = plan.nextVersion;
|
|
9764
|
+
const latestVersionPlanLength = plan.plannedMigrations.length;
|
|
9765
|
+
const recordList = await getRecordList(
|
|
9766
|
+
config?.database,
|
|
9767
|
+
config?.entity,
|
|
9768
|
+
config?.entityColumnNames,
|
|
9769
|
+
latestVersion,
|
|
9770
|
+
latestVersionPlanLength
|
|
9771
|
+
);
|
|
9772
|
+
await migrateRecords({
|
|
9773
|
+
config,
|
|
9774
|
+
recordList,
|
|
9775
|
+
beforeMigrateRecord,
|
|
9776
|
+
afterMigrateRecord,
|
|
9777
|
+
onMigrationErrors
|
|
9778
|
+
});
|
|
9779
|
+
};
|
|
9780
|
+
|
|
9571
9781
|
const parsePlan = (plan) => {
|
|
9572
9782
|
return (() => {
|
|
9573
9783
|
try {
|
|
@@ -9616,4 +9826,4 @@ const printVersionHistory = async ({ config }) => {
|
|
|
9616
9826
|
}
|
|
9617
9827
|
};
|
|
9618
9828
|
|
|
9619
|
-
export { createMigration, getPlannedMigrations, getPlannedVersion, getVersions, migrate, pipe, printVersionHistory };
|
|
9829
|
+
export { createMigration, getPlannedMigrations, getPlannedVersion, getVersions, migrate, migrateAll, pipe, printVersionHistory };
|
package/package.json
CHANGED