cake

Cake is an SQL query building library for RDBMS:

For examples see the tests.

Summary

Cake is a composable SQL query-building library for Gleam. It targets four major RDBMS dialects β€” 🐘 PostgreSQL, πŸͺΆ SQLite, 🦭 MariaDB, and 🐬 MySQL β€” and produces prepared statements (parameterised SQL + typed parameter lists) that are safe from SQL injection. Cake does not execute queries or decode result rows; it hands a PreparedStatement to a dialect adapter library that does so.


Module Overview

ModuleAliasPurpose
cake/selectsSELECT queries
cake/insertiINSERT queries
cake/updateuUPDATE queries
cake/deletedDELETE queries
cake/combinedcUNION / EXCEPT / INTERSECT
cake/wherewWHERE / HAVING conditions
cake/joinjJOIN clauses
cake/fragmentfRaw SQL fragments (safe & unsafe)
cake/parampTyped parameter values

Dialect helpers live under cake/dialect/:

ModuleDialect
cake/dialect/postgres_dialect🐘 PostgreSQL
cake/dialect/sqlite_dialectπŸͺΆ SQLite
cake/dialect/maria_dialect🦭 MariaDB
cake/dialect/mysql_dialect🐬 MySQL

Recommended Imports

import cake
import cake/select as s
import cake/insert as i
import cake/update as u
import cake/delete as d
import cake/combined as c
import cake/where as w
import cake/join as j
import cake/fragment as f
import cake/param as p

Query Flow

Every query is built using a pipeline of builder functions that accumulate clauses, then converted to a ReadQuery or WriteQuery for execution via your chosen adapter.

flowchart TD
    A[new] --> B[add clauses]
    B --> C[to_query]
    C --> D{query type}
    D -->|ReadQuery| E[adapter: run_read_query]
    D -->|WriteQuery| F[adapter: run_write_query]
    E --> G[decode results]
    F --> H[inspect returning / rows affected]

Quick Example

import cake/select as s
import cake/where as w

s.new()
|> s.from_table("users")
|> s.col("id")
|> s.col("name")
|> s.where(w.eq(w.col("active"), w.bool(True)))
|> s.order_by_asc("name")
|> s.limit(10)
|> s.to_query

Generates:

SELECT id, name FROM users WHERE active = $1 ORDER BY name ASC LIMIT 10

How It Works

Build query  β†’  call to_query()  β†’  call to_prepared_statement()  β†’  pass to adapter
  1. Build – use one of the query-builder modules (select, insert, update, delete, combined) to assemble a typed query value.
  2. Compile – call cake.to_prepared_statement(query, dialect) (or the dialect-specific helper) to get a PreparedStatement.
  3. Execute – extract cake.get_sql(ps) and cake.get_params(ps) and pass them to the appropriate adapter.

cake β€” Core

Key types re-exported for adapter use:

TypeDescription
CakeQuery(a)Union of CakeReadQuery and CakeWriteQuery
ReadQueryAny read query (SELECT, combined)
WriteQuery(a)Any write query (INSERT, UPDATE, DELETE)
PreparedStatementCompiled SQL string + parameter list
DialectTarget database dialect
ParamTyped query parameter

Key functions:

FunctionDescription
to_read_query(query)Wrap a ReadQuery as a CakeQuery
to_write_query(query)Wrap a WriteQuery as a CakeQuery
to_prepared_statement(query, dialect)Compile a CakeQuery to a PreparedStatement
read_query_to_prepared_statement(query, dialect)Compile a ReadQuery directly
write_query_to_prepared_statement(query, dialect)Compile a WriteQuery directly
get_sql(ps)Extract the SQL string from a PreparedStatement
get_params(ps)Extract the List(Param) from a PreparedStatement

cake/select β€” SELECT Queries

Build SELECT statements. All builder functions return a new Select, making them pipeable.

Constructors

FunctionDescription
new()Empty select query
to_query(select)Convert to ReadQuery

Column selection

