Tutorial: Trading Demo

An end-to-end change-driven app: live prices joined against a PostgreSQL database.

The trading demo is a self-contained desktop app that embeds @drasi/lib and renders live query results in its own window — no browser, no HTTP/SSE, no REST, no Python. It’s a faithful port of drasi-server’s examples/trading demo, and it’s the best way to see every concept in this documentation working together.

The full source is in examples/trading.

What it demonstrates

  • Real PostgreSQL CDC — reference data (stocks, portfolio, watchlist) lives in a real Postgres database and is streamed into the engine via Drasi’s Postgres source (logical replication) plus a Postgres bootstrap snapshot.
  • Synthetic joinsHAS_PRICE, OWNS_STOCK, and ON_WATCHLIST relate elements across sources (and across a database and a live feed) with no foreign keys, entirely inside the query. See Concepts → Synthetic joins.
  • In-process price feed — a tiny Node random-walk generator pushes stock_prices into a JavaScript source.
  • Application reactions — one addJsReaction per query streams result diffs straight to the renderer over a single IPC channel; the dashboard merges ADD/UPDATE/DELETE/aggregation diffs into live tables.
  • Plugins downloaded at runtime — the Postgres source and bootstrap plugins are pulled from ghcr.io/drasi-project on first launch and cached locally. Nothing is baked in. See Working with plugins.

Architecture

flowchart LR
  subgraph pg[PostgreSQL - Docker]
    T1[stocks]
    T2[portfolio]
    T3[watchlist]
  end
  subgraph main[Electron main - embeds @drasi/lib]
    PS[postgres source<br/>downloaded OCI]
    PF[price-feed<br/>JS source]
    Q[5 continuous queries<br/>+ synthetic joins]
    RX[addJsReaction]
  end
  R[Electron renderer<br/>React dashboard]

  pg -->|logical replication + bootstrap| PS
  PS --> Q
  PF -->|pushChange| Q
  Q --> RX
  RX -->|IPC: trading:stream| R

The native addon is N-API v9 (ABI-stable), so it loads directly in Electron’s main process with no electron-rebuild.

The queries

Five continuous queries power the dashboard panels. Their definitions live in src/shared/queries.ts and are ported verbatim from the upstream demo:

PanelDemonstrates
Watchlist3-way synthetic join across two sources (watchlist → stocks → stock_prices) + computed change %
Portfolio P&LMulti-source join + computed fields (value, P&L, P&L %) recomputed on every tick
Top GainersWHERE filtering that re-evaluates as prices move
Sector PerformanceReal-time GROUP BY aggregation (count / sum / min / max)
Price TickerSingle-source, high-frequency feed (no joins)

Prerequisites

  • Docker Desktop running (for the PostgreSQL database).
  • Network access on first launch (to download the Postgres plugins from ghcr.io/drasi-project; cached afterwards).
  • The root @drasi/lib package built first.

Run it

# 1. Build the @drasi/lib addon from the repository root.
git clone https://github.com/drasi-project/drasi-nodejs.git
cd drasi-nodejs
npm install
npm run build

# 2. Start the demo.
cd examples/trading
npm install
npm run db:up      # start PostgreSQL (waits until healthy)
npm run dev        # launch the Electron app

Stock prices start moving immediately; the panels update live as joins and aggregations recompute. When you’re done:

npm run db:down    # stop PostgreSQL and remove its volume

How it maps to the upstream demo

Upstream (drasi-server trading)This example
PostgreSQL via docker-compose (wal_level=logical)Same (database/docker-compose.yml + trimmed init.sql)
postgres-stocks CDC source + postgres bootstrapSame plugins, downloaded from OCI at startup
HTTP price feed + Python generatorIn-process Node random-walk → JavaScript source price-feed
SSE reaction + browser EventSourceaddJsReaction → single IPC channel → renderer
REST API to create queries/reactionsDirect engine calls in main at startup