appwrite-utils-cli 0.0.37 → 0.0.38

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.
@@ -93,6 +93,7 @@ export class DataLoader {
93
93
  * It iterates through the target object's keys and updates the source object if:
94
94
  * - The source object has the key.
95
95
  * - The target object's value for that key is not null, undefined, or an empty string.
96
+ * - If the target object has an array value, it concatenates the values and removes duplicates.
96
97
  *
97
98
  * @param source - The source object to be updated.
98
99
  * @param target - The target object with values to update the source object.
@@ -162,8 +163,26 @@ export class DataLoader {
162
163
  // Method to generate a unique ID that doesn't conflict with existing IDs
163
164
  getTrueUniqueId(collectionName: string) {
164
165
  let newId = ID.unique();
165
- while (this.checkMapValuesForId(newId, collectionName)) {
166
+ let condition =
167
+ this.checkMapValuesForId(newId, collectionName) ||
168
+ this.userExistsMap.has(newId) ||
169
+ this.importMap
170
+ .get(this.getCollectionKey("users"))
171
+ ?.data.some(
172
+ (user) =>
173
+ user.finalData.docId === newId || user.finalData.userId === newId
174
+ );
175
+ while (condition) {
166
176
  newId = ID.unique();
177
+ condition =
178
+ this.checkMapValuesForId(newId, collectionName) ||
179
+ this.userExistsMap.has(newId) ||
180
+ this.importMap
181
+ .get(this.getCollectionKey("users"))
182
+ ?.data.some(
183
+ (user) =>
184
+ user.finalData.docId === newId || user.finalData.userId === newId
185
+ );
167
186
  }
168
187
  return newId;
169
188
  }
@@ -271,6 +290,21 @@ export class DataLoader {
271
290
  this.phoneToUserIdMap.set(user.phone, user.$id);
272
291
  }
273
292
  this.userExistsMap.set(user.$id, true);
293
+ let importData = this.importMap.get(this.getCollectionKey("users"));
294
+ if (!importData) {
295
+ importData = {
296
+ data: [],
297
+ };
298
+ }
299
+ importData.data.push({
300
+ finalData: {
301
+ ...user,
302
+ userId: user.$id,
303
+ docId: user.$id,
304
+ },
305
+ rawData: user,
306
+ });
307
+ this.importMap.set(this.getCollectionKey("users"), importData);
274
308
  }
275
309
  return allUsers;
276
310
  }
@@ -312,15 +346,11 @@ export class DataLoader {
312
346
  for (const createDef of createDefs) {
313
347
  if (!isUsersCollection) {
314
348
  console.log(`${collection.name} is not users collection`);
315
- await this.prepareCreateData(db, collection, createDef);
349
+ this.prepareCreateData(db, collection, createDef);
316
350
  } else {
317
351
  // Special handling for users collection if needed
318
352
  console.log(`${collection.name} is users collection`);
319
- await this.prepareUserCollectionCreateData(
320
- db,
321
- collection,
322
- createDef
323
- );
353
+ this.prepareUserCollectionCreateData(db, collection, createDef);
324
354
  }
325
355
  }
326
356
  for (const updateDef of updateDefs) {
@@ -331,11 +361,11 @@ export class DataLoader {
331
361
  continue;
332
362
  }
333
363
  // Prepare the update data for the collection
334
- await this.prepareUpdateData(db, collection, updateDef);
364
+ this.prepareUpdateData(db, collection, updateDef);
335
365
  }
336
366
  }
337
367
  console.log("Running update references");
338
- this.dealWithMergedUsers();
368
+ // this.dealWithMergedUsers();
339
369
  this.updateOldReferencesForNew();
340
370
  console.log("Done running update references");
341
371
  }
@@ -355,9 +385,15 @@ export class DataLoader {
355
385
  this.config.usersCollectionName
356
386
  );
357
387
  const usersCollectionPrimaryKeyFields = new Set();