FunctionDescription
col(name)Reference a column by name
alias(value, alias)Alias a select value
bool/float/int/string/date/null/fragment(...)Literal select values
select_col(query, col)Append a single column
select(query, value)Append a SelectValue
selects(query, values)Append multiple SelectValues
replace_select_col/replace_select/replace_select_cols/replace_selects(...)Replace current selection
all(query) / distinct(query)Set SELECT ALL or SELECT DISTINCT

FROM clause

FunctionDescription
from_table(query, name)FROM table_name
from_query(query, subquery, alias)FROM (subquery) AS alias
no_from(query)Remove FROM clause

Filtering

FunctionDescription
where(query, condition)Append to AND WHERE
or_where(query, condition)Append to OR WHERE
xor_where(query, condition)Append to XOR WHERE
not_where(query, condition)Append negated condition
replace_where(query, condition)Replace entire WHERE
no_where(query)Remove WHERE clause

Aggregation

FunctionDescription
group_by(query, col) / group_bys(query, cols)Add GROUP BY columns
having(query, condition)Append to AND HAVING
or_having / xor_having / not_having(...)Other HAVING combinators
replace_having / no_having(...)Replace or remove HAVING

Joins

FunctionDescription
join(query, join)Append a join
joins(query, joins)Append multiple joins
replace_join / replace_joins / no_join(...)Replace or remove joins

Ordering, paging, extras

FunctionDescription
order_by_asc / order_by_desc(query, col)Append ascending/descending order
order_by_asc_nulls_first/last / order_by_desc_nulls_first/last(...)Order with NULL placement
replace_order_by_* / no_order_by(...)Replace or remove ORDER BY
limit(query, n) / no_limit(query)Set or clear LIMIT
offset(query, n) / no_offset(query)Set or clear OFFSET
epilog(query, sql) / no_epilog(query)Append raw SQL after the query
comment(query, text) / no_comment(query)Attach an SQL comment

cake/insert β€” INSERT Queries

Constructors

FunctionDescription
new()Empty insert query
from_records(table, columns, records, encoder)Build from a list of Gleam records
from_values(table, columns, rows)Build from a list of InsertRows
to_query(insert)Convert to WriteQuery

Row / value helpers

FunctionDescription
row(values)Create an InsertRow
bool/float/int/string/null/date/fragment(...)Create typed InsertValues

Configuration

FunctionDescription
table(insert, name)Set the target table
columns(insert, cols)Set column names
source_records / source_values(...)Change the data source
modifier(insert, keyword) / no_modifier(insert)Set a query modifier (e.g. OR REPLACE)

Conflict handling (upsert)

FunctionDescription
on_conflict_error(insert)Error on conflict (default)
on_columns_conflict_ignore(insert, cols, where)Ignore on column conflict (🐘 / πŸͺΆ)
on_constraint_conflict_ignore(insert, constraint, where)Ignore on named constraint conflict (🐘)
on_columns_conflict_update(insert, cols, where, update)Upsert by columns (🐘 / πŸͺΆ)
on_constraint_conflict_update(insert, constraint, where, update)Upsert by constraint (🐘)
on_duplicate_key_update(insert, update)ON DUPLICATE KEY UPDATE (🦭 / 🐬)

Returning / extras

FunctionDescription
returning(insert, cols) / no_returning(insert)RETURNING clause (🐘 / πŸͺΆ)
epilog / no_epilog / comment / no_comment(...)Raw SQL epilog and comment

cake/update β€” UPDATE Queries

Constructor

FunctionDescription
new()Empty update query
to_query(update)Convert to WriteQuery

SET clause

FunctionDescription
set_bool/set_float/set_int/set_string/set_null/set_date(column, value)Typed column assignments
set_true / set_false(column)Boolean shorthand
set_expression(column, expr)Raw SQL expression assignment
set_sub_query(column, query)Sub-query assignment
set_fragment(column, fragment)Fragment assignment with parameter binding
sets_expression / sets_sub_query(columns, ...)Multi-column assignment
set(update, set) / sets(update, sets)Append one or more UpdateSets
set_replace / sets_replace(...)Replace all SET items

