SemiLayerDocs

Query — Quickstart

From "I have a lens" to "I can read through the bridge" in three moves.

queryorders
orders: {
  source: 'main-db',
  table: 'public.orders',
  fields: {
    id:          { type: 'number',  primaryKey: true },
    customer_id: { type: 'number' },
    status:      { type: 'enum',    values: ['pending', 'shipped', 'delivered', 'cancelled'] },
    total_cents: { type: 'number' },
    placed_at:   { type: 'date' },
  },
  grants: {
    query: 'authenticated',   //  scope to signed-in users
  },
}

Three moves

Opt in with grants.query

Add query to the lens's grants block. Values match the standard access-rule vocabulary:

orders: {
  // ... fields, etc.
  grants: {
    query: 'authenticated',   // any signed-in user
    // query: 'public',       // no auth required (careful — this reads your DB)
    // query: 'staff',        // custom claim check, see Auth & RBAC
  },
}

Without this, beam.orders.query doesn't exist at the type level, and the HTTP endpoint returns 403.

Push

semilayer push

push re-validates the config and makes query() available for the lens. No ingest re-run is needed — query doesn't touch the vector index.

Call from your app

import { beam } from './beam'

const { rows, meta } = await beam.orders.query({
  where: { status: 'shipped' },
  orderBy: { field: 'placed_at', dir: 'desc' },
  limit: 20,
})
// rows[0].customer_id is number (typed from your config)
// meta.durationMs gives you end-to-end latency

That's it — the call proxies through SemiLayer to your bridge, which runs the underlying SQL and streams rows back.

What comes back

Every query returns { rows, meta }:

interface QueryResponse<M> {
  rows: M[]           // each row typed from your lens's field definitions
  meta: {
    lens: string      // e.g. 'orders'
    count: number     // number of rows in this response
    total?: number    // total matching — when the bridge reports it
    nextCursor?: string  // opaque cursor for the next page (cursor mode)
    durationMs: number
  }
}

Common errors

CodeMeaningLikely cause
403Access deniedgrants.query not set, or the user's role doesn't satisfy the rule
422 SOURCE_QUERY_FAILEDBridge rejected the queryColumn doesn't exist, type mismatch, invalid operator
502 SOURCE_UNREACHABLEYour DB is down or unreachableCredentials expired, network partition, source paused
504 QUERY_TIMEOUTQuery took longer than 30sMissing index on a where column, or pull-too-many-rows

Next: Predicates — the full where grammar.