NexBase (nex_base v0.4.3)

A fluent database query builder for Elixir, modeled after the Supabase JS SDK (postgrest-js). Supports PostgreSQL and SQLite with automatic adapter detection and multiple simultaneous database connections.

Quick Start

# Single connection (simplest)
NexBase.init(url: "postgres://localhost/mydb")
NexBase.from("users") |> NexBase.select("*") |> NexBase.run()

# Multiple connections
main = NexBase.init(url: "postgres://localhost/main")
cache = NexBase.init(url: "sqlite::memory:")

main |> NexBase.from("users") |> NexBase.run()
cache |> NexBase.from("sessions") |> NexBase.run()

Supabase API parity

All PostgrestFilterBuilder, PostgrestTransformBuilder, and PostgrestQueryBuilder methods are implemented with equivalent semantics.

Summary

Functions

Returns the adapter for a connection (:postgres or :sqlite).

Supabase .containedBy(column, value) equivalent. Named contained_in/3 in Elixir for natural-language phrasing.

Supabase .contains(column, value) equivalent.

Supabase .count(mode) equivalent. Accepts :exact, :planned, or :estimated.

Supabase .csv() equivalent. Returns query results as a CSV string.

Returns the default connection, or raises if none configured.

Supabase .delete(opts) equivalent.

Supabase .eq(column, value) equivalent.

Supabase .explain(opts) equivalent.

Adds a generic filter clause. Supabase filter(column, operator, value) equivalent.

Starts a query builder for the given table. Supabase .from(table) equivalent.

Supabase .fts(column, query, opts) — plainto_tsquery full text search.

Supabase .geojson() equivalent.

Supabase .gt(column, value) equivalent.

Supabase .gte(column, value) equivalent.

Supabase .ilike(column, pattern) equivalent.

Supabase .ilikeAllOf(column, patterns) equivalent. Case-insensitive.

Supabase .ilikeAnyOf(column, patterns) equivalent. Case-insensitive.

Supabase .in(column, values) equivalent. Named in_list to avoid the reserved in/2 operator. Use filter_in/3 for a friendlier alias.

Initialize a database connection. Returns a %NexBase.Conn{} struct.

Supabase .insert(values, opts) equivalent.

Supabase .is(column, value) equivalent. Use for NULL checks and boolean columns.

Shorthand for not_filter(column, :is, nil).

Shorthand for is(column, nil).

Supabase .like(column, pattern) equivalent.

Supabase .likeAllOf(column, patterns) equivalent. Matches if the column matches ALL of the given LIKE patterns (ANDed together).

Supabase .likeAnyOf(column, patterns) equivalent. Matches if the column matches ANY of the given LIKE patterns (ORed together).

Supabase .limit(count, opts) equivalent.

Supabase .lt(column, value) equivalent.

Supabase .lte(column, value) equivalent.

Supabase .match(map) equivalent — multiple eq filters ANDed together.

Set the maximum number of rows that can be affected by an update or delete. Supabase .maxAffected(n) equivalent (PostgREST 13+).

Supabase .maybeSingle(): returns one row or nil. Raises only if >1 rows.

Supabase .maybeSingle() equivalent. Returns the query as a single unwrapped object or nil when .run()/.run!() executes. Raises only if >1 rows are returned.

Supabase .neq(column, value) equivalent.

Supabase .not(column, :ilike, pattern) convenience.

Supabase .not(column, :like, pattern) convenience.

Adds a negated filter. Supabase .not(column, operator, value) equivalent.

Supabase .not(column, :in, values) convenience. Equivalent to not_filter(column, :in, values).

Supabase .offset(value, opts) equivalent.

Supabase .single() enforcement: returns exactly one row; raises if 0 or >1.

Adds an OR filter group. Supabase .or(filters, opts) equivalent.

Supabase .order(column, opts) equivalent.

Supabase .overlaps(column, value) equivalent.

Supabase .phfts(column, query, opts) — phraseto_tsquery full text search.

Supabase .plfts(column, query, opts) — plainto_tsquery full text search.

Executes a raw SQL query and returns the raw driver result.

Executes a raw SQL query, raising on error.

Supabase .range(from, to, opts) equivalent. from and to are 0-based inclusive.

Supabase .rangeAdjacent(column, range) — ranges are adjacent.

Supabase .rangeGt(column, range) — strictly right of.

Supabase .rangeGte(column, range) — does not extend to the right of.

Supabase .rangeLt(column, range) — strictly left of.

