mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
fix(migrations): resolveResourceIds preserves single-root semantics
Cloud's backup migrations write resourceId=databaseId, resourceType="database" — a single root resource with no child filter. The previous resolveResourceIds() unconditionally treated resourceId as the leaf (collection/table), so for backup docs it returned ["", databaseId] and Transfer::run was invoked with rootResourceId="", rootResourceChildId=databaseId. Sources/Appwrite then tried to filter tables by id=databaseId and matched zero, producing empty backups and restore failures. Resolve to [rootResourceId, rootResourceChildId] now: - parentResourceId set → [parent, leaf] (new-shape CSV/JSON) - resourceId is "x:y" → split (legacy CSV/JSON) - otherwise → [resourceId, ''] (backup, full imports) CSV/JSON paths still see [database, collection]. Backup paths now correctly see [database, ''] so the upstream lib filters to just that database with no leaf scope. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
acaf2f7900
commit
17c1e8d570
@@ -615,29 +615,37 @@ class Migrations extends Action
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve [databaseId, tableId] from a migration document.
|
||||
* Resolve [rootResourceId, rootResourceChildId] from a migration document.
|
||||
*
|
||||
* Handles three input shapes so a 1.9.4 worker keeps working before V25
|
||||
* has run, while in-flight migrations enqueued on 1.9.3 drain, and after
|
||||
* a backup taken on 1.9.3 is restored:
|
||||
* - 1.9.4 (post-backfill): parentResourceId/resourceId set separately.
|
||||
* - 1.9.3 (legacy): resourceId is the composite "{databaseId}:{tableId}",
|
||||
* parentResourceId is empty.
|
||||
* - 1.9.4 mid-backfill: V25 attributes added but a given doc not yet
|
||||
* rewritten, same as the legacy case.
|
||||
* Returns the root resource ID (e.g. databaseId for CSV/JSON or backup
|
||||
* migrations) and an optional child filter under that root (the
|
||||
* collection/table ID for CSV/JSON migrations). Three input shapes:
|
||||
*
|
||||
* - 1.9.4 CSV/JSON migration: parentResourceId is set to the root,
|
||||
* resourceId is the leaf. Returns [parent, leaf].
|
||||
* - Pre-1.9.4 CSV/JSON migration (V25 not yet run, queue drain after
|
||||
* upgrade, restored backup): resourceId is the composite
|
||||
* "{databaseId}:{tableId}", parentResourceId is empty. Split it.
|
||||
* - Single-root migration (Backup, full Appwrite/Supabase/Firebase/
|
||||
* NHost imports): resourceId is the root resource ID with no leaf.
|
||||
* Returns [root, ''].
|
||||
*
|
||||
* @return array{0: string, 1: string}
|
||||
*/
|
||||
protected function resolveResourceIds(Document $migration): array
|
||||
{
|
||||
$databaseId = (string) $migration->getAttribute('parentResourceId', '');
|
||||
$tableId = (string) $migration->getAttribute('resourceId', '');
|
||||
$parent = (string) $migration->getAttribute('parentResourceId', '');
|
||||
$resource = (string) $migration->getAttribute('resourceId', '');
|
||||
|
||||
if ($databaseId === '' && \str_contains($tableId, ':')) {
|
||||
[$databaseId, $tableId] = \explode(':', $tableId, 2);
|
||||
if ($parent !== '') {
|
||||
return [$parent, $resource];
|
||||
}
|
||||
|
||||
return [$databaseId, $tableId];
|
||||
if (\str_contains($resource, ':')) {
|
||||
return \explode(':', $resource, 2);
|
||||
}
|
||||
|
||||
return [$resource, ''];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user