388
+
358
389
  if (!this.config.collections) {
390
+ console.log("No collections found in configuration.");
359
391
  return;
360
392
  }
393
+
394
+ let needsUpdate = false;
395
+ let numUpdates = 0;
396
+
361
397
  // Collect primary key fields from the users collection definitions
362
398
  this.config.collections.forEach((collection) => {
363
399
  if (this.getCollectionKey(collection.name) === usersCollectionKey) {
@@ -373,45 +409,95 @@ export class DataLoader {
373
409
  }
374
410
  });
375
411
 
412
+ console.log(
413
+ `Primary key fields collected for users collection: ${[
414
+ ...usersCollectionPrimaryKeyFields,
415
+ ]}`
416
+ );
417
+
376
418
  // Iterate over all collections to update references based on merged users
377
419
  this.config.collections.forEach((collection) => {
378
420
  const collectionData = this.importMap.get(
379
421
  this.getCollectionKey(collection.name)
380
422
  );
381
- if (!collectionData || !collectionData.data) return;
423
+
424
+ if (!collectionData || !collectionData.data) {
425
+ console.log(`No data found for collection ${collection.name}`);
426
+ return;
427
+ }
428
+
382
429
  const collectionImportDefs = collection.importDefs;
383
430
  if (!collectionImportDefs || !collectionImportDefs.length) {
431
+ console.log(
432
+ `No import definitions found for collection ${collection.name}`
433
+ );
384
434
  return;
385
435
  }
436
+
386
437
  collectionImportDefs.forEach((importDef) => {
387
438
  importDef.idMappings?.forEach((idMapping) => {
388
439
  if (
389
440
  this.getCollectionKey(idMapping.targetCollection) ===
390
441
  usersCollectionKey
391
442
  ) {
443
+ const fieldToSetKey = idMapping.fieldToSet || idMapping.sourceField;
392
444
  const targetFieldKey =
393
445
  idMapping.targetFieldToMatch || idMapping.targetField;
446
+
394
447
  if (usersCollectionPrimaryKeyFields.has(targetFieldKey)) {
448
+ console.log(
449
+ `Processing collection ${collection.name} with target field ${targetFieldKey}`
450
+ );
451
+
395
452
  // Process each item in the collection
396
453
  collectionData.data.forEach((item) => {
397
- const oldId = item.context[idMapping.sourceField];
454
+ const oldId =
455
+ item.finalData[idMapping.sourceField] ||
456
+ item.context[idMapping.sourceField];
457
+
458
+ if (oldId === undefined || oldId === null) {
459
+ console.log(
460
+ `Skipping item with undefined or null oldId in collection ${collection.name}`
461
+ );
462
+ return;
463
+ }
464
+
398
465
  const newId = this.mergedUserMap.get(`${oldId}`);
399
466
 
400
467
  if (newId) {
468
+ needsUpdate = true;
469
+ numUpdates++;
470
+ console.log(
471
+ `Updating old ID ${oldId} to new ID ${newId} in collection ${collection.name}`
472
+ );
473
+
401
474
  // Update context to use new user ID
402
- item.finalData[
403
- idMapping.fieldToSet || idMapping.sourceField
404
- ] = newId;
475
+ item.finalData[fieldToSetKey] = newId;
476
+ item.context[fieldToSetKey] = newId;
477
+ } else {
478
+ console.log(
479
+ `No new ID found for old ID ${oldId} in mergedUserMap.`
480
+ );
405
481
  }
406
482
  });
407
483
  }
408
484
  }
409
485
  });
410
486
  });
487
+
488
+ if (needsUpdate) {
489
+ console.log(
490
+ `Updated ${numUpdates} references for collection ${collection.name}`
491
+ );
492
+ this.importMap.set(
493
+ this.getCollectionKey(collection.name),
494
+ collectionData
495
+ );
496
+ }
411
497
  });
412
498
  }
413
499
 