Supabase .rangeLte(column, range) — does not extend to the left of.

Supabase .rollback() equivalent. Executes the query inside a transaction and rolls it back (data is not persisted, but query results are returned).

Supabase .rpc(function_name, args, opts) equivalent. Executes a stored procedure / function (PostgreSQL only).

Executes the built query.

Bang variant of run/1. Raises on error instead of returning {:error, reason}.

Switch the schema for this query. Supabase PostgrestClient.schema(name) equivalent.

Selects specific columns. Supabase .select(columns) equivalent.

Like select/2 but accepts options head: and count:. Supabase .select("col", { head: true, count: "exact" }) equivalent.

Supabase .single() equivalent. Returns the query as a single unwrapped object when .run()/.run!() executes. Raises if 0 rows or >1 rows are returned.

Executes a raw SQL query and returns results as a list of maps. Parameterize with $1, $2, ... — placeholders are automatically adapted for SQLite.

Returns rows as a list (executes the query eagerly and returns them).

Supabase .textSearch(column, query, opts) equivalent.

Supabase .throwOnError() equivalent. Causes run/1 to raise instead of returning {:error, reason}.

Supabase .rpc / transaction flow equivalent. Runs fun in a transaction; fun receives the connection as argument.

Supabase .update(values, opts) equivalent.

Supabase .upsert(values, opts) equivalent.

Supabase .wfts(column, query, opts) — websearch_to_tsquery full text search.

Functions

adapter()

adapter(conn)

Returns the adapter for a connection (:postgres or :sqlite).

contained_by(query, column, values)

Alias for contained_in/3.

contained_in(query, column, values)

Supabase .containedBy(column, value) equivalent. Named contained_in/3 in Elixir for natural-language phrasing.

contains(query, column, values)

Supabase .contains(column, value) equivalent.

count(query, mode \\ :exact)

Supabase .count(mode) equivalent. Accepts :exact, :planned, or :estimated.

When run/1 executes with a count set, it returns {:ok, data, count}.

csv(query)

Supabase .csv() equivalent. Returns query results as a CSV string.

default_conn()

Returns the default connection, or raises if none configured.

delete(query, opts \\ [])

Supabase .delete(opts) equivalent.

Options

  • :count — count mode

eq(query, column, value)

Supabase .eq(column, value) equivalent.

explain(query, opts \\ [])

Supabase .explain(opts) equivalent.

Causes the query to return its EXPLAIN plan instead of rows.

Options

  • :analyze — execute the query and show actual timing
  • :verbose — include query identifier and output columns
  • :settings — include configuration parameters affecting the plan
  • :buffers — include buffer usage information
  • :wal — include WAL record generation info
  • :format:text (default) or :json

filter(query, column, operator, value)

Adds a generic filter clause. Supabase filter(column, operator, value) equivalent.

operator can be either an atom (:eq, :gt, ...) or a string, including the "not.eq" form supported by Supabase.

Examples

NexBase.from("users") |> NexBase.filter(:status, :eq, "active")
NexBase.from("users") |> NexBase.filter("status", "not.eq", "banned")

filter_in(query, column, values)

Alias for in_list/3.

from(table_name)

from(conn, table_name)

Starts a query builder for the given table. Supabase .from(table) equivalent.

fts(query, column, query_text, opts \\ [])

Supabase .fts(column, query, opts) — plainto_tsquery full text search.

geojson(query)

Supabase .geojson() equivalent.

Returns results as a GeoJSON FeatureCollection. Each row becomes a Feature; columns named geometry/geom are treated as the Feature geometry. Remaining columns become Feature properties.

Requires PostgreSQL with PostGIS for true spatial output; the Ecto adapter converts rows to GeoJSON maps at the client level.

gt(query, column, value)

Supabase .gt(column, value) equivalent.

gte(query, column, value)

Supabase .gte(column, value) equivalent.

ilike(query, column, pattern)

Supabase .ilike(column, pattern) equivalent.

ilike_all_of(query, column, patterns)

Supabase .ilikeAllOf(column, patterns) equivalent. Case-insensitive.

ilike_any_of(query, column, patterns)

Supabase .ilikeAnyOf(column, patterns) equivalent. Case-insensitive.

in_list(query, column, values)

Supabase .in(column, values) equivalent. Named in_list to avoid the reserved in/2 operator. Use filter_in/3 for a friendlier alias.

init(opts \\ [])

