Query Builder
View SourceThe query builder provides composable, functional query construction. Build queries by chaining functions, then execute with kura_repo_worker:all/2 or kura_repo_worker:one/2.
Basic Queries
%% All users
Q = kura_query:from(my_user),
{ok, Users} = kura_repo_worker:all(my_repo, Q).
%% With conditions
Q = kura_query:from(my_user),
Q1 = kura_query:where(Q, {active, true}),
{ok, Users} = kura_repo_worker:all(my_repo, Q1).WHERE Conditions
Equality
kura_query:where(Q, {name, ~"Alice"}).
kura_query:where(Q, {name, '=', ~"Alice"}).Comparison Operators
kura_query:where(Q, {age, '>', 18}).
kura_query:where(Q, {age, '>=', 18}).
kura_query:where(Q, {age, '<', 65}).
kura_query:where(Q, {age, '<=', 65}).
kura_query:where(Q, {age, '!=', 0}).IN / NOT IN
kura_query:where(Q, {role, in, [~"admin", ~"moderator"]}).
kura_query:where(Q, {status, not_in, [~"banned", ~"deleted"]}).BETWEEN
kura_query:where(Q, {age, between, {18, 65}}).LIKE / ILIKE
kura_query:where(Q, {name, like, ~"A%"}).
kura_query:where(Q, {email, ilike, ~"%@example.com"}).NULL Checks
kura_query:where(Q, {deleted_at, is_nil}).
kura_query:where(Q, {email, is_not_nil}).Boolean Combinators
%% AND (multiple where calls are implicitly AND'd)
Q1 = kura_query:where(Q, {active, true}),
Q2 = kura_query:where(Q1, {age, '>', 18}).
%% Explicit AND
kura_query:where(Q, {'and', [{active, true}, {age, '>', 18}]}).
%% OR
kura_query:where(Q, {'or', [{role, ~"admin"}, {role, ~"moderator"}]}).
%% NOT
kura_query:where(Q, {'not', {banned, true}}).Fragments
Raw SQL fragments with ? placeholders:
kura_query:where(Q, {fragment, ~"lower(?) = ?", [~"Email", ~"alice@example.com"]}).SELECT
%% Specific fields
kura_query:select(Q, [name, email]).ORDER BY
kura_query:order_by(Q, [{name, asc}]).
kura_query:order_by(Q, [{inserted_at, desc}, {name, asc}]).LIMIT / OFFSET
Q1 = kura_query:limit(Q, 10),
Q2 = kura_query:offset(Q1, 20).GROUP BY / HAVING
Q1 = kura_query:group_by(Q, [role]),
Q2 = kura_query:having(Q1, {count, '>', 5}).DISTINCT
%% Simple DISTINCT
kura_query:distinct(Q).
%% DISTINCT ON (PostgreSQL-specific)
kura_query:distinct(Q, [email]).LOCK
kura_query:lock(Q, ~"FOR UPDATE").
kura_query:lock(Q, ~"FOR SHARE").Schema Prefix
kura_query:prefix(Q, ~"my_schema").JOINs
Q = kura_query:from(my_user),
Q1 = kura_query:join(Q, inner, posts, {user_id, id}).
%% With alias
Q1 = kura_query:join(Q, left, posts, {user_id, id}, p).Join types: inner, left, right, full.
Aggregates
%% COUNT(*)
Q1 = kura_query:count(Q),
{ok, [#{count := Count}]} = kura_repo_worker:all(my_repo, Q1).
%% COUNT(field)
kura_query:count(Q, email).
%% SUM / AVG / MIN / MAX
kura_query:sum(Q, amount).
kura_query:avg(Q, score).
kura_query:min(Q, price).
kura_query:max(Q, price).Preloading (in queries)
See the Associations guide for preloading details.
Q = kura_query:from(my_post),
Q1 = kura_query:preload(Q, [author]),
{ok, Posts} = kura_repo_worker:all(my_repo, Q1).