appwrite-utils-cli 0.10.82 → 0.10.84
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/README.md +1 -0
- package/dist/collections/attributes.js +86 -41
- package/dist/collections/methods.d.ts +6 -0
- package/dist/collections/methods.js +137 -2
- package/dist/migrations/appwriteToX.js +1 -1
- package/dist/migrations/attributes.js +0 -1
- package/dist/migrations/converters.js +3 -4
- package/dist/migrations/dataLoader.js +3 -3
- package/dist/migrations/importController.js +0 -1
- package/dist/migrations/queue.js +1 -2
- package/dist/migrations/relationships.js +1 -1
- package/dist/migrations/users.js +5 -4
- package/dist/migrations/validationRules.js +30 -30
- package/package.json +1 -1
- package/src/collections/attributes.ts +126 -50
- package/src/collections/methods.ts +222 -2
- package/src/migrations/appwriteToX.ts +4 -4
- package/src/migrations/attributes.ts +0 -1
- package/src/migrations/converters.ts +3 -5
- package/src/migrations/dataLoader.ts +4 -4
- package/src/migrations/importController.ts +0 -1
- package/src/migrations/queue.ts +1 -2
- package/src/migrations/relationships.ts +1 -1
- package/src/migrations/users.ts +8 -7
- package/src/migrations/validationRules.ts +56 -31
- package/src/migrations/collections.ts +0 -545
@@ -5,7 +5,6 @@ import {
|
|
5
5
|
type Attribute,
|
6
6
|
} from "appwrite-utils";
|
7
7
|
import { nameToIdMapping, enqueueOperation } from "../migrations/queue.js";
|
8
|
-
import _ from "lodash";
|
9
8
|
import { delay, tryAwaitWithRetry } from "../utils/helperFunctions.js";
|
10
9
|
import chalk from "chalk";
|
11
10
|
|
@@ -14,24 +13,24 @@ const attributesSame = (
|
|
14
13
|
configAttribute: Attribute
|
15
14
|
): boolean => {
|
16
15
|
const attributesToCheck = [
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
16
|
+
"key",
|
17
|
+
"type",
|
18
|
+
"array",
|
19
|
+
"encrypted",
|
20
|
+
"required",
|
21
|
+
"size",
|
22
|
+
"min",
|
23
|
+
"max",
|
24
|
+
"xdefault",
|
25
|
+
"elements",
|
26
|
+
"relationType",
|
27
|
+
"twoWay",
|
28
|
+
"twoWayKey",
|
29
|
+
"onDelete",
|
30
|
+
"relatedCollection",
|
32
31
|
];
|
33
32
|
|
34
|
-
return attributesToCheck.every(attr => {
|
33
|
+
return attributesToCheck.every((attr) => {
|
35
34
|
// Check if both objects have the attribute
|
36
35
|
const dbHasAttr = attr in databaseAttribute;
|
37
36
|
const configHasAttr = attr in configAttribute;
|
@@ -42,7 +41,10 @@ const attributesSame = (
|
|
42
41
|
const configValue = configAttribute[attr as keyof typeof configAttribute];
|
43
42
|
|
44
43
|
// Consider undefined and null as equivalent
|
45
|
-
if (
|
44
|
+
if (
|
45
|
+
(dbValue === undefined || dbValue === null) &&
|
46
|
+
(configValue === undefined || configValue === null)
|
47
|
+
) {
|
46
48
|
return true;
|
47
49
|
}
|
48
50
|
|
@@ -91,10 +93,18 @@ export const createOrUpdateAttribute = async (
|
|
91
93
|
foundAttribute = undefined;
|
92
94
|
}
|
93
95
|
|
94
|
-
if (
|
96
|
+
if (
|
97
|
+
foundAttribute &&
|
98
|
+
attributesSame(foundAttribute, attribute) &&
|
99
|
+
updateEnabled
|
100
|
+
) {
|
95
101
|
// No need to do anything, they are the same
|
96
102
|
return;
|
97
|
-
} else if (
|
103
|
+
} else if (
|
104
|
+
foundAttribute &&
|
105
|
+
!attributesSame(foundAttribute, attribute) &&
|
106
|
+
updateEnabled
|
107
|
+
) {
|
98
108
|
// console.log(
|
99
109
|
// `Updating attribute with same key ${attribute.key} but different values`
|
100
110
|
// );
|
@@ -103,9 +113,15 @@ export const createOrUpdateAttribute = async (
|
|
103
113
|
...attribute,
|
104
114
|
};
|
105
115
|
action = "update";
|
106
|
-
} else if (
|
116
|
+
} else if (
|
117
|
+
!updateEnabled &&
|
118
|
+
foundAttribute &&
|
119
|
+
!attributesSame(foundAttribute, attribute)
|
120
|
+
) {
|
107
121
|
await db.deleteAttribute(dbId, collection.$id, attribute.key);
|
108
|
-
console.log(
|
122
|
+
console.log(
|
123
|
+
`Deleted attribute: ${attribute.key} to recreate it because they diff (update disabled temporarily)`
|
124
|
+
);
|
109
125
|
return;
|
110
126
|
}
|
111
127
|
|
@@ -168,7 +184,9 @@ export const createOrUpdateAttribute = async (
|
|
168
184
|
finalAttribute.key,
|
169
185
|
finalAttribute.size,
|
170
186
|
finalAttribute.required || false,
|
171
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
187
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
188
|
+
? finalAttribute.xdefault
|
189
|
+
: null,
|
172
190
|
finalAttribute.array || false,
|
173
191
|
finalAttribute.encrypted
|
174
192
|
)
|
@@ -181,7 +199,9 @@ export const createOrUpdateAttribute = async (
|
|
181
199
|
collection.$id,
|
182
200
|
finalAttribute.key,
|
183
201
|
finalAttribute.required || false,
|
184
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
202
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
203
|
+
? finalAttribute.xdefault
|
204
|
+
: null
|
185
205
|
)
|
186
206
|
);
|
187
207
|
}
|
@@ -209,7 +229,9 @@ export const createOrUpdateAttribute = async (
|
|
209
229
|
finalAttribute.required || false,
|
210
230
|
finalAttribute.min || -2147483647,
|
211
231
|
finalAttribute.max || 2147483647,
|
212
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
232
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
233
|
+
? finalAttribute.xdefault
|
234
|
+
: null,
|
213
235
|
finalAttribute.array || false
|
214
236
|
)
|
215
237
|
);
|
@@ -235,7 +257,9 @@ export const createOrUpdateAttribute = async (
|
|
235
257
|
finalAttribute.required || false,
|
236
258
|
finalAttribute.min || -2147483647,
|
237
259
|
finalAttribute.max || 2147483647,
|
238
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
260
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
261
|
+
? finalAttribute.xdefault
|
262
|
+
: null
|
239
263
|
)
|
240
264
|
);
|
241
265
|
}
|
@@ -251,7 +275,9 @@ export const createOrUpdateAttribute = async (
|
|
251
275
|
finalAttribute.required || false,
|
252
276
|
finalAttribute.min || -2147483647,
|
253
277
|
finalAttribute.max || 2147483647,
|
254
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
278
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
279
|
+
? finalAttribute.xdefault
|
280
|
+
: null,
|
255
281
|
finalAttribute.array || false
|
256
282
|
)
|
257
283
|
);
|
@@ -265,7 +291,9 @@ export const createOrUpdateAttribute = async (
|
|
265
291
|
finalAttribute.required || false,
|
266
292
|
finalAttribute.min || -2147483647,
|
267
293
|
finalAttribute.max || 2147483647,
|
268
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
294
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
295
|
+
? finalAttribute.xdefault
|
296
|
+
: null
|
269
297
|
)
|
270
298
|
);
|
271
299
|
}
|
@@ -279,7 +307,9 @@ export const createOrUpdateAttribute = async (
|
|
279
307
|
collection.$id,
|
280
308
|
finalAttribute.key,
|
281
309
|
finalAttribute.required || false,
|
282
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
310
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
311
|
+
? finalAttribute.xdefault
|
312
|
+
: null,
|
283
313
|
finalAttribute.array || false
|
284
314
|
)
|
285
315
|
);
|
@@ -291,7 +321,9 @@ export const createOrUpdateAttribute = async (
|
|
291
321
|
collection.$id,
|
292
322
|
finalAttribute.key,
|
293
323
|
finalAttribute.required || false,
|
294
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
324
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
325
|
+
? finalAttribute.xdefault
|
326
|
+
: null
|
295
327
|
)
|
296
328
|
);
|
297
329
|
}
|
@@ -305,7 +337,9 @@ export const createOrUpdateAttribute = async (
|
|
305
337
|
collection.$id,
|
306
338
|
finalAttribute.key,
|
307
339
|
finalAttribute.required || false,
|
308
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
340
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
341
|
+
? finalAttribute.xdefault
|
342
|
+
: null,
|
309
343
|
finalAttribute.array || false
|
310
344
|
)
|
311
345
|
);
|
@@ -317,7 +351,9 @@ export const createOrUpdateAttribute = async (
|
|
317
351
|
collection.$id,
|
318
352
|
finalAttribute.key,
|
319
353
|
finalAttribute.required || false,
|
320
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
354
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
355
|
+
? finalAttribute.xdefault
|
356
|
+
: null
|
321
357
|
)
|
322
358
|
);
|
323
359
|
}
|
@@ -331,7 +367,9 @@ export const createOrUpdateAttribute = async (
|
|
331
367
|
collection.$id,
|
332
368
|
finalAttribute.key,
|
333
369
|
finalAttribute.required || false,
|
334
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
370
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
371
|
+
? finalAttribute.xdefault
|
372
|
+
: null,
|
335
373
|
finalAttribute.array || false
|
336
374
|
)
|
337
375
|
);
|
@@ -343,7 +381,9 @@ export const createOrUpdateAttribute = async (
|
|
343
381
|
collection.$id,
|
344
382
|
finalAttribute.key,
|
345
383
|
finalAttribute.required || false,
|
346
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
384
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
385
|
+
? finalAttribute.xdefault
|
386
|
+
: null
|
347
387
|
)
|
348
388
|
);
|
349
389
|
}
|
@@ -357,7 +397,9 @@ export const createOrUpdateAttribute = async (
|
|
357
397
|
collection.$id,
|
358
398
|
finalAttribute.key,
|
359
399
|
finalAttribute.required || false,
|
360
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
400
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
401
|
+
? finalAttribute.xdefault
|
402
|
+
: null,
|
361
403
|
finalAttribute.array || false
|
362
404
|
)
|
363
405
|
);
|
@@ -369,7 +411,9 @@ export const createOrUpdateAttribute = async (
|
|
369
411
|
collection.$id,
|
370
412
|
finalAttribute.key,
|
371
413
|
finalAttribute.required || false,
|
372
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
414
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
415
|
+
? finalAttribute.xdefault
|
416
|
+
: null
|
373
417
|
)
|
374
418
|
);
|
375
419
|
}
|
@@ -383,7 +427,9 @@ export const createOrUpdateAttribute = async (
|
|
383
427
|
collection.$id,
|
384
428
|
finalAttribute.key,
|
385
429
|
finalAttribute.required || false,
|
386
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
430
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
431
|
+
? finalAttribute.xdefault
|
432
|
+
: null,
|
387
433
|
finalAttribute.array || false
|
388
434
|
)
|
389
435
|
);
|
@@ -395,7 +441,9 @@ export const createOrUpdateAttribute = async (
|
|
395
441
|
collection.$id,
|
396
442
|
finalAttribute.key,
|
397
443
|
finalAttribute.required || false,
|
398
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
444
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
445
|
+
? finalAttribute.xdefault
|
446
|
+
: null
|
399
447
|
)
|
400
448
|
);
|
401
449
|
}
|
@@ -410,7 +458,9 @@ export const createOrUpdateAttribute = async (
|
|
410
458
|
finalAttribute.key,
|
411
459
|
finalAttribute.elements,
|
412
460
|
finalAttribute.required || false,
|
413
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
461
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
462
|
+
? finalAttribute.xdefault
|
463
|
+
: null,
|
414
464
|
finalAttribute.array || false
|
415
465
|
)
|
416
466
|
);
|
@@ -423,7 +473,9 @@ export const createOrUpdateAttribute = async (
|
|
423
473
|
finalAttribute.key,
|
424
474
|
finalAttribute.elements,
|
425
475
|
finalAttribute.required || false,
|
426
|
-
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
476
|
+
finalAttribute.xdefault !== undefined && !finalAttribute.required
|
477
|
+
? finalAttribute.xdefault
|
478
|
+
: null
|
427
479
|
)
|
428
480
|
);
|
429
481
|
}
|
@@ -468,26 +520,47 @@ export const createUpdateCollectionAttributes = async (
|
|
468
520
|
attributes: Attribute[]
|
469
521
|
): Promise<void> => {
|
470
522
|
console.log(
|
471
|
-
chalk.green(
|
523
|
+
chalk.green(
|
524
|
+
`Creating/Updating attributes for collection: ${collection.name}`
|
525
|
+
)
|
472
526
|
);
|
473
527
|
|
474
|
-
|
475
|
-
|
528
|
+
const existingAttributes: Attribute[] =
|
529
|
+
// @ts-expect-error
|
530
|
+
collection.attributes.map((attr) => parseAttribute(attr)) || [];
|
476
531
|
|
477
|
-
const attributesToRemove = existingAttributes.filter(
|
478
|
-
|
532
|
+
const attributesToRemove = existingAttributes.filter(
|
533
|
+
(attr) => !attributes.some((a) => a.key === attr.key)
|
534
|
+
);
|
535
|
+
const indexesToRemove = collection.indexes.filter((index) =>
|
536
|
+
attributesToRemove.some((attr) => index.attributes.includes(attr.key))
|
537
|
+
);
|
479
538
|
|
480
539
|
if (attributesToRemove.length > 0) {
|
481
540
|
if (indexesToRemove.length > 0) {
|
482
|
-
console.log(
|
541
|
+
console.log(
|
542
|
+
chalk.red(
|
543
|
+
`Removing indexes as they rely on an attribute that is being removed: ${indexesToRemove
|
544
|
+
.map((index) => index.key)
|
545
|
+
.join(", ")}`
|
546
|
+
)
|
547
|
+
);
|
483
548
|
for (const index of indexesToRemove) {
|
484
|
-
await tryAwaitWithRetry(
|
549
|
+
await tryAwaitWithRetry(
|
550
|
+
async () => await db.deleteIndex(dbId, collection.$id, index.key)
|
551
|
+
);
|
485
552
|
await delay(100);
|
486
553
|
}
|
487
554
|
}
|
488
555
|
for (const attr of attributesToRemove) {
|
489
|
-
console.log(
|
490
|
-
|
556
|
+
console.log(
|
557
|
+
chalk.red(
|
558
|
+
`Removing attribute: ${attr.key} as it is no longer in the collection`
|
559
|
+
)
|
560
|
+
);
|
561
|
+
await tryAwaitWithRetry(
|
562
|
+
async () => await db.deleteAttribute(dbId, collection.$id, attr.key)
|
563
|
+
);
|
491
564
|
await delay(50);
|
492
565
|
}
|
493
566
|
}
|
@@ -496,7 +569,10 @@ export const createUpdateCollectionAttributes = async (
|
|
496
569
|
for (let i = 0; i < attributes.length; i += batchSize) {
|
497
570
|
const batch = attributes.slice(i, i + batchSize);
|
498
571
|
const attributePromises = batch.map((attribute) =>
|
499
|
-
tryAwaitWithRetry(
|
572
|
+
tryAwaitWithRetry(
|
573
|
+
async () =>
|
574
|
+
await createOrUpdateAttribute(db, dbId, collection, attribute)
|
575
|
+
)
|
500
576
|
);
|
501
577
|
|
502
578
|
const results = await Promise.allSettled(attributePromises);
|
@@ -157,7 +157,7 @@ async function wipeDocumentsFromCollection(
|
|
157
157
|
const docsResponse = await database.listDocuments(
|
158
158
|
databaseId,
|
159
159
|
collectionId,
|
160
|
-
[Query.limit(1000)]
|
160
|
+
[Query.limit(1000), ...(cursor ? [Query.cursorAfter(cursor)] : [])]
|
161
161
|
);
|
162
162
|
documents.push(...docsResponse.documents);
|
163
163
|
totalDocuments = documents.length;
|
@@ -391,12 +391,18 @@ export const createOrUpdateCollections = async (
|
|
391
391
|
// Add delay after creating attributes
|
392
392
|
await delay(250);
|
393
393
|
|
394
|
+
const indexesToUse =
|
395
|
+
indexes.length > 0
|
396
|
+
? indexes
|
397
|
+
: config.collections?.find((c) => c.$id === collectionToUse!.$id)
|
398
|
+
?.indexes ?? [];
|
399
|
+
|
394
400
|
console.log("Creating Indexes");
|
395
401
|
await createOrUpdateIndexes(
|
396
402
|
databaseId,
|
397
403
|
database,
|
398
404
|
collectionToUse!.$id,
|
399
|
-
|
405
|
+
indexesToUse as Indexes
|
400
406
|
);
|
401
407
|
|
402
408
|
// Add delay after creating indexes
|
@@ -455,3 +461,217 @@ export const fetchAllCollections = async (
|
|
455
461
|
console.log(`Fetched a total of ${collections.length} collections.`);
|
456
462
|
return collections;
|
457
463
|
};
|
464
|
+
|
465
|
+
/**
|
466
|
+
* Transfers all documents from one collection to another in a different database
|
467
|
+
* within the same Appwrite Project
|
468
|
+
*/
|
469
|
+
export const transferDocumentsBetweenDbsLocalToLocal = async (
|
470
|
+
db: Databases,
|
471
|
+
fromDbId: string,
|
472
|
+
toDbId: string,
|
473
|
+
fromCollId: string,
|
474
|
+
toCollId: string
|
475
|
+
) => {
|
476
|
+
let fromCollDocs = await tryAwaitWithRetry(async () =>
|
477
|
+
db.listDocuments(fromDbId, fromCollId, [Query.limit(50)])
|
478
|
+
);
|
479
|
+
let totalDocumentsTransferred = 0;
|
480
|
+
|
481
|
+
if (fromCollDocs.documents.length === 0) {
|
482
|
+
console.log(`No documents found in collection ${fromCollId}`);
|
483
|
+
return;
|
484
|
+
} else if (fromCollDocs.documents.length < 50) {
|
485
|
+
const batchedPromises = fromCollDocs.documents.map((doc) => {
|
486
|
+
const toCreateObject: Partial<typeof doc> = {
|
487
|
+
...doc,
|
488
|
+
};
|
489
|
+
delete toCreateObject.$databaseId;
|
490
|
+
delete toCreateObject.$collectionId;
|
491
|
+
delete toCreateObject.$createdAt;
|
492
|
+
delete toCreateObject.$updatedAt;
|
493
|
+
delete toCreateObject.$id;
|
494
|
+
delete toCreateObject.$permissions;
|
495
|
+
return tryAwaitWithRetry(
|
496
|
+
async () =>
|
497
|
+
await db.createDocument(
|
498
|
+
toDbId,
|
499
|
+
toCollId,
|
500
|
+
doc.$id,
|
501
|
+
toCreateObject,
|
502
|
+
doc.$permissions
|
503
|
+
)
|
504
|
+
);
|
505
|
+
});
|
506
|
+
await Promise.all(batchedPromises);
|
507
|
+
totalDocumentsTransferred += fromCollDocs.documents.length;
|
508
|
+
} else {
|
509
|
+
const batchedPromises = fromCollDocs.documents.map((doc) => {
|
510
|
+
const toCreateObject: Partial<typeof doc> = {
|
511
|
+
...doc,
|
512
|
+
};
|
513
|
+
delete toCreateObject.$databaseId;
|
514
|
+
delete toCreateObject.$collectionId;
|
515
|
+
delete toCreateObject.$createdAt;
|
516
|
+
delete toCreateObject.$updatedAt;
|
517
|
+
delete toCreateObject.$id;
|
518
|
+
delete toCreateObject.$permissions;
|
519
|
+
return tryAwaitWithRetry(async () =>
|
520
|
+
db.createDocument(
|
521
|
+
toDbId,
|
522
|
+
toCollId,
|
523
|
+
doc.$id,
|
524
|
+
toCreateObject,
|
525
|
+
doc.$permissions
|
526
|
+
)
|
527
|
+
);
|
528
|
+
});
|
529
|
+
await Promise.all(batchedPromises);
|
530
|
+
totalDocumentsTransferred += fromCollDocs.documents.length;
|
531
|
+
while (fromCollDocs.documents.length === 50) {
|
532
|
+
fromCollDocs = await tryAwaitWithRetry(
|
533
|
+
async () =>
|
534
|
+
await db.listDocuments(fromDbId, fromCollId, [
|
535
|
+
Query.limit(50),
|
536
|
+
Query.cursorAfter(
|
537
|
+
fromCollDocs.documents[fromCollDocs.documents.length - 1].$id
|
538
|
+
),
|
539
|
+
])
|
540
|
+
);
|
541
|
+
const batchedPromises = fromCollDocs.documents.map((doc) => {
|
542
|
+
const toCreateObject: Partial<typeof doc> = {
|
543
|
+
...doc,
|
544
|
+
};
|
545
|
+
delete toCreateObject.$databaseId;
|
546
|
+
delete toCreateObject.$collectionId;
|
547
|
+
delete toCreateObject.$createdAt;
|
548
|
+
delete toCreateObject.$updatedAt;
|
549
|
+
delete toCreateObject.$id;
|
550
|
+
delete toCreateObject.$permissions;
|
551
|
+
return tryAwaitWithRetry(
|
552
|
+
async () =>
|
553
|
+
await db.createDocument(
|
554
|
+
toDbId,
|
555
|
+
toCollId,
|
556
|
+
doc.$id,
|
557
|
+
toCreateObject,
|
558
|
+
doc.$permissions
|
559
|
+
)
|
560
|
+
);
|
561
|
+
});
|
562
|
+
await Promise.all(batchedPromises);
|
563
|
+
totalDocumentsTransferred += fromCollDocs.documents.length;
|
564
|
+
}
|
565
|
+
}
|
566
|
+
|
567
|
+
console.log(
|
568
|
+
`Transferred ${totalDocumentsTransferred} documents from database ${fromDbId} to database ${toDbId} -- collection ${fromCollId} to collection ${toCollId}`
|
569
|
+
);
|
570
|
+
};
|
571
|
+
|
572
|
+
export const transferDocumentsBetweenDbsLocalToRemote = async (
|
573
|
+
localDb: Databases,
|
574
|
+
endpoint: string,
|
575
|
+
projectId: string,
|
576
|
+
apiKey: string,
|
577
|
+
fromDbId: string,
|
578
|
+
toDbId: string,
|
579
|
+
fromCollId: string,
|
580
|
+
toCollId: string
|
581
|
+
) => {
|
582
|
+
const client = new Client()
|
583
|
+
.setEndpoint(endpoint)
|
584
|
+
.setProject(projectId)
|
585
|
+
.setKey(apiKey);
|
586
|
+
let totalDocumentsTransferred = 0;
|
587
|
+
const remoteDb = new Databases(client);
|
588
|
+
let fromCollDocs = await tryAwaitWithRetry(async () =>
|
589
|
+
localDb.listDocuments(fromDbId, fromCollId, [Query.limit(50)])
|
590
|
+
);
|
591
|
+
|
592
|
+
if (fromCollDocs.documents.length === 0) {
|
593
|
+
console.log(`No documents found in collection ${fromCollId}`);
|
594
|
+
return;
|
595
|
+
} else if (fromCollDocs.documents.length < 50) {
|
596
|
+
const batchedPromises = fromCollDocs.documents.map((doc) => {
|
597
|
+
const toCreateObject: Partial<typeof doc> = {
|
598
|
+
...doc,
|
599
|
+
};
|
600
|
+
delete toCreateObject.$databaseId;
|
601
|
+
delete toCreateObject.$collectionId;
|
602
|
+
delete toCreateObject.$createdAt;
|
603
|
+
delete toCreateObject.$updatedAt;
|
604
|
+
delete toCreateObject.$id;
|
605
|
+
delete toCreateObject.$permissions;
|
606
|
+
return tryAwaitWithRetry(async () =>
|
607
|
+
remoteDb.createDocument(
|
608
|
+
toDbId,
|
609
|
+
toCollId,
|
610
|
+
doc.$id,
|
611
|
+
toCreateObject,
|
612
|
+
doc.$permissions
|
613
|
+
)
|
614
|
+
);
|
615
|
+
});
|
616
|
+
await Promise.all(batchedPromises);
|
617
|
+
totalDocumentsTransferred += fromCollDocs.documents.length;
|
618
|
+
} else {
|
619
|
+
const batchedPromises = fromCollDocs.documents.map((doc) => {
|
620
|
+
const toCreateObject: Partial<typeof doc> = {
|
621
|
+
...doc,
|
622
|
+
};
|
623
|
+
delete toCreateObject.$databaseId;
|
624
|
+
delete toCreateObject.$collectionId;
|
625
|
+
delete toCreateObject.$createdAt;
|
626
|
+
delete toCreateObject.$updatedAt;
|
627
|
+
delete toCreateObject.$id;
|
628
|
+
delete toCreateObject.$permissions;
|
629
|
+
return tryAwaitWithRetry(async () =>
|
630
|
+
remoteDb.createDocument(
|
631
|
+
toDbId,
|
632
|
+
toCollId,
|
633
|
+
doc.$id,
|
634
|
+
toCreateObject,
|
635
|
+
doc.$permissions
|
636
|
+
)
|
637
|
+
);
|
638
|
+
});
|
639
|
+
await Promise.all(batchedPromises);
|
640
|
+
totalDocumentsTransferred += fromCollDocs.documents.length;
|
641
|
+
while (fromCollDocs.documents.length === 50) {
|
642
|
+
fromCollDocs = await tryAwaitWithRetry(async () =>
|
643
|
+
localDb.listDocuments(fromDbId, fromCollId, [
|
644
|
+
Query.limit(50),
|
645
|
+
Query.cursorAfter(
|
646
|
+
fromCollDocs.documents[fromCollDocs.documents.length - 1].$id
|
647
|
+
),
|
648
|
+
])
|
649
|
+
);
|
650
|
+
const batchedPromises = fromCollDocs.documents.map((doc) => {
|
651
|
+
const toCreateObject: Partial<typeof doc> = {
|
652
|
+
...doc,
|
653
|
+
};
|
654
|
+
delete toCreateObject.$databaseId;
|
655
|
+
delete toCreateObject.$collectionId;
|
656
|
+
delete toCreateObject.$createdAt;
|
657
|
+
delete toCreateObject.$updatedAt;
|
658
|
+
delete toCreateObject.$id;
|
659
|
+
delete toCreateObject.$permissions;
|
660
|
+
return tryAwaitWithRetry(async () =>
|
661
|
+
remoteDb.createDocument(
|
662
|
+
toDbId,
|
663
|
+
toCollId,
|
664
|
+
doc.$id,
|
665
|
+
toCreateObject,
|
666
|
+
doc.$permissions
|
667
|
+
)
|
668
|
+
);
|
669
|
+
});
|
670
|
+
await Promise.all(batchedPromises);
|
671
|
+
totalDocumentsTransferred += fromCollDocs.documents.length;
|
672
|
+
}
|
673
|
+
}
|
674
|
+
console.log(
|
675
|
+
`Total documents transferred from database ${fromDbId} to database ${toDbId} -- collection ${fromCollId} to collection ${toCollId}: ${totalDocumentsTransferred}`
|
676
|
+
);
|
677
|
+
};
|
@@ -8,7 +8,7 @@ import {
|
|
8
8
|
type Models,
|
9
9
|
type Permission,
|
10
10
|
} from "node-appwrite";
|
11
|
-
import { fetchAllCollections } from "
|
11
|
+
import { fetchAllCollections } from "../collections/methods.js";
|
12
12
|
import { fetchAllDatabases } from "./databases.js";
|
13
13
|
import {
|
14
14
|
CollectionSchema,
|
@@ -138,7 +138,7 @@ export class AppwriteToX {
|
|
138
138
|
.map((attr: any) => {
|
139
139
|
return parseAttribute(attr);
|
140
140
|
})
|
141
|
-
.filter((attribute) =>
|
141
|
+
.filter((attribute: Attribute) =>
|
142
142
|
attribute.type === "relationship"
|
143
143
|
? attribute.side !== "child"
|
144
144
|
: true
|
@@ -169,10 +169,10 @@ export class AppwriteToX {
|
|
169
169
|
}
|
170
170
|
}
|
171
171
|
this.collToAttributeMap.set(collection.name, collAttributes);
|
172
|
-
const finalIndexes = collection.indexes.map((index) => {
|
172
|
+
const finalIndexes = collection.indexes.map((index: Models.Index) => {
|
173
173
|
return {
|
174
174
|
...index,
|
175
|
-
orders: index.orders?.filter((order) => {
|
175
|
+
orders: index.orders?.filter((order: string) => {
|
176
176
|
return order !== null && order;
|
177
177
|
}),
|
178
178
|
};
|
@@ -1,7 +1,5 @@
|
|
1
|
-
import _ from "lodash";
|
2
1
|
import { converterFunctions, type AttributeMappings } from "appwrite-utils";
|
3
|
-
|
4
|
-
const { cloneDeep, isObject } = _;
|
2
|
+
import { cloneDeep, isPlainObject } from "es-toolkit";
|
5
3
|
|
6
4
|
/**
|
7
5
|
* Deeply converts all properties of an object (or array) to strings.
|
@@ -11,7 +9,7 @@ const { cloneDeep, isObject } = _;
|
|
11
9
|
export const deepAnyToString = (data: any): any => {
|
12
10
|
if (Array.isArray(data)) {
|
13
11
|
return data.map((item) => deepAnyToString(item));
|
14
|
-
} else if (
|
12
|
+
} else if (isPlainObject(data)) {
|
15
13
|
return Object.keys(data).reduce((acc, key) => {
|
16
14
|
acc[key] = deepAnyToString(data[key as keyof typeof data]);
|
17
15
|
return acc;
|
@@ -34,7 +32,7 @@ export const deepConvert = <T>(
|
|
34
32
|
): any => {
|
35
33
|
if (Array.isArray(data)) {
|
36
34
|
return data.map((item) => deepConvert(item, convertFn));
|
37
|
-
} else if (
|
35
|
+
} else if (isPlainObject(data)) {
|
38
36
|
return Object.keys(data).reduce((acc: Record<string, T>, key: string) => {
|
39
37
|
acc[key] = deepConvert(data[key as keyof typeof data], convertFn);
|
40
38
|
return acc;
|