appwrite-utils-cli 0.0.38 → 0.0.40
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/migrations/converters.js +15 -1
- package/dist/migrations/dataLoader.d.ts +2 -2
- package/dist/migrations/dataLoader.js +207 -175
- package/dist/migrations/importDataActions.d.ts +8 -0
- package/dist/migrations/importDataActions.js +11 -0
- package/dist/migrations/migrationHelper.js +1 -1
- package/package.json +1 -1
- package/src/migrations/converters.ts +17 -1
- package/src/migrations/dataLoader.ts +280 -248
- package/src/migrations/importDataActions.ts +11 -0
- package/src/migrations/migrationHelper.ts +1 -1
|
@@ -103,32 +103,53 @@ export class DataLoader {
|
|
|
103
103
|
// Create a new object to hold the merged result
|
|
104
104
|
const result = { ...source };
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const sourceArray = Array.isArray(sourceValue) ? sourceValue : [];
|
|
113
|
-
result[key] = [...new Set([...sourceArray, ...updateValue])];
|
|
114
|
-
}
|
|
115
|
-
// If the update value is an object, recursively merge
|
|
116
|
-
else if (
|
|
117
|
-
updateValue !== null &&
|
|
118
|
-
typeof updateValue === "object" &&
|
|
119
|
-
!(updateValue instanceof Date)
|
|
120
|
-
) {
|
|
121
|
-
result[key] = this.mergeObjects(sourceValue, updateValue);
|
|
106
|
+
// Loop through the keys of the object we care about
|
|
107
|
+
for (const [key, value] of Object.entries(source)) {
|
|
108
|
+
// Check if the key exists in the target object
|
|
109
|
+
if (!Object.hasOwn(update, key)) {
|
|
110
|
+
// If the key doesn't exist, we can just skip it like bad cheese
|
|
111
|
+
continue;
|
|
122
112
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
result[key] = updateValue;
|
|
113
|
+
if (update[key] === value) {
|
|
114
|
+
continue;
|
|
126
115
|
}
|
|
127
|
-
// If the
|
|
128
|
-
|
|
129
|
-
|
|
116
|
+
// If the value ain't here, we can just do whatever man
|
|
117
|
+
if (value === undefined || value === null || value === "") {
|
|
118
|
+
// If the update key is defined
|
|
119
|
+
if (
|
|
120
|
+
update[key] !== undefined &&
|
|
121
|
+
update[key] !== null &&
|
|
122
|
+
update[key] !== ""
|
|
123
|
+
) {
|
|
124
|
+
// might as well use it eh?
|
|
125
|
+
result[key] = update[key];
|
|
126
|
+
}
|
|
127
|
+
// ELSE if the value is an array, because it would then not be === to those things above
|
|
128
|
+
} else if (Array.isArray(value)) {
|
|
129
|
+
// Get the update value
|
|
130
|
+
const updateValue = update[key];
|
|
131
|
+
// If the update value is an array, concatenate and remove duplicates
|
|
132
|
+
// and poopy data
|
|
133
|
+
if (Array.isArray(updateValue)) {
|
|
134
|
+
result[key] = [...new Set([...value, ...updateValue])].filter(
|
|
135
|
+
(item) => item !== null && item !== undefined && item !== ""
|
|
136
|
+
);
|
|
137
|
+
} else {
|
|
138
|
+
// If the update value is not an array, just use it
|
|
139
|
+
result[key] = [...value, updateValue].filter(
|
|
140
|
+
(item) => item !== null && item !== undefined && item !== ""
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
} else if (typeof value === "object") {
|
|
144
|
+
// If the value is an object, we need to merge it
|
|
145
|
+
if (typeof update[key] === "object") {
|
|
146
|
+
result[key] = this.mergeObjects(value, update[key]);
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
// Finally, the source value is defined, and not an array, so we don't care about the update value
|
|
150
|
+
continue;
|
|
130
151
|
}
|
|
131
|
-
}
|
|
152
|
+
}
|
|
132
153
|
|
|
133
154
|
return result;
|
|
134
155
|
}
|
|
@@ -219,6 +240,9 @@ export class DataLoader {
|
|
|
219
240
|
item,
|
|
220
241
|
attributeMappings
|
|
221
242
|
);
|
|
243
|
+
if (item["region"]) {
|
|
244
|
+
logger.info(`Converted item: ${JSON.stringify(convertedItem, null, 2)}`);
|
|
245
|
+
}
|
|
222
246
|
// Run additional converter functions on the converted item, if any
|
|
223
247
|
return this.importDataActions.runConverterFunctions(
|
|
224
248
|
convertedItem,
|
|
@@ -346,11 +370,15 @@ export class DataLoader {
|
|
|
346
370
|
for (const createDef of createDefs) {
|
|
347
371
|
if (!isUsersCollection) {
|
|
348
372
|
console.log(`${collection.name} is not users collection`);
|
|
349
|
-
this.prepareCreateData(db, collection, createDef);
|
|
373
|
+
await this.prepareCreateData(db, collection, createDef);
|
|
350
374
|
} else {
|
|
351
375
|
// Special handling for users collection if needed
|
|
352
376
|
console.log(`${collection.name} is users collection`);
|
|
353
|
-
this.prepareUserCollectionCreateData(
|
|
377
|
+
await this.prepareUserCollectionCreateData(
|
|
378
|
+
db,
|
|
379
|
+
collection,
|
|
380
|
+
createDef
|
|
381
|
+
);
|
|
354
382
|
}
|
|
355
383
|
}
|
|
356
384
|
for (const updateDef of updateDefs) {
|
|
@@ -361,7 +389,7 @@ export class DataLoader {
|
|
|
361
389
|
continue;
|
|
362
390
|
}
|
|
363
391
|
// Prepare the update data for the collection
|
|
364
|
-
this.prepareUpdateData(db, collection, updateDef);
|
|
392
|
+
await this.prepareUpdateData(db, collection, updateDef);
|
|
365
393
|
}
|
|
366
394
|
}
|
|
367
395
|
console.log("Running update references");
|
|
@@ -531,7 +559,12 @@ export class DataLoader {
|
|
|
531
559
|
collectionData.data[i].context[idMapping.sourceField];
|
|
532
560
|
|
|
533
561
|
// Skip if value to match is missing or empty
|
|
534
|
-
if (
|
|
562
|
+
if (
|
|
563
|
+
!valueToMatch ||
|
|
564
|
+
_.isEmpty(valueToMatch) ||
|
|
565
|
+
valueToMatch === null
|
|
566
|
+
)
|
|
567
|
+
continue;
|
|
535
568
|
|
|
536
569
|
const isFieldToSetArray = collectionConfig.attributes.find(
|
|
537
570
|
(attribute) => attribute.key === fieldToSetKey
|
|
@@ -814,11 +847,11 @@ export class DataLoader {
|
|
|
814
847
|
* @param collection - The collection configuration.
|
|
815
848
|
* @param importDef - The import definition containing the attribute mappings and other relevant info.
|
|
816
849
|
*/
|
|
817
|
-
prepareUserCollectionCreateData(
|
|
850
|
+
async prepareUserCollectionCreateData(
|
|
818
851
|
db: ConfigDatabase,
|
|
819
852
|
collection: CollectionCreate,
|
|
820
853
|
importDef: ImportDef
|
|
821
|
-
): void {
|
|
854
|
+
): Promise<void> {
|
|
822
855
|
// Load the raw data based on the import definition
|
|
823
856
|
const rawData = this.loadData(importDef);
|
|
824
857
|
const operationId = this.collectionImportOperations.get(
|
|
@@ -842,157 +875,136 @@ export class DataLoader {
|
|
|
842
875
|
`No import operation found for collection ${collection.name}`
|
|
843
876
|
);
|
|
844
877
|
}
|
|
845
|
-
updateOperation(this.database, operationId, {
|
|
878
|
+
await updateOperation(this.database, operationId, {
|
|
846
879
|
status: "ready",
|
|
847
880
|
total: rawData.length,
|
|
848
|
-
})
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
881
|
+
});
|
|
882
|
+
// Retrieve the current user data and the current collection data from the import map
|
|
883
|
+
const currentUserData = this.importMap.get(this.getCollectionKey("users"));
|
|
884
|
+
const currentData = this.importMap.get(
|
|
885
|
+
this.getCollectionKey(collection.name)
|
|
886
|
+
);
|
|
887
|
+
// Log errors if the necessary data is not found in the import map
|
|
888
|
+
if (!currentUserData) {
|
|
889
|
+
logger.error(
|
|
890
|
+
`No data found for collection ${"users"} for createDef but it says it's supposed to have one...`
|
|
852
891
|
);
|
|
853
|
-
|
|
854
|
-
|
|
892
|
+
return;
|
|
893
|
+
} else if (!currentData) {
|
|
894
|
+
logger.error(
|
|
895
|
+
`No data found for collection ${collection.name} for createDef but it says it's supposed to have one...`
|
|
896
|
+
);
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
// Iterate through each item in the raw data
|
|
900
|
+
for (const item of rawData) {
|
|
901
|
+
// Prepare user data, check for duplicates, and remove user-specific keys
|
|
902
|
+
let { transformedItem, existingId, userData } = this.prepareUserData(
|
|
903
|
+
item,
|
|
904
|
+
importDef.attributeMappings,
|
|
905
|
+
importDef.primaryKeyField,
|
|
906
|
+
this.getTrueUniqueId(this.getCollectionKey("users"))
|
|
855
907
|
);
|
|
856
|
-
// Log errors if the necessary data is not found in the import map
|
|
857
|
-
if (!currentUserData) {
|
|
858
|
-
logger.error(
|
|
859
|
-
`No data found for collection ${"users"} for createDef but it says it's supposed to have one...`
|
|
860
|
-
);
|
|
861
|
-
return;
|
|
862
|
-
} else if (!currentData) {
|
|
863
|
-
logger.error(
|
|
864
|
-
`No data found for collection ${collection.name} for createDef but it says it's supposed to have one...`
|
|
865
|
-
);
|
|
866
|
-
return;
|
|
867
|
-
}
|
|
868
|
-
// Iterate through each item in the raw data
|
|
869
|
-
for (const item of rawData) {
|
|
870
|
-
// Prepare user data, check for duplicates, and remove user-specific keys
|
|
871
|
-
let { transformedItem, existingId, userData } = this.prepareUserData(
|
|
872
|
-
item,
|
|
873
|
-
importDef.attributeMappings,
|
|
874
|
-
importDef.primaryKeyField,
|
|
875
|
-
this.getTrueUniqueId(this.getCollectionKey("users"))
|
|
876
|
-
);
|
|
877
908
|
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
909
|
+
logger.info(
|
|
910
|
+
`In create user -- transformedItem: ${JSON.stringify(
|
|
911
|
+
transformedItem,
|
|
912
|
+
null,
|
|
913
|
+
2
|
|
914
|
+
)}`
|
|
915
|
+
);
|
|
885
916
|
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
917
|
+
// Generate a new unique ID for the item or use existing ID
|
|
918
|
+
if (!existingId) {
|
|
919
|
+
// No existing user ID, generate a new unique ID
|
|
920
|
+
existingId = this.getTrueUniqueId(this.getCollectionKey("users"));
|
|
921
|
+
transformedItem.docId = existingId; // Assign the new ID to the transformed data's docId field
|
|
922
|
+
}
|
|
892
923
|
|
|
893
|
-
|
|
894
|
-
|
|
924
|
+
// Create a context object for the item, including the new ID
|
|
925
|
+
let context = this.createContext(db, collection, item, existingId);
|
|
895
926
|
|
|
896
|
-
|
|
897
|
-
|
|
927
|
+
// Merge the transformed data into the context
|
|
928
|
+
context = { ...context, ...transformedItem, ...userData.finalData };
|
|
898
929
|
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
930
|
+
// If a primary key field is defined, handle the ID mapping and check for duplicates
|
|
931
|
+
if (importDef.primaryKeyField) {
|
|
932
|
+
const oldId = item[importDef.primaryKeyField];
|
|
902
933
|
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
}
|
|
934
|
+
// Check if the oldId already exists to handle potential duplicates
|
|
935
|
+
if (
|
|
936
|
+
this.oldIdToNewIdPerCollectionMap
|
|
937
|
+
.get(this.getCollectionKey(collection.name))
|
|
938
|
+
?.has(`${oldId}`)
|
|
939
|
+
) {
|
|
940
|
+
// Found a duplicate oldId, now decide how to merge or handle these duplicates
|
|
941
|
+
for (const data of currentData.data) {
|
|
942
|
+
if (
|
|
943
|
+
data.finalData.docId === oldId ||
|
|
944
|
+
data.finalData.userId === oldId
|
|
945
|
+
) {
|
|
946
|
+
transformedItem = this.mergeObjects(
|
|
947
|
+
data.finalData,
|
|
948
|
+
transformedItem
|
|
949
|
+
);
|
|
920
950
|
}
|
|
921
|
-
} else {
|
|
922
|
-
// No duplicate found, simply map the oldId to the new itemId
|
|
923
|
-
collectionOldIdToNewIdMap?.set(`${oldId}`, `${existingId}`);
|
|
924
951
|
}
|
|
952
|
+
} else {
|
|
953
|
+
// No duplicate found, simply map the oldId to the new itemId
|
|
954
|
+
collectionOldIdToNewIdMap?.set(`${oldId}`, `${existingId}`);
|
|
925
955
|
}
|
|
956
|
+
}
|
|
926
957
|
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
958
|
+
// Handle merging for currentUserData
|
|
959
|
+
for (let i = 0; i < currentUserData.data.length; i++) {
|
|
960
|
+
const currentUserDataItem = currentUserData.data[i];
|
|
961
|
+
const samePhones =
|
|
962
|
+
currentUserDataItem.finalData.phone &&
|
|
963
|
+
transformedItem.phone &&
|
|
964
|
+
currentUserDataItem.finalData.phone === transformedItem.phone;
|
|
965
|
+
const sameEmails =
|
|
966
|
+
currentUserDataItem.finalData.email &&
|
|
967
|
+
transformedItem.email &&
|
|
968
|
+
currentUserDataItem.finalData.email === transformedItem.email;
|
|
969
|
+
if (
|
|
970
|
+
(currentUserDataItem.finalData.docId === existingId ||
|
|
971
|
+
currentUserDataItem.finalData.userId === existingId) &&
|
|
972
|
+
(samePhones || sameEmails) &&
|
|
973
|
+
currentUserDataItem.finalData &&
|
|
974
|
+
userData.finalData
|
|
975
|
+
) {
|
|
976
|
+
const userDataMerged = this.mergeObjects(
|
|
977
|
+
currentUserData.data[i].finalData,
|
|
943
978
|
userData.finalData
|
|
944
|
-
)
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
userData.finalData
|
|
948
|
-
);
|
|
949
|
-
currentUserData.data[i].finalData = userDataMerged;
|
|
950
|
-
this.importMap.set(this.getCollectionKey("users"), currentUserData);
|
|
951
|
-
}
|
|
979
|
+
);
|
|
980
|
+
currentUserData.data[i].finalData = userDataMerged;
|
|
981
|
+
this.importMap.set(this.getCollectionKey("users"), currentUserData);
|
|
952
982
|
}
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
983
|
+
}
|
|
984
|
+
// Update the attribute mappings with any actions that need to be performed post-import
|
|
985
|
+
const mappingsWithActions = this.getAttributeMappingsWithActions(
|
|
986
|
+
importDef.attributeMappings,
|
|
987
|
+
context,
|
|
988
|
+
transformedItem
|
|
989
|
+
);
|
|
990
|
+
// Update the import definition with the new attribute mappings
|
|
991
|
+
const newImportDef = {
|
|
992
|
+
...importDef,
|
|
993
|
+
attributeMappings: mappingsWithActions,
|
|
994
|
+
};
|
|
964
995
|
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
this.importMap.set(
|
|
978
|
-
this.getCollectionKey(collection.name),
|
|
979
|
-
currentData
|
|
980
|
-
);
|
|
981
|
-
this.oldIdToNewIdPerCollectionMap.set(
|
|
982
|
-
this.getCollectionKey(collection.name),
|
|
983
|
-
collectionOldIdToNewIdMap!
|
|
984
|
-
);
|
|
985
|
-
foundData = true;
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
if (!foundData) {
|
|
989
|
-
// Add new data to the associated collection
|
|
990
|
-
currentData.data.push({
|
|
991
|
-
rawData: item,
|
|
992
|
-
context: context,
|
|
993
|
-
importDef: newImportDef,
|
|
994
|
-
finalData: transformedItem,
|
|
995
|
-
});
|
|
996
|
+
let foundData = false;
|
|
997
|
+
for (let i = 0; i < currentData.data.length; i++) {
|
|
998
|
+
if (
|
|
999
|
+
currentData.data[i].finalData.docId === existingId ||
|
|
1000
|
+
currentData.data[i].finalData.userId === existingId
|
|
1001
|
+
) {
|
|
1002
|
+
currentData.data[i].finalData = this.mergeObjects(
|
|
1003
|
+
currentData.data[i].finalData,
|
|
1004
|
+
transformedItem
|
|
1005
|
+
);
|
|
1006
|
+
currentData.data[i].context = context;
|
|
1007
|
+
currentData.data[i].importDef = newImportDef;
|
|
996
1008
|
this.importMap.set(
|
|
997
1009
|
this.getCollectionKey(collection.name),
|
|
998
1010
|
currentData
|
|
@@ -1001,9 +1013,24 @@ export class DataLoader {
|
|
|
1001
1013
|
this.getCollectionKey(collection.name),
|
|
1002
1014
|
collectionOldIdToNewIdMap!
|
|
1003
1015
|
);
|
|
1016
|
+
foundData = true;
|
|
1004
1017
|
}
|
|
1005
1018
|
}
|
|
1006
|
-
|
|
1019
|
+
if (!foundData) {
|
|
1020
|
+
// Add new data to the associated collection
|
|
1021
|
+
currentData.data.push({
|
|
1022
|
+
rawData: item,
|
|
1023
|
+
context: context,
|
|
1024
|
+
importDef: newImportDef,
|
|
1025
|
+
finalData: transformedItem,
|
|
1026
|
+
});
|
|
1027
|
+
this.importMap.set(this.getCollectionKey(collection.name), currentData);
|
|
1028
|
+
this.oldIdToNewIdPerCollectionMap.set(
|
|
1029
|
+
this.getCollectionKey(collection.name),
|
|
1030
|
+
collectionOldIdToNewIdMap!
|
|
1031
|
+
);
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1007
1034
|
}
|
|
1008
1035
|
|
|
1009
1036
|
/**
|
|
@@ -1014,11 +1041,11 @@ export class DataLoader {
|
|
|
1014
1041
|
* @param collection - The collection configuration.
|
|
1015
1042
|
* @param importDef - The import definition containing the attribute mappings and other relevant info.
|
|
1016
1043
|
*/
|
|
1017
|
-
prepareCreateData(
|
|
1044
|
+
async prepareCreateData(
|
|
1018
1045
|
db: ConfigDatabase,
|
|
1019
1046
|
collection: CollectionCreate,
|
|
1020
1047
|
importDef: ImportDef
|
|
1021
|
-
): void {
|
|
1048
|
+
): Promise<void> {
|
|
1022
1049
|
// Load the raw data based on the import definition
|
|
1023
1050
|
const rawData = this.loadData(importDef);
|
|
1024
1051
|
const operationId = this.collectionImportOperations.get(
|
|
@@ -1029,97 +1056,102 @@ export class DataLoader {
|
|
|
1029
1056
|
`No import operation found for collection ${collection.name}`
|
|
1030
1057
|
);
|
|
1031
1058
|
}
|
|
1032
|
-
updateOperation(this.database, operationId, {
|
|
1059
|
+
await updateOperation(this.database, operationId, {
|
|
1033
1060
|
status: "ready",
|
|
1034
1061
|
total: rawData.length,
|
|
1035
|
-
})
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1062
|
+
});
|
|
1063
|
+
// Initialize a new map for old ID to new ID mappings
|
|
1064
|
+
const oldIdToNewIdMapNew = new Map<string, string>();
|
|
1065
|
+
// Retrieve or initialize the collection-specific old ID to new ID map
|
|
1066
|
+
const collectionOldIdToNewIdMap =
|
|
1067
|
+
this.oldIdToNewIdPerCollectionMap.get(
|
|
1068
|
+
this.getCollectionKey(collection.name)
|
|
1069
|
+
) ||
|
|
1070
|
+
this.oldIdToNewIdPerCollectionMap
|
|
1071
|
+
.set(this.getCollectionKey(collection.name), oldIdToNewIdMapNew)
|
|
1072
|
+
.get(this.getCollectionKey(collection.name));
|
|
1073
|
+
console.log(
|
|
1074
|
+
`${collection.name} -- collectionOldIdToNewIdMap: ${collectionOldIdToNewIdMap}`
|
|
1075
|
+
);
|
|
1076
|
+
const isRegions = collection.name.toLowerCase() === "regions";
|
|
1077
|
+
// Iterate through each item in the raw data
|
|
1078
|
+
for (const item of rawData) {
|
|
1079
|
+
// Generate a new unique ID for the item
|
|
1080
|
+
const itemIdNew = this.getTrueUniqueId(
|
|
1081
|
+
this.getCollectionKey(collection.name)
|
|
1048
1082
|
);
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
)
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
// If a primary key field is defined, handle the ID mapping and check for duplicates
|
|
1067
|
-
if (importDef.primaryKeyField) {
|
|
1068
|
-
const oldId = item[importDef.primaryKeyField];
|
|
1069
|
-
if (collectionOldIdToNewIdMap?.has(`${oldId}`)) {
|
|
1070
|
-
logger.error(
|
|
1071
|
-
`Collection ${collection.name} has multiple documents with the same primary key ${oldId}`
|
|
1072
|
-
);
|
|
1073
|
-
continue;
|
|
1074
|
-
}
|
|
1075
|
-
collectionOldIdToNewIdMap?.set(`${oldId}`, `${itemIdNew}`);
|
|
1076
|
-
}
|
|
1077
|
-
// Merge the transformed data into the context
|
|
1078
|
-
context = { ...context, ...transformedData };
|
|
1079
|
-
// Validate the item before proceeding
|
|
1080
|
-
const isValid = this.importDataActions.validateItem(
|
|
1081
|
-
transformedData,
|
|
1082
|
-
importDef.attributeMappings,
|
|
1083
|
-
context
|
|
1084
|
-
);
|
|
1085
|
-
if (!isValid) {
|
|
1086
|
-
continue;
|
|
1087
|
-
}
|
|
1088
|
-
// Update the attribute mappings with any actions that need to be performed post-import
|
|
1089
|
-
const mappingsWithActions = this.getAttributeMappingsWithActions(
|
|
1090
|
-
importDef.attributeMappings,
|
|
1091
|
-
context,
|
|
1092
|
-
transformedData
|
|
1083
|
+
if (isRegions) {
|
|
1084
|
+
logger.info(`Creating region: ${JSON.stringify(item, null, 2)}`);
|
|
1085
|
+
}
|
|
1086
|
+
// Retrieve the current collection data from the import map
|
|
1087
|
+
const currentData = this.importMap.get(
|
|
1088
|
+
this.getCollectionKey(collection.name)
|
|
1089
|
+
);
|
|
1090
|
+
// Create a context object for the item, including the new ID
|
|
1091
|
+
let context = this.createContext(db, collection, item, itemIdNew);
|
|
1092
|
+
// Transform the item data based on the attribute mappings
|
|
1093
|
+
const transformedData = this.transformData(
|
|
1094
|
+
item,
|
|
1095
|
+
importDef.attributeMappings
|
|
1096
|
+
);
|
|
1097
|
+
if (isRegions) {
|
|
1098
|
+
logger.info(
|
|
1099
|
+
`Transformed region: ${JSON.stringify(transformedData, null, 2)}`
|
|
1093
1100
|
);
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
}
|
|
1099
|
-
// If the current collection data exists, add the item with its context and final data
|
|
1100
|
-
if (currentData && currentData.data) {
|
|
1101
|
-
currentData.data.push({
|
|
1102
|
-
rawData: item,
|
|
1103
|
-
context: context,
|
|
1104
|
-
importDef: newImportDef,
|
|
1105
|
-
finalData: transformedData,
|
|
1106
|
-
});
|
|
1107
|
-
this.importMap.set(
|
|
1108
|
-
this.getCollectionKey(collection.name),
|
|
1109
|
-
currentData
|
|
1110
|
-
);
|
|
1111
|
-
this.oldIdToNewIdPerCollectionMap.set(
|
|
1112
|
-
this.getCollectionKey(collection.name),
|
|
1113
|
-
collectionOldIdToNewIdMap!
|
|
1114
|
-
);
|
|
1115
|
-
} else {
|
|
1101
|
+
}
|
|
1102
|
+
// If a primary key field is defined, handle the ID mapping and check for duplicates
|
|
1103
|
+
if (importDef.primaryKeyField) {
|
|
1104
|
+
const oldId = item[importDef.primaryKeyField];
|
|
1105
|
+
if (collectionOldIdToNewIdMap?.has(`${oldId}`)) {
|
|
1116
1106
|
logger.error(
|
|
1117
|
-
`
|
|
1107
|
+
`Collection ${collection.name} has multiple documents with the same primary key ${oldId}`
|
|
1118
1108
|
);
|
|
1119
1109
|
continue;
|
|
1120
1110
|
}
|
|
1111
|
+
collectionOldIdToNewIdMap?.set(`${oldId}`, `${itemIdNew}`);
|
|
1121
1112
|
}
|
|
1122
|
-
|
|
1113
|
+
// Merge the transformed data into the context
|
|
1114
|
+
context = { ...context, ...transformedData };
|
|
1115
|
+
// Validate the item before proceeding
|
|
1116
|
+
const isValid = this.importDataActions.validateItem(
|
|
1117
|
+
transformedData,
|
|
1118
|
+
importDef.attributeMappings,
|
|
1119
|
+
context
|
|
1120
|
+
);
|
|
1121
|
+
if (!isValid) {
|
|
1122
|
+
continue;
|
|
1123
|
+
}
|
|
1124
|
+
// Update the attribute mappings with any actions that need to be performed post-import
|
|
1125
|
+
const mappingsWithActions = this.getAttributeMappingsWithActions(
|
|
1126
|
+
importDef.attributeMappings,
|
|
1127
|
+
context,
|
|
1128
|
+
transformedData
|
|
1129
|
+
);
|
|
1130
|
+
// Update the import definition with the new attribute mappings
|
|
1131
|
+
const newImportDef = {
|
|
1132
|
+
...importDef,
|
|
1133
|
+
attributeMappings: mappingsWithActions,
|
|
1134
|
+
};
|
|
1135
|
+
// If the current collection data exists, add the item with its context and final data
|
|
1136
|
+
if (currentData && currentData.data) {
|
|
1137
|
+
currentData.data.push({
|
|
1138
|
+
rawData: item,
|
|
1139
|
+
context: context,
|
|
1140
|
+
importDef: newImportDef,
|
|
1141
|
+
finalData: transformedData,
|
|
1142
|
+
});
|
|
1143
|
+
this.importMap.set(this.getCollectionKey(collection.name), currentData);
|
|
1144
|
+
this.oldIdToNewIdPerCollectionMap.set(
|
|
1145
|
+
this.getCollectionKey(collection.name),
|
|
1146
|
+
collectionOldIdToNewIdMap!
|
|
1147
|
+
);
|
|
1148
|
+
} else {
|
|
1149
|
+
logger.error(
|
|
1150
|
+
`No data found for collection ${collection.name} for createDef but it says it's supposed to have one...`
|
|
1151
|
+
);
|
|
1152
|
+
continue;
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1123
1155
|
}
|
|
1124
1156
|
|
|
1125
1157
|
/**
|
|
@@ -42,9 +42,19 @@ export class ImportDataActions {
|
|
|
42
42
|
this.afterImportActionsDefinitions = afterImportActionsDefinitions;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Runs converter functions on the item based on the provided attribute mappings.
|
|
47
|
+
*
|
|
48
|
+
* @param item - The item to be transformed.
|
|
49
|
+
* @param attributeMappings - The mappings that define how each attribute should be transformed.
|
|
50
|
+
* @returns The transformed item.
|
|
51
|
+
*/
|
|
45
52
|
runConverterFunctions(item: any, attributeMappings: AttributeMappings) {
|
|
46
53
|
const conversionSchema = attributeMappings.reduce((schema, mapping) => {
|
|
47
54
|
schema[mapping.targetKey] = (originalValue: any) => {
|
|
55
|
+
if (!mapping.converters) {
|
|
56
|
+
return originalValue;
|
|
57
|
+
}
|
|
48
58
|
return mapping.converters?.reduce((value, converterName) => {
|
|
49
59
|
let shouldProcessAsArray = false;
|
|
50
60
|
if (
|
|
@@ -95,6 +105,7 @@ export class ImportDataActions {
|
|
|
95
105
|
/**
|
|
96
106
|
* Validates a single data item based on defined validation rules.
|
|
97
107
|
* @param item The data item to validate.
|
|
108
|
+
* @param attributeMap The attribute mappings for the data item.
|
|
98
109
|
* @param context The context for resolving templated parameters in validation rules.
|
|
99
110
|
* @returns A promise that resolves to true if the item is valid, false otherwise.
|
|
100
111
|
*/
|