feat(types): declare bucket_id, size and filename on the upload and image domains - #116
Merged
Conversation
…mage domains The documents are projections of a files row, so the contract now constrains the keys the platform actually resolves storage with. bucket_id must parse as a canonical uuid; size and filename get json type checks. Every key stays optional, so url-only external references keep validating.
Contributor
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
Base automatically changed from
feat/sync-constructive-db-catalog-assertions
to
main
August 7, 2026 23:31
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
public.upload/public.imagedocuments are projections of afilesrow ({id, key, mime, bucket_id, size, filename, versions}, constructive-planning#1476), but the domain contract only constrainedbucket— the bucket name — and said nothing aboutbucket_id, the uuid the platform actually resolves storage with. A document could carry a garbagebucket_idand validate fine.This widens both checks; nothing becomes required, so url-only external references and every existing document keep validating:
sizeandfilename: yes, they belong. #1476 lists both in the authoritativefilesshape and in the projection the upload path is supposed to write (#1477 shows today's client droppingfileId/keyand persisting a presigned url instead). Constraining them costs nothing, is a widening, and stops asize: "12345"string from silently entering the projection.Why a regex and not
::uuid. A domain CHECK must be immutable and cannot trap an error, so a cast would abort the statement instead of rejecting the row, andjsonb_typeof(...) = 'string'alone accepts"not-a-uuid". The regex demands the canonical 8-4-4-4-12 hex form — deliberately stricter than PostgreSQL's uuid input (which also accepts braces/unhyphenated), because every producer here writesuuid::text. Non-string json fails too:->>renders12345as'12345', which the pattern rejects.Why a new change rather than editing
domains/upload. pgpm is deterministic — already-deployed databases never re-run a change, so editing the originalCREATE DOMAINwould silently leave them on the old contract. Insteadschemas/public/domains/{upload,image}_file_ref_keyssits on top of it and rewrites the constraint by name:upload_checkis exactly the name PostgreSQL gave the anonymous CHECK in the original change, soassert_domain('public.upload'::regtype, 'jsonb'::regtype, _constraints => 1)still holds and the revert restores the previous predicate verbatim. Verify does not just look at the catalog: it casts a full projection, a non-uuidbucket_id, a stringsizeand a url-only document, and fails if the contract disagrees.Testing
packages/types: 39 tests pass (describe.each(['upload','image'])covers full projection accepted, non-uuid / unhyphenated / non-stringbucket_idrejected,size/filenametyped, url-only still accepted, all keys optional).pgpm test-packages --full-cycleacross the workspace: all modules deploy → verify → revert clean.sql/pgpm-types--0.39.0.{sql,bundle.tar.gz}regenerated withpgpm package.Based on #115 (the sync PR), which this needs for the 0.39.0 line and the
assert_*verify style.Link to Devin session: https://app.devin.ai/sessions/43b0b10711174fa49d51907bf2b0c25f
Requested by: @pyramation