appwrite-utils-cli 0.0.62 → 0.0.63

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.
@@ -291,7 +291,8 @@ export class DataLoader {
291
291
  console.log("---------------------------------");
292
292
  await this.setupMaps(dbId);
293
293
  const allUsers = await this.getAllUsers();
294
- console.log(`Fetched ${allUsers.length} users`);
294
+ console.log(`Fetched ${allUsers.length} users, waiting a few seconds to let the program catch up...`);
295
+ await new Promise((resolve) => setTimeout(resolve, 5000));
295
296
  // Iterate over the configured databases to find the matching one
296
297
  for (const db of this.config.databases) {
297
298
  if (db.$id !== dbId) {
@@ -728,9 +729,18 @@ export class DataLoader {
728
729
  let { transformedItem, existingId, userData } = this.prepareUserData(item, importDef.attributeMappings, importDef.primaryKeyField, this.getTrueUniqueId(this.getCollectionKey("users")));
729
730
  logger.info(`In create user -- transformedItem: ${JSON.stringify(transformedItem, null, 2)}`);
730
731
  // Generate a new unique ID for the item or use existing ID
731
- if (!existingId) {
732
+ if (!existingId && !userData.finalData?.userId) {
732
733
  // No existing user ID, generate a new unique ID
733
- existingId = this.getTrueUniqueId(this.getCollectionKey("users"));
734
+ existingId = this.getTrueUniqueId(this.getCollectionKey(collection.name));
735
+ transformedItem = {
736
+ ...transformedItem,
737
+ userId: existingId,
738
+ docId: existingId,
739
+ };
740
+ }
741
+ else if (!existingId && userData.finalData?.userId) {
742
+ // Existing user ID, use it as the new ID
743
+ existingId = userData.finalData.userId;
734
744
  transformedItem = {
735
745
  ...transformedItem,
736
746
  userId: existingId,
@@ -751,7 +761,9 @@ export class DataLoader {
751
761
  // Found a duplicate oldId, now decide how to merge or handle these duplicates
752
762
  for (const data of currentData.data) {
753
763
  if (data.finalData.docId === oldId ||
754
- data.finalData.userId === oldId) {
764
+ data.finalData.userId === oldId ||
765
+ data.context.docId === oldId ||
766
+ data.context.userId === oldId) {
755
767
  transformedItem = this.mergeObjects(data.finalData, transformedItem);
756
768
  }
757
769
  }
@@ -787,30 +799,30 @@ export class DataLoader {
787
799
  ...importDef,
788
800
  attributeMappings: mappingsWithActions,
789
801
  };
802
+ const updatedData = this.importMap.get(this.getCollectionKey(collection.name));
790
803
  let foundData = false;
791
- for (let i = 0; i < currentData.data.length; i++) {
792
- if (currentData.data[i].finalData.docId === existingId ||
793
- currentData.data[i].finalData.userId === existingId) {
794
- currentData.data[i].finalData = this.mergeObjects(currentData.data[i].finalData, transformedItem);
795
- currentData.data[i].context = {
796
- ...currentData.data[i].context,
797
- ...context,
798
- };
799
- currentData.data[i].importDef = newImportDef;
800
- this.importMap.set(this.getCollectionKey(collection.name), currentData);
804
+ for (let i = 0; i < updatedData.data.length; i++) {
805
+ if (updatedData.data[i].finalData.docId === existingId ||
806
+ updatedData.data[i].finalData.userId === existingId ||
807
+ updatedData.data[i].context.docId === existingId ||
808
+ updatedData.data[i].context.userId === existingId) {
809
+ updatedData.data[i].finalData = this.mergeObjects(updatedData.data[i].finalData, transformedItem);
810
+ updatedData.data[i].context = this.mergeObjects(updatedData.data[i].context, context);
811
+ updatedData.data[i].importDef = this.mergeObjects(updatedData.data[i].importDef, newImportDef);
812
+ this.importMap.set(this.getCollectionKey(collection.name), updatedData);
801
813
  this.oldIdToNewIdPerCollectionMap.set(this.getCollectionKey(collection.name), collectionOldIdToNewIdMap);
802
814
  foundData = true;
803
815
  }
804
816
  }
805
817
  if (!foundData) {
806
818
  // Add new data to the associated collection
807
- currentData.data.push({
819
+ updatedData.data.push({
808
820
  rawData: item,
809
821
  context: context,
810
822
  importDef: newImportDef,
811
823
  finalData: transformedItem,
812
824
  });
813
- this.importMap.set(this.getCollectionKey(collection.name), currentData);
825
+ this.importMap.set(this.getCollectionKey(collection.name), updatedData);
814
826
  this.oldIdToNewIdPerCollectionMap.set(this.getCollectionKey(collection.name), collectionOldIdToNewIdMap);
815
827
  }
816
828
  }
@@ -854,13 +866,7 @@ export class DataLoader {
854
866
  // Create a context object for the item, including the new ID
855
867
  let context = this.createContext(db, collection, item, itemIdNew);
856
868
  // Transform the item data based on the attribute mappings
857
- const transformedData = this.transformData(item, importDef.attributeMappings);
858
- if (collection.name.toLowerCase() === "councils") {
859
- console.log("Transformed Council: ", transformedData);
860
- }
861
- if (isRegions) {
862
- logger.info(`Transformed region: ${JSON.stringify(transformedData, null, 2)}`);
863
- }
869
+ let transformedData = this.transformData(item, importDef.attributeMappings);
864
870
  // If a primary key field is defined, handle the ID mapping and check for duplicates
865
871
  if (importDef.primaryKeyField) {
866
872
  const oldId = item[importDef.primaryKeyField];
@@ -157,6 +157,7 @@ export class ImportController {
157
157
  status: "in_progress",
158
158
  });
159
159
  const collectionData = dataLoader.importMap.get(dataLoader.getCollectionKey(collection.name));
160
+ console.log(`Processing collection: ${collection.name}...`);
160
161
  if (!collectionData) {
161
162
  console.log("No collection data for ", collection.name);
162
163
  continue;
@@ -253,7 +253,7 @@ export const transferStorageLocalToLocal = async (storage, fromBucketId, toBucke
253
253
  let numberOfFiles = 0;
254
254
  if (fromFiles.files.length < 100) {
255
255
  for (const file of allFromFiles) {
256
- const fileData = await storage.getFileDownload(file.bucketId, file.$id);
256
+ const fileData = await tryAwaitWithRetry(async () => await storage.getFileDownload(file.bucketId, file.$id));
257
257
  const fileToCreate = InputFile.fromBuffer(Buffer.from(fileData), file.name);
258
258
  console.log(`Creating file: ${file.name}`);
259
259
  tryAwaitWithRetry(async () => await storage.createFile(toBucketId, file.$id, fileToCreate, file.$permissions));
@@ -263,10 +263,10 @@ export const transferStorageLocalToLocal = async (storage, fromBucketId, toBucke
263
263
  else {
264
264
  lastFileId = fromFiles.files[fromFiles.files.length - 1].$id;
265
265
  while (lastFileId) {
266
- const files = await storage.listFiles(fromBucketId, [
266
+ const files = await tryAwaitWithRetry(async () => await storage.listFiles(fromBucketId, [
267
267
  Query.limit(100),
268
268
  Query.cursorAfter(lastFileId),
269
- ]);
269
+ ]));
270
270
  allFromFiles.push(...files.files);
271
271
  if (files.files.length < 100) {
272
272
  lastFileId = undefined;
@@ -276,7 +276,7 @@ export const transferStorageLocalToLocal = async (storage, fromBucketId, toBucke
276
276
  }
277
277
  }
278
278
  for (const file of allFromFiles) {
279
- const fileData = await storage.getFileDownload(file.bucketId, file.$id);
279
+ const fileData = await tryAwaitWithRetry(async () => await storage.getFileDownload(file.bucketId, file.$id));
280
280
  const fileToCreate = InputFile.fromBuffer(Buffer.from(fileData), file.name);
281
281
  await tryAwaitWithRetry(async () => await storage.createFile(toBucketId, file.$id, fileToCreate, file.$permissions));
282
282
  numberOfFiles++;
@@ -295,10 +295,10 @@ export const transferStorageLocalToRemote = async (localStorage, endpoint, proje
295
295
  if (fromFiles.files.length === 100) {
296
296
  lastFileId = fromFiles.files[fromFiles.files.length - 1].$id;
297
297
  while (lastFileId) {
298
- const files = await localStorage.listFiles(fromBucketId, [
298
+ const files = await tryAwaitWithRetry(async () => await localStorage.listFiles(fromBucketId, [
299
299
  Query.limit(100),
300
300
  Query.cursorAfter(lastFileId),
301
- ]);
301
+ ]));
302
302
  allFromFiles.push(...files.files);
303
303
  if (files.files.length < 100) {
304
304
  break;
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.62",
4
+ "version": "0.0.63",
5
5
  "main": "src/main.ts",
6
6
  "type": "module",
7
7
  "repository": {
@@ -362,7 +362,10 @@ export class DataLoader {
362
362
  console.log("---------------------------------");
363
363
  await this.setupMaps(dbId);
364
364
  const allUsers = await this.getAllUsers();
365
- console.log(`Fetched ${allUsers.length} users`);
365
+ console.log(
366
+ `Fetched ${allUsers.length} users, waiting a few seconds to let the program catch up...`
367
+ );
368
+ await new Promise((resolve) => setTimeout(resolve, 5000));
366
369
  // Iterate over the configured databases to find the matching one
367
370
  for (const db of this.config.databases) {
368
371
  if (db.$id !== dbId) {
@@ -940,9 +943,19 @@ export class DataLoader {
940
943
  );
941
944
 
942
945
  // Generate a new unique ID for the item or use existing ID
943
- if (!existingId) {
946
+ if (!existingId && !userData.finalData?.userId) {
944
947
  // No existing user ID, generate a new unique ID
945
- existingId = this.getTrueUniqueId(this.getCollectionKey("users"));
948
+ existingId = this.getTrueUniqueId(
949
+ this.getCollectionKey(collection.name)
950
+ );
951
+ transformedItem = {
952
+ ...transformedItem,
953
+ userId: existingId,
954
+ docId: existingId,
955
+ };
956
+ } else if (!existingId && userData.finalData?.userId) {
957
+ // Existing user ID, use it as the new ID
958
+ existingId = userData.finalData.userId;
946
959
  transformedItem = {
947
960
  ...transformedItem,
948
961
  userId: existingId,
@@ -951,7 +964,7 @@ export class DataLoader {
951
964
  }
952
965
 
953
966
  // Create a context object for the item, including the new ID
954
- let context = this.createContext(db, collection, item, existingId);
967
+ let context = this.createContext(db, collection, item, existingId!);
955
968
 
956
969
  // Merge the transformed data into the context
957
970
  context = { ...context, ...transformedItem, ...userData.finalData };
@@ -970,7 +983,9 @@ export class DataLoader {
970
983
  for (const data of currentData.data) {
971
984
  if (
972
985
  data.finalData.docId === oldId ||
973
- data.finalData.userId === oldId
986
+ data.finalData.userId === oldId ||
987
+ data.context.docId === oldId ||
988
+ data.context.userId === oldId
974
989
  ) {
975
990
  transformedItem = this.mergeObjects(
976
991
  data.finalData,
@@ -1022,41 +1037,51 @@ export class DataLoader {
1022
1037
  attributeMappings: mappingsWithActions,
1023
1038
  };
1024
1039
 
1040
+ const updatedData = this.importMap.get(
1041
+ this.getCollectionKey(collection.name)
1042
+ )!;
1043
+
1025
1044
  let foundData = false;
1026
- for (let i = 0; i < currentData.data.length; i++) {
1045
+ for (let i = 0; i < updatedData.data.length; i++) {
1027
1046
  if (
1028
- currentData.data[i].finalData.docId === existingId ||
1029
- currentData.data[i].finalData.userId === existingId
1047
+ updatedData.data[i].finalData.docId === existingId ||
1048
+ updatedData.data[i].finalData.userId === existingId ||
1049
+ updatedData.data[i].context.docId === existingId ||
1050
+ updatedData.data[i].context.userId === existingId
1030
1051
  ) {
1031
- currentData.data[i].finalData = this.mergeObjects(
1032
- currentData.data[i].finalData,
1052
+ updatedData.data[i].finalData = this.mergeObjects(
1053
+ updatedData.data[i].finalData,
1033
1054
  transformedItem
1034
1055
  );
1035
- currentData.data[i].context = {
1036
- ...currentData.data[i].context,
1037
- ...context,
1038
- };
1039
- currentData.data[i].importDef = newImportDef;
1056
+ updatedData.data[i].context = this.mergeObjects(
1057
+ updatedData.data[i].context,
1058
+ context
1059
+ );
1060
+ updatedData.data[i].importDef = this.mergeObjects(
1061
+ updatedData.data[i].importDef,
1062
+ newImportDef
1063
+ );
1040
1064
  this.importMap.set(
1041
1065
  this.getCollectionKey(collection.name),
1042
- currentData
1066
+ updatedData
1043
1067
  );
1044
1068
  this.oldIdToNewIdPerCollectionMap.set(
1045
1069
  this.getCollectionKey(collection.name),
1046
1070
  collectionOldIdToNewIdMap!
1047
1071
  );
1072
+
1048
1073
  foundData = true;
1049
1074
  }
1050
1075
  }
1051
1076
  if (!foundData) {
1052
1077
  // Add new data to the associated collection
1053
- currentData.data.push({
1078
+ updatedData.data.push({
1054
1079
  rawData: item,
1055
1080
  context: context,
1056
1081
  importDef: newImportDef,
1057
1082
  finalData: transformedItem,
1058
1083
  });
1059
- this.importMap.set(this.getCollectionKey(collection.name), currentData);
1084
+ this.importMap.set(this.getCollectionKey(collection.name), updatedData);
1060
1085
  this.oldIdToNewIdPerCollectionMap.set(
1061
1086
  this.getCollectionKey(collection.name),
1062
1087
  collectionOldIdToNewIdMap!
@@ -1119,18 +1144,10 @@ export class DataLoader {
1119
1144
  // Create a context object for the item, including the new ID
1120
1145
  let context = this.createContext(db, collection, item, itemIdNew);
1121
1146
  // Transform the item data based on the attribute mappings
1122
- const transformedData = this.transformData(
1147
+ let transformedData = this.transformData(
1123
1148
  item,
1124
1149
  importDef.attributeMappings
1125
1150
  );
1126
- if (collection.name.toLowerCase() === "councils") {
1127
- console.log("Transformed Council: ", transformedData);
1128
- }
1129
- if (isRegions) {
1130
- logger.info(
1131
- `Transformed region: ${JSON.stringify(transformedData, null, 2)}`
1132
- );
1133
- }
1134
1151
  // If a primary key field is defined, handle the ID mapping and check for duplicates
1135
1152
  if (importDef.primaryKeyField) {
1136
1153
  const oldId = item[importDef.primaryKeyField];
@@ -237,6 +237,7 @@ export class ImportController {
237
237
  const collectionData = dataLoader.importMap.get(
238
238
  dataLoader.getCollectionKey(collection.name)
239
239
  );
240
+ console.log(`Processing collection: ${collection.name}...`);
240
241
  if (!collectionData) {
241
242
  console.log("No collection data for ", collection.name);
242
243
  continue;
@@ -390,7 +390,9 @@ export const transferStorageLocalToLocal = async (
390
390
  let numberOfFiles = 0;
391
391
  if (fromFiles.files.length < 100) {
392
392
  for (const file of allFromFiles) {
393
- const fileData = await storage.getFileDownload(file.bucketId, file.$id);
393
+ const fileData = await tryAwaitWithRetry(
394
+ async () => await storage.getFileDownload(file.bucketId, file.$id)
395
+ );
394
396
  const fileToCreate = InputFile.fromBuffer(
395
397
  Buffer.from(fileData),
396
398
  file.name
@@ -410,10 +412,13 @@ export const transferStorageLocalToLocal = async (
410
412
  } else {
411
413
  lastFileId = fromFiles.files[fromFiles.files.length - 1].$id;
412
414
  while (lastFileId) {
413
- const files = await storage.listFiles(fromBucketId, [
414
- Query.limit(100),
415
- Query.cursorAfter(lastFileId),
416
- ]);
415
+ const files = await tryAwaitWithRetry(
416
+ async () =>
417
+ await storage.listFiles(fromBucketId, [
418
+ Query.limit(100),
419
+ Query.cursorAfter(lastFileId!),
420
+ ])
421
+ );
417
422
  allFromFiles.push(...files.files);
418
423
  if (files.files.length < 100) {
419
424
  lastFileId = undefined;
@@ -422,7 +427,9 @@ export const transferStorageLocalToLocal = async (
422
427
  }
423
428
  }
424
429
  for (const file of allFromFiles) {
425
- const fileData = await storage.getFileDownload(file.bucketId, file.$id);
430
+ const fileData = await tryAwaitWithRetry(
431
+ async () => await storage.getFileDownload(file.bucketId, file.$id)
432
+ );
426
433
  const fileToCreate = InputFile.fromBuffer(
427
434
  Buffer.from(fileData),
428
435
  file.name
@@ -467,10 +474,13 @@ export const transferStorageLocalToRemote = async (
467
474
  if (fromFiles.files.length === 100) {
468
475
  lastFileId = fromFiles.files[fromFiles.files.length - 1].$id;
469
476
  while (lastFileId) {
470
- const files = await localStorage.listFiles(fromBucketId, [
471
- Query.limit(100),
472
- Query.cursorAfter(lastFileId),
473
- ]);
477
+ const files = await tryAwaitWithRetry(
478
+ async () =>
479
+ await localStorage.listFiles(fromBucketId, [
480
+ Query.limit(100),
481
+ Query.cursorAfter(lastFileId!),
482
+ ])
483
+ );
474
484
  allFromFiles.push(...files.files);
475
485
  if (files.files.length < 100) {
476
486
  break;