1. Overview
Goal
pg_liquid maps the Liquid blog language and data model into PostgreSQL
without inventing a separate public API surface.
Shipped Interface
The extension exports:
liquid.query(program text)
liquid.query_as(principal text, program text)
liquid.read_as(principal text, program text)
liquid.create_row_normalizer(source_table regclass, normalizer_name text, compound_type text, role_columns jsonb, backfill boolean default true)
liquid.drop_row_normalizer(source_table regclass, normalizer_name text, purge boolean default true)
liquid.rebuild_row_normalizer(source_table regclass, normalizer_name text)
program is a Liquid Datalog program containing:
%comments.-terminated assertions and rule definitions- one terminal
?query - bare variables and
_ - quoted string constants
Edge(...)Type@(cid=..., role=...)
Deliberate Scope
Implemented:
- graph-backed bootstrap schema
- query-local rule evaluation
- relative-identity compounds
- table-to-compound normalization through row triggers
- trusted-principal query and read wrappers plus session-principal CLS filtering with explicit grants, derived policy compounds, and inherited
liquid/acts_forprincipal scope - install and upgrade support
- regression coverage for blog examples and parser/compound/tombstone edge cases
Not implemented:
- subgraph query APIs
- parallel custom scan execution
- persisted global rules
PostgreSQL-Specific Tradeoffs
This implementation uses PostgreSQL tables and indexes rather than Liquid’s custom in-memory storage engine. That means:
- MVCC still applies
- physical storage is relational
- equality-heavy probes are improved with both btree and hash indexes
- the execution engine relies on in-memory caches and adaptive constraint ordering rather than a custom storage access method