appwrite-utils-cli 1.1.1 → 1.1.2
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/collections/attributes.js +74 -26
- package/dist/collections/indexes.js +31 -13
- package/dist/interactiveCLI.js +3 -1
- package/dist/migrations/comprehensiveTransfer.js +4 -2
- package/package.json +1 -1
- package/src/collections/attributes.ts +103 -33
- package/src/collections/indexes.ts +42 -19
- package/src/interactiveCLI.ts +4 -1
- package/src/migrations/comprehensiveTransfer.ts +4 -2
@@ -164,16 +164,38 @@ export const createOrUpdateAttributeWithStatusCheck = async (db, dbId, collectio
|
|
164
164
|
if (success) {
|
165
165
|
return true;
|
166
166
|
}
|
167
|
-
// If not successful and we have retries left, delete
|
167
|
+
// If not successful and we have retries left, delete specific attribute and try again
|
168
168
|
if (retryCount < maxRetries) {
|
169
|
-
console.log(chalk.yellow(`Attribute '${attribute.key}' failed/stuck, retrying...`));
|
170
|
-
//
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
169
|
+
console.log(chalk.yellow(`Attribute '${attribute.key}' failed/stuck, deleting and retrying...`));
|
170
|
+
// Try to delete the specific stuck attribute instead of the entire collection
|
171
|
+
try {
|
172
|
+
await db.deleteAttribute(dbId, collection.$id, attribute.key);
|
173
|
+
console.log(chalk.yellow(`Deleted stuck attribute '${attribute.key}', will retry creation`));
|
174
|
+
// Wait a bit before retry
|
175
|
+
await delay(3000);
|
176
|
+
// Get fresh collection data
|
177
|
+
const freshCollection = await db.getCollection(dbId, collection.$id);
|
178
|
+
// Retry with the same collection (attribute should be gone now)
|
179
|
+
return await createOrUpdateAttributeWithStatusCheck(db, dbId, freshCollection, attribute, retryCount + 1, maxRetries);
|
180
|
+
}
|
181
|
+
catch (deleteError) {
|
182
|
+
console.log(chalk.red(`Failed to delete stuck attribute '${attribute.key}': ${deleteError}`));
|
183
|
+
// If attribute deletion fails, only then try collection recreation as last resort
|
184
|
+
if (retryCount >= maxRetries - 1) {
|
185
|
+
console.log(chalk.yellow(`Last resort: Recreating collection for attribute '${attribute.key}'`));
|
186
|
+
// Get fresh collection data
|
187
|
+
const freshCollection = await db.getCollection(dbId, collection.$id);
|
188
|
+
// Delete and recreate collection
|
189
|
+
const newCollection = await deleteAndRecreateCollection(db, dbId, freshCollection, retryCount + 1);
|
190
|
+
if (newCollection) {
|
191
|
+
// Retry with the new collection
|
192
|
+
return await createOrUpdateAttributeWithStatusCheck(db, dbId, newCollection, attribute, retryCount + 1, maxRetries);
|
193
|
+
}
|
194
|
+
}
|
195
|
+
else {
|
196
|
+
// Continue to next retry without collection recreation
|
197
|
+
return await createOrUpdateAttributeWithStatusCheck(db, dbId, collection, attribute, retryCount + 1, maxRetries);
|
198
|
+
}
|
177
199
|
}
|
178
200
|
}
|
179
201
|
console.log(chalk.red(`❌ Failed to create attribute '${attribute.key}' after ${maxRetries + 1} attempts`));
|
@@ -437,32 +459,58 @@ export const createUpdateCollectionAttributesWithStatusCheck = async (db, dbId,
|
|
437
459
|
await delay(500); // Longer delay for deletions
|
438
460
|
}
|
439
461
|
}
|
440
|
-
// Create attributes ONE BY ONE with proper status checking
|
462
|
+
// Create attributes ONE BY ONE with proper status checking and persistent retry logic
|
441
463
|
console.log(chalk.blue(`Creating ${attributes.length} attributes sequentially with status monitoring...`));
|
442
464
|
let currentCollection = collection;
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
465
|
+
let attributesToProcess = [...attributes];
|
466
|
+
let overallRetryCount = 0;
|
467
|
+
const maxOverallRetries = 3;
|
468
|
+
while (attributesToProcess.length > 0 && overallRetryCount < maxOverallRetries) {
|
469
|
+
const remainingAttributes = [...attributesToProcess];
|
470
|
+
attributesToProcess = []; // Reset for next iteration
|
471
|
+
console.log(chalk.blue(`\n=== Attempt ${overallRetryCount + 1}/${maxOverallRetries} - Processing ${remainingAttributes.length} attributes ===`));
|
472
|
+
for (const attribute of remainingAttributes) {
|
473
|
+
console.log(chalk.blue(`\n--- Processing attribute: ${attribute.key} ---`));
|
474
|
+
const success = await createOrUpdateAttributeWithStatusCheck(db, dbId, currentCollection, attribute);
|
475
|
+
if (success) {
|
476
|
+
console.log(chalk.green(`✅ Successfully created attribute: ${attribute.key}`));
|
477
|
+
// Get updated collection data for next iteration
|
478
|
+
try {
|
479
|
+
currentCollection = await db.getCollection(dbId, collection.$id);
|
480
|
+
}
|
481
|
+
catch (error) {
|
482
|
+
console.log(chalk.yellow(`Warning: Could not refresh collection data: ${error}`));
|
483
|
+
}
|
484
|
+
// Add delay between successful attributes
|
485
|
+
await delay(1000);
|
486
|
+
}
|
487
|
+
else {
|
488
|
+
console.log(chalk.red(`❌ Failed to create attribute: ${attribute.key}, will retry in next round`));
|
489
|
+
attributesToProcess.push(attribute); // Add back to retry list
|
490
|
+
}
|
491
|
+
}
|
492
|
+
if (attributesToProcess.length === 0) {
|
493
|
+
console.log(chalk.green(`\n✅ Successfully created all ${attributes.length} attributes for collection: ${collection.name}`));
|
494
|
+
return true;
|
495
|
+
}
|
496
|
+
overallRetryCount++;
|
497
|
+
if (overallRetryCount < maxOverallRetries) {
|
498
|
+
console.log(chalk.yellow(`\n⏳ Waiting 5 seconds before retrying ${attributesToProcess.length} failed attributes...`));
|
499
|
+
await delay(5000);
|
500
|
+
// Refresh collection data before retry
|
450
501
|
try {
|
451
502
|
currentCollection = await db.getCollection(dbId, collection.$id);
|
503
|
+
console.log(chalk.blue(`Refreshed collection data for retry`));
|
452
504
|
}
|
453
505
|
catch (error) {
|
454
|
-
console.log(chalk.yellow(`Warning: Could not refresh collection data: ${error}`));
|
506
|
+
console.log(chalk.yellow(`Warning: Could not refresh collection data for retry: ${error}`));
|
455
507
|
}
|
456
|
-
// Add delay between successful attributes
|
457
|
-
await delay(1000);
|
458
|
-
}
|
459
|
-
else {
|
460
|
-
console.log(chalk.red(`❌ Failed to create attribute: ${attribute.key}`));
|
461
|
-
failedAttributes.push(attribute.key);
|
462
508
|
}
|
463
509
|
}
|
464
|
-
|
465
|
-
|
510
|
+
// If we get here, some attributes still failed after all retries
|
511
|
+
if (attributesToProcess.length > 0) {
|
512
|
+
console.log(chalk.red(`\n❌ Failed to create ${attributesToProcess.length} attributes after ${maxOverallRetries} attempts: ${attributesToProcess.map(a => a.key).join(', ')}`));
|
513
|
+
console.log(chalk.red(`This may indicate a fundamental issue with the attribute definitions or Appwrite instance`));
|
466
514
|
return false;
|
467
515
|
}
|
468
516
|
console.log(chalk.green(`\n✅ Successfully created all ${attributes.length} attributes for collection: ${collection.name}`));
|
@@ -130,22 +130,40 @@ export const createOrUpdateIndexWithStatusCheck = async (dbId, db, collectionId,
|
|
130
130
|
*/
|
131
131
|
export const createOrUpdateIndexesWithStatusCheck = async (dbId, db, collectionId, collection, indexes) => {
|
132
132
|
console.log(chalk.blue(`Creating/updating ${indexes.length} indexes with status monitoring...`));
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
133
|
+
let indexesToProcess = [...indexes];
|
134
|
+
let overallRetryCount = 0;
|
135
|
+
const maxOverallRetries = 3;
|
136
|
+
while (indexesToProcess.length > 0 && overallRetryCount < maxOverallRetries) {
|
137
|
+
const remainingIndexes = [...indexesToProcess];
|
138
|
+
indexesToProcess = []; // Reset for next iteration
|
139
|
+
console.log(chalk.blue(`\n=== Attempt ${overallRetryCount + 1}/${maxOverallRetries} - Processing ${remainingIndexes.length} indexes ===`));
|
140
|
+
for (const index of remainingIndexes) {
|
141
|
+
console.log(chalk.blue(`\n--- Processing index: ${index.key} ---`));
|
142
|
+
const success = await createOrUpdateIndexWithStatusCheck(dbId, db, collectionId, collection, index);
|
143
|
+
if (success) {
|
144
|
+
console.log(chalk.green(`✅ Successfully created index: ${index.key}`));
|
145
|
+
// Add delay between successful indexes
|
146
|
+
await delay(1000);
|
147
|
+
}
|
148
|
+
else {
|
149
|
+
console.log(chalk.red(`❌ Failed to create index: ${index.key}, will retry in next round`));
|
150
|
+
indexesToProcess.push(index); // Add back to retry list
|
151
|
+
}
|
152
|
+
}
|
153
|
+
if (indexesToProcess.length === 0) {
|
154
|
+
console.log(chalk.green(`\n✅ Successfully created all ${indexes.length} indexes`));
|
155
|
+
return true;
|
141
156
|
}
|
142
|
-
|
143
|
-
|
144
|
-
|
157
|
+
overallRetryCount++;
|
158
|
+
if (overallRetryCount < maxOverallRetries) {
|
159
|
+
console.log(chalk.yellow(`\n⏳ Waiting 5 seconds before retrying ${indexesToProcess.length} failed indexes...`));
|
160
|
+
await delay(5000);
|
145
161
|
}
|
146
162
|
}
|
147
|
-
|
148
|
-
|
163
|
+
// If we get here, some indexes still failed after all retries
|
164
|
+
if (indexesToProcess.length > 0) {
|
165
|
+
console.log(chalk.red(`\n❌ Failed to create ${indexesToProcess.length} indexes after ${maxOverallRetries} attempts: ${indexesToProcess.map(i => i.key).join(', ')}`));
|
166
|
+
console.log(chalk.red(`This may indicate a fundamental issue with the index definitions or Appwrite instance`));
|
149
167
|
return false;
|
150
168
|
}
|
151
169
|
console.log(chalk.green(`\n✅ Successfully created all ${indexes.length} indexes`));
|
package/dist/interactiveCLI.js
CHANGED
@@ -1516,7 +1516,9 @@ export class InteractiveCLI {
|
|
1516
1516
|
async comprehensiveTransfer() {
|
1517
1517
|
MessageFormatter.info("Starting comprehensive transfer configuration...", { prefix: "Transfer" });
|
1518
1518
|
try {
|
1519
|
-
// Initialize controller to optionally load config if available (supports both YAML and TypeScript configs)
|
1519
|
+
// Initialize controller to optionally load config if available (supports both YAML and TypeScript configs)
|
1520
|
+
await this.initControllerIfNeeded();
|
1521
|
+
// Check if user has an appwrite config for easier setup
|
1520
1522
|
const hasAppwriteConfig = this.controller?.config?.appwriteEndpoint &&
|
1521
1523
|
this.controller?.config?.appwriteProject &&
|
1522
1524
|
this.controller?.config?.appwriteKey;
|
@@ -213,7 +213,9 @@ export class ComprehensiveTransfer {
|
|
213
213
|
const attributesSuccess = await this.createCollectionAttributesWithStatusCheck(this.targetDatabases, dbId, targetCollection, attributesToCreate);
|
214
214
|
if (!attributesSuccess) {
|
215
215
|
MessageFormatter.error(`Failed to create some attributes for collection ${collection.name}`, undefined, { prefix: "Transfer" });
|
216
|
-
|
216
|
+
MessageFormatter.error(`Skipping index creation and document transfer for collection ${collection.name} due to attribute failures`, undefined, { prefix: "Transfer" });
|
217
|
+
// Skip indexes and document transfer if attributes failed
|
218
|
+
continue;
|
217
219
|
}
|
218
220
|
else {
|
219
221
|
MessageFormatter.success(`All attributes created successfully for collection ${collection.name}`, { prefix: "Transfer" });
|
@@ -223,7 +225,7 @@ export class ComprehensiveTransfer {
|
|
223
225
|
const indexesSuccess = await this.createCollectionIndexesWithStatusCheck(dbId, this.targetDatabases, targetCollection.$id, targetCollection, collection.indexes);
|
224
226
|
if (!indexesSuccess) {
|
225
227
|
MessageFormatter.error(`Failed to create some indexes for collection ${collection.name}`, undefined, { prefix: "Transfer" });
|
226
|
-
|
228
|
+
MessageFormatter.warning(`Proceeding with document transfer despite index failures for collection ${collection.name}`, { prefix: "Transfer" });
|
227
229
|
}
|
228
230
|
else {
|
229
231
|
MessageFormatter.success(`All indexes created successfully for collection ${collection.name}`, { prefix: "Transfer" });
|
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": "1.1.
|
4
|
+
"version": "1.1.2",
|
5
5
|
"main": "src/main.ts",
|
6
6
|
"type": "module",
|
7
7
|
"repository": {
|
@@ -263,26 +263,65 @@ export const createOrUpdateAttributeWithStatusCheck = async (
|
|
263
263
|
return true;
|
264
264
|
}
|
265
265
|
|
266
|
-
// If not successful and we have retries left, delete
|
266
|
+
// If not successful and we have retries left, delete specific attribute and try again
|
267
267
|
if (retryCount < maxRetries) {
|
268
|
-
console.log(chalk.yellow(`Attribute '${attribute.key}' failed/stuck, retrying...`));
|
268
|
+
console.log(chalk.yellow(`Attribute '${attribute.key}' failed/stuck, deleting and retrying...`));
|
269
269
|
|
270
|
-
//
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
270
|
+
// Try to delete the specific stuck attribute instead of the entire collection
|
271
|
+
try {
|
272
|
+
await db.deleteAttribute(dbId, collection.$id, attribute.key);
|
273
|
+
console.log(chalk.yellow(`Deleted stuck attribute '${attribute.key}', will retry creation`));
|
274
|
+
|
275
|
+
// Wait a bit before retry
|
276
|
+
await delay(3000);
|
277
|
+
|
278
|
+
// Get fresh collection data
|
279
|
+
const freshCollection = await db.getCollection(dbId, collection.$id);
|
280
|
+
|
281
|
+
// Retry with the same collection (attribute should be gone now)
|
278
282
|
return await createOrUpdateAttributeWithStatusCheck(
|
279
283
|
db,
|
280
284
|
dbId,
|
281
|
-
|
285
|
+
freshCollection,
|
282
286
|
attribute,
|
283
287
|
retryCount + 1,
|
284
288
|
maxRetries
|
285
289
|
);
|
290
|
+
} catch (deleteError) {
|
291
|
+
console.log(chalk.red(`Failed to delete stuck attribute '${attribute.key}': ${deleteError}`));
|
292
|
+
|
293
|
+
// If attribute deletion fails, only then try collection recreation as last resort
|
294
|
+
if (retryCount >= maxRetries - 1) {
|
295
|
+
console.log(chalk.yellow(`Last resort: Recreating collection for attribute '${attribute.key}'`));
|
296
|
+
|
297
|
+
// Get fresh collection data
|
298
|
+
const freshCollection = await db.getCollection(dbId, collection.$id);
|
299
|
+
|
300
|
+
// Delete and recreate collection
|
301
|
+
const newCollection = await deleteAndRecreateCollection(db, dbId, freshCollection, retryCount + 1);
|
302
|
+
|
303
|
+
if (newCollection) {
|
304
|
+
// Retry with the new collection
|
305
|
+
return await createOrUpdateAttributeWithStatusCheck(
|
306
|
+
db,
|
307
|
+
dbId,
|
308
|
+
newCollection,
|
309
|
+
attribute,
|
310
|
+
retryCount + 1,
|
311
|
+
maxRetries
|
312
|
+
);
|
313
|
+
}
|
314
|
+
} else {
|
315
|
+
// Continue to next retry without collection recreation
|
316
|
+
return await createOrUpdateAttributeWithStatusCheck(
|
317
|
+
db,
|
318
|
+
dbId,
|
319
|
+
collection,
|
320
|
+
attribute,
|
321
|
+
retryCount + 1,
|
322
|
+
maxRetries
|
323
|
+
);
|
324
|
+
}
|
286
325
|
}
|
287
326
|
}
|
288
327
|
|
@@ -810,42 +849,73 @@ export const createUpdateCollectionAttributesWithStatusCheck = async (
|
|
810
849
|
}
|
811
850
|
}
|
812
851
|
|
813
|
-
// Create attributes ONE BY ONE with proper status checking
|
852
|
+
// Create attributes ONE BY ONE with proper status checking and persistent retry logic
|
814
853
|
console.log(chalk.blue(`Creating ${attributes.length} attributes sequentially with status monitoring...`));
|
815
854
|
|
816
855
|
let currentCollection = collection;
|
817
|
-
|
856
|
+
let attributesToProcess = [...attributes];
|
857
|
+
let overallRetryCount = 0;
|
858
|
+
const maxOverallRetries = 3;
|
818
859
|
|
819
|
-
|
820
|
-
|
860
|
+
while (attributesToProcess.length > 0 && overallRetryCount < maxOverallRetries) {
|
861
|
+
const remainingAttributes = [...attributesToProcess];
|
862
|
+
attributesToProcess = []; // Reset for next iteration
|
821
863
|
|
822
|
-
|
823
|
-
db,
|
824
|
-
dbId,
|
825
|
-
currentCollection,
|
826
|
-
attribute
|
827
|
-
);
|
864
|
+
console.log(chalk.blue(`\n=== Attempt ${overallRetryCount + 1}/${maxOverallRetries} - Processing ${remainingAttributes.length} attributes ===`));
|
828
865
|
|
829
|
-
|
830
|
-
console.log(chalk.
|
866
|
+
for (const attribute of remainingAttributes) {
|
867
|
+
console.log(chalk.blue(`\n--- Processing attribute: ${attribute.key} ---`));
|
868
|
+
|
869
|
+
const success = await createOrUpdateAttributeWithStatusCheck(
|
870
|
+
db,
|
871
|
+
dbId,
|
872
|
+
currentCollection,
|
873
|
+
attribute
|
874
|
+
);
|
875
|
+
|
876
|
+
if (success) {
|
877
|
+
console.log(chalk.green(`✅ Successfully created attribute: ${attribute.key}`));
|
878
|
+
|
879
|
+
// Get updated collection data for next iteration
|
880
|
+
try {
|
881
|
+
currentCollection = await db.getCollection(dbId, collection.$id);
|
882
|
+
} catch (error) {
|
883
|
+
console.log(chalk.yellow(`Warning: Could not refresh collection data: ${error}`));
|
884
|
+
}
|
885
|
+
|
886
|
+
// Add delay between successful attributes
|
887
|
+
await delay(1000);
|
888
|
+
} else {
|
889
|
+
console.log(chalk.red(`❌ Failed to create attribute: ${attribute.key}, will retry in next round`));
|
890
|
+
attributesToProcess.push(attribute); // Add back to retry list
|
891
|
+
}
|
892
|
+
}
|
893
|
+
|
894
|
+
if (attributesToProcess.length === 0) {
|
895
|
+
console.log(chalk.green(`\n✅ Successfully created all ${attributes.length} attributes for collection: ${collection.name}`));
|
896
|
+
return true;
|
897
|
+
}
|
898
|
+
|
899
|
+
overallRetryCount++;
|
900
|
+
|
901
|
+
if (overallRetryCount < maxOverallRetries) {
|
902
|
+
console.log(chalk.yellow(`\n⏳ Waiting 5 seconds before retrying ${attributesToProcess.length} failed attributes...`));
|
903
|
+
await delay(5000);
|
831
904
|
|
832
|
-
//
|
905
|
+
// Refresh collection data before retry
|
833
906
|
try {
|
834
907
|
currentCollection = await db.getCollection(dbId, collection.$id);
|
908
|
+
console.log(chalk.blue(`Refreshed collection data for retry`));
|
835
909
|
} catch (error) {
|
836
|
-
console.log(chalk.yellow(`Warning: Could not refresh collection data: ${error}`));
|
910
|
+
console.log(chalk.yellow(`Warning: Could not refresh collection data for retry: ${error}`));
|
837
911
|
}
|
838
|
-
|
839
|
-
// Add delay between successful attributes
|
840
|
-
await delay(1000);
|
841
|
-
} else {
|
842
|
-
console.log(chalk.red(`❌ Failed to create attribute: ${attribute.key}`));
|
843
|
-
failedAttributes.push(attribute.key);
|
844
912
|
}
|
845
913
|
}
|
846
914
|
|
847
|
-
|
848
|
-
|
915
|
+
// If we get here, some attributes still failed after all retries
|
916
|
+
if (attributesToProcess.length > 0) {
|
917
|
+
console.log(chalk.red(`\n❌ Failed to create ${attributesToProcess.length} attributes after ${maxOverallRetries} attempts: ${attributesToProcess.map(a => a.key).join(', ')}`));
|
918
|
+
console.log(chalk.red(`This may indicate a fundamental issue with the attribute definitions or Appwrite instance`));
|
849
919
|
return false;
|
850
920
|
}
|
851
921
|
|
@@ -233,32 +233,55 @@ export const createOrUpdateIndexesWithStatusCheck = async (
|
|
233
233
|
): Promise<boolean> => {
|
234
234
|
console.log(chalk.blue(`Creating/updating ${indexes.length} indexes with status monitoring...`));
|
235
235
|
|
236
|
-
|
236
|
+
let indexesToProcess = [...indexes];
|
237
|
+
let overallRetryCount = 0;
|
238
|
+
const maxOverallRetries = 3;
|
237
239
|
|
238
|
-
|
239
|
-
|
240
|
+
while (indexesToProcess.length > 0 && overallRetryCount < maxOverallRetries) {
|
241
|
+
const remainingIndexes = [...indexesToProcess];
|
242
|
+
indexesToProcess = []; // Reset for next iteration
|
240
243
|
|
241
|
-
|
242
|
-
dbId,
|
243
|
-
db,
|
244
|
-
collectionId,
|
245
|
-
collection,
|
246
|
-
index
|
247
|
-
);
|
244
|
+
console.log(chalk.blue(`\n=== Attempt ${overallRetryCount + 1}/${maxOverallRetries} - Processing ${remainingIndexes.length} indexes ===`));
|
248
245
|
|
249
|
-
|
250
|
-
console.log(chalk.
|
246
|
+
for (const index of remainingIndexes) {
|
247
|
+
console.log(chalk.blue(`\n--- Processing index: ${index.key} ---`));
|
251
248
|
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
249
|
+
const success = await createOrUpdateIndexWithStatusCheck(
|
250
|
+
dbId,
|
251
|
+
db,
|
252
|
+
collectionId,
|
253
|
+
collection,
|
254
|
+
index
|
255
|
+
);
|
256
|
+
|
257
|
+
if (success) {
|
258
|
+
console.log(chalk.green(`✅ Successfully created index: ${index.key}`));
|
259
|
+
|
260
|
+
// Add delay between successful indexes
|
261
|
+
await delay(1000);
|
262
|
+
} else {
|
263
|
+
console.log(chalk.red(`❌ Failed to create index: ${index.key}, will retry in next round`));
|
264
|
+
indexesToProcess.push(index); // Add back to retry list
|
265
|
+
}
|
266
|
+
}
|
267
|
+
|
268
|
+
if (indexesToProcess.length === 0) {
|
269
|
+
console.log(chalk.green(`\n✅ Successfully created all ${indexes.length} indexes`));
|
270
|
+
return true;
|
271
|
+
}
|
272
|
+
|
273
|
+
overallRetryCount++;
|
274
|
+
|
275
|
+
if (overallRetryCount < maxOverallRetries) {
|
276
|
+
console.log(chalk.yellow(`\n⏳ Waiting 5 seconds before retrying ${indexesToProcess.length} failed indexes...`));
|
277
|
+
await delay(5000);
|
257
278
|
}
|
258
279
|
}
|
259
280
|
|
260
|
-
|
261
|
-
|
281
|
+
// If we get here, some indexes still failed after all retries
|
282
|
+
if (indexesToProcess.length > 0) {
|
283
|
+
console.log(chalk.red(`\n❌ Failed to create ${indexesToProcess.length} indexes after ${maxOverallRetries} attempts: ${indexesToProcess.map(i => i.key).join(', ')}`));
|
284
|
+
console.log(chalk.red(`This may indicate a fundamental issue with the index definitions or Appwrite instance`));
|
262
285
|
return false;
|
263
286
|
}
|
264
287
|
|
package/src/interactiveCLI.ts
CHANGED
@@ -2052,7 +2052,10 @@ export class InteractiveCLI {
|
|
2052
2052
|
MessageFormatter.info("Starting comprehensive transfer configuration...", { prefix: "Transfer" });
|
2053
2053
|
|
2054
2054
|
try {
|
2055
|
-
// Initialize controller to optionally load config if available (supports both YAML and TypeScript configs)
|
2055
|
+
// Initialize controller to optionally load config if available (supports both YAML and TypeScript configs)
|
2056
|
+
await this.initControllerIfNeeded();
|
2057
|
+
|
2058
|
+
// Check if user has an appwrite config for easier setup
|
2056
2059
|
const hasAppwriteConfig = this.controller?.config?.appwriteEndpoint &&
|
2057
2060
|
this.controller?.config?.appwriteProject &&
|
2058
2061
|
this.controller?.config?.appwriteKey;
|
@@ -331,7 +331,9 @@ export class ComprehensiveTransfer {
|
|
331
331
|
|
332
332
|
if (!attributesSuccess) {
|
333
333
|
MessageFormatter.error(`Failed to create some attributes for collection ${collection.name}`, undefined, { prefix: "Transfer" });
|
334
|
-
|
334
|
+
MessageFormatter.error(`Skipping index creation and document transfer for collection ${collection.name} due to attribute failures`, undefined, { prefix: "Transfer" });
|
335
|
+
// Skip indexes and document transfer if attributes failed
|
336
|
+
continue;
|
335
337
|
} else {
|
336
338
|
MessageFormatter.success(`All attributes created successfully for collection ${collection.name}`, { prefix: "Transfer" });
|
337
339
|
}
|
@@ -349,7 +351,7 @@ export class ComprehensiveTransfer {
|
|
349
351
|
|
350
352
|
if (!indexesSuccess) {
|
351
353
|
MessageFormatter.error(`Failed to create some indexes for collection ${collection.name}`, undefined, { prefix: "Transfer" });
|
352
|
-
|
354
|
+
MessageFormatter.warning(`Proceeding with document transfer despite index failures for collection ${collection.name}`, { prefix: "Transfer" });
|
353
355
|
} else {
|
354
356
|
MessageFormatter.success(`All indexes created successfully for collection ${collection.name}`, { prefix: "Transfer" });
|
355
357
|
}
|