FROM, JOIN, WHERE, RETURNING, extras

Same API shape as cake/select β€” from_table, from_sub_query, no_from, join, where, or_where, xor_where, not_where, replace_where, no_where, returning, no_returning, epilog, comment, etc.

Note: RETURNING is not supported on 🦭 MariaDB or 🐬 MySQL for UPDATE.


cake/delete β€” DELETE Queries

Constructor

FunctionDescription
new()Empty delete query
to_query(delete)Convert to WriteQuery

Configuration

FunctionDescription
table(delete, name)Set the table to delete from
modifier(delete, keyword) / no_modifier(delete)Optional modifier
using_table / using_sub_query(...)USING clause for multi-table deletes (🐘 / 🦭 / 🐬)
replace_using_table / replace_using_sub_query / no_using(...)Replace or remove USING

JOIN, WHERE, RETURNING, extras

Same API shape as cake/update β€” join, where, or_where, xor_where, not_where, replace_where, no_where, returning, no_returning, epilog, comment, etc.

Note: πŸͺΆ SQLite does not support USING. RETURNING is not supported on 🦭 MariaDB or 🐬 MySQL for DELETE.


cake/combined β€” UNION / EXCEPT / INTERSECT

Combines two or more Select queries.

FunctionDescription
union(a, b) / unions(a, b, rest)UNION (distinct)
union_all(a, b) / unions_all(a, b, rest)UNION ALL
except(a, b) / excepts(a, b, rest)EXCEPT (distinct)
except_all(a, b) / excepts_all(a, b, rest)EXCEPT ALL (not πŸͺΆ SQLite)
intersect(a, b) / intersects(a, b, rest)INTERSECT (distinct)
intersect_all(a, b) / intersects_all(a, b, rest)INTERSECT ALL (not πŸͺΆ SQLite)
to_query(combined)Convert to ReadQuery

Supports limit, offset, order_by_*, epilog, and comment with the same API as cake/select.


cake/where β€” WHERE / HAVING Conditions

Used to build WHERE clauses (and HAVING clauses, which share the same type).

Value constructors

FunctionDescription
col(name)Reference a column
bool/float/int/string/null/date(value)Typed literal values
true() / false()Boolean shortcuts
sub_query(query)Scalar sub-query value
fragment_value(fragment)Fragment value

Logical combinators

FunctionDescription
and(wheres)AND of a list of conditions
or(wheres)OR of a list of conditions
xor(wheres)Strict XOR β€” exactly one true
xor_parity(wheres)Odd-parity XOR β€” uses native XOR on 🦭 / 🐬
not(where)Negate a condition
none()No condition (NoWhere)

Comparisons

eq, neq, lt, lte, gt, gte β€” compare two WhereValues.

eq_any_query, lt_any_query, lte_any_query, gt_any_query, gte_any_query, neq_any_query β€” compare against ANY result of a sub-query (not πŸͺΆ SQLite).

eq_all_query, lt_all_query, lte_all_query, gt_all_query, gte_all_query, neq_all_query β€” compare against ALL results of a sub-query (not πŸͺΆ SQLite).

Other predicates

FunctionDescription
is_null / is_not_null(value)NULL checks
is_bool / is_not_bool / is_true / is_false(value, ...)Boolean checks
in(value, values)IN (...) with a list of values
in_query(value, query)IN (subquery)
exists_in_query(query)EXISTS (subquery)
between(a, b, c)BETWEEN b AND c
like(value, pattern)LIKE pattern match
ilike(value, pattern)Case-insensitive LIKE
similar_to(value, pattern, escape)SIMILAR TO (not πŸͺΆ SQLite)
fragment(fragment)Raw SQL condition

cake/join β€” JOIN Clauses

Join target constructors

FunctionDescription
table(name)Join a table by name
sub_query(query)Join a sub-query

Join kind constructors

