@njdamstra/appwrite-utils-cli 1.11.6 → 1.11.7

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.
@@ -275,6 +275,27 @@ export async function executeMigrationPlan(adapter, options) {
275
275
  MessageFormatter.error(` ${entry.attributeKey}: FAILED — ${cpEntry.error}`, undefined, { prefix: "Execute" });
276
276
  }
277
277
  }
278
+ // Restore required flags after all attributes in this collection are done.
279
+ // This must happen AFTER all migrations to avoid partial-update validation
280
+ // errors (Appwrite rejects updateRow if a required attribute is missing
281
+ // from the payload, even for partial updates).
282
+ const completedRequired = entries.filter((e) => {
283
+ const cp = findCheckpointEntry(checkpoint, e);
284
+ return cp?.phase === "completed" && e.isRequired;
285
+ });
286
+ for (const entry of completedRequired) {
287
+ try {
288
+ await tryAwaitWithRetry(() => adapter.updateAttribute({
289
+ databaseId: entry.databaseId,
290
+ tableId: entry.collectionId,
291
+ key: entry.attributeKey,
292
+ required: true,
293
+ }));
294
+ }
295
+ catch {
296
+ MessageFormatter.info(` Warning: could not set ${entry.attributeKey} back to required`, { prefix: "Execute" });
297
+ }
298
+ }
278
299
  // After collection completes, offer to update local YAML
279
300
  const successInGroup = entries.filter((e) => {
280
301
  const cp = findCheckpointEntry(checkpoint, e);
@@ -426,21 +447,8 @@ async function migrateOneAttribute(adapter, entry, cpEntry, checkpoint, checkpoi
426
447
  advance("backup_deleted");
427
448
  }
428
449
  // Step 9: Mark completed
429
- // If the original attribute was required, update it now (after data is in place)
430
- if (entry.isRequired) {
431
- try {
432
- await tryAwaitWithRetry(() => adapter.updateAttribute({
433
- databaseId,
434
- tableId: collectionId,
435
- key: attributeKey,
436
- required: true,
437
- }));
438
- }
439
- catch {
440
- // Non-fatal — attribute is migrated, just not set back to required
441
- MessageFormatter.info(` Warning: could not set ${attributeKey} back to required`, { prefix: "Migrate" });
442
- }
443
- }
450
+ // NOTE: required flag is restored AFTER all attributes in the collection
451
+ // are migrated, to avoid partial-update validation errors on other attributes.
444
452
  advance("completed");
445
453
  }
446
454
  // ────────────────────────────────────────────────────────
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@njdamstra/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.11.6",
4
+ "version": "1.11.7",
5
5
  "main": "dist/main.js",
6
6
  "type": "module",
7
7
  "repository": {
@@ -382,6 +382,32 @@ export async function executeMigrationPlan(
382
382
  }
383
383
  }
384
384
 
385
+ // Restore required flags after all attributes in this collection are done.
386
+ // This must happen AFTER all migrations to avoid partial-update validation
387
+ // errors (Appwrite rejects updateRow if a required attribute is missing
388
+ // from the payload, even for partial updates).
389
+ const completedRequired = entries.filter((e) => {
390
+ const cp = findCheckpointEntry(checkpoint, e);
391
+ return cp?.phase === "completed" && e.isRequired;
392
+ });
393
+ for (const entry of completedRequired) {
394
+ try {
395
+ await tryAwaitWithRetry(() =>
396
+ adapter.updateAttribute({
397
+ databaseId: entry.databaseId,
398
+ tableId: entry.collectionId,
399
+ key: entry.attributeKey,
400
+ required: true,
401
+ } as any)
402
+ );
403
+ } catch {
404
+ MessageFormatter.info(
405
+ ` Warning: could not set ${entry.attributeKey} back to required`,
406
+ { prefix: "Execute" }
407
+ );
408
+ }
409
+ }
410
+
385
411
  // After collection completes, offer to update local YAML
386
412
  const successInGroup = entries.filter((e) => {
387
413
  const cp = findCheckpointEntry(checkpoint, e);
@@ -630,25 +656,8 @@ async function migrateOneAttribute(
630
656
  }
631
657
 
632
658
  // Step 9: Mark completed
633
- // If the original attribute was required, update it now (after data is in place)
634
- if (entry.isRequired) {
635
- try {
636
- await tryAwaitWithRetry(() =>
637
- adapter.updateAttribute({
638
- databaseId,
639
- tableId: collectionId,
640
- key: attributeKey,
641
- required: true,
642
- } as any)
643
- );
644
- } catch {
645
- // Non-fatal — attribute is migrated, just not set back to required
646
- MessageFormatter.info(
647
- ` Warning: could not set ${attributeKey} back to required`,
648
- { prefix: "Migrate" }
649
- );
650
- }
651
- }
659
+ // NOTE: required flag is restored AFTER all attributes in the collection
660
+ // are migrated, to avoid partial-update validation errors on other attributes.
652
661
  advance("completed");
653
662
  }
654
663