fix(core): surface missing deleted_at column in admin content list#1079
fix(core): surface missing deleted_at column in admin content list#1079eyupcanakman wants to merge 1 commit into
Conversation
🦋 Changeset detectedLatest commit: 4394173 The changes in this PR will be included in the next version bump. This PR includes changesets to release 13 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/blocks
@emdash-cms/cloudflare
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
There was a problem hiding this comment.
Pull request overview
This PR improves debuggability of admin content listing failures when an ec_{collection} table exists but is missing the deleted_at column expected by ContentRepository.findMany(). Instead of returning the generic CONTENT_LIST_ERROR, the API now surfaces a specific COLLECTION_SCHEMA_MISMATCH error so operators can identify schema drift / non-migrated tables.
Changes:
- Add cross-dialect detection for “missing column” DB errors via
isMissingColumnError(error, column?). - Update
handleContentListto returnCOLLECTION_SCHEMA_MISMATCHwhen the missing column is specificallydeleted_at. - Add unit tests covering the new DB error helper and the content list handler behavior; add a changeset and map the new error code to HTTP 500.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| packages/core/src/utils/db-errors.ts | Adds isMissingColumnError helper for SQLite/D1 and Postgres missing-column messages. |
| packages/core/src/api/handlers/content.ts | Detects missing deleted_at column and returns COLLECTION_SCHEMA_MISMATCH instead of a generic list error. |
| packages/core/src/api/errors.ts | Registers the new error code and maps it to HTTP 500. |
| packages/core/tests/unit/utils/db-errors.test.ts | Adds test coverage for isMissingColumnError (dialects, case handling, column scoping, non-Error inputs). |
| packages/core/tests/unit/api/content-handlers.test.ts | Adds regression tests for missing-deleted_at schema mismatch vs. unrelated unknown-column failures (e.g., orderBy). |
| .changeset/fix-content-list-missing-deleted-at-column.md | Adds a patch changeset documenting the behavior change. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
handleContentList only special-cased a missing table, so a backing
ec_{collection} table without the deleted_at column threw "no such
column" and fell through to a generic CONTENT_LIST_ERROR, hiding
published content from editors with no diagnostic.
Detect the missing deleted_at column and return
COLLECTION_SCHEMA_MISMATCH naming the collection. isMissingColumnError
mirrors isMissingTableError and takes an optional column scope so an
unrelated unknown-column error still returns the generic error.
Closes emdash-cms#709
2c33c51 to
4394173
Compare
What does this PR do?
Fixes #709, where the admin content list silently breaks when a collection's backing
ec_{collection}table is missing thedeleted_atcolumn.ContentRepository.findManyalways filters withWHERE deleted_at IS NULL. When the table was provisioned outside EmDash's migrations (for example a custom import script or schema drift on an old install) and has nodeleted_atcolumn, SQLite/D1 throwsno such column: deleted_at.handleContentListonly special-cased a missing table viaisMissingTableError, so a missing column fell through to the genericCONTENT_LIST_ERROR("Failed to list content"). An editor just sees published content go missing with nothing pointing at the cause.The list handler now detects the missing
deleted_atcolumn and returnsCOLLECTION_SCHEMA_MISMATCHnaming the collection, so the operator can tell the table does not match the expected schema. A newisMissingColumnErrorinutils/db-errors.tsmirrors the existingisMissingTableError. It takes an optional column argument, and the handler passes"deleted_at"so an unknown-column error from something else (such as ordering by a field a collection does not define) still returns the generic error rather than the wrong message.The HTTP status stays 500. The issue's suggested fix asks for a 500 with a diagnostic message, and this path already returned 500, so only the error code is more specific now. I looked at 404 and 409 but kept 500 to match what the issue asked for. The public delivery path in
loader.tsis left unchanged: it returns empty on a pre-migration database by design, and the issue notes the bot-facing surface is unaffected.Closes #709
Type of change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runCOLLECTION_NOT_FOUND.AI-generated code disclosure
Screenshots / test output
New tests:
tests/unit/utils/db-errors.test.tscoversisMissingColumnError(SQLite/D1, Postgres, case handling, non-Error inputs, the optional column argument).tests/unit/api/content-handlers.test.tscovers the missing-deleted_attable returningCOLLECTION_SCHEMA_MISMATCH, and a healthy collection ordered by a field it does not define still getting the generic error.