Melange v0.10.3
Melange v0.10.3 is a tooling release. melange doctor gives index advice you can apply as written, melange migrate removes all of a deleted relation’s functions, and paths in melange.yaml work from any directory of your project. Studio gets a redesigned History page and an easier-to-read Tuples browser. The generated SQL is unchanged.
Upgrading
The permission functions are the same as in v0.10.2, so nothing about access changes. Run melange migrate after upgrading anyway:
- It records the new codegen version, which clears doctor’s “Codegen version has changed” warning.
- It drops any
expand_*andexplain_*functions left behind when you removed or renamed relations on an earlier version (see below).
One behaviour change: relative paths in a discovered melange.yaml now resolve against the project root rather than the current directory. From the project root nothing changes. See Config paths.
Doctor’s index advice
When melange_tuples is a view over your own tables, its performance depends on indexes on those tables. Two of doctor’s checks gave advice you couldn’t apply as written; both now name the index to create.
Columns cast to text
Doctor asked for a ::text expression index on every column the view casts to text. That’s needed for char(n), uuid and numeric columns, whose cast converts the value. For varchar it isn’t: casting varchar to text only relabels the value, so Postgres already uses an ordinary index on the column for col::text = $1.
Doctor now reads each column’s type:
- A
varcharortextcolumn with a plain index raises no warning. - One with no index gets a plain
CREATE INDEX … (col)hint. - Other types still get the expression-index hint, now with the reason.
On one production schema this removed 16 warnings that each asked for a redundant index.
Composite indexes on source tables
For a view, doctor used to print the DDL it would use for a table, with “Replace ‘melange_tuples’ with the actual table name”. That couldn’t be done: your tables don’t have object_type or subject_type columns, which are constants in each branch of the view, and the check passed without looking at anything.
Doctor now reads each branch of the view and works out the index its object lookups need on the real table. That’s the object id column, then the relation if a column holds it, then the subject id column:
⚠ Missing index on organization_users (organization_id, (user_id::text)) for object lookups
Fix: CREATE INDEX idx_organization_users_by_object ON organization_users (organization_id, (user_id::text));It only warns when no existing index covers the lookup. It skips tables where the object or subject column is unique (such as a primary key), branches that join tables, and ids that are computed rather than read from a column.
On a membership table with 10,000 members per organization, this index took a permission check from reading every member (3.2 ms) to a single-row index scan (0.4 ms).
Other doctor fixes
- Modular schemas: doctor no longer reports “Schema file has changed since last migration” right after you migrate. It was hashing only the
fga.modmanifest; it now hashes the manifest and every module, asmigrateandstatusdo. - Codegen version: doctor no longer reports a change when only the
vprefix differs. Release binaries record0.10.3, whilego installbuilds recordv0.10.3.
Migrate removes every function of a removed relation
When a relation was removed or renamed, melange migrate dropped its check_ and list_ functions but left its expand_ and explain_ functions behind. Doctor then reported them as orphans on every run, and migrate --force didn’t clear them.
Migrate now removes all four kinds. It only drops functions that a previous migration recorded, so a function of your own whose name happens to start with check_ or explain_ is never touched.
Config paths work from any directory
Melange finds melange.yaml by walking up from the current directory, but it then read relative paths in the file against the current directory. A config at the repository root worked only from the root, and from a subdirectory status reported the schema missing.
Relative paths in a discovered config now resolve against the directory the config was found from. That’s the directory holding melange.yaml, or the one holding melange/ for melange/config.yaml (what melange init writes). This applies to schema, an environment’s schema, and the generate output paths.
Paths in a file passed with --config, and values from flags and MELANGE_* variables, stay relative to the current directory. See Relative paths.
Studio
History
The History page is now a list of migrations on the left and one migration in detail on the right:
- The list shows each migration’s line changes and a short summary of model changes (
+1 type · +4 rel · ~2 rel). Badges mark breaking changes, and the list notes migrations that changed nothing or restored an earlier schema. - The detail counts the changed lines, types and relations. It lists the grants each relation lost and gained, marking breaking changes as
melange statusdoes, and shows a line diff against the previous migration. For a modular schema, the diff is file by file with each module’s own line numbers.
Tuples browser
- Ids lead: entities read
[type] id label. Long labels and ids are cut off with an ellipsis instead of wrapping one word per line or overlapping their neighbours. - Access tabs: Can access and Accessed by list each entity with its relations underneath, and more than 12 collapse behind +N more.
- Direct tuples: relation, type, id and label columns, and clicking a row opens the entity at its other end.
- More labels: column names match regardless of case, and studio falls back to any column ending in
name, then todescription. View branches that choose the type with aCASEexpression are labelled too.
Fixes
- Relation pages on Postgres 13: the generated SQL failed to load with
function array_position(name[], text) does not exist. Postgres 13 is below melange’s supported minimum of 14, but the page now works there. - Health without a schema file: run with no config, studio checked a default
schemas/schema.fgaand failed the Schema File check for a file nobody asked for. It now uses a schema only when you configure one, and otherwise skips those checks.
See the Studio guide for the full tour.
Try it out
# Upgrade the CLI
brew upgrade pthm/tap/melange # Homebrew
scoop update melange # Scoop
go install github.com/pthm/melange@v0.10.3
# Or pull the container image
docker pull ghcr.io/pthm/melange:v0.10.3
# Then record the new version and clean up leftover functions
melange migrate
melange doctorSee the installation guide for every channel.
Feedback
Open an issue for bugs or feature requests, and report security issues through private vulnerability reporting.
