Cookbook
Add a ViewModel
- Create your target table (includes
_sync_sequence_id,_sync_*internals). - Write the projector function (returns composite rows for given keys).
- Register sources, watched columns, and key maps.
- Run
synctable validate. - Run
synctable bootstrapto seed.
-- Register the ViewModel
INSERT INTO synctable.viewmodel (view_id, target_relid, key_columns, strategy, projector_fn)
VALUES ('sales.order_summary', 'mv_order_summary'::regclass,
ARRAY['organization_id','customer_id'], 'INCREMENTAL',
'synctable.project_order_summary');
-- Attach capture on source tables
SELECT synctable.attach_capture('orders'::regclass);
SELECT synctable.attach_capture('order_items'::regclass);
-- Register source with watched columns
INSERT INTO synctable.view_source (view_id, source_relid, watched_columns, key_map_sql)
VALUES ('sales.order_summary', 'orders'::regclass,
ARRAY['status','amount_due'],
$SELECT jsonb_build_object('organization_id', organization_id, 'customer_id', customer_id)$);Compose VMs
A ViewModel can consume another VM as a source. Add a dependency_edge row and the DAG ensures parent views refresh before children.
INSERT INTO synctable.dependency_edge (parent_view_id, child_view_id, key_map_sql)
VALUES ('sales.order_summary', 'billing.customer_tier',
$SELECT jsonb_build_object('organization_id', organization_id, 'user_id', customer_id)$);Subscribe from the server
import { createSynctable } from '@synctable/core/server'
const st = createSynctable({
connectionString: process.env.DATABASE_URL!,
models: [orderSummary],
authorize: authorizeScope,
})
await st.start()
// boots: outbox drain, subscriber, Graphile Worker