SemiLayerDocs

Query — Predicates

The where clause accepts a Record<string, unknown>. At the top level, keys AND together; per-field values can be a literal (equality) or an object with one of the supported operators.

Equality

The simplest shape. Direct equality on one or more fields:

await beam.products.query({
  where: { category: 'footwear', in_stock: true },
})
// Postgres equivalent: WHERE category = 'footwear' AND in_stock = true

Top-level keys always AND.

Operators

Wrap a value in an object to use a range or set operator. The grammar uses Mongo-style $ prefixes:

OperatorMeaningExample
$eqEqual (rarely needed — bare value works){ status: { $eq: 'open' } }
$inValue is one of an array{ status: { $in: ['open', 'triaged'] } }
$gt, $gteGreater than, greater-or-equal{ rating: { $gte: 4 } }
$lt, $lteLess than, less-or-equal{ price: { $lt: 100 } }

Combine operators on one field with an object:

await beam.products.query({
  where: {
    price: { $gte: 20, $lt: 100 },     // 20 ≤ price < 100
    category: { $in: ['footwear', 'apparel'] },
    in_stock: true,
  },
})
ℹ️

Nested or / top-level arbitrary AND/OR grouping is roadmapped. For v0.1, compose on the client: run two narrower query() calls and merge, or pass result IDs to a follow-up call. For complex filters that a human would write in SQL — reach for include with where on the joined lens, or use a view in your source DB.

Full example

queryreviews
reviews: {
  source: 'main-db',
  table: 'public.reviews',
  fields: {
    id:            { type: 'number',  primaryKey: true },
    product_id:    { type: 'number' },
    author:        { type: 'text' },
    rating:        { type: 'number' },
    verified:      { type: 'boolean' },
    helpful_count: { type: 'number' },
  },
  grants: { query: 'public' },
}

orderBy

A single rule or an array (applied in order):

// Single
orderBy: { field: 'placed_at', dir: 'desc' }

// Multiple — first tiebreaker first
orderBy: [
  { field: 'priority',  dir: 'desc' },
  { field: 'placed_at', dir: 'asc' },
]

Default direction is 'asc'. Default ordering is whatever the bridge returns if you omit orderBy entirely — which is not guaranteed stable for pagination. Always set orderBy if you're going to paginate.

select

Restrict the projection to specific fields. Cheaper over the wire and often cheaper to compute.

await beam.products.query({
  where: { category: 'footwear' },
  select: ['id', 'name', 'price'],     // only these fields in the result
  limit: 50,
})

Omit select to get all fields declared on the lens. Selecting a field not declared on the lens is a validation error (422).

Beyond: joining across lenses

For "products with their recent reviews", reach for include:

await beam.products.query({
  where: { category: 'footwear' },
  include: {
    reviews: {
      where:   { rating: { $gte: 4 } },
      orderBy: { field: 'helpful_count', dir: 'desc' },
      limit:   3,
    },
  },
})

The full join grammar lives in Joins → Include Syntax.

Next: Pagination — handling more rows than fit in a single response.