FunctionDescription
inner(with, on, alias)INNER JOIN
left(with, on, alias)LEFT JOIN
right(with, on, alias)RIGHT JOIN
full(with, on, alias)FULL JOIN
cross(with, alias)CROSS JOIN
inner_lateral(with, alias)INNER JOIN LATERAL ... ON TRUE (🐘 / recent 🐬)
left_lateral(with, alias)LEFT JOIN LATERAL ... ON TRUE (🐘 / recent 🐬)
cross_lateral(with, alias)CROSS JOIN LATERAL (🐘 / recent 🐬)

cake/fragment β€” Raw SQL Fragments

Fragments allow injecting custom SQL into a query while keeping parameter binding safe.

Function / ConstantDescription
placeholderThe placeholder grapheme used in prepared fragments (? by default)
prepared(sql, params)Create a fragment with bound parameters β€” safe for user input
literal(sql)Create a fragment from a raw string β€” never use with user input
bool/float/int/string/null/date/true/false(value)Convenience Param constructors mirroring cake/param

cake/param β€” Typed Parameters

Param is the boxed value type used in prepared statements.

Constructor / FunctionDescription
StringParam(value) / string(value)UTF-8 string
IntParam(value) / int(value)Integer
FloatParam(value) / float(value)Float
BoolParam(value) / bool(value)Boolean
NullParam / null()SQL NULL
DateParam(value) / date(value)calendar.Date

Dialect Compatibility Summary

Feature🐘 PostgreSQLπŸͺΆ SQLite🦭 MariaDB🐬 MySQL
ANY / ALL sub-queryβœ…βŒβœ…βœ…
SIMILAR TOβœ…βŒβœ…βœ…
EXCEPT ALL / INTERSECT ALLβœ…βŒβœ…βœ…
ON CONFLICT ... DO UPDATEβœ…βœ…βŒβŒ
ON DUPLICATE KEY UPDATEβŒβŒβœ…βœ…
RETURNING (INSERT / UPDATE / DELETE)βœ…βœ…βŒβŒ
USING in DELETEβœ…βŒβœ…βœ…
LATERAL joinsβœ…βŒβŒβœ… (recent)
NULLS FIRST / NULLS LASTβœ…βœ…βŒβŒ

Types

Base wrapper query type to be able to pass around read and write queries in the same way.

pub type CakeQuery(a) {
  CakeReadQuery(query: ReadQuery)
  CakeWriteQuery(query: WriteQuery(a))
}

Constructors

pub type Dialect =
  @internal Dialect
pub type PreparedStatement =
  @internal PreparedStatement
pub type ReadQuery =
  @internal ReadQuery
pub type WriteQuery(a) =
  @internal WriteQuery(a)

Values

pub fn get_params(
  prepared_statement prepared_statement: PreparedStatement,
) -> List(param.Param)

Get the parameters of the prepared statement.

pub fn get_sql(
  prepared_statement prepared_statement: PreparedStatement,
) -> String

Get the SQL of the prepared statement.

pub fn main() -> Nil

As a library Cake cannot be invoked directly in a meaningful way.

pub fn read_query_to_prepared_statement(
  query query: ReadQuery,
  dialect dialect: Dialect,
) -> PreparedStatement

Create a prepared statement from a read query.

pub fn to_prepared_statement(
  query query: CakeQuery(a),
  dialect dialect: Dialect,
) -> PreparedStatement

Create a prepared statement from a Cake query.

Also see cake/dialect/* for dialect specific implementations of this.

pub fn to_read_query(query query: ReadQuery) -> CakeQuery(a)

Create a Cake read query from a read query.

Also see cake/dialect/* for dialect specific implementations of this.

pub fn to_write_query(query query: WriteQuery(a)) -> CakeQuery(a)

Create a Cake write query from a write query.

Also see cake/dialect/* for dialect specific implementations of this.

pub fn write_query_to_prepared_statement(
  query query: WriteQuery(a),
  dialect dialect: Dialect,
) -> PreparedStatement

Create a prepared statement from a write query.

✨ Search Document