OriginChain docs
examples · ask · 2 / 6

2. Narrow with a schemas hint

← Ask examples
what this does

Same endpoint as the simple count, but the body now includes a "schemas" array. The compiler only considers the schemas you list - it never has to disambiguate against schemas in other namespaces.

when to use it
  • You know which table the question is about - typical for app code where the surface is constrained.
  • You have multiple namespaces in the same tenant and the same noun appears in more than one (crm.customers vs shop.customers).
  • You're in a hot path and want compile cost to be a function of N schemas you control, not the whole tenant catalog.

The hint is included in the plan-cache key. Two calls with the same question but different schemas lists are different cache entries.

the schema

Register this once with POST /v1/tenants/:t/schemas.

namespace   = "shop"
table       = "customers"
primary_key = ["id"]

[[columns]]
name = "id"
ty   = "str"
required = true

[[columns]]
name = "email"
ty   = "str"

[[columns]]
name = "tier"
ty   = "str"

[[indexes]]
name    = "by_tier"
columns = ["tier"]
seed data
# Seed customers across two tiers so the count below is non-trivial.
curl -X POST "https://$OC_HOST/v1/tenants/$OC_TENANT/rows/shop.customers/_batch" \
  -H "Authorization: Bearer $OC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '[
    { "id": "c_1", "email": "alice@example.com", "tier": "gold" },
    { "id": "c_2", "email": "bob@example.com",   "tier": "silver" },
    { "id": "c_3", "email": "carol@example.com", "tier": "gold" },
    { "id": "c_4", "email": "dan@example.com",   "tier": "silver" }
  ]'
the request
POST /v1/tenants/:t/ask
curl -X POST "https://$OC_HOST/v1/tenants/$OC_TENANT/ask" \
  -H "Authorization: Bearer $OC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "nl":      "how many gold-tier customers do I have?",
    "schemas": ["shop.customers"]
  }'
what you get back
{
  "rows": [
    { "count": 2 }
  ],
  "cache": "miss"
}

The shape is the same as the unhinted call - rows and cache. The difference is that the compiler walked one schema, not the whole tenant.

how it works
  • The schemas list is part of the cache key - same question, different schemas list, different entry.
  • The compiler sees only the listed schemas in its catalog. Tables in other namespaces are invisible for this call.
  • Recognising "gold-tier" hits the tier column. Because there's a by_tier index, the plan becomes Aggregate(count) → IndexScan(tier = "gold").
  • Fewer schemas = a smaller compile prompt and a smaller search space for join planning, so first-call latency drops.
common mistakes
  • Listing only one side of a join. If the question implies a join across two schemas, both must be in the schemas list. Otherwise the compiler can't see the relation and falls back to no_plan_compiled.
  • Bare table name without namespace. Schemas are addressed as namespace.table. "customers" alone returns 400 unknown_schema.
  • Expecting it to change rows. The hint changes which plans the compiler considers, not the results. If the hint is satisfiable, you get the same answer as the unhinted call - just compiled faster.