414
- async updateOldReferencesForNew() {
500
+ updateOldReferencesForNew() {
415
501
  if (!this.config.collections) {
416
502
  return;
417
503
  }
@@ -612,12 +698,19 @@ export class DataLoader {
612
698
  * @param attributeMappings - The attribute mappings for the item.
613
699
  * @returns The transformed item with user-specific keys removed.
614
700
  */
615
- async prepareUserData(
701
+ prepareUserData(
616
702
  item: any,
617
703
  attributeMappings: AttributeMappings,
618
704
  primaryKeyField: string,
619
705
  newId: string
620
- ): Promise<any> {
706
+ ): {
707
+ transformedItem: any;
708
+ existingId: string | undefined;
709
+ userData: {
710
+ rawData: any;
711
+ finalData: z.infer<typeof AuthUserCreateSchema>;
712
+ };
713
+ } {
621
714
  let transformedItem = this.transformData(item, attributeMappings);
622
715
  const userData = AuthUserCreateSchema.safeParse(transformedItem);
623
716
  if (!userData.success) {
@@ -666,15 +759,24 @@ export class DataLoader {
666
759
  });
667
760
  if (userFound) {
668
761
  userFound.finalData.userId = existingId;
762
+ userFound.finalData.docId = existingId;
763
+ this.userExistsMap.set(existingId, true);
669
764
  }
670
- return [
765
+
766
+ const userKeys = ["email", "phone", "name", "labels", "prefs"];
767
+ userKeys.forEach((key) => {
768
+ if (transformedItem.hasOwnProperty(key)) {
769
+ delete transformedItem[key];
770
+ }
771
+ });
772
+ return {
671
773
  transformedItem,
672
774
  existingId,
673
- {
775
+ userData: {
674
776
  rawData: userFound?.rawData,
675
777
  finalData: userFound?.finalData,
676
778
  },
677
- ];
779
+ };
678
780
  } else {
679
781
  existingId = newId;
680
782
  userData.data.userId = existingId;
@@ -696,7 +798,11 @@ export class DataLoader {
696
798
  data: [...(usersMap?.data || []), userDataToAdd],
697
799
  });
698
800
 
699
- return [transformedItem, existingId, userDataToAdd];
801
+ return {
802
+ transformedItem,
803
+ existingId,
804
+ userData: userDataToAdd,
805
+ };
700
806
  }
701
807
 
702
808
  /**
@@ -708,11 +814,11 @@ export class DataLoader {
708
814
  * @param collection - The collection configuration.
709
815
  * @param importDef - The import definition containing the attribute mappings and other relevant info.
710
816
  */
711
- async prepareUserCollectionCreateData(
817
+ prepareUserCollectionCreateData(
712
818
  db: ConfigDatabase,
713
819
  collection: CollectionCreate,
714
820
  importDef: ImportDef
715
- ): Promise<void> {
821
+ ): void {
716
822
  // Load the raw data based on the import definition
717
823
  const rawData = this.loadData(importDef);
718
824
  const operationId = this.collectionImportOperations.get(
@@ -736,127 +842,157 @@ export class DataLoader {
736
842
  `No import operation found for collection ${collection.name}`
737
843
  );
738
844
  }
739
- await updateOperation(this.database, operationId, {
845
+ updateOperation(this.database, operationId, {
740
846
  status: "ready",
741
847
  total: rawData.length,
742
- });
743
- // Retrieve the current user data and the current collection data from the import map
744
- const currentUserData = this.importMap.get(this.getCollectionKey("users"));
745
- const currentData = this.importMap.get(
746
- this.getCollectionKey(collection.name)
747
- );
748
- // Log errors if the necessary data is not found in the import map
749
- if (!currentUserData) {
750
- logger.error(
751
- `No data found for collection ${"users"} for createDef but it says it's supposed to have one...`
848
+ }).then(() => {
849
+ // Retrieve the current user data and the current collection data from the import map
850
+ const currentUserData = this.importMap.get(
851
+ this.getCollectionKey("users")
752
852
  );
753
- return;
754
- } else if (!currentData) {
755
- logger.error(
756
- `No data found for collection ${collection.name} for createDef but it says it's supposed to have one...`
757
- );
758
- return;
759
- }
760
- // Iterate through each item in the raw data
761
- for (const item of rawData) {
762
- // Prepare user data, check for duplicates, and remove user-specific keys
763
- let [transformedItem, existingId, userData] = await this.prepareUserData(
764
- item,
765
- importDef.attributeMappings,
766
- importDef.primaryKeyField,
767
- this.getTrueUniqueId(this.getCollectionKey("users"))
853
+ const currentData = this.importMap.get(
854
+ this.getCollectionKey(collection.name)
768
855
  );
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
+ );
769
877
 
770
- logger.info(
771
- `In create user -- transformedItem: ${JSON.stringify(
772
- transformedItem,
773
- null,
774
- 2
775
- )}`
776
- );
878
+ logger.info(
879
+ `In create user -- transformedItem: ${JSON.stringify(
880
+ transformedItem,
881
+ null,
882
+ 2
883
+ )}`
884
+ );
777
885
 
778
- // Generate a new unique ID for the item or use existing ID
779
- if (!existingId) {
780
- // No existing user ID, generate a new unique ID
781
- existingId = this.getTrueUniqueId(this.getCollectionKey("users"));
782
- transformedItem.docId = existingId; // Assign the new ID to the transformed data's docId field
783
- }
886
+ // Generate a new unique ID for the item or use existing ID
887
+ if (!existingId) {
888
+ // No existing user ID, generate a new unique ID
889
+ existingId = this.getTrueUniqueId(this.getCollectionKey("users"));
890
+ transformedItem.docId = existingId; // Assign the new ID to the transformed data's docId field
891
+ }
784
892
 
785
- // Create a context object for the item, including the new ID
786
- let context = this.createContext(db, collection, item, existingId);
893
+ // Create a context object for the item, including the new ID
894
+ let context = this.createContext(db, collection, item, existingId);
787
895
 
788
- // Merge the transformed data into the context
789
- context = { ...context, ...transformedItem, ...userData.finalData };
896
+ // Merge the transformed data into the context
897
+ context = { ...context, ...transformedItem, ...userData.finalData };
790
898
 
791
- // If a primary key field is defined, handle the ID mapping and check for duplicates
792
- if (importDef.primaryKeyField) {
793
- const oldId = item[importDef.primaryKeyField];
899
+ // If a primary key field is defined, handle the ID mapping and check for duplicates
900
+ if (importDef.primaryKeyField) {
901
+ const oldId = item[importDef.primaryKeyField];
794
902
 
795
- // Check if the oldId already exists to handle potential duplicates
796
- if (
797
- this.oldIdToNewIdPerCollectionMap
798
- .get(this.getCollectionKey(collection.name))
799
- ?.has(`${oldId}`)
800
- ) {
801
- // Found a duplicate oldId, now decide how to merge or handle these duplicates
802
- for (const data of currentData.data) {
803
- if (
804
- data.finalData.docId === oldId ||
805
- data.finalData.userId === oldId
806
- ) {
807
- transformedItem = this.mergeObjects(
808
- data.finalData,
809
- transformedItem
810
- );
903
+ // Check if the oldId already exists to handle potential duplicates
904
+ if (
905
+ this.oldIdToNewIdPerCollectionMap
906
+ .get(this.getCollectionKey(collection.name))
907
+ ?.has(`${oldId}`)
908
+ ) {
909
+ // Found a duplicate oldId, now decide how to merge or handle these duplicates
910
+ for (const data of currentData.data) {
911
+ if (
912
+ data.finalData.docId === oldId ||
913
+ data.finalData.userId === oldId
914
+ ) {
915
+ transformedItem = this.mergeObjects(
916
+ data.finalData,
917
+ transformedItem
918
+ );
919
+ }
811
920
  }
921
+ } else {
922
+ // No duplicate found, simply map the oldId to the new itemId
923
+ collectionOldIdToNewIdMap?.set(`${oldId}`, `${existingId}`);
812
924
  }
813
- } else {
814
- // No duplicate found, simply map the oldId to the new itemId
815
- collectionOldIdToNewIdMap?.set(`${oldId}`, `${existingId}`);
816
925
  }
817
- }
818
- // Merge the final user data into the context
819
- context = { ...context, ...userData.finalData };
820
926
 
821
- // Handle merging for currentUserData
822
- for (let i = 0; i < currentUserData.data.length; i++) {
823
- if (
824
- (currentUserData.data[i].finalData.docId === existingId ||
825
- currentUserData.data[i].finalData.userId === existingId) &&
826
- !_.isEqual(currentUserData.data[i], userData)
827
- ) {
828
- this.mergeObjects(
829
- currentUserData.data[i].finalData,
927
+ // Handle merging for currentUserData
928
+ for (let i = 0; i < currentUserData.data.length; i++) {
929
+ const currentUserDataItem = currentUserData.data[i];
930
+ const samePhones =
931
+ currentUserDataItem.finalData.phone &&
932
+ transformedItem.phone &&
933
+ currentUserDataItem.finalData.phone === transformedItem.phone;
934
+ const sameEmails =
935
+ currentUserDataItem.finalData.email &&
936
+ transformedItem.email &&
937
+ currentUserDataItem.finalData.email === transformedItem.email;
938
+ if (
939
+ (currentUserDataItem.finalData.docId === existingId ||
940
+ currentUserDataItem.finalData.userId === existingId) &&
941
+ (samePhones || sameEmails) &&
942
+ currentUserDataItem.finalData &&
830
943
  userData.finalData
831
- );
832
- console.log("Merging user data", currentUserData.data[i].finalData);
833
- this.importMap.set(this.getCollectionKey("users"), currentUserData);
944
+ ) {
945
+ const userDataMerged = this.mergeObjects(
946
+ currentUserData.data[i].finalData,
947
+ userData.finalData
948
+ );
949
+ currentUserData.data[i].finalData = userDataMerged;
950
+ this.importMap.set(this.getCollectionKey("users"), currentUserData);
951
+ }
834
952
  }
835
- }
836
- // Update the attribute mappings with any actions that need to be performed post-import
837
- const mappingsWithActions = this.getAttributeMappingsWithActions(
838
- importDef.attributeMappings,
839
- context,
840
- transformedItem
841
- );
842
- // Update the import definition with the new attribute mappings
843
- const newImportDef = {
844
- ...importDef,
845
- attributeMappings: mappingsWithActions,
846
- };
953
+ // Update the attribute mappings with any actions that need to be performed post-import
954
+ const mappingsWithActions = this.getAttributeMappingsWithActions(
955
+ importDef.attributeMappings,
956
+ context,
957
+ transformedItem
958
+ );
959
+ // Update the import definition with the new attribute mappings
960
+ const newImportDef = {
961
+ ...importDef,
962
+ attributeMappings: mappingsWithActions,
963
+ };
847
964
 
848
- let foundData = false;
849
- for (let i = 0; i < currentData.data.length; i++) {
850
- if (
851
- currentData.data[i].finalData.docId === existingId ||
852
- currentData.data[i].finalData.userId === existingId
853
- ) {
854
- currentData.data[i].finalData = this.mergeObjects(
855
- currentData.data[i].finalData,
856
- transformedItem
857
- );
858
- currentData.data[i].context = context;
859
- currentData.data[i].importDef = newImportDef;
965
+ let foundData = false;
966
+ for (let i = 0; i < currentData.data.length; i++) {
967
+ if (
968
+ currentData.data[i].finalData.docId === existingId ||
969
+ currentData.data[i].finalData.userId === existingId
970
+ ) {
971
+ currentData.data[i].finalData = this.mergeObjects(
972
+ currentData.data[i].finalData,
973
+ transformedItem
974
+ );
975
+ currentData.data[i].context = context;
976
+ currentData.data[i].importDef = newImportDef;
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
+ });
860
996
  this.importMap.set(
861
997
  this.getCollectionKey(collection.name),
862
998
  currentData
@@ -865,24 +1001,9 @@ export class DataLoader {
865
1001
  this.getCollectionKey(collection.name),
866
1002
  collectionOldIdToNewIdMap!
867
1003
  );
868
- foundData = true;
869
1004
  }
870
1005
  }
871
- if (!foundData) {
872
- // Add new data to the associated collection
873
- currentData.data.push({
874
- rawData: item,
875
- context: context,
876
- importDef: newImportDef,
877
- finalData: transformedItem,
878
- });
879
- this.importMap.set(this.getCollectionKey(collection.name), currentData);
880
- this.oldIdToNewIdPerCollectionMap.set(
881
- this.getCollectionKey(collection.name),
882
- collectionOldIdToNewIdMap!
883
- );
884
- }
885
- }
1006
+ });
886
1007
  }
887
1008
 
888
1009
  /**
@@ -893,11 +1014,11 @@ export class DataLoader {
893
1014
  * @param collection - The collection configuration.
894
1015
  * @param importDef - The import definition containing the attribute mappings and other relevant info.
895
1016
  */
896
- async prepareCreateData(
1017
+ prepareCreateData(
897
1018
  db: ConfigDatabase,
898
1019
  collection: CollectionCreate,
899
1020
  importDef: ImportDef
900
- ): Promise<void> {
1021
+ ): void {
901
1022
  // Load the raw data based on the import definition
902
1023
  const rawData = this.loadData(importDef);
903
1024
  const operationId = this.collectionImportOperations.get(
@@ -908,94 +1029,99 @@ export class DataLoader {
908
1029
  `No import operation found for collection ${collection.name}`
909
1030
  );
910
1031
  }
911
- await updateOperation(this.database, operationId, {
1032
+ updateOperation(this.database, operationId, {
912
1033
  status: "ready",
913
1034
  total: rawData.length,
914
- });
915
- // Initialize a new map for old ID to new ID mappings
916
- const oldIdToNewIdMapNew = new Map<string, string>();
917
- // Retrieve or initialize the collection-specific old ID to new ID map
918
- const collectionOldIdToNewIdMap =
919
- this.oldIdToNewIdPerCollectionMap.get(
920
- this.getCollectionKey(collection.name)
921
- ) ||
922
- this.oldIdToNewIdPerCollectionMap
923
- .set(this.getCollectionKey(collection.name), oldIdToNewIdMapNew)
924
- .get(this.getCollectionKey(collection.name));
925
- console.log(
926
- `${collection.name} -- collectionOldIdToNewIdMap: ${collectionOldIdToNewIdMap}`
927
- );
928
- // Iterate through each item in the raw data
929
- for (const item of rawData) {
930
- // Generate a new unique ID for the item
931
- const itemIdNew = this.getTrueUniqueId(
932
- this.getCollectionKey(collection.name)
933
- );
934
- // Retrieve the current collection data from the import map
935
- const currentData = this.importMap.get(
936
- this.getCollectionKey(collection.name)
937
- );
938
- // Create a context object for the item, including the new ID
939
- let context = this.createContext(db, collection, item, itemIdNew);
940
- // Transform the item data based on the attribute mappings
941
- const transformedData = this.transformData(
942
- item,
943
- importDef.attributeMappings
1035
+ }).then(() => {
1036
+ // Initialize a new map for old ID to new ID mappings
1037
+ const oldIdToNewIdMapNew = new Map<string, string>();
1038
+ // Retrieve or initialize the collection-specific old ID to new ID map
1039
+ const collectionOldIdToNewIdMap =
1040
+ this.oldIdToNewIdPerCollectionMap.get(
1041
+ this.getCollectionKey(collection.name)
1042
+ ) ||
1043
+ this.oldIdToNewIdPerCollectionMap
1044
+ .set(this.getCollectionKey(collection.name), oldIdToNewIdMapNew)
1045
+ .get(this.getCollectionKey(collection.name));
1046
+ console.log(
1047
+ `${collection.name} -- collectionOldIdToNewIdMap: ${collectionOldIdToNewIdMap}`
944
1048
  );
945
- // If a primary key field is defined, handle the ID mapping and check for duplicates
946
- if (importDef.primaryKeyField) {
947
- const oldId = item[importDef.primaryKeyField];
948
- if (collectionOldIdToNewIdMap?.has(`${oldId}`)) {
1049
+ // Iterate through each item in the raw data
1050
+ for (const item of rawData) {
1051
+ // Generate a new unique ID for the item
1052
+ const itemIdNew = this.getTrueUniqueId(
1053
+ this.getCollectionKey(collection.name)
1054
+ );
1055
+ // Retrieve the current collection data from the import map
1056
+ const currentData = this.importMap.get(
1057
+ this.getCollectionKey(collection.name)
1058
+ );
1059
+ // Create a context object for the item, including the new ID
1060
+ let context = this.createContext(db, collection, item, itemIdNew);
1061
+ // Transform the item data based on the attribute mappings
1062
+ const transformedData = this.transformData(
1063
+ item,
1064
+ importDef.attributeMappings
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
1093
+ );
1094
+ // Update the import definition with the new attribute mappings
1095
+ const newImportDef = {
1096
+ ...importDef,
1097
+ attributeMappings: mappingsWithActions,
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 {
949
1116
  logger.error(
950
- `Collection ${collection.name} has multiple documents with the same primary key ${oldId}`
1117
+ `No data found for collection ${collection.name} for createDef but it says it's supposed to have one...`
951
1118
  );
952
1119
  continue;
953
1120
  }
954
- collectionOldIdToNewIdMap?.set(`${oldId}`, `${itemIdNew}`);
955
1121
  }
956
- // Merge the transformed data into the context
957
- context = { ...context, ...transformedData };
958
- // Validate the item before proceeding
959
- const isValid = await this.importDataActions.validateItem(
960
- transformedData,
961
- importDef.attributeMappings,
962
- context
963
- );
964
- if (!isValid) {
965
- continue;
966
- }
967
- // Update the attribute mappings with any actions that need to be performed post-import
968
- const mappingsWithActions = this.getAttributeMappingsWithActions(
969
- importDef.attributeMappings,
970
- context,
971
- transformedData
972
- );
973
- // Update the import definition with the new attribute mappings
974
- const newImportDef = {
975
- ...importDef,
976
- attributeMappings: mappingsWithActions,
977
- };
978
- // If the current collection data exists, add the item with its context and final data
979
- if (currentData && currentData.data) {
980
- currentData.data.push({
981
- rawData: item,
982
- context: context,
983
- importDef: newImportDef,
984
- finalData: transformedData,
985
- });
986
- this.importMap.set(this.getCollectionKey(collection.name), currentData);
987
- this.oldIdToNewIdPerCollectionMap.set(
988
- this.getCollectionKey(collection.name),
989
- collectionOldIdToNewIdMap!
990
- );
991
- } else {
992
- logger.error(
993
- `No data found for collection ${collection.name} for createDef but it says it's supposed to have one...`
994
- );
995
- continue;
996
- }
997
- }
1122
+ });
998
1123
  }
1124
+
999
1125
  /**
1000
1126
  * Prepares the data for updating documents within a collection.
1001
1127
  * This method loads the raw data based on the import definition, transforms it according to the attribute mappings,
@@ -1006,7 +1132,7 @@ export class DataLoader {
1006
1132
  * @param collection - The collection configuration.
1007
1133
  * @param importDef - The import definition containing the attribute mappings and other relevant info.
1008
1134
  */
1009
- async prepareUpdateData(
1135
+ prepareUpdateData(
1010
1136
  db: ConfigDatabase,
1011
1137
  collection: CollectionCreate,
1012
1138
  importDef: ImportDef
@@ -1047,11 +1173,7 @@ export class DataLoader {
1047
1173
  let newId: string | undefined;
1048
1174
  let oldId: string | undefined;
1049
1175
  // Determine the new ID for the item based on the primary key field or update mapping
1050
- if (importDef.primaryKeyField) {
1051
- oldId = item[importDef.primaryKeyField];
1052
- } else if (importDef.updateMapping) {
1053
- oldId = item[importDef.updateMapping.originalIdField];
1054
- }
1176
+ oldId = item[importDef.primaryKeyField];
1055
1177
  if (oldId) {
1056
1178
  newId = oldIdToNewIdMap?.get(`${oldId}`);
1057
1179
  if (
@@ -1074,8 +1196,13 @@ export class DataLoader {
1074
1196
  );
1075
1197
  continue;
1076
1198
  }
1199
+ const itemDataToUpdate = this.importMap
1200
+ .get(this.getCollectionKey(collection.name))
1201
+ ?.data.find(
1202
+ (data) => `${data.context[importDef.primaryKeyField]}` === `${oldId}`
1203
+ );
1077
1204
  // Log an error and continue to the next item if no new ID is found
1078
- if (!newId) {
1205
+ if (!newId && !itemDataToUpdate) {
1079
1206
  logger.error(
1080
1207
  `No new id found for collection ${
1081
1208
  collection.name
@@ -1086,15 +1213,24 @@ export class DataLoader {
1086
1213
  )} but it says it's supposed to have one...`
1087
1214
  );
1088
1215
  continue;
1216
+ } else if (itemDataToUpdate) {
1217
+ newId = itemDataToUpdate.finalData.docId;
1218
+ if (!newId) {
1219
+ logger.error(
1220
+ `No new id found for collection ${
1221
+ collection.name
1222
+ } for updateDef ${JSON.stringify(
1223
+ item,
1224
+ null,
1225
+ 2
1226
+ )} but it says it's supposed to have one...`
1227
+ );
1228
+ continue;
1229
+ }
1089
1230
  }
1090
- const itemDataToUpdate = this.importMap
1091
- .get(this.getCollectionKey(collection.name))
1092
- ?.data.find(
1093
- (data) => data.rawData[importDef.primaryKeyField] === oldId
1094
- );
1095
- if (!itemDataToUpdate) {
1231
+ if (!itemDataToUpdate || !newId) {
1096
1232
  logger.error(
1097
- `No data found for collection ${
1233
+ `No data or ID (docId) found for collection ${
1098
1234
  collection.name
1099
1235
  } for updateDef ${JSON.stringify(
1100
1236
  item,
@@ -1110,9 +1246,9 @@ export class DataLoader {
1110
1246
  );
1111
1247
  // Create a context object for the item, including the new ID and transformed data
1112
1248
  let context = this.createContext(db, collection, item, newId);
1113
- context = this.mergeObjects(context, transformedData);
1249
+ context = { ...context, ...transformedData };
1114
1250
  // Validate the item before proceeding
1115
- const isValid = await this.importDataActions.validateItem(
1251
+ const isValid = this.importDataActions.validateItem(
1116
1252
  item,
1117
1253
  importDef.attributeMappings,
1118
1254
  context
@@ -1144,6 +1280,7 @@ export class DataLoader {
1144
1280
  );
1145
1281
  itemDataToUpdate.context = context;
1146
1282
  itemDataToUpdate.importDef = newImportDef;
1283
+ currentData!.data.push(itemDataToUpdate);
1147
1284
  } else {
1148
1285
  // If no existing item matches, then add the new item
1149
1286
  currentData!.data.push({