appwrite-utils-cli 0.0.252 → 0.0.253
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.
- package/dist/main.js +6 -0
- package/dist/migrations/dataLoader.d.ts +3 -2
- package/dist/migrations/dataLoader.js +58 -73
- package/dist/migrations/importController.js +1 -1
- package/dist/utilsController.d.ts +1 -0
- package/package.json +1 -1
- package/src/main.ts +6 -0
- package/src/migrations/dataLoader.ts +73 -92
- package/src/migrations/importController.ts +2 -1
- package/src/utilsController.ts +1 -0
package/dist/main.js
CHANGED
@@ -13,6 +13,7 @@ async function main() {
|
|
13
13
|
let generateSchemas = false;
|
14
14
|
let importData = false;
|
15
15
|
let wipeDocuments = false;
|
16
|
+
let shouldWriteFile = false;
|
16
17
|
if (args.includes("--prod")) {
|
17
18
|
runProd = true;
|
18
19
|
}
|
@@ -40,6 +41,9 @@ async function main() {
|
|
40
41
|
if (args.includes("--wipe-users") || args.includes("--wipeUsers")) {
|
41
42
|
wipeUsers = true;
|
42
43
|
}
|
44
|
+
if (args.includes("--write-data") || args.includes("--writeData")) {
|
45
|
+
shouldWriteFile = true;
|
46
|
+
}
|
43
47
|
if (args.includes("--init")) {
|
44
48
|
await controller.run({
|
45
49
|
runProd: runProd,
|
@@ -53,6 +57,7 @@ async function main() {
|
|
53
57
|
generateMockData: false,
|
54
58
|
importData: false,
|
55
59
|
checkDuplicates: false,
|
60
|
+
shouldWriteFile: shouldWriteFile,
|
56
61
|
});
|
57
62
|
}
|
58
63
|
else {
|
@@ -68,6 +73,7 @@ async function main() {
|
|
68
73
|
wipeUsers: wipeUsers,
|
69
74
|
importData: importData,
|
70
75
|
checkDuplicates: false,
|
76
|
+
shouldWriteFile: shouldWriteFile,
|
71
77
|
});
|
72
78
|
}
|
73
79
|
}
|
@@ -1559,7 +1559,8 @@ export declare class DataLoader {
|
|
1559
1559
|
private emailToUserIdMap;
|
1560
1560
|
private phoneToUserIdMap;
|
1561
1561
|
userExistsMap: Map<string, boolean>;
|
1562
|
-
|
1562
|
+
private shouldWriteFile;
|
1563
|
+
constructor(appwriteFolderPath: string, importDataActions: ImportDataActions, database: Databases, config: AppwriteConfig, shouldWriteFile?: boolean);
|
1563
1564
|
getCollectionKey(name: string): string;
|
1564
1565
|
loadData(importDef: ImportDef): Promise<any[]>;
|
1565
1566
|
checkMapValuesForId(newId: string, collectionName: string): string | false;
|
@@ -1578,7 +1579,7 @@ export declare class DataLoader {
|
|
1578
1579
|
getAllUsers(): Promise<import("node-appwrite").Models.User<import("node-appwrite").Models.Preferences>[]>;
|
1579
1580
|
start(dbId: string): Promise<void>;
|
1580
1581
|
updateReferencesInRelatedCollections(): Promise<void>;
|
1581
|
-
|
1582
|
+
private writeMapsToJsonFile;
|
1582
1583
|
/**
|
1583
1584
|
* Prepares user data by checking for duplicates based on email or phone, adding to a duplicate map if found,
|
1584
1585
|
* and then returning the transformed item without user-specific keys.
|
@@ -45,13 +45,15 @@ export class DataLoader {
|
|
45
45
|
emailToUserIdMap = new Map();
|
46
46
|
phoneToUserIdMap = new Map();
|
47
47
|
userExistsMap = new Map();
|
48
|
+
shouldWriteFile = false;
|
48
49
|
// Constructor to initialize the DataLoader with necessary configurations
|
49
|
-
constructor(appwriteFolderPath, importDataActions, database, config) {
|
50
|
+
constructor(appwriteFolderPath, importDataActions, database, config, shouldWriteFile) {
|
50
51
|
this.appwriteFolderPath = appwriteFolderPath;
|
51
52
|
this.importDataActions = importDataActions;
|
52
53
|
this.database = database;
|
53
54
|
this.usersController = new UsersController(config, database);
|
54
55
|
this.config = config;
|
56
|
+
this.shouldWriteFile = shouldWriteFile || false;
|
55
57
|
}
|
56
58
|
// Helper method to generate a consistent key for collections
|
57
59
|
getCollectionKey(name) {
|
@@ -156,7 +158,14 @@ export class DataLoader {
|
|
156
158
|
async getAllUsers() {
|
157
159
|
const users = new UsersController(this.config, this.database);
|
158
160
|
const allUsers = await users.getAllUsers();
|
161
|
+
// Iterate over the users and setup our maps ahead of time for email and phone
|
159
162
|
for (const user of allUsers) {
|
163
|
+
if (user.email) {
|
164
|
+
this.emailToUserIdMap.set(user.email, user.$id);
|
165
|
+
}
|
166
|
+
if (user.phone) {
|
167
|
+
this.phoneToUserIdMap.set(user.phone, user.$id);
|
168
|
+
}
|
160
169
|
this.userExistsMap.set(user.$id, true);
|
161
170
|
}
|
162
171
|
return allUsers;
|
@@ -169,15 +178,6 @@ export class DataLoader {
|
|
169
178
|
await this.setupMaps(dbId);
|
170
179
|
const allUsers = await this.getAllUsers();
|
171
180
|
console.log(`Fetched ${allUsers.length} users`);
|
172
|
-
// Iterate over the users and setup our maps ahead of time for email and phone
|
173
|
-
for (const user of allUsers) {
|
174
|
-
if (user.email) {
|
175
|
-
this.emailToUserIdMap.set(user.email, user.$id);
|
176
|
-
}
|
177
|
-
if (user.phone) {
|
178
|
-
this.phoneToUserIdMap.set(user.phone, user.$id);
|
179
|
-
}
|
180
|
-
}
|
181
181
|
// Iterate over the configured databases to find the matching one
|
182
182
|
for (const db of this.config.databases) {
|
183
183
|
if (db.$id !== dbId) {
|
@@ -222,7 +222,9 @@ export class DataLoader {
|
|
222
222
|
console.log("---------------------------------");
|
223
223
|
console.log(`Data setup for database: ${dbId} completed`);
|
224
224
|
console.log("---------------------------------");
|
225
|
-
|
225
|
+
if (this.shouldWriteFile) {
|
226
|
+
this.writeMapsToJsonFile();
|
227
|
+
}
|
226
228
|
}
|
227
229
|
async updateReferencesInRelatedCollections() {
|
228
230
|
// Iterate over each collection configuration
|
@@ -299,24 +301,6 @@ export class DataLoader {
|
|
299
301
|
}
|
300
302
|
}
|
301
303
|
}
|
302
|
-
updateObjectWithNonNullishValues(sourceObject, inputObject) {
|
303
|
-
// Iterate through the keys of the inputObject
|
304
|
-
for (const key of Object.keys(inputObject)) {
|
305
|
-
const inputValue = inputObject[key];
|
306
|
-
const sourceValue = sourceObject[key];
|
307
|
-
// Check if the inputObject's value for the current key is non-nullish
|
308
|
-
// and either the key doesn't exist in the sourceObject or its value is nullish
|
309
|
-
if (inputValue !== null &&
|
310
|
-
inputValue !== undefined &&
|
311
|
-
inputValue !== "" &&
|
312
|
-
(sourceValue === null ||
|
313
|
-
sourceValue === undefined ||
|
314
|
-
sourceValue === "")) {
|
315
|
-
// Update the sourceObject with the inputObject's value for the current key
|
316
|
-
sourceObject[key] = inputValue;
|
317
|
-
}
|
318
|
-
}
|
319
|
-
}
|
320
304
|
// async updateReferencesInRelatedCollections() {
|
321
305
|
// // Process each collection defined in the config
|
322
306
|
// for (const collection of this.config.collections) {
|
@@ -368,43 +352,36 @@ export class DataLoader {
|
|
368
352
|
// }
|
369
353
|
// }
|
370
354
|
// }
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
// console.error("Error writing data to JSON file:", err);
|
402
|
-
// return;
|
403
|
-
// }
|
404
|
-
// console.log(`Data successfully written to ${outputFile}`);
|
405
|
-
// }
|
406
|
-
// );
|
407
|
-
// }
|
355
|
+
writeMapsToJsonFile() {
|
356
|
+
const outputDir = path.resolve(process.cwd());
|
357
|
+
const outputFile = path.join(outputDir, "dataLoaderOutput.json");
|
358
|
+
const dataToWrite = {
|
359
|
+
dataFromCollections: Array.from(this.importMap.entries()).map(([key, value]) => {
|
360
|
+
return {
|
361
|
+
collection: key,
|
362
|
+
data: value.data.map((item) => item.finalData),
|
363
|
+
};
|
364
|
+
}),
|
365
|
+
// Convert Maps to arrays of entries for serialization
|
366
|
+
mergedUserMap: Array.from(this.mergedUserMap.entries()),
|
367
|
+
// emailToUserIdMap: Array.from(this.emailToUserIdMap.entries()),
|
368
|
+
// phoneToUserIdMap: Array.from(this.phoneToUserIdMap.entries()),
|
369
|
+
};
|
370
|
+
// Use JSON.stringify with a replacer function to handle Maps
|
371
|
+
const replacer = (key, value) => {
|
372
|
+
if (value instanceof Map) {
|
373
|
+
return Array.from(value.entries());
|
374
|
+
}
|
375
|
+
return value;
|
376
|
+
};
|
377
|
+
fs.writeFile(outputFile, JSON.stringify(dataToWrite, replacer, 2), "utf8", (err) => {
|
378
|
+
if (err) {
|
379
|
+
console.error("Error writing data to JSON file:", err);
|
380
|
+
return;
|
381
|
+
}
|
382
|
+
console.log(`Data successfully written to ${outputFile}`);
|
383
|
+
});
|
384
|
+
}
|
408
385
|
/**
|
409
386
|
* Prepares user data by checking for duplicates based on email or phone, adding to a duplicate map if found,
|
410
387
|
* and then returning the transformed item without user-specific keys.
|
@@ -499,6 +476,7 @@ export class DataLoader {
|
|
499
476
|
this.oldIdToNewIdPerCollectionMap
|
500
477
|
.set(this.getCollectionKey(collection.name), oldIdToNewIdMap)
|
501
478
|
.get(this.getCollectionKey(collection.name));
|
479
|
+
console.log(`${collection.name} -- collectionOldIdToNewIdMap: ${collectionOldIdToNewIdMap}`);
|
502
480
|
if (!operationId) {
|
503
481
|
throw new Error(`No import operation found for collection ${collection.name}`);
|
504
482
|
}
|
@@ -528,7 +506,6 @@ export class DataLoader {
|
|
528
506
|
// No existing user ID, generate a new unique ID
|
529
507
|
existingId = this.getTrueUniqueId(this.getCollectionKey("users"));
|
530
508
|
transformedItem.userId = existingId; // Assign the new ID to the transformed data's userId field
|
531
|
-
transformedItem.docId = existingId;
|
532
509
|
}
|
533
510
|
// Create a context object for the item, including the new ID
|
534
511
|
let context = this.createContext(db, collection, item, existingId);
|
@@ -542,7 +519,12 @@ export class DataLoader {
|
|
542
519
|
.get(this.getCollectionKey(collection.name))
|
543
520
|
?.has(`${oldId}`)) {
|
544
521
|
// Found a duplicate oldId, now decide how to merge or handle these duplicates
|
545
|
-
|
522
|
+
for (const data of currentData.data) {
|
523
|
+
if (data.finalData.docId === oldId ||
|
524
|
+
data.finalData.userId === oldId) {
|
525
|
+
Object.assign(data.finalData, transformedItem);
|
526
|
+
}
|
527
|
+
}
|
546
528
|
}
|
547
529
|
else {
|
548
530
|
// No duplicate found, simply map the oldId to the new itemId
|
@@ -556,7 +538,8 @@ export class DataLoader {
|
|
556
538
|
if ((currentUserData.data[i].finalData.docId === existingId ||
|
557
539
|
currentUserData.data[i].finalData.userId === existingId) &&
|
558
540
|
!_.isEqual(currentUserData.data[i], userData)) {
|
559
|
-
|
541
|
+
Object.assign(currentUserData.data[i].finalData, transformedItem);
|
542
|
+
Object.assign(currentUserData.data[i].rawData, item);
|
560
543
|
console.log("Merging user data", currentUserData.data[i].finalData);
|
561
544
|
this.importMap.set(this.getCollectionKey("users"), currentUserData);
|
562
545
|
}
|
@@ -572,7 +555,10 @@ export class DataLoader {
|
|
572
555
|
for (let i = 0; i < currentData.data.length; i++) {
|
573
556
|
if (currentData.data[i].finalData.docId === existingId ||
|
574
557
|
currentData.data[i].finalData.userId === existingId) {
|
575
|
-
|
558
|
+
currentData.data[i].finalData = {
|
559
|
+
...currentData.data[i].finalData,
|
560
|
+
...transformedItem,
|
561
|
+
};
|
576
562
|
currentData.data[i].importDef = newImportDef;
|
577
563
|
this.importMap.set(this.getCollectionKey(collection.name), currentData);
|
578
564
|
this.oldIdToNewIdPerCollectionMap.set(this.getCollectionKey(collection.name), collectionOldIdToNewIdMap);
|
@@ -722,9 +708,8 @@ export class DataLoader {
|
|
722
708
|
}
|
723
709
|
}
|
724
710
|
else {
|
725
|
-
|
726
|
-
|
727
|
-
newId = foundItem ? oldIdToNewIdMap?.get(`${oldId}`) : undefined;
|
711
|
+
logger.error(`No old ID found (to update another document with) in prepareUpdateData for ${collection.name}, ${JSON.stringify(item, null, 2)}`);
|
712
|
+
continue;
|
728
713
|
}
|
729
714
|
// Log an error and continue to the next item if no new ID is found
|
730
715
|
if (!newId) {
|
@@ -58,7 +58,7 @@ export class ImportController {
|
|
58
58
|
console.log(`Starting import data for database: ${db.name}`);
|
59
59
|
console.log(`---------------------------------`);
|
60
60
|
// await this.importCollections(db);
|
61
|
-
const dataLoader = new DataLoader(this.appwriteFolderPath, this.importDataActions, this.database, this.config);
|
61
|
+
const dataLoader = new DataLoader(this.appwriteFolderPath, this.importDataActions, this.database, this.config, this.setupOptions.shouldWriteFile);
|
62
62
|
await dataLoader.start(db.$id);
|
63
63
|
await this.importCollections(db, dataLoader);
|
64
64
|
await resolveAndUpdateRelationships(db.$id, this.database, this.config);
|
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.253",
|
5
5
|
"main": "src/main.ts",
|
6
6
|
"type": "module",
|
7
7
|
"repository": {
|
package/src/main.ts
CHANGED
@@ -16,6 +16,7 @@ async function main() {
|
|
16
16
|
let generateSchemas = false;
|
17
17
|
let importData = false;
|
18
18
|
let wipeDocuments = false;
|
19
|
+
let shouldWriteFile = false;
|
19
20
|
if (args.includes("--prod")) {
|
20
21
|
runProd = true;
|
21
22
|
}
|
@@ -43,6 +44,9 @@ async function main() {
|
|
43
44
|
if (args.includes("--wipe-users") || args.includes("--wipeUsers")) {
|
44
45
|
wipeUsers = true;
|
45
46
|
}
|
47
|
+
if (args.includes("--write-data") || args.includes("--writeData")) {
|
48
|
+
shouldWriteFile = true;
|
49
|
+
}
|
46
50
|
if (args.includes("--init")) {
|
47
51
|
await controller.run({
|
48
52
|
runProd: runProd,
|
@@ -56,6 +60,7 @@ async function main() {
|
|
56
60
|
generateMockData: false,
|
57
61
|
importData: false,
|
58
62
|
checkDuplicates: false,
|
63
|
+
shouldWriteFile: shouldWriteFile,
|
59
64
|
});
|
60
65
|
} else {
|
61
66
|
await controller.run({
|
@@ -70,6 +75,7 @@ async function main() {
|
|
70
75
|
wipeUsers: wipeUsers,
|
71
76
|
importData: importData,
|
72
77
|
checkDuplicates: false,
|
78
|
+
shouldWriteFile: shouldWriteFile,
|
73
79
|
});
|
74
80
|
}
|
75
81
|
}
|
@@ -63,19 +63,22 @@ export class DataLoader {
|
|
63
63
|
private emailToUserIdMap = new Map<string, string>();
|
64
64
|
private phoneToUserIdMap = new Map<string, string>();
|
65
65
|
userExistsMap = new Map<string, boolean>();
|
66
|
+
private shouldWriteFile = false;
|
66
67
|
|
67
68
|
// Constructor to initialize the DataLoader with necessary configurations
|
68
69
|
constructor(
|
69
70
|
appwriteFolderPath: string,
|
70
71
|
importDataActions: ImportDataActions,
|
71
72
|
database: Databases,
|
72
|
-
config: AppwriteConfig
|
73
|
+
config: AppwriteConfig,
|
74
|
+
shouldWriteFile?: boolean
|
73
75
|
) {
|
74
76
|
this.appwriteFolderPath = appwriteFolderPath;
|
75
77
|
this.importDataActions = importDataActions;
|
76
78
|
this.database = database;
|
77
79
|
this.usersController = new UsersController(config, database);
|
78
80
|
this.config = config;
|
81
|
+
this.shouldWriteFile = shouldWriteFile || false;
|
79
82
|
}
|
80
83
|
|
81
84
|
// Helper method to generate a consistent key for collections
|
@@ -213,7 +216,14 @@ export class DataLoader {
|
|
213
216
|
async getAllUsers() {
|
214
217
|
const users = new UsersController(this.config, this.database);
|
215
218
|
const allUsers = await users.getAllUsers();
|
219
|
+
// Iterate over the users and setup our maps ahead of time for email and phone
|
216
220
|
for (const user of allUsers) {
|
221
|
+
if (user.email) {
|
222
|
+
this.emailToUserIdMap.set(user.email, user.$id);
|
223
|
+
}
|
224
|
+
if (user.phone) {
|
225
|
+
this.phoneToUserIdMap.set(user.phone, user.$id);
|
226
|
+
}
|
217
227
|
this.userExistsMap.set(user.$id, true);
|
218
228
|
}
|
219
229
|
return allUsers;
|
@@ -227,15 +237,6 @@ export class DataLoader {
|
|
227
237
|
await this.setupMaps(dbId);
|
228
238
|
const allUsers = await this.getAllUsers();
|
229
239
|
console.log(`Fetched ${allUsers.length} users`);
|
230
|
-
// Iterate over the users and setup our maps ahead of time for email and phone
|
231
|
-
for (const user of allUsers) {
|
232
|
-
if (user.email) {
|
233
|
-
this.emailToUserIdMap.set(user.email, user.$id);
|
234
|
-
}
|
235
|
-
if (user.phone) {
|
236
|
-
this.phoneToUserIdMap.set(user.phone, user.$id);
|
237
|
-
}
|
238
|
-
}
|
239
240
|
// Iterate over the configured databases to find the matching one
|
240
241
|
for (const db of this.config.databases) {
|
241
242
|
if (db.$id !== dbId) {
|
@@ -290,7 +291,9 @@ export class DataLoader {
|
|
290
291
|
console.log("---------------------------------");
|
291
292
|
console.log(`Data setup for database: ${dbId} completed`);
|
292
293
|
console.log("---------------------------------");
|
293
|
-
|
294
|
+
if (this.shouldWriteFile) {
|
295
|
+
this.writeMapsToJsonFile();
|
296
|
+
}
|
294
297
|
}
|
295
298
|
|
296
299
|
async updateReferencesInRelatedCollections() {
|
@@ -389,31 +392,6 @@ export class DataLoader {
|
|
389
392
|
}
|
390
393
|
}
|
391
394
|
|
392
|
-
updateObjectWithNonNullishValues(
|
393
|
-
sourceObject: Record<string, any>,
|
394
|
-
inputObject: Record<string, any>
|
395
|
-
): void {
|
396
|
-
// Iterate through the keys of the inputObject
|
397
|
-
for (const key of Object.keys(inputObject)) {
|
398
|
-
const inputValue = inputObject[key];
|
399
|
-
const sourceValue = sourceObject[key];
|
400
|
-
|
401
|
-
// Check if the inputObject's value for the current key is non-nullish
|
402
|
-
// and either the key doesn't exist in the sourceObject or its value is nullish
|
403
|
-
if (
|
404
|
-
inputValue !== null &&
|
405
|
-
inputValue !== undefined &&
|
406
|
-
inputValue !== "" &&
|
407
|
-
(sourceValue === null ||
|
408
|
-
sourceValue === undefined ||
|
409
|
-
sourceValue === "")
|
410
|
-
) {
|
411
|
-
// Update the sourceObject with the inputObject's value for the current key
|
412
|
-
sourceObject[key] = inputValue;
|
413
|
-
}
|
414
|
-
}
|
415
|
-
}
|
416
|
-
|
417
395
|
// async updateReferencesInRelatedCollections() {
|
418
396
|
// // Process each collection defined in the config
|
419
397
|
// for (const collection of this.config.collections) {
|
@@ -471,46 +449,46 @@ export class DataLoader {
|
|
471
449
|
// }
|
472
450
|
// }
|
473
451
|
|
474
|
-
|
475
|
-
|
476
|
-
|
452
|
+
private writeMapsToJsonFile() {
|
453
|
+
const outputDir = path.resolve(process.cwd());
|
454
|
+
const outputFile = path.join(outputDir, "dataLoaderOutput.json");
|
477
455
|
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
456
|
+
const dataToWrite = {
|
457
|
+
dataFromCollections: Array.from(this.importMap.entries()).map(
|
458
|
+
([key, value]) => {
|
459
|
+
return {
|
460
|
+
collection: key,
|
461
|
+
data: value.data.map((item: any) => item.finalData),
|
462
|
+
};
|
463
|
+
}
|
464
|
+
),
|
465
|
+
// Convert Maps to arrays of entries for serialization
|
466
|
+
mergedUserMap: Array.from(this.mergedUserMap.entries()),
|
467
|
+
// emailToUserIdMap: Array.from(this.emailToUserIdMap.entries()),
|
468
|
+
// phoneToUserIdMap: Array.from(this.phoneToUserIdMap.entries()),
|
469
|
+
};
|
492
470
|
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
471
|
+
// Use JSON.stringify with a replacer function to handle Maps
|
472
|
+
const replacer = (key: any, value: any) => {
|
473
|
+
if (value instanceof Map) {
|
474
|
+
return Array.from(value.entries());
|
475
|
+
}
|
476
|
+
return value;
|
477
|
+
};
|
500
478
|
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
479
|
+
fs.writeFile(
|
480
|
+
outputFile,
|
481
|
+
JSON.stringify(dataToWrite, replacer, 2),
|
482
|
+
"utf8",
|
483
|
+
(err) => {
|
484
|
+
if (err) {
|
485
|
+
console.error("Error writing data to JSON file:", err);
|
486
|
+
return;
|
487
|
+
}
|
488
|
+
console.log(`Data successfully written to ${outputFile}`);
|
489
|
+
}
|
490
|
+
);
|
491
|
+
}
|
514
492
|
|
515
493
|
/**
|
516
494
|
* Prepares user data by checking for duplicates based on email or phone, adding to a duplicate map if found,
|
@@ -630,6 +608,9 @@ export class DataLoader {
|
|
630
608
|
this.oldIdToNewIdPerCollectionMap
|
631
609
|
.set(this.getCollectionKey(collection.name), oldIdToNewIdMap)
|
632
610
|
.get(this.getCollectionKey(collection.name));
|
611
|
+
console.log(
|
612
|
+
`${collection.name} -- collectionOldIdToNewIdMap: ${collectionOldIdToNewIdMap}`
|
613
|
+
);
|
633
614
|
if (!operationId) {
|
634
615
|
throw new Error(
|
635
616
|
`No import operation found for collection ${collection.name}`
|
@@ -679,7 +660,6 @@ export class DataLoader {
|
|
679
660
|
// No existing user ID, generate a new unique ID
|
680
661
|
existingId = this.getTrueUniqueId(this.getCollectionKey("users"));
|
681
662
|
transformedItem.userId = existingId; // Assign the new ID to the transformed data's userId field
|
682
|
-
transformedItem.docId = existingId;
|
683
663
|
}
|
684
664
|
|
685
665
|
// Create a context object for the item, including the new ID
|
@@ -699,10 +679,14 @@ export class DataLoader {
|
|
699
679
|
?.has(`${oldId}`)
|
700
680
|
) {
|
701
681
|
// Found a duplicate oldId, now decide how to merge or handle these duplicates
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
682
|
+
for (const data of currentData.data) {
|
683
|
+
if (
|
684
|
+
data.finalData.docId === oldId ||
|
685
|
+
data.finalData.userId === oldId
|
686
|
+
) {
|
687
|
+
Object.assign(data.finalData, transformedItem);
|
688
|
+
}
|
689
|
+
}
|
706
690
|
} else {
|
707
691
|
// No duplicate found, simply map the oldId to the new itemId
|
708
692
|
collectionOldIdToNewIdMap?.set(`${oldId}`, `${existingId}`);
|
@@ -718,10 +702,8 @@ export class DataLoader {
|
|
718
702
|
currentUserData.data[i].finalData.userId === existingId) &&
|
719
703
|
!_.isEqual(currentUserData.data[i], userData)
|
720
704
|
) {
|
721
|
-
|
722
|
-
|
723
|
-
userData.finalData
|
724
|
-
);
|
705
|
+
Object.assign(currentUserData.data[i].finalData, transformedItem);
|
706
|
+
Object.assign(currentUserData.data[i].rawData, item);
|
725
707
|
console.log("Merging user data", currentUserData.data[i].finalData);
|
726
708
|
this.importMap.set(this.getCollectionKey("users"), currentUserData);
|
727
709
|
}
|
@@ -744,10 +726,10 @@ export class DataLoader {
|
|
744
726
|
currentData.data[i].finalData.docId === existingId ||
|
745
727
|
currentData.data[i].finalData.userId === existingId
|
746
728
|
) {
|
747
|
-
|
748
|
-
currentData.data[i].finalData,
|
749
|
-
transformedItem
|
750
|
-
|
729
|
+
currentData.data[i].finalData = {
|
730
|
+
...currentData.data[i].finalData,
|
731
|
+
...transformedItem,
|
732
|
+
};
|
751
733
|
currentData.data[i].importDef = newImportDef;
|
752
734
|
this.importMap.set(
|
753
735
|
this.getCollectionKey(collection.name),
|
@@ -962,13 +944,12 @@ export class DataLoader {
|
|
962
944
|
}
|
963
945
|
}
|
964
946
|
} else {
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
(dataItem) => dataItem.rawData[importDef.primaryKeyField] === oldId
|
947
|
+
logger.error(
|
948
|
+
`No old ID found (to update another document with) in prepareUpdateData for ${
|
949
|
+
collection.name
|
950
|
+
}, ${JSON.stringify(item, null, 2)}`
|
970
951
|
);
|
971
|
-
|
952
|
+
continue;
|
972
953
|
}
|
973
954
|
// Log an error and continue to the next item if no new ID is found
|
974
955
|
if (!newId) {
|
@@ -107,7 +107,8 @@ export class ImportController {
|
|
107
107
|
this.appwriteFolderPath,
|
108
108
|
this.importDataActions,
|
109
109
|
this.database,
|
110
|
-
this.config
|
110
|
+
this.config,
|
111
|
+
this.setupOptions.shouldWriteFile
|
111
112
|
);
|
112
113
|
await dataLoader.start(db.$id);
|
113
114
|
await this.importCollections(db, dataLoader);
|