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.
@@ -65,6 +65,7 @@ export class DataLoader {
65
65
  * It iterates through the target object's keys and updates the source object if:
66
66
  * - The source object has the key.
67
67
  * - The target object's value for that key is not null, undefined, or an empty string.
68
+ * - If the target object has an array value, it concatenates the values and removes duplicates.
68
69
  *
69
70
  * @param source - The source object to be updated.
70
71
  * @param target - The target object with values to update the source object.
@@ -125,8 +126,19 @@ export class DataLoader {
125
126
  // Method to generate a unique ID that doesn't conflict with existing IDs
126
127
  getTrueUniqueId(collectionName) {
127
128
  let newId = ID.unique();
128
- while (this.checkMapValuesForId(newId, collectionName)) {
129
+ let condition = this.checkMapValuesForId(newId, collectionName) ||
130
+ this.userExistsMap.has(newId) ||
131
+ this.importMap
132
+ .get(this.getCollectionKey("users"))
133
+ ?.data.some((user) => user.finalData.docId === newId || user.finalData.userId === newId);
134
+ while (condition) {
129
135
  newId = ID.unique();
136
+ condition =
137
+ this.checkMapValuesForId(newId, collectionName) ||
138
+ this.userExistsMap.has(newId) ||
139
+ this.importMap
140
+ .get(this.getCollectionKey("users"))
141
+ ?.data.some((user) => user.finalData.docId === newId || user.finalData.userId === newId);
130
142
  }
131
143
  return newId;
132
144
  }
@@ -209,6 +221,21 @@ export class DataLoader {
209
221
  this.phoneToUserIdMap.set(user.phone, user.$id);
210
222
  }
211
223
  this.userExistsMap.set(user.$id, true);
224
+ let importData = this.importMap.get(this.getCollectionKey("users"));
225
+ if (!importData) {
226
+ importData = {
227
+ data: [],
228
+ };
229
+ }
230
+ importData.data.push({
231
+ finalData: {
232
+ ...user,
233
+ userId: user.$id,
234
+ docId: user.$id,
235
+ },
236
+ rawData: user,
237
+ });
238
+ this.importMap.set(this.getCollectionKey("users"), importData);
212
239
  }
213
240
  return allUsers;
214
241
  }
@@ -244,12 +271,12 @@ export class DataLoader {
244
271
  for (const createDef of createDefs) {
245
272
  if (!isUsersCollection) {
246
273
  console.log(`${collection.name} is not users collection`);
247
- await this.prepareCreateData(db, collection, createDef);
274
+ this.prepareCreateData(db, collection, createDef);
248
275
  }
249
276
  else {
250
277
  // Special handling for users collection if needed
251
278
  console.log(`${collection.name} is users collection`);
252
- await this.prepareUserCollectionCreateData(db, collection, createDef);
279
+ this.prepareUserCollectionCreateData(db, collection, createDef);
253
280
  }
254
281
  }
255
282
  for (const updateDef of updateDefs) {
@@ -258,11 +285,11 @@ export class DataLoader {
258
285
  continue;
259
286
  }
260
287
  // Prepare the update data for the collection
261
- await this.prepareUpdateData(db, collection, updateDef);
288
+ this.prepareUpdateData(db, collection, updateDef);
262
289
  }
263
290
  }
264
291
  console.log("Running update references");
265
- this.dealWithMergedUsers();
292
+ // this.dealWithMergedUsers();
266
293
  this.updateOldReferencesForNew();
267
294
  console.log("Done running update references");
268
295
  }
@@ -280,8 +307,11 @@ export class DataLoader {
280
307
  const usersCollectionKey = this.getCollectionKey(this.config.usersCollectionName);
281
308
  const usersCollectionPrimaryKeyFields = new Set();
282
309
  if (!this.config.collections) {
310
+ console.log("No collections found in configuration.");
283
311
  return;
284
312
  }
313
+ let needsUpdate = false;
314
+ let numUpdates = 0;
285
315
  // Collect primary key fields from the users collection definitions
286
316
  this.config.collections.forEach((collection) => {
287
317
  if (this.getCollectionKey(collection.name) === usersCollectionKey) {
@@ -296,37 +326,61 @@ export class DataLoader {
296
326
  });
297
327
  }
298
328
  });