Initialize a database connection. Returns a %NexBase.Conn{} struct.

The adapter is auto-detected from the URL scheme:

  • postgres:// or postgresql:// → PostgreSQL
  • sqlite:// → SQLite

Options

  • :url - Database URL (falls back to DATABASE_URL env var)
  • :ssl - Enable SSL for cloud databases (default: false, ignored for SQLite)
  • :pool_size - Connection pool size (default: 10)
  • :start - Start the Repo immediately (for scripts, default: false)

Examples

# Single connection (in application.ex)
NexBase.init(url: "postgres://localhost/mydb", ssl: true)

# In a script
conn = NexBase.init(url: "sqlite::memory:", start: true, pool_size: 1)
conn |> NexBase.from("users") |> NexBase.run()

insert(query, data, opts \\ [])

Supabase .insert(values, opts) equivalent.

Options

  • :count — count mode (:exact, :planned, :estimated)
  • :default_to_null — when false, missing fields use column defaults instead of NULL (PostgREST missing=default); default is true

is(query, column, value)

Supabase .is(column, value) equivalent. Use for NULL checks and boolean columns.

Examples

NexBase.from("users") |> NexBase.is(:deleted_at, nil)
NexBase.from("users") |> NexBase.is(:active, true)

is_not_null(query, column)

Shorthand for not_filter(column, :is, nil).

is_null(query, column)

Shorthand for is(column, nil).

like(query, column, pattern)

Supabase .like(column, pattern) equivalent.

like_all_of(query, column, patterns)

Supabase .likeAllOf(column, patterns) equivalent. Matches if the column matches ALL of the given LIKE patterns (ANDed together).

like_any_of(query, column, patterns)

Supabase .likeAnyOf(column, patterns) equivalent. Matches if the column matches ANY of the given LIKE patterns (ORed together).

limit(query, count, opts \\ [])

Supabase .limit(count, opts) equivalent.

Options

  • :referenced_table / :foreign_table — apply to a referenced/embedded table

lt(query, column, value)

Supabase .lt(column, value) equivalent.

lte(query, column, value)

Supabase .lte(column, value) equivalent.

match(query, conditions)

Supabase .match(map) equivalent — multiple eq filters ANDed together.

max_affected(query, n)

Set the maximum number of rows that can be affected by an update or delete. Supabase .maxAffected(n) equivalent (PostgREST 13+).

maybe_one(query)

Supabase .maybeSingle(): returns one row or nil. Raises only if >1 rows.

maybe_single(query)

Supabase .maybeSingle() equivalent. Returns the query as a single unwrapped object or nil when .run()/.run!() executes. Raises only if >1 rows are returned.

neq(query, column, value)

Supabase .neq(column, value) equivalent.

nilike(query, column, pattern)

Supabase .not(column, :ilike, pattern) convenience.

nlike(query, column, pattern)

Supabase .not(column, :like, pattern) convenience.

not_filter(query, column, operator, value)

Adds a negated filter. Supabase .not(column, operator, value) equivalent.

Named not_filter/4 in Elixir because not is a reserved keyword.

not_in_list(query, column, values)

Supabase .not(column, :in, values) convenience. Equivalent to not_filter(column, :in, values).

offset(query, offset, opts \\ [])

Supabase .offset(value, opts) equivalent.

one!(query)

Supabase .single() enforcement: returns exactly one row; raises if 0 or >1.

or_filter(query, filters, opts \\ [])

Adds an OR filter group. Supabase .or(filters, opts) equivalent.

Accepts a list of filter tuples {operator, column, value}. All filters inside are joined with OR and combined with the query's AND filters.

Options

  • :referenced_table / :foreign_table — filter on a referenced/embedded table

order(query, column, direction_or_opts \\ :asc)

Supabase .order(column, opts) equivalent.

Options

  • :ascending — boolean, default true
  • :nulls_first — if true, NULLs sort first; if false, NULLs sort last
  • :nulls_last — alias for nulls_first: false
  • :referenced_table / :foreign_table — apply to a referenced/embedded table

Backward-compatible: order(query, col, :asc) or order(query, col, :desc, nulls_first: true) are still supported.

order(query, column, direction, opts)

overlaps(query, column, values)

Supabase .overlaps(column, value) equivalent.

phfts(query, column, query_text, opts \\ [])

Supabase .phfts(column, query, opts) — phraseto_tsquery full text search.

plfts(query, column, query_text, opts \\ [])

