appwrite-utils-cli 0.0.258 → 0.0.260

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.
@@ -1562,6 +1562,17 @@ export declare class DataLoader {
1562
1562
  private shouldWriteFile;
1563
1563
  constructor(appwriteFolderPath: string, importDataActions: ImportDataActions, database: Databases, config: AppwriteConfig, shouldWriteFile?: boolean);
1564
1564
  getCollectionKey(name: string): string;
1565
+ /**
1566
+ * Merges two objects by updating the source object with the target object's values.
1567
+ * It iterates through the target object's keys and updates the source object if:
1568
+ * - The source object has the key.
1569
+ * - The target object's value for that key is not null, undefined, or an empty string.
1570
+ *
1571
+ * @param source - The source object to be updated.
1572
+ * @param target - The target object with values to update the source object.
1573
+ * @returns The updated source object.
1574
+ */
1575
+ mergeObjects(source: Record<string, any>, target: Record<string, any>): Record<string, any>;
1565
1576
  loadData(importDef: ImportDef): Promise<any[]>;
1566
1577
  checkMapValuesForId(newId: string, collectionName: string): string | false;
1567
1578
  getTrueUniqueId(collectionName: string): string;
@@ -59,6 +59,28 @@ export class DataLoader {
59
59
  getCollectionKey(name) {
60
60
  return name.toLowerCase().replace(" ", "");
61
61
  }
62
+ /**
63
+ * Merges two objects by updating the source object with the target object's values.
64
+ * It iterates through the target object's keys and updates the source object if:
65
+ * - The source object has the key.
66
+ * - The target object's value for that key is not null, undefined, or an empty string.
67
+ *
68
+ * @param source - The source object to be updated.
69
+ * @param target - The target object with values to update the source object.
70
+ * @returns The updated source object.
71
+ */
72
+ mergeObjects(source, target) {
73
+ Object.keys(target).forEach((key) => {
74
+ const targetValue = target[key];
75
+ if (source.hasOwnProperty(key) &&
76
+ targetValue !== null &&
77
+ targetValue !== undefined &&
78
+ targetValue !== "") {
79
+ source[key] = targetValue;
80
+ }
81
+ });
82
+ return source;
83
+ }
62
84
  // Method to load data from a file specified in the import definition
63
85
  async loadData(importDef) {
64
86
  // Resolve the file path and check if the file exists
@@ -414,16 +436,11 @@ export class DataLoader {
414
436
  }
415
437
  });
416
438
  const usersMap = this.importMap.get(this.getCollectionKey("users"));
417
- if (usersMap) {
418
- usersMap.data.push({
419
- rawData: item,
420
- finalData: userData.data,
421
- });
422
- }
423
439
  const userDataToAdd = {
424
440
  rawData: item,
425
441
  finalData: userData.data,
426
442
  };
443
+ // Directly update the importMap with the new user data, without pushing to usersMap.data first
427
444
  this.importMap.set(this.getCollectionKey("users"), {
428
445
  data: [...(usersMap?.data || []), userDataToAdd],
429
446
  });
@@ -495,7 +512,7 @@ export class DataLoader {
495
512
  for (const data of currentData.data) {
496
513
  if (data.finalData.docId === oldId ||
497
514
  data.finalData.userId === oldId) {
498
- Object.assign(data.finalData, transformedItem);
515
+ transformedItem = this.mergeObjects(data.finalData, transformedItem);
499
516
  }
500
517
  }
501
518
  }
@@ -511,8 +528,7 @@ export class DataLoader {
511
528
  if ((currentUserData.data[i].finalData.docId === existingId ||
512
529
  currentUserData.data[i].finalData.userId === existingId) &&
513
530
  !_.isEqual(currentUserData.data[i], userData)) {
514
- Object.assign(currentUserData.data[i].finalData, transformedItem);
515
- Object.assign(currentUserData.data[i].rawData, item);
531
+ this.mergeObjects(currentUserData.data[i].finalData, userData.finalData);
516
532
  console.log("Merging user data", currentUserData.data[i].finalData);
517
533
  this.importMap.set(this.getCollectionKey("users"), currentUserData);
518
534
  }
@@ -528,10 +544,8 @@ export class DataLoader {
528
544
  for (let i = 0; i < currentData.data.length; i++) {
529
545
  if (currentData.data[i].finalData.docId === existingId ||
530
546
  currentData.data[i].finalData.userId === existingId) {
531
- currentData.data[i].finalData = {
532
- ...currentData.data[i].finalData,
533
- ...transformedItem,
534
- };
547
+ currentData.data[i].finalData = this.mergeObjects(currentData.data[i].finalData, transformedItem);
548
+ currentData.data[i].context = context;
535
549
  currentData.data[i].importDef = newImportDef;
536
550
  this.importMap.set(this.getCollectionKey(collection.name), currentData);
537
551
  this.oldIdToNewIdPerCollectionMap.set(this.getCollectionKey(collection.name), collectionOldIdToNewIdMap);
@@ -656,7 +670,7 @@ export class DataLoader {
656
670
  }
657
671
  for (const item of rawData) {
658
672
  // Transform the item data based on the attribute mappings
659
- const transformedData = await this.transformData(item, importDef.attributeMappings);
673
+ let transformedData = await this.transformData(item, importDef.attributeMappings);
660
674
  let newId;
661
675
  let oldId;
662
676
  // Determine the new ID for the item based on the primary key field or update mapping
@@ -688,9 +702,17 @@ export class DataLoader {
688
702
  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...`);
689
703
  continue;
690
704
  }
705
+ const itemDataToUpdate = this.importMap
706
+ .get(this.getCollectionKey(collection.name))
707
+ ?.data.find((data) => data.rawData[importDef.primaryKeyField] === oldId);
708
+ if (!itemDataToUpdate) {
709
+ 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...`);
710
+ continue;
711
+ }
712
+ transformedData = this.mergeObjects(itemDataToUpdate.finalData, transformedData);
691
713
  // Create a context object for the item, including the new ID and transformed data
692
714
  let context = this.createContext(db, collection, item, newId);
693
- context = { ...context, ...transformedData };
715
+ context = this.mergeObjects(context, transformedData);
694
716
  // Validate the item before proceeding
695
717
  const isValid = await this.importDataActions.validateItem(item, importDef.attributeMappings, context);
696
718
  // Log info and continue to the next item if it's invalid
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "appwrite-utils-cli",
3
3
  "description": "Appwrite Utility Functions to help with database management, data conversion, data import, migrations, and much more. Meant to be used as a CLI tool, I do not recommend installing this in frontend environments.",
4
- "version": "0.0.258",
4
+ "version": "0.0.260",
5
5
  "main": "src/main.ts",
6
6
  "type": "module",
7
7
  "repository": {
@@ -86,6 +86,34 @@ export class DataLoader {
86
86
  return name.toLowerCase().replace(" ", "");
87
87
  }
88
88
 
89
+ /**
90
+ * Merges two objects by updating the source object with the target object's values.
91
+ * It iterates through the target object's keys and updates the source object if:
92
+ * - The source object has the key.
93
+ * - The target object's value for that key is not null, undefined, or an empty string.
94
+ *
95
+ * @param source - The source object to be updated.
96
+ * @param target - The target object with values to update the source object.
97
+ * @returns The updated source object.
98
+ */
99
+ mergeObjects(
100
+ source: Record<string, any>,
101
+ target: Record<string, any>
102
+ ): Record<string, any> {
103
+ Object.keys(target).forEach((key) => {
104
+ const targetValue = target[key];
105
+ if (
106
+ source.hasOwnProperty(key) &&
107
+ targetValue !== null &&
108
+ targetValue !== undefined &&
109
+ targetValue !== ""
110
+ ) {
111
+ source[key] = targetValue;
112
+ }
113
+ });
114
+ return source;
115
+ }
116
+
89
117
  // Method to load data from a file specified in the import definition
90
118
  async loadData(importDef: ImportDef): Promise<any[]> {
91
119
  // Resolve the file path and check if the file exists
@@ -522,16 +550,11 @@ export class DataLoader {
522
550
  }
523
551
  });
524
552
  const usersMap = this.importMap.get(this.getCollectionKey("users"));
525
- if (usersMap) {
526
- usersMap.data.push({
527
- rawData: item,
528
- finalData: userData.data,
529
- });
530
- }
531
553
  const userDataToAdd = {
532
554
  rawData: item,
533
555
  finalData: userData.data,
534
556
  };
557
+ // Directly update the importMap with the new user data, without pushing to usersMap.data first
535
558
  this.importMap.set(this.getCollectionKey("users"), {
536
559
  data: [...(usersMap?.data || []), userDataToAdd],
537
560
  });
@@ -644,7 +667,10 @@ export class DataLoader {
644
667
  data.finalData.docId === oldId ||
645
668
  data.finalData.userId === oldId
646
669
  ) {
647
- Object.assign(data.finalData, transformedItem);
670
+ transformedItem = this.mergeObjects(
671
+ data.finalData,
672
+ transformedItem
673
+ );
648
674
  }
649
675
  }
650
676
  } else {
@@ -662,8 +688,10 @@ export class DataLoader {
662
688
  currentUserData.data[i].finalData.userId === existingId) &&
663
689
  !_.isEqual(currentUserData.data[i], userData)
664
690
  ) {
665
- Object.assign(currentUserData.data[i].finalData, transformedItem);
666
- Object.assign(currentUserData.data[i].rawData, item);
691
+ this.mergeObjects(
692
+ currentUserData.data[i].finalData,
693
+ userData.finalData
694
+ );
667
695
  console.log("Merging user data", currentUserData.data[i].finalData);
668
696
  this.importMap.set(this.getCollectionKey("users"), currentUserData);
669
697
  }
@@ -686,10 +714,11 @@ export class DataLoader {
686
714
  currentData.data[i].finalData.docId === existingId ||
687
715
  currentData.data[i].finalData.userId === existingId
688
716
  ) {
689
- currentData.data[i].finalData = {
690
- ...currentData.data[i].finalData,
691
- ...transformedItem,
692
- };
717
+ currentData.data[i].finalData = this.mergeObjects(
718
+ currentData.data[i].finalData,
719
+ transformedItem
720
+ );
721
+ currentData.data[i].context = context;
693
722
  currentData.data[i].importDef = newImportDef;
694
723
  this.importMap.set(
695
724
  this.getCollectionKey(collection.name),
@@ -874,7 +903,7 @@ export class DataLoader {
874
903
  }
875
904
  for (const item of rawData) {
876
905
  // Transform the item data based on the attribute mappings
877
- const transformedData = await this.transformData(
906
+ let transformedData = await this.transformData(
878
907
  item,
879
908
  importDef.attributeMappings
880
909
  );
@@ -921,9 +950,30 @@ export class DataLoader {
921
950
  );
922
951
  continue;
923
952
  }
953
+ const itemDataToUpdate = this.importMap
954
+ .get(this.getCollectionKey(collection.name))
955
+ ?.data.find(
956
+ (data) => data.rawData[importDef.primaryKeyField] === oldId
957
+ );
958
+ if (!itemDataToUpdate) {
959
+ logger.error(
960
+ `No data found for collection ${
961
+ collection.name
962
+ } for updateDef ${JSON.stringify(
963
+ item,
964
+ null,
965
+ 2
966
+ )} but it says it's supposed to have one...`
967
+ );
968
+ continue;
969
+ }
970
+ transformedData = this.mergeObjects(
971
+ itemDataToUpdate.finalData,
972
+ transformedData
973
+ );
924
974
  // Create a context object for the item, including the new ID and transformed data
925
975
  let context = this.createContext(db, collection, item, newId);
926
- context = { ...context, ...transformedData };
976
+ context = this.mergeObjects(context, transformedData);
927
977
  // Validate the item before proceeding
928
978
  const isValid = await this.importDataActions.validateItem(
929
979
  item,