329
+ console.log(`Primary key fields collected for users collection: ${[
330
+ ...usersCollectionPrimaryKeyFields,
331
+ ]}`);
299
332
  // Iterate over all collections to update references based on merged users
300
333
  this.config.collections.forEach((collection) => {
301
334
  const collectionData = this.importMap.get(this.getCollectionKey(collection.name));
302
- if (!collectionData || !collectionData.data)
335
+ if (!collectionData || !collectionData.data) {
336
+ console.log(`No data found for collection ${collection.name}`);
303
337
  return;
338
+ }
304
339
  const collectionImportDefs = collection.importDefs;
305
340
  if (!collectionImportDefs || !collectionImportDefs.length) {
341
+ console.log(`No import definitions found for collection ${collection.name}`);
306
342
  return;
307
343
  }
308
344
  collectionImportDefs.forEach((importDef) => {
309
345
  importDef.idMappings?.forEach((idMapping) => {
310
346
  if (this.getCollectionKey(idMapping.targetCollection) ===
311
347
  usersCollectionKey) {
348
+ const fieldToSetKey = idMapping.fieldToSet || idMapping.sourceField;
312
349
  const targetFieldKey = idMapping.targetFieldToMatch || idMapping.targetField;
313
350
  if (usersCollectionPrimaryKeyFields.has(targetFieldKey)) {
351
+ console.log(`Processing collection ${collection.name} with target field ${targetFieldKey}`);
314
352
  // Process each item in the collection
315
353
  collectionData.data.forEach((item) => {
316
- const oldId = item.context[idMapping.sourceField];
354
+ const oldId = item.finalData[idMapping.sourceField] ||
355
+ item.context[idMapping.sourceField];
356
+ if (oldId === undefined || oldId === null) {
357
+ console.log(`Skipping item with undefined or null oldId in collection ${collection.name}`);
358
+ return;
359
+ }
317
360
  const newId = this.mergedUserMap.get(`${oldId}`);
318
361
  if (newId) {
362
+ needsUpdate = true;
363
+ numUpdates++;
364
+ console.log(`Updating old ID ${oldId} to new ID ${newId} in collection ${collection.name}`);
319
365
  // Update context to use new user ID
320
- item.finalData[idMapping.fieldToSet || idMapping.sourceField] = newId;
366
+ item.finalData[fieldToSetKey] = newId;
367
+ item.context[fieldToSetKey] = newId;
368
+ }
369
+ else {
370
+ console.log(`No new ID found for old ID ${oldId} in mergedUserMap.`);
321
371
  }
322
372
  });
323
373
  }
324
374
  }
325
375
  });
326
376
  });
377
+ if (needsUpdate) {
378
+ console.log(`Updated ${numUpdates} references for collection ${collection.name}`);
379
+ this.importMap.set(this.getCollectionKey(collection.name), collectionData);
380
+ }
327
381
  });
328
382
  }
