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(
|
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 <
|
792
|
-
if (
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
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
|
-
|
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),
|
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
|
-
|
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.
|
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(
|
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(
|
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 <
|
1045
|
+
for (let i = 0; i < updatedData.data.length; i++) {
|
1027
1046
|
if (
|
1028
|
-
|
1029
|
-
|
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
|
-
|
1032
|
-
|
1052
|
+
updatedData.data[i].finalData = this.mergeObjects(
|
1053
|
+
updatedData.data[i].finalData,
|
1033
1054
|
transformedItem
|
1034
1055
|
);
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
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
|
-
|
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
|
-
|
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),
|
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
|
-
|
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
|
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
|
414
|
-
|
415
|
-
|
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
|
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
|
471
|
-
|
472
|
-
|
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;
|