Supabase .plfts(column, query, opts) — plainto_tsquery full text search.

query(sql_str, params \\ [])

query(conn, sql_str, params)

Executes a raw SQL query and returns the raw driver result.

query!(sql_str, params \\ [])

query!(conn, sql_str, params)

Executes a raw SQL query, raising on error.

range(query, from, to, opts \\ [])

Supabase .range(from, to, opts) equivalent. from and to are 0-based inclusive.

range_adjacent(query, column, value)

Supabase .rangeAdjacent(column, range) — ranges are adjacent.

range_gt(query, column, value)

Supabase .rangeGt(column, range) — strictly right of.

range_gte(query, column, value)

Supabase .rangeGte(column, range) — does not extend to the right of.

range_lt(query, column, value)

Supabase .rangeLt(column, range) — strictly left of.

range_lte(query, column, value)

Supabase .rangeLte(column, range) — does not extend to the left of.

rollback(query)

Supabase .rollback() equivalent. Executes the query inside a transaction and rolls it back (data is not persisted, but query results are returned).

rpc(function_name, params \\ %{}, opts \\ [])

Supabase .rpc(function_name, args, opts) equivalent. Executes a stored procedure / function (PostgreSQL only).

Options

  • :head — return count only (no body). Supabase head: true.
  • :get — call via GET instead of POST (read-only mode)
  • :count — count mode for set-returning functions
  • :conn — use a specific connection (otherwise uses default)

run(query)

Executes the built query.

Returns:

  • {:ok, data} for normal select (list of maps, or single unwrapped map when .single()/.maybe_single() is set)
  • {:ok, data, count} when .count(mode) is set
  • {:error, exception} on failure

run!(query)

Bang variant of run/1. Raises on error instead of returning {:error, reason}.

schema(query, name)

Switch the schema for this query. Supabase PostgrestClient.schema(name) equivalent.

When called on a %Query{}, all subsequent SQL references the given schema. When called on a %Conn{}, returns a new connection tagged with that schema (useful for schema("private") |> from("users") style).

select(query, columns \\ "*")

Selects specific columns. Supabase .select(columns) equivalent.

Accepts either a list of columns (atoms or strings) or a Supabase-style comma-separated column string, which supports column aliases via alias:column syntax. Calling .select() on insert/update/upsert/delete queries enables RETURNING, so the affected rows are returned (Supabase return=representation).

Examples

# List of atoms
NexBase.from("users") |> NexBase.select([:id, :name])

# String with aliases
NexBase.from("users") |> NexBase.select("id,display_name:name,profile(*)")

# Enable RETURNING after insert
NexBase.from("users") |> NexBase.insert(%{name: "Alice"}) |> NexBase.select() |> NexBase.run()

select(query, columns, opts)

Like select/2 but accepts options head: and count:. Supabase .select("col", { head: true, count: "exact" }) equivalent.

single(query)

Supabase .single() equivalent. Returns the query as a single unwrapped object when .run()/.run!() executes. Raises if 0 rows or >1 rows are returned.

sql(sql_str, params \\ [])

sql(conn, sql_str, params)

Executes a raw SQL query and returns results as a list of maps. Parameterize with $1, $2, ... — placeholders are automatically adapted for SQLite.

stream(query, opts \\ [])

Returns rows as a list (executes the query eagerly and returns them).

text_search(query, column, query_text, opts \\ [])

Supabase .textSearch(column, query, opts) equivalent.

Options

  • :config — text search config (default: "english")
  • :type:plain (default), :phrase, or :websearch

throw_on_error(query)

Supabase .throwOnError() equivalent. Causes run/1 to raise instead of returning {:error, reason}.

transaction(fun, opts \\ [])

Supabase .rpc / transaction flow equivalent. Runs fun in a transaction; fun receives the connection as argument.

Options

  • :conn — connection to use (default: default connection)
  • :timeout — transaction timeout in ms (default: 60_000)

update(query, data, opts \\ [])

Supabase .update(values, opts) equivalent.

Options

  • :count — count mode

upsert(query, data, opts \\ [])

Supabase .upsert(values, opts) equivalent.

Options

  • :on_conflict — column or list of columns defining the unique constraint
  • :ignore_duplicates — if true, ignore duplicates instead of merging (Supabase resolution=ignore-duplicates)
  • :default_to_null — default true
  • :count — count mode

wfts(query, column, query_text, opts \\ [])

Supabase .wfts(column, query, opts) — websearch_to_tsquery full text search.