329
- async updateOldReferencesForNew() {
383
+ updateOldReferencesForNew() {
330
384
  if (!this.config.collections) {
331
385
  return;
332
386
  }
@@ -467,7 +521,7 @@ export class DataLoader {
467
521
  * @param attributeMappings - The attribute mappings for the item.
468
522
  * @returns The transformed item with user-specific keys removed.
469
523
  */
470
- async prepareUserData(item, attributeMappings, primaryKeyField, newId) {
524
+ prepareUserData(item, attributeMappings, primaryKeyField, newId) {
471
525
  let transformedItem = this.transformData(item, attributeMappings);
472
526
  const userData = AuthUserCreateSchema.safeParse(transformedItem);
473
527
  if (!userData.success) {
@@ -515,15 +569,23 @@ export class DataLoader {
515
569
  });
516
570
  if (userFound) {
517
571
  userFound.finalData.userId = existingId;
572
+ userFound.finalData.docId = existingId;
573
+ this.userExistsMap.set(existingId, true);
518
574
  }
519
- return [
575
+ const userKeys = ["email", "phone", "name", "labels", "prefs"];
576
+ userKeys.forEach((key) => {
577
+ if (transformedItem.hasOwnProperty(key)) {
578
+ delete transformedItem[key];
579
+ }
580
+ });
581
+ return {
520
582
  transformedItem,
521
583
  existingId,
522
- {
584
+ userData: {
523
585
  rawData: userFound?.rawData,
524
586
  finalData: userFound?.finalData,
525
587
  },
526
- ];
588
+ };
527
589
  }
528
590
  else {
529
591
  existingId = newId;
@@ -543,7 +605,11 @@ export class DataLoader {
543
605
  this.importMap.set(this.getCollectionKey("users"), {
544
606
  data: [...(usersMap?.data || []), userDataToAdd],
545
607
  });
546
- return [transformedItem, existingId, userDataToAdd];
608
+ return {
609
+ transformedItem,
610
+ existingId,
611
+ userData: userDataToAdd,
612
+ };
547
613
  }
548
614
  /**
549
615
  * Prepares the data for creating user collection documents.
@@ -554,7 +620,7 @@ export class DataLoader {
554
620
  * @param collection - The collection configuration.
555
621
  * @param importDef - The import definition containing the attribute mappings and other relevant info.
556
622
  */
557
- async prepareUserCollectionCreateData(db, collection, importDef) {
623
+ prepareUserCollectionCreateData(db, collection, importDef) {
558
624
  // Load the raw data based on the import definition
559
625
  const rawData = this.loadData(importDef);
560
626
  const operationId = this.collectionImportOperations.get(this.getCollectionKey(collection.name));
@@ -569,100 +635,108 @@ export class DataLoader {
569
635
  if (!operationId) {
570
636
  throw new Error(`No import operation found for collection ${collection.name}`);
571
637
  }
572
- await updateOperation(this.database, operationId, {
638
+ updateOperation(this.database, operationId, {
573
639
  status: "ready",
574
640
  total: rawData.length,
575
- });
576
- // Retrieve the current user data and the current collection data from the import map
577
- const currentUserData = this.importMap.get(this.getCollectionKey("users"));
578
- const currentData = this.importMap.get(this.getCollectionKey(collection.name));
579
- // Log errors if the necessary data is not found in the import map
580
- if (!currentUserData) {
581
- logger.error(`No data found for collection ${"users"} for createDef but it says it's supposed to have one...`);
582
- return;
583
- }
584
- else if (!currentData) {
585
- logger.error(`No data found for collection ${collection.name} for createDef but it says it's supposed to have one...`);
586
- return;
587
- }
588
- // Iterate through each item in the raw data
589
- for (const item of rawData) {
590
- // Prepare user data, check for duplicates, and remove user-specific keys
591
- let [transformedItem, existingId, userData] = await this.prepareUserData(item, importDef.attributeMappings, importDef.primaryKeyField, this.getTrueUniqueId(this.getCollectionKey("users")));
592
- logger.info(`In create user -- transformedItem: ${JSON.stringify(transformedItem, null, 2)}`);
593
- // Generate a new unique ID for the item or use existing ID
594
- if (!existingId) {
595
- // No existing user ID, generate a new unique ID
596
- existingId = this.getTrueUniqueId(this.getCollectionKey("users"));
597
- transformedItem.docId = existingId; // Assign the new ID to the transformed data's docId field
598
- }
599
- // Create a context object for the item, including the new ID
600
- let context = this.createContext(db, collection, item, existingId);
601
- // Merge the transformed data into the context
602
- context = { ...context, ...transformedItem, ...userData.finalData };
603
- // If a primary key field is defined, handle the ID mapping and check for duplicates
604
- if (importDef.primaryKeyField) {
605
- const oldId = item[importDef.primaryKeyField];
606
- // Check if the oldId already exists to handle potential duplicates
607
- if (this.oldIdToNewIdPerCollectionMap
608
- .get(this.getCollectionKey(collection.name))
609
- ?.has(`${oldId}`)) {
610
- // Found a duplicate oldId, now decide how to merge or handle these duplicates
611
- for (const data of currentData.data) {
612
- if (data.finalData.docId === oldId ||
613
- data.finalData.userId === oldId) {
614
- transformedItem = this.mergeObjects(data.finalData, transformedItem);
641
+ }).then(() => {
642
+ // Retrieve the current user data and the current collection data from the import map
643
+ const currentUserData = this.importMap.get(this.getCollectionKey("users"));
644
+ const currentData = this.importMap.get(this.getCollectionKey(collection.name));
645
+ // Log errors if the necessary data is not found in the import map
646
+ if (!currentUserData) {
647
+ logger.error(`No data found for collection ${"users"} for createDef but it says it's supposed to have one...`);
648
+ return;
649
+ }
650
+ else if (!currentData) {
651
+ logger.error(`No data found for collection ${collection.name} for createDef but it says it's supposed to have one...`);
652
+ return;
653
+ }
654
+ // Iterate through each item in the raw data
655
+ for (const item of rawData) {
656
+ // Prepare user data, check for duplicates, and remove user-specific keys
657
+ let { transformedItem, existingId, userData } = this.prepareUserData(item, importDef.attributeMappings, importDef.primaryKeyField, this.getTrueUniqueId(this.getCollectionKey("users")));
658
+ logger.info(`In create user -- transformedItem: ${JSON.stringify(transformedItem, null, 2)}`);
659
+ // Generate a new unique ID for the item or use existing ID
660
+ if (!existingId) {
661
+ // No existing user ID, generate a new unique ID
662
+ existingId = this.getTrueUniqueId(this.getCollectionKey("users"));
663
+ transformedItem.docId = existingId; // Assign the new ID to the transformed data's docId field
664
+ }
665
+ // Create a context object for the item, including the new ID
666
+ let context = this.createContext(db, collection, item, existingId);
667
+ // Merge the transformed data into the context
668
+ context = { ...context, ...transformedItem, ...userData.finalData };
669
+ // If a primary key field is defined, handle the ID mapping and check for duplicates
670
+ if (importDef.primaryKeyField) {
671
+ const oldId = item[importDef.primaryKeyField];
672
+ // Check if the oldId already exists to handle potential duplicates
673
+ if (this.oldIdToNewIdPerCollectionMap
674
+ .get(this.getCollectionKey(collection.name))
675
+ ?.has(`${oldId}`)) {
676
+ // Found a duplicate oldId, now decide how to merge or handle these duplicates
677
+ for (const data of currentData.data) {
678
+ if (data.finalData.docId === oldId ||
679
+ data.finalData.userId === oldId) {
680
+ transformedItem = this.mergeObjects(data.finalData, transformedItem);
681
+ }
615
682
  }
616
683
  }
684
+ else {
685
+ // No duplicate found, simply map the oldId to the new itemId
686
+ collectionOldIdToNewIdMap?.set(`${oldId}`, `${existingId}`);
687
+ }
617
688
  }
618
- else {
619
- // No duplicate found, simply map the oldId to the new itemId
620
- collectionOldIdToNewIdMap?.set(`${oldId}`, `${existingId}`);
689
+ // Handle merging for currentUserData
690
+ for (let i = 0; i < currentUserData.data.length; i++) {
691
+ const currentUserDataItem = currentUserData.data[i];
692
+ const samePhones = currentUserDataItem.finalData.phone &&
693
+ transformedItem.phone &&
694
+ currentUserDataItem.finalData.phone === transformedItem.phone;
695
+ const sameEmails = currentUserDataItem.finalData.email &&
696
+ transformedItem.email &&
697
+ currentUserDataItem.finalData.email === transformedItem.email;
698
+ if ((currentUserDataItem.finalData.docId === existingId ||
699
+ currentUserDataItem.finalData.userId === existingId) &&
700
+ (samePhones || sameEmails) &&
701
+ currentUserDataItem.finalData &&
702
+ userData.finalData) {
703
+ const userDataMerged = this.mergeObjects(currentUserData.data[i].finalData, userData.finalData);
704
+ currentUserData.data[i].finalData = userDataMerged;
705
+ this.importMap.set(this.getCollectionKey("users"), currentUserData);
706
+ }
621
707
  }
622
- }
623
- // Merge the final user data into the context
624
- context = { ...context, ...userData.finalData };
625
- // Handle merging for currentUserData
626
- for (let i = 0; i < currentUserData.data.length; i++) {
627
- if ((currentUserData.data[i].finalData.docId === existingId ||
628
- currentUserData.data[i].finalData.userId === existingId) &&
629
- !_.isEqual(currentUserData.data[i], userData)) {
630
- this.mergeObjects(currentUserData.data[i].finalData, userData.finalData);
631
- console.log("Merging user data", currentUserData.data[i].finalData);
632
- this.importMap.set(this.getCollectionKey("users"), currentUserData);
708
+ // Update the attribute mappings with any actions that need to be performed post-import
709
+ const mappingsWithActions = this.getAttributeMappingsWithActions(importDef.attributeMappings, context, transformedItem);
710
+ // Update the import definition with the new attribute mappings
711
+ const newImportDef = {
712
+ ...importDef,
713
+ attributeMappings: mappingsWithActions,
714
+ };
715
+ let foundData = false;
716
+ for (let i = 0; i < currentData.data.length; i++) {
717
+ if (currentData.data[i].finalData.docId === existingId ||
718
+ currentData.data[i].finalData.userId === existingId) {
719
+ currentData.data[i].finalData = this.mergeObjects(currentData.data[i].finalData, transformedItem);
720
+ currentData.data[i].context = context;
721
+ currentData.data[i].importDef = newImportDef;
722
+ this.importMap.set(this.getCollectionKey(collection.name), currentData);
723
+ this.oldIdToNewIdPerCollectionMap.set(this.getCollectionKey(collection.name), collectionOldIdToNewIdMap);
724
+ foundData = true;
725
+ }
633
726
  }
634
- }
635
- // Update the attribute mappings with any actions that need to be performed post-import
636
- const mappingsWithActions = this.getAttributeMappingsWithActions(importDef.attributeMappings, context, transformedItem);
637
- // Update the import definition with the new attribute mappings
638
- const newImportDef = {
639
- ...importDef,
640
- attributeMappings: mappingsWithActions,
641
- };
642
- let foundData = false;
643
- for (let i = 0; i < currentData.data.length; i++) {
644
- if (currentData.data[i].finalData.docId === existingId ||
645
- currentData.data[i].finalData.userId === existingId) {
646
- currentData.data[i].finalData = this.mergeObjects(currentData.data[i].finalData, transformedItem);
647
- currentData.data[i].context = context;
648
- currentData.data[i].importDef = newImportDef;
727
+ if (!foundData) {
728
+ // Add new data to the associated collection
729
+ currentData.data.push({
730
+ rawData: item,
731
+ context: context,
732
+ importDef: newImportDef,
733
+ finalData: transformedItem,
734
+ });
649
735
  this.importMap.set(this.getCollectionKey(collection.name), currentData);
650
736
  this.oldIdToNewIdPerCollectionMap.set(this.getCollectionKey(collection.name), collectionOldIdToNewIdMap);
651
- foundData = true;
652
737
  }
653
738
  }
654
- if (!foundData) {
655
- // Add new data to the associated collection
656
- currentData.data.push({
657
- rawData: item,
658
- context: context,
659
- importDef: newImportDef,
660
- finalData: transformedItem,
661
- });
662
- this.importMap.set(this.getCollectionKey(collection.name), currentData);
663
- this.oldIdToNewIdPerCollectionMap.set(this.getCollectionKey(collection.name), collectionOldIdToNewIdMap);
664
- }
665
- }
739
+ });
666
740
  }
667
741
  /**
668
742
  * Prepares the data for creating documents in a collection.
@@ -672,74 +746,75 @@ export class DataLoader {
672
746
  * @param collection - The collection configuration.
673
747
  * @param importDef - The import definition containing the attribute mappings and other relevant info.
674
748
  */
675
- async prepareCreateData(db, collection, importDef) {
749
+ prepareCreateData(db, collection, importDef) {
676
750
  // Load the raw data based on the import definition
677
751
  const rawData = this.loadData(importDef);
678
752
  const operationId = this.collectionImportOperations.get(this.getCollectionKey(collection.name));
679
753
  if (!operationId) {
680
754
  throw new Error(`No import operation found for collection ${collection.name}`);
681
755
  }
682
- await updateOperation(this.database, operationId, {
756
+ updateOperation(this.database, operationId, {
683
757
  status: "ready",
684
758
  total: rawData.length,
685
- });
686
- // Initialize a new map for old ID to new ID mappings
687
- const oldIdToNewIdMapNew = new Map();
688
- // Retrieve or initialize the collection-specific old ID to new ID map
689
- const collectionOldIdToNewIdMap = this.oldIdToNewIdPerCollectionMap.get(this.getCollectionKey(collection.name)) ||
690
- this.oldIdToNewIdPerCollectionMap
691
- .set(this.getCollectionKey(collection.name), oldIdToNewIdMapNew)
692
- .get(this.getCollectionKey(collection.name));
693
- console.log(`${collection.name} -- collectionOldIdToNewIdMap: ${collectionOldIdToNewIdMap}`);
694
- // Iterate through each item in the raw data
695
- for (const item of rawData) {
696
- // Generate a new unique ID for the item
697
- const itemIdNew = this.getTrueUniqueId(this.getCollectionKey(collection.name));
698
- // Retrieve the current collection data from the import map
699
- const currentData = this.importMap.get(this.getCollectionKey(collection.name));
700
- // Create a context object for the item, including the new ID
701
- let context = this.createContext(db, collection, item, itemIdNew);
702
- // Transform the item data based on the attribute mappings
703
- const transformedData = this.transformData(item, importDef.attributeMappings);
704
- // If a primary key field is defined, handle the ID mapping and check for duplicates
705
- if (importDef.primaryKeyField) {
706
- const oldId = item[importDef.primaryKeyField];
707
- if (collectionOldIdToNewIdMap?.has(`${oldId}`)) {
708
- logger.error(`Collection ${collection.name} has multiple documents with the same primary key ${oldId}`);
759
+ }).then(() => {
760
+ // Initialize a new map for old ID to new ID mappings
761
+ const oldIdToNewIdMapNew = new Map();
762
+ // Retrieve or initialize the collection-specific old ID to new ID map
763
+ const collectionOldIdToNewIdMap = this.oldIdToNewIdPerCollectionMap.get(this.getCollectionKey(collection.name)) ||
764
+ this.oldIdToNewIdPerCollectionMap
765
+ .set(this.getCollectionKey(collection.name), oldIdToNewIdMapNew)
766
+ .get(this.getCollectionKey(collection.name));
767
+ console.log(`${collection.name} -- collectionOldIdToNewIdMap: ${collectionOldIdToNewIdMap}`);
768
+ // Iterate through each item in the raw data
769
+ for (const item of rawData) {
770
+ // Generate a new unique ID for the item
771
+ const itemIdNew = this.getTrueUniqueId(this.getCollectionKey(collection.name));
772
+ // Retrieve the current collection data from the import map
773
+ const currentData = this.importMap.get(this.getCollectionKey(collection.name));
774
+ // Create a context object for the item, including the new ID
775
+ let context = this.createContext(db, collection, item, itemIdNew);
776
+ // Transform the item data based on the attribute mappings
777
+ const transformedData = this.transformData(item, importDef.attributeMappings);
778
+ // If a primary key field is defined, handle the ID mapping and check for duplicates
779
+ if (importDef.primaryKeyField) {
780
+ const oldId = item[importDef.primaryKeyField];
781
+ if (collectionOldIdToNewIdMap?.has(`${oldId}`)) {
782
+ logger.error(`Collection ${collection.name} has multiple documents with the same primary key ${oldId}`);
783
+ continue;
784
+ }
785
+ collectionOldIdToNewIdMap?.set(`${oldId}`, `${itemIdNew}`);
786
+ }
787
+ // Merge the transformed data into the context
788
+ context = { ...context, ...transformedData };
789
+ // Validate the item before proceeding
790
+ const isValid = this.importDataActions.validateItem(transformedData, importDef.attributeMappings, context);
791
+ if (!isValid) {
792
+ continue;
793
+ }
794
+ // Update the attribute mappings with any actions that need to be performed post-import
795
+ const mappingsWithActions = this.getAttributeMappingsWithActions(importDef.attributeMappings, context, transformedData);
796
+ // Update the import definition with the new attribute mappings
797
+ const newImportDef = {
798
+ ...importDef,
799
+ attributeMappings: mappingsWithActions,
800
+ };
801
+ // If the current collection data exists, add the item with its context and final data
802
+ if (currentData && currentData.data) {
803
+ currentData.data.push({
804
+ rawData: item,
805
+ context: context,
806
+ importDef: newImportDef,
807
+ finalData: transformedData,
808
+ });
809
+ this.importMap.set(this.getCollectionKey(collection.name), currentData);
810
+ this.oldIdToNewIdPerCollectionMap.set(this.getCollectionKey(collection.name), collectionOldIdToNewIdMap);
811
+ }
812
+ else {
813
+ logger.error(`No data found for collection ${collection.name} for createDef but it says it's supposed to have one...`);
709
814
  continue;
710
815
  }
711
- collectionOldIdToNewIdMap?.set(`${oldId}`, `${itemIdNew}`);
712
- }
713
- // Merge the transformed data into the context
714
- context = { ...context, ...transformedData };
715
- // Validate the item before proceeding
716
- const isValid = await this.importDataActions.validateItem(transformedData, importDef.attributeMappings, context);
717
- if (!isValid) {
718
- continue;
719
- }
720
- // Update the attribute mappings with any actions that need to be performed post-import
721
- const mappingsWithActions = this.getAttributeMappingsWithActions(importDef.attributeMappings, context, transformedData);
722
- // Update the import definition with the new attribute mappings
723
- const newImportDef = {
724
- ...importDef,
725
- attributeMappings: mappingsWithActions,
726
- };
727
- // If the current collection data exists, add the item with its context and final data
728
- if (currentData && currentData.data) {
729
- currentData.data.push({
730
- rawData: item,
731
- context: context,
732
- importDef: newImportDef,
733
- finalData: transformedData,
734
- });
735
- this.importMap.set(this.getCollectionKey(collection.name), currentData);
736
- this.oldIdToNewIdPerCollectionMap.set(this.getCollectionKey(collection.name), collectionOldIdToNewIdMap);
737
- }
738
- else {
739
- logger.error(`No data found for collection ${collection.name} for createDef but it says it's supposed to have one...`);
740
- continue;
741
816
  }
742
- }
817
+ });
743
818
  }
744
819
  /**
745
820
  * Prepares the data for updating documents within a collection.
@@ -751,7 +826,7 @@ export class DataLoader {
751
826
  * @param collection - The collection configuration.
752
827
  * @param importDef - The import definition containing the attribute mappings and other relevant info.
753
828
  */
754
- async prepareUpdateData(db, collection, importDef) {
829
+ prepareUpdateData(db, collection, importDef) {
755
830
  // Retrieve the current collection data and old-to-new ID map from the import map
756
831
  const currentData = this.importMap.get(this.getCollectionKey(collection.name));
757
832
  const oldIdToNewIdMap = this.oldIdToNewIdPerCollectionMap.get(this.getCollectionKey(collection.name));
@@ -773,12 +848,7 @@ export class DataLoader {
773
848
  let newId;
774
849
  let oldId;
775
850
  // Determine the new ID for the item based on the primary key field or update mapping
776
- if (importDef.primaryKeyField) {
777
- oldId = item[importDef.primaryKeyField];
778
- }
779
- else if (importDef.updateMapping) {
780
- oldId = item[importDef.updateMapping.originalIdField];
781
- }
851
+ oldId = item[importDef.primaryKeyField];
782
852
  if (oldId) {
783
853
  newId = oldIdToNewIdMap?.get(`${oldId}`);
784
854
  if (!newId &&
@@ -796,24 +866,31 @@ export class DataLoader {
796
866
  logger.error(`No old ID found (to update another document with) in prepareUpdateData for ${collection.name}, ${JSON.stringify(item, null, 2)}`);
797
867
  continue;
798
868
  }
869
+ const itemDataToUpdate = this.importMap
870
+ .get(this.getCollectionKey(collection.name))
871
+ ?.data.find((data) => `${data.context[importDef.primaryKeyField]}` === `${oldId}`);
799
872
  // Log an error and continue to the next item if no new ID is found
800
- if (!newId) {
873
+ if (!newId && !itemDataToUpdate) {
801
874
  logger.error(`No new id found for collection ${collection.name} for updateDef ${JSON.stringify(item, null, 2)} but it says it's supposed to have one...`);
802
875
  continue;
803
876
  }
804
- const itemDataToUpdate = this.importMap
805
- .get(this.getCollectionKey(collection.name))
806
- ?.data.find((data) => data.rawData[importDef.primaryKeyField] === oldId);
807
- if (!itemDataToUpdate) {
808
- logger.error(`No data found for collection ${collection.name} for updateDef ${JSON.stringify(item, null, 2)} but it says it's supposed to have one...`);
877
+ else if (itemDataToUpdate) {
878
+ newId = itemDataToUpdate.finalData.docId;
879
+ if (!newId) {
880
+ logger.error(`No new id found for collection ${collection.name} for updateDef ${JSON.stringify(item, null, 2)} but it says it's supposed to have one...`);
881
+ continue;
882
+ }
883
+ }
884
+ if (!itemDataToUpdate || !newId) {
885
+ logger.error(`No data or ID (docId) found for collection ${collection.name} for updateDef ${JSON.stringify(item, null, 2)} but it says it's supposed to have one...`);
809
886
  continue;
810
887
  }
811
888
  transformedData = this.mergeObjects(itemDataToUpdate.finalData, transformedData);
812
889
  // Create a context object for the item, including the new ID and transformed data
813
890
  let context = this.createContext(db, collection, item, newId);
814
- context = this.mergeObjects(context, transformedData);
891
+ context = { ...context, ...transformedData };
815
892
  // Validate the item before proceeding
816
- const isValid = await this.importDataActions.validateItem(item, importDef.attributeMappings, context);
893
+ const isValid = this.importDataActions.validateItem(item, importDef.attributeMappings, context);
817
894
  // Log info and continue to the next item if it's invalid
818
895
  if (!isValid) {
819
896
  logger.info(`Skipping item: ${JSON.stringify(item, null, 2)} because it's invalid`);
@@ -832,6 +909,7 @@ export class DataLoader {
832
909
  itemDataToUpdate.finalData = this.mergeObjects(itemDataToUpdate.finalData, transformedData);
833
910
  itemDataToUpdate.context = context;
834
911
  itemDataToUpdate.importDef = newImportDef;
912
+ currentData.data.push(itemDataToUpdate);
835
913
  }
836
914
  else {
837
915
  // If no existing item matches, then add the new item
@@ -1,6 +1,7 @@
1
1
  import { Databases, Query } from "node-appwrite";
2
+ import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
2
3
  export const fetchAllDatabases = async (database) => {
3
- const databases = await database.list([Query.limit(25)]);
4
+ const databases = await tryAwaitWithRetry(async () => await database.list([Query.limit(25)]));
4
5
  const allDatabases = databases.databases;
5
6
  let lastDatabaseId = allDatabases[allDatabases.length - 1].$id;
6
7
  if (databases.databases.length < 25) {