appwrite-utils-cli 1.0.9 → 1.1.1
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 +48 -0
- package/dist/collections/attributes.d.ts +8 -0
- package/dist/collections/attributes.js +195 -0
- package/dist/collections/indexes.d.ts +8 -0
- package/dist/collections/indexes.js +150 -0
- package/dist/collections/methods.js +105 -53
- package/dist/interactiveCLI.js +134 -42
- package/dist/migrations/comprehensiveTransfer.d.ts +28 -0
- package/dist/migrations/comprehensiveTransfer.js +225 -7
- package/dist/migrations/transfer.js +29 -40
- package/package.json +1 -1
- package/src/collections/attributes.ts +339 -0
- package/src/collections/indexes.ts +264 -0
- package/src/collections/methods.ts +175 -87
- package/src/interactiveCLI.ts +137 -42
- package/src/migrations/comprehensiveTransfer.ts +348 -14
- package/src/migrations/transfer.ts +48 -99
@@ -1,4 +1,4 @@
|
|
1
|
-
import { converterFunctions, tryAwaitWithRetry } from "appwrite-utils";
|
1
|
+
import { converterFunctions, tryAwaitWithRetry, parseAttribute } from "appwrite-utils";
|
2
2
|
import {
|
3
3
|
Client,
|
4
4
|
Databases,
|
@@ -204,7 +204,10 @@ export class ComprehensiveTransfer {
|
|
204
204
|
return;
|
205
205
|
}
|
206
206
|
|
207
|
-
|
207
|
+
// Phase 1: Create all databases and collections (structure only)
|
208
|
+
MessageFormatter.info("Phase 1: Creating database structures (databases, collections, attributes, indexes)", { prefix: "Transfer" });
|
209
|
+
|
210
|
+
const structureCreationTasks = sourceDatabases.databases.map(db =>
|
208
211
|
this.limit(async () => {
|
209
212
|
try {
|
210
213
|
// Check if database exists in target
|
@@ -216,32 +219,189 @@ export class ComprehensiveTransfer {
|
|
216
219
|
MessageFormatter.success(`Created database: ${db.name}`, { prefix: "Transfer" });
|
217
220
|
}
|
218
221
|
|
219
|
-
//
|
220
|
-
await
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
222
|
+
// Create collections, attributes, and indexes WITHOUT transferring documents
|
223
|
+
await this.createDatabaseStructure(db.$id);
|
224
|
+
|
225
|
+
MessageFormatter.success(`Database structure created: ${db.name}`, { prefix: "Transfer" });
|
226
|
+
} catch (error) {
|
227
|
+
MessageFormatter.error(`Database structure creation failed for ${db.name}`, error instanceof Error ? error : new Error(String(error)), { prefix: "Transfer" });
|
228
|
+
this.results.databases.failed++;
|
229
|
+
}
|
230
|
+
})
|
231
|
+
);
|
232
|
+
|
233
|
+
await Promise.all(structureCreationTasks);
|
234
|
+
|
235
|
+
// Phase 2: Transfer all documents after all structures are created
|
236
|
+
MessageFormatter.info("Phase 2: Transferring documents to all collections", { prefix: "Transfer" });
|
237
|
+
|
238
|
+
const documentTransferTasks = sourceDatabases.databases.map(db =>
|
239
|
+
this.limit(async () => {
|
240
|
+
try {
|
241
|
+
// Transfer documents for this database
|
242
|
+
await this.transferDatabaseDocuments(db.$id);
|
228
243
|
|
229
244
|
this.results.databases.transferred++;
|
230
|
-
MessageFormatter.success(`Database ${db.name}
|
245
|
+
MessageFormatter.success(`Database documents transferred: ${db.name}`, { prefix: "Transfer" });
|
231
246
|
} catch (error) {
|
232
|
-
MessageFormatter.error(`
|
247
|
+
MessageFormatter.error(`Document transfer failed for ${db.name}`, error instanceof Error ? error : new Error(String(error)), { prefix: "Transfer" });
|
233
248
|
this.results.databases.failed++;
|
234
249
|
}
|
235
250
|
})
|
236
251
|
);
|
237
252
|
|
238
|
-
await Promise.all(
|
253
|
+
await Promise.all(documentTransferTasks);
|
239
254
|
MessageFormatter.success("Database transfer phase completed", { prefix: "Transfer" });
|
240
255
|
} catch (error) {
|
241
256
|
MessageFormatter.error("Database transfer phase failed", error instanceof Error ? error : new Error(String(error)), { prefix: "Transfer" });
|
242
257
|
}
|
243
258
|
}
|
244
259
|
|
260
|
+
/**
|
261
|
+
* Phase 1: Create database structure (collections, attributes, indexes) without transferring documents
|
262
|
+
*/
|
263
|
+
private async createDatabaseStructure(dbId: string): Promise<void> {
|
264
|
+
MessageFormatter.info(`Creating database structure for ${dbId}`, { prefix: "Transfer" });
|
265
|
+
|
266
|
+
try {
|
267
|
+
// Get all collections from source database
|
268
|
+
const sourceCollections = await this.fetchAllCollections(dbId, this.sourceDatabases);
|
269
|
+
MessageFormatter.info(`Found ${sourceCollections.length} collections in source database ${dbId}`, { prefix: "Transfer" });
|
270
|
+
|
271
|
+
// Process each collection
|
272
|
+
for (const collection of sourceCollections) {
|
273
|
+
MessageFormatter.info(`Processing collection: ${collection.name} (${collection.$id})`, { prefix: "Transfer" });
|
274
|
+
|
275
|
+
try {
|
276
|
+
// Create or update collection in target
|
277
|
+
let targetCollection: Models.Collection;
|
278
|
+
const existingCollection = await tryAwaitWithRetry(async () =>
|
279
|
+
this.targetDatabases.listCollections(dbId, [Query.equal("$id", collection.$id)])
|
280
|
+
);
|
281
|
+
|
282
|
+
if (existingCollection.collections.length > 0) {
|
283
|
+
targetCollection = existingCollection.collections[0];
|
284
|
+
MessageFormatter.info(`Collection ${collection.name} exists in target database`, { prefix: "Transfer" });
|
285
|
+
|
286
|
+
// Update collection if needed
|
287
|
+
if (
|
288
|
+
targetCollection.name !== collection.name ||
|
289
|
+
JSON.stringify(targetCollection.$permissions) !== JSON.stringify(collection.$permissions) ||
|
290
|
+
targetCollection.documentSecurity !== collection.documentSecurity ||
|
291
|
+
targetCollection.enabled !== collection.enabled
|
292
|
+
) {
|
293
|
+
targetCollection = await tryAwaitWithRetry(async () =>
|
294
|
+
this.targetDatabases.updateCollection(
|
295
|
+
dbId,
|
296
|
+
collection.$id,
|
297
|
+
collection.name,
|
298
|
+
collection.$permissions,
|
299
|
+
collection.documentSecurity,
|
300
|
+
collection.enabled
|
301
|
+
)
|
302
|
+
);
|
303
|
+
MessageFormatter.success(`Collection ${collection.name} updated`, { prefix: "Transfer" });
|
304
|
+
}
|
305
|
+
} else {
|
306
|
+
MessageFormatter.info(`Creating collection ${collection.name} in target database...`, { prefix: "Transfer" });
|
307
|
+
targetCollection = await tryAwaitWithRetry(async () =>
|
308
|
+
this.targetDatabases.createCollection(
|
309
|
+
dbId,
|
310
|
+
collection.$id,
|
311
|
+
collection.name,
|
312
|
+
collection.$permissions,
|
313
|
+
collection.documentSecurity,
|
314
|
+
collection.enabled
|
315
|
+
)
|
316
|
+
);
|
317
|
+
MessageFormatter.success(`Collection ${collection.name} created`, { prefix: "Transfer" });
|
318
|
+
}
|
319
|
+
|
320
|
+
// Handle attributes with enhanced status checking
|
321
|
+
MessageFormatter.info(`Creating attributes for collection ${collection.name} with enhanced monitoring...`, { prefix: "Transfer" });
|
322
|
+
|
323
|
+
const attributesToCreate = collection.attributes.map(attr => parseAttribute(attr as any));
|
324
|
+
|
325
|
+
const attributesSuccess = await this.createCollectionAttributesWithStatusCheck(
|
326
|
+
this.targetDatabases,
|
327
|
+
dbId,
|
328
|
+
targetCollection,
|
329
|
+
attributesToCreate
|
330
|
+
);
|
331
|
+
|
332
|
+
if (!attributesSuccess) {
|
333
|
+
MessageFormatter.error(`Failed to create some attributes for collection ${collection.name}`, undefined, { prefix: "Transfer" });
|
334
|
+
// Continue with the transfer even if some attributes failed
|
335
|
+
} else {
|
336
|
+
MessageFormatter.success(`All attributes created successfully for collection ${collection.name}`, { prefix: "Transfer" });
|
337
|
+
}
|
338
|
+
|
339
|
+
// Handle indexes with enhanced status checking
|
340
|
+
MessageFormatter.info(`Creating indexes for collection ${collection.name} with enhanced monitoring...`, { prefix: "Transfer" });
|
341
|
+
|
342
|
+
const indexesSuccess = await this.createCollectionIndexesWithStatusCheck(
|
343
|
+
dbId,
|
344
|
+
this.targetDatabases,
|
345
|
+
targetCollection.$id,
|
346
|
+
targetCollection,
|
347
|
+
collection.indexes as any
|
348
|
+
);
|
349
|
+
|
350
|
+
if (!indexesSuccess) {
|
351
|
+
MessageFormatter.error(`Failed to create some indexes for collection ${collection.name}`, undefined, { prefix: "Transfer" });
|
352
|
+
// Continue with the transfer even if some indexes failed
|
353
|
+
} else {
|
354
|
+
MessageFormatter.success(`All indexes created successfully for collection ${collection.name}`, { prefix: "Transfer" });
|
355
|
+
}
|
356
|
+
|
357
|
+
MessageFormatter.success(`Structure complete for collection ${collection.name}`, { prefix: "Transfer" });
|
358
|
+
} catch (error) {
|
359
|
+
MessageFormatter.error(`Error processing collection ${collection.name}`, error instanceof Error ? error : new Error(String(error)), { prefix: "Transfer" });
|
360
|
+
}
|
361
|
+
}
|
362
|
+
} catch (error) {
|
363
|
+
MessageFormatter.error(`Failed to create database structure for ${dbId}`, error instanceof Error ? error : new Error(String(error)), { prefix: "Transfer" });
|
364
|
+
throw error;
|
365
|
+
}
|
366
|
+
}
|
367
|
+
|
368
|
+
/**
|
369
|
+
* Phase 2: Transfer documents to all collections in the database
|
370
|
+
*/
|
371
|
+
private async transferDatabaseDocuments(dbId: string): Promise<void> {
|
372
|
+
MessageFormatter.info(`Transferring documents for database ${dbId}`, { prefix: "Transfer" });
|
373
|
+
|
374
|
+
try {
|
375
|
+
// Get all collections from source database
|
376
|
+
const sourceCollections = await this.fetchAllCollections(dbId, this.sourceDatabases);
|
377
|
+
MessageFormatter.info(`Transferring documents for ${sourceCollections.length} collections in database ${dbId}`, { prefix: "Transfer" });
|
378
|
+
|
379
|
+
// Process each collection
|
380
|
+
for (const collection of sourceCollections) {
|
381
|
+
MessageFormatter.info(`Transferring documents for collection: ${collection.name} (${collection.$id})`, { prefix: "Transfer" });
|
382
|
+
|
383
|
+
try {
|
384
|
+
// Transfer documents
|
385
|
+
await this.transferDocumentsBetweenDatabases(
|
386
|
+
this.sourceDatabases,
|
387
|
+
this.targetDatabases,
|
388
|
+
dbId,
|
389
|
+
dbId,
|
390
|
+
collection.$id,
|
391
|
+
collection.$id
|
392
|
+
);
|
393
|
+
|
394
|
+
MessageFormatter.success(`Documents transferred for collection ${collection.name}`, { prefix: "Transfer" });
|
395
|
+
} catch (error) {
|
396
|
+
MessageFormatter.error(`Error transferring documents for collection ${collection.name}`, error instanceof Error ? error : new Error(String(error)), { prefix: "Transfer" });
|
397
|
+
}
|
398
|
+
}
|
399
|
+
} catch (error) {
|
400
|
+
MessageFormatter.error(`Failed to transfer documents for database ${dbId}`, error instanceof Error ? error : new Error(String(error)), { prefix: "Transfer" });
|
401
|
+
throw error;
|
402
|
+
}
|
403
|
+
}
|
404
|
+
|
245
405
|
private async transferAllBuckets(): Promise<void> {
|
246
406
|
MessageFormatter.info("Starting bucket transfer phase", { prefix: "Transfer" });
|
247
407
|
|
@@ -483,6 +643,180 @@ export class ComprehensiveTransfer {
|
|
483
643
|
}
|
484
644
|
}
|
485
645
|
|
646
|
+
/**
|
647
|
+
* Helper method to fetch all collections from a database
|
648
|
+
*/
|
649
|
+
private async fetchAllCollections(dbId: string, databases: Databases): Promise<Models.Collection[]> {
|
650
|
+
const collections: Models.Collection[] = [];
|
651
|
+
let lastId: string | undefined;
|
652
|
+
|
653
|
+
while (true) {
|
654
|
+
const queries = [Query.limit(100)];
|
655
|
+
if (lastId) {
|
656
|
+
queries.push(Query.cursorAfter(lastId));
|
657
|
+
}
|
658
|
+
|
659
|
+
const result = await tryAwaitWithRetry(async () => databases.listCollections(dbId, queries));
|
660
|
+
|
661
|
+
if (result.collections.length === 0) {
|
662
|
+
break;
|
663
|
+
}
|
664
|
+
|
665
|
+
collections.push(...result.collections);
|
666
|
+
|
667
|
+
if (result.collections.length < 100) {
|
668
|
+
break;
|
669
|
+
}
|
670
|
+
|
671
|
+
lastId = result.collections[result.collections.length - 1].$id;
|
672
|
+
}
|
673
|
+
|
674
|
+
return collections;
|
675
|
+
}
|
676
|
+
|
677
|
+
/**
|
678
|
+
* Helper method to parse attribute objects (simplified version of parseAttribute)
|
679
|
+
*/
|
680
|
+
private parseAttribute(attr: any): any {
|
681
|
+
// This is a simplified version - in production you'd use the actual parseAttribute from appwrite-utils
|
682
|
+
return {
|
683
|
+
key: attr.key,
|
684
|
+
type: attr.type,
|
685
|
+
size: attr.size,
|
686
|
+
required: attr.required,
|
687
|
+
array: attr.array,
|
688
|
+
default: attr.default,
|
689
|
+
format: attr.format,
|
690
|
+
elements: attr.elements,
|
691
|
+
min: attr.min,
|
692
|
+
max: attr.max,
|
693
|
+
relatedCollection: attr.relatedCollection,
|
694
|
+
relationType: attr.relationType,
|
695
|
+
twoWay: attr.twoWay,
|
696
|
+
twoWayKey: attr.twoWayKey,
|
697
|
+
onDelete: attr.onDelete,
|
698
|
+
side: attr.side
|
699
|
+
};
|
700
|
+
}
|
701
|
+
|
702
|
+
/**
|
703
|
+
* Helper method to create collection attributes with status checking
|
704
|
+
*/
|
705
|
+
private async createCollectionAttributesWithStatusCheck(
|
706
|
+
databases: Databases,
|
707
|
+
dbId: string,
|
708
|
+
collection: Models.Collection,
|
709
|
+
attributes: any[]
|
710
|
+
): Promise<boolean> {
|
711
|
+
// Import the enhanced attribute creation function
|
712
|
+
const { createUpdateCollectionAttributesWithStatusCheck } = await import("../collections/attributes.js");
|
713
|
+
|
714
|
+
return await createUpdateCollectionAttributesWithStatusCheck(
|
715
|
+
databases,
|
716
|
+
dbId,
|
717
|
+
collection,
|
718
|
+
attributes
|
719
|
+
);
|
720
|
+
}
|
721
|
+
|
722
|
+
/**
|
723
|
+
* Helper method to create collection indexes with status checking
|
724
|
+
*/
|
725
|
+
private async createCollectionIndexesWithStatusCheck(
|
726
|
+
dbId: string,
|
727
|
+
databases: Databases,
|
728
|
+
collectionId: string,
|
729
|
+
collection: Models.Collection,
|
730
|
+
indexes: any[]
|
731
|
+
): Promise<boolean> {
|
732
|
+
// Import the enhanced index creation function
|
733
|
+
const { createOrUpdateIndexesWithStatusCheck } = await import("../collections/indexes.js");
|
734
|
+
|
735
|
+
return await createOrUpdateIndexesWithStatusCheck(
|
736
|
+
dbId,
|
737
|
+
databases,
|
738
|
+
collectionId,
|
739
|
+
collection,
|
740
|
+
indexes
|
741
|
+
);
|
742
|
+
}
|
743
|
+
|
744
|
+
/**
|
745
|
+
* Helper method to transfer documents between databases
|
746
|
+
*/
|
747
|
+
private async transferDocumentsBetweenDatabases(
|
748
|
+
sourceDb: Databases,
|
749
|
+
targetDb: Databases,
|
750
|
+
sourceDbId: string,
|
751
|
+
targetDbId: string,
|
752
|
+
sourceCollectionId: string,
|
753
|
+
targetCollectionId: string
|
754
|
+
): Promise<void> {
|
755
|
+
MessageFormatter.info(`Transferring documents from ${sourceCollectionId} to ${targetCollectionId}`, { prefix: "Transfer" });
|
756
|
+
|
757
|
+
let lastId: string | undefined;
|
758
|
+
let totalTransferred = 0;
|
759
|
+
|
760
|
+
while (true) {
|
761
|
+
const queries = [Query.limit(50)]; // Smaller batch size for better performance
|
762
|
+
if (lastId) {
|
763
|
+
queries.push(Query.cursorAfter(lastId));
|
764
|
+
}
|
765
|
+
|
766
|
+
const documents = await tryAwaitWithRetry(async () =>
|
767
|
+
sourceDb.listDocuments(sourceDbId, sourceCollectionId, queries)
|
768
|
+
);
|
769
|
+
|
770
|
+
if (documents.documents.length === 0) {
|
771
|
+
break;
|
772
|
+
}
|
773
|
+
|
774
|
+
// Transfer documents with rate limiting
|
775
|
+
const transferTasks = documents.documents.map(doc =>
|
776
|
+
this.limit(async () => {
|
777
|
+
try {
|
778
|
+
// Check if document already exists
|
779
|
+
try {
|
780
|
+
await targetDb.getDocument(targetDbId, targetCollectionId, doc.$id);
|
781
|
+
MessageFormatter.info(`Document ${doc.$id} already exists, skipping`, { prefix: "Transfer" });
|
782
|
+
return;
|
783
|
+
} catch (error) {
|
784
|
+
// Document doesn't exist, proceed with creation
|
785
|
+
}
|
786
|
+
|
787
|
+
// Create document in target
|
788
|
+
const { $id, $createdAt, $updatedAt, $permissions, $databaseId, $collectionId, ...docData } = doc;
|
789
|
+
|
790
|
+
await tryAwaitWithRetry(async () =>
|
791
|
+
targetDb.createDocument(
|
792
|
+
targetDbId,
|
793
|
+
targetCollectionId,
|
794
|
+
doc.$id,
|
795
|
+
docData,
|
796
|
+
doc.$permissions
|
797
|
+
)
|
798
|
+
);
|
799
|
+
|
800
|
+
totalTransferred++;
|
801
|
+
MessageFormatter.success(`Transferred document ${doc.$id}`, { prefix: "Transfer" });
|
802
|
+
} catch (error) {
|
803
|
+
MessageFormatter.error(`Failed to transfer document ${doc.$id}`, error instanceof Error ? error : new Error(String(error)), { prefix: "Transfer" });
|
804
|
+
}
|
805
|
+
})
|
806
|
+
);
|
807
|
+
|
808
|
+
await Promise.all(transferTasks);
|
809
|
+
|
810
|
+
if (documents.documents.length < 50) {
|
811
|
+
break;
|
812
|
+
}
|
813
|
+
|
814
|
+
lastId = documents.documents[documents.documents.length - 1].$id;
|
815
|
+
}
|
816
|
+
|
817
|
+
MessageFormatter.info(`Transferred ${totalTransferred} documents from ${sourceCollectionId} to ${targetCollectionId}`, { prefix: "Transfer" });
|
818
|
+
}
|
819
|
+
|
486
820
|
private printSummary(): void {
|
487
821
|
const duration = Math.round((Date.now() - this.startTime) / 1000);
|
488
822
|
|
@@ -13,6 +13,7 @@ import { getAppwriteClient } from "../utils/helperFunctions.js";
|
|
13
13
|
import {
|
14
14
|
createOrUpdateAttribute,
|
15
15
|
createUpdateCollectionAttributes,
|
16
|
+
createUpdateCollectionAttributesWithStatusCheck,
|
16
17
|
} from "../collections/attributes.js";
|
17
18
|
import { parseAttribute } from "appwrite-utils";
|
18
19
|
import chalk from "chalk";
|
@@ -22,6 +23,7 @@ import { ProgressManager } from "../shared/progressManager.js";
|
|
22
23
|
import {
|
23
24
|
createOrUpdateIndex,
|
24
25
|
createOrUpdateIndexes,
|
26
|
+
createOrUpdateIndexesWithStatusCheck,
|
25
27
|
} from "../collections/indexes.js";
|
26
28
|
import { getClient } from "../utils/getClientFromConfig.js";
|
27
29
|
|
@@ -305,44 +307,23 @@ export const transferDatabaseLocalToLocal = async (
|
|
305
307
|
);
|
306
308
|
}
|
307
309
|
|
308
|
-
// Handle attributes
|
309
|
-
|
310
|
-
|
311
|
-
|
310
|
+
// Handle attributes with enhanced status checking
|
311
|
+
console.log(chalk.blue(`Creating attributes for collection ${collection.name} with enhanced monitoring...`));
|
312
|
+
|
313
|
+
const allAttributes = collection.attributes.map(attr => parseAttribute(attr as any));
|
314
|
+
const attributeSuccess = await createUpdateCollectionAttributesWithStatusCheck(
|
315
|
+
localDb,
|
316
|
+
targetDbId,
|
317
|
+
targetCollection,
|
318
|
+
allAttributes
|
312
319
|
);
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
(attr: any) => attr.key === parsedAttribute.key
|
318
|
-
);
|
319
|
-
|
320
|
-
if (!existingAttribute) {
|
321
|
-
await tryAwaitWithRetry(async () =>
|
322
|
-
createOrUpdateAttribute(
|
323
|
-
localDb,
|
324
|
-
targetDbId,
|
325
|
-
targetCollection,
|
326
|
-
parsedAttribute
|
327
|
-
)
|
328
|
-
);
|
329
|
-
console.log(chalk.green(`Attribute ${parsedAttribute.key} created`));
|
330
|
-
} else {
|
331
|
-
console.log(
|
332
|
-
chalk.blue(
|
333
|
-
`Attribute ${parsedAttribute.key} exists, checking for updates...`
|
334
|
-
)
|
335
|
-
);
|
336
|
-
await tryAwaitWithRetry(async () =>
|
337
|
-
createOrUpdateAttribute(
|
338
|
-
localDb,
|
339
|
-
targetDbId,
|
340
|
-
targetCollection,
|
341
|
-
parsedAttribute
|
342
|
-
)
|
343
|
-
);
|
344
|
-
}
|
320
|
+
|
321
|
+
if (!attributeSuccess) {
|
322
|
+
console.log(chalk.red(`❌ Failed to create all attributes for collection ${collection.name}, skipping to next collection`));
|
323
|
+
continue;
|
345
324
|
}
|
325
|
+
|
326
|
+
console.log(chalk.green(`✅ All attributes created successfully for collection ${collection.name}`));
|
346
327
|
|
347
328
|
// Handle indexes
|
348
329
|
const existingIndexes = await tryAwaitWithRetry(
|
@@ -474,73 +455,41 @@ export const transferDatabaseLocalToRemote = async (
|
|
474
455
|
);
|
475
456
|
}
|
476
457
|
|
477
|
-
// Handle attributes
|
478
|
-
|
479
|
-
|
458
|
+
// Handle attributes with enhanced status checking
|
459
|
+
console.log(chalk.blue(`Creating attributes for collection ${collection.name} with enhanced monitoring...`));
|
460
|
+
|
461
|
+
const attributesToCreate = collection.attributes.map(attr => parseAttribute(attr as any));
|
462
|
+
|
463
|
+
const attributesSuccess = await createUpdateCollectionAttributesWithStatusCheck(
|
464
|
+
remoteDb,
|
465
|
+
toDbId,
|
466
|
+
targetCollection,
|
467
|
+
attributesToCreate
|
480
468
|
);
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
);
|
487
|
-
|
488
|
-
if (!existingAttribute) {
|
489
|
-
await tryAwaitWithRetry(async () =>
|
490
|
-
createOrUpdateAttribute(
|
491
|
-
remoteDb,
|
492
|
-
toDbId,
|
493
|
-
targetCollection,
|
494
|
-
parsedAttribute
|
495
|
-
)
|
496
|
-
);
|
497
|
-
console.log(chalk.green(`Attribute ${parsedAttribute.key} created`));
|
498
|
-
} else {
|
499
|
-
console.log(
|
500
|
-
chalk.blue(
|
501
|
-
`Attribute ${parsedAttribute.key} exists, checking for updates...`
|
502
|
-
)
|
503
|
-
);
|
504
|
-
await tryAwaitWithRetry(async () =>
|
505
|
-
createOrUpdateAttribute(
|
506
|
-
remoteDb,
|
507
|
-
toDbId,
|
508
|
-
targetCollection,
|
509
|
-
parsedAttribute
|
510
|
-
)
|
511
|
-
);
|
512
|
-
}
|
469
|
+
|
470
|
+
if (!attributesSuccess) {
|
471
|
+
console.log(chalk.red(`Failed to create some attributes for collection ${collection.name}`));
|
472
|
+
// Continue with the transfer even if some attributes failed
|
473
|
+
} else {
|
474
|
+
console.log(chalk.green(`All attributes created successfully for collection ${collection.name}`));
|
513
475
|
}
|
514
476
|
|
515
|
-
// Handle indexes
|
516
|
-
|
517
|
-
|
477
|
+
// Handle indexes with enhanced status checking
|
478
|
+
console.log(chalk.blue(`Creating indexes for collection ${collection.name} with enhanced monitoring...`));
|
479
|
+
|
480
|
+
const indexesSuccess = await createOrUpdateIndexesWithStatusCheck(
|
481
|
+
toDbId,
|
482
|
+
remoteDb,
|
483
|
+
targetCollection.$id,
|
484
|
+
targetCollection,
|
485
|
+
collection.indexes as any
|
518
486
|
);
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
if (!existingIndex) {
|
526
|
-
await createOrUpdateIndex(
|
527
|
-
toDbId,
|
528
|
-
remoteDb,
|
529
|
-
targetCollection.$id,
|
530
|
-
index as any
|
531
|
-
);
|
532
|
-
console.log(chalk.green(`Index ${index.key} created`));
|
533
|
-
} else {
|
534
|
-
console.log(
|
535
|
-
chalk.blue(`Index ${index.key} exists, checking for updates...`)
|
536
|
-
);
|
537
|
-
await createOrUpdateIndex(
|
538
|
-
toDbId,
|
539
|
-
remoteDb,
|
540
|
-
targetCollection.$id,
|
541
|
-
index as any
|
542
|
-
);
|
543
|
-
}
|
487
|
+
|
488
|
+
if (!indexesSuccess) {
|
489
|
+
console.log(chalk.red(`Failed to create some indexes for collection ${collection.name}`));
|
490
|
+
// Continue with the transfer even if some indexes failed
|
491
|
+
} else {
|
492
|
+
console.log(chalk.green(`All indexes created successfully for collection ${collection.name}`));
|
544
493
|
}
|
545
494
|
|
546
495
|
// Transfer documents
|