Cookbook

Add a ViewModel

  1. Create your target table (includes _sync_sequence_id, _sync_* internals).
  2. Write the projector function (returns composite rows for given keys).
  3. Register sources, watched columns, and key maps.
  4. Run synctable validate.
  5. Run synctable bootstrap to 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