Three new test methods in MigrationsBase, following the existing
testCreateCSVImport setup pattern:
- testCreateCSVImportSkipDuplicates
Seeds documents.csv, mutates one row, re-imports with skip=true.
Asserts the mutated row keeps its mutated value (not overwritten
by the CSV's original value) and the row count stays at 100.
- testCreateCSVImportOverwrite
Seeds documents.csv, mutates one row, re-imports with overwrite=true.
Asserts the mutated row is restored to the CSV's original value
(proving upsertDocuments actually replaced the row) and the row
count stays at 100.
- testCreateCSVImportDefaultFailsOnDuplicate
Regression guard: re-imports documents.csv with no flags. Asserts
the migration goes to status=failed with errors populated, proving
the default duplicate-throws behavior is preserved.
All three share a prepareCsvImportFixture() helper that sets up
database + table (name, age columns) + bucket + documents.csv
upload. Returns the known first-row id + original name/age so tests
can mutate and assert on a predictable row.
Reuses the existing documents.csv fixture (100 rows with \$id as the
first column). No new fixture files needed.
Exposes two new optional boolean params on the three migration
creation endpoints so CSV / JSON / appwrite-to-appwrite imports can
choose how to handle rows whose IDs already exist at the destination.
Endpoints updated (app/controllers/api/migrations.php):
- POST /v1/migrations/appwrite
- POST /v1/migrations/csv/imports
- POST /v1/migrations/json/imports
Parameter semantics:
- overwrite=true -> destination uses upsertDocuments instead of
createDocuments; existing rows are replaced
with imported values
- skip=true -> destination wraps createDocuments in
skipDuplicates; existing rows are preserved
unchanged, duplicate-id rows silently no-op
- both false -> default; fails fast on DuplicateException
(original behavior, unchanged)
- both true -> overwrite wins (upsert subsumes skip)
Both params are stored in the migration Document's options array
(matches the existing pattern for destination behavior config like
path, size, delimiter, bucketId, etc.) and read back in the worker's
processDestination() to instantiate DestinationAppwrite with the
new constructor params.
Feature-branch note: depends on utopia-php/migration#feat/skip-duplicates
(DestinationAppwrite constructor params) which in turn depends on
utopia-php/database#852 (skipDuplicates scope guard). composer.json is
temporarily pinned to dev-feat/skip-duplicates and
dev-csv-import-upsert-v2 respectively; both must be reset to proper
release versions once the upstream PRs merge.