Overview
PostgREST query builder, filters, modifiers, and RPC.
The database surface is the PostgREST query builder reachable through the top-level Supabase::Client. Every chain starts with supabase.from(table), then adds a verb (select / insert / update / upsert / delete), optional filters and modifiers, and ends with .execute to fire the request.
supabase = Supabase.create_client(
supabase_url: ENV.fetch("SUPABASE_URL"),
supabase_key: ENV.fetch("SUPABASE_ANON_KEY")
)
response = supabase
.from("countries")
.select("id, name")
.eq("continent", "Africa")
.order("name")
.limit(20)
.execute
response.data # => [{ "id" => 1, "name" => "Algeria" }, ...]
response.count # => nil unless you asked for count: "exact"supabase.from returns a RequestBuilder; calling a verb returns a sub-builder that mixes in FilterMixin (every filter you'd expect from PostgREST) and, for select, SelectMixin (order / limit / offset / range). Nothing hits the wire until .execute.
Builders
| Method | Description |
|---|---|
from | Open a builder for a table. from_ and table are aliases. |
select | Read rows. Accepts a column list, count:, and head:. |
insert | Insert one row (Hash) or many (Array<Hash>). |
update | Patch rows that match the chained filters. |
upsert | Insert-or-update via Prefer: resolution=merge-duplicates. |
delete | Delete rows that match the chained filters. |
rpc | Call a stored procedure (POST by default, GET / HEAD opt-in). |
schema | Switch the active Postgres schema. Returns a new client. |
Filters
Filter methods are mixed into every verb builder. They mutate the request and return self so they chain. Every PostgREST operator is exposed.
| Method | PostgREST operator |
|---|---|
eq | eq |
neq | neq |
gt | gt |
gte | gte |
lt | lt |
lte | lte |
like | like |
ilike | ilike |
like_all_of | like(all) |
like_any_of | like(any) |
ilike_all_of | ilike(all) |
ilike_any_of | ilike(any) |
is_ | is (null / true / false) |
in_ | in |
contains | cs |
contained_by | cd |
overlaps | ov |
range_lt / range_gt / range_gte / range_lte / range_adjacent | sl / sr / nxl / nxr / adj |
fts / plfts / phfts / wfts | full-text search variants |
text_search | high-level FTS helper (sets type: / config:) |
match | eq over every key in a Hash |
or_ | grouped OR clause (reference_table: for joins) |
not_ | negate the next filter |
filter | escape hatch — pass operator / criteria verbatim |
max_affected | cap the number of rows a write may touch |
Modifiers
Modifiers are added by SelectMixin. They apply to select (and rpc) builders.
| Method | Description |
|---|---|
order | ORDER BY column ASC/DESC. foreign_table: orders an embedded relation. |
limit | LIMIT n. foreign_table: limits an embedded relation. |
offset | OFFSET n. |
range | Inclusive start..finish (sets offset + limit). |
Result-shape switchers
These live on the select builder and change how the response is parsed.
| Method | Description |
|---|---|
single | Expect exactly one row; raise if the row count is not 1. |
maybe_single | Expect 0 or 1 row; nil on 0, raise on more than 1. |
csv | Return the body as CSV text instead of JSON. |
explain | Return the PostgREST query plan instead of executing. |
Executing a chain
Every builder returns from each step so you can keep chaining. The wire request only fires when you call .execute, which returns a Supabase::Postgrest::APIResponse with two readers:
data— the parsed JSON body (typically anArray<Hash>;Hashforsingle).count— populated only when you opted in withcount: "exact" | "planned" | "estimated".
A non-2xx response raises Supabase::Postgrest::Errors::APIError. The error carries :message, :code, :details, and :hint and accepts both string and symbol keys.
begin
supabase.from("countries").select("*").eq("id", -1).single.execute
rescue Supabase::Postgrest::Errors::APIError => e
e.code # => "PGRST116" (no rows)
e.message # => "Cannot coerce the result to a single JSON object"
end