SagaSaga
Kraken

Kraken.Write

Types

InsertCell

type InsertCell =
  | Bind String InsertValue
  | Skip

InsertInput

opaque type InsertInput slot

InsertOf

opaque type InsertOf row

Insert

type Insert =
  | Insert

Writer

opaque type Writer cols input

Effects

Update

effect Update {
  fun set : Col a -> a -> Unit where {a: PgType}
  fun where_ : Expr -> Unit
}

The UPDATE builder DSL. Use set! and where_! inside the closure passed to update. This is the surgical update path: you write only the columns that change, so it stays compact even on wide tables.

Functions

insert_value

fun insert_value : a -> InsertInput (Col a) where {a: PgType}

insert_default

fun insert_default : InsertInput (Col a)

insert_auto

fun insert_auto : InsertInput (Generated a)

insert_generated

fun insert_generated : GeneratedValue a -> InsertInput (Generated a) where {a: PgType}

insert_into

fun insert_into : row -> InsertOf row

insert_field

fun insert_field : String -> InsertInput slot -> InsertOf (slot -> row) -> InsertOf row

writer

fun writer : cols -> input -> List InsertCell -> Writer cols input

set

fun set : Col a -> a -> InsertCell where {a: PgType}

set_default

fun set_default : Col a -> DefaultValue a -> InsertCell where {a: PgType}

set_generated

fun set_generated : Generated a -> GeneratedValue a -> InsertCell where {a: PgType}

insert_with_writer

fun insert_with_writer : Table cols -> Writer cols input -> input -> Prepared Unit

Build an INSERT statement using a table-specific writer. Column names come from the writer's column handles; Skip cells are omitted.

insert

fun insert : Table cols -> InsertOf row -> Prepared Unit where {cols: ColumnSet}

Build an INSERT from an anonymous record builder:

Db.insert users build Db.Insert Users { id: Db.insert_auto, name: Db.insert_value "Carol", age: Db.insert_value 31, }

Use the table's column record (Users here) as the Db.InsertOf shape to make the compiler check that every field is present. Field labels map to SQL names via ColumnSet.column_names (identity by default).

insert_with_writer_returning

fun insert_with_writer_returning : Table cols -> Writer cols input -> input -> cols -> Projection row -> Prepared row

Like insert_with_writer, but appends a RETURNING clause built from the projection callback (the table's columns are passed in, exactly like select). The result is a Prepared row; run it with Db.one (single insert) or Db.all.

insert_returning

fun insert_returning : Table cols -> InsertOf insert_row -> cols -> Projection row -> Prepared row where {cols: ColumnSet}

Like insert, but appends a RETURNING clause.

insert_all_with_writer

fun insert_all_with_writer : Table cols -> Writer cols input -> List input -> Prepared Unit

Bulk insert: one INSERT … VALUES (…), (…), … statement for a list of rows. A single round trip instead of one per row — meaningful over a network, where a per-row loop (even inside a transaction) pays N round trips. Column names and value order come from the writer, exactly like insert.

An empty list is a no-op: there is no valid zero-row VALUES SQL, so this returns a noop Prepared that Db.exec short-circuits to Ok 0 (and Db.all to Ok []) without a database round trip — no call-site guard needed.

Note Postgres caps a statement at 65535 bind parameters, so a single call is limited to ~floor(65535 / columns) rows — chunk larger batches caller-side.

insert_all

fun insert_all : Table cols -> List (InsertOf row) -> Prepared Unit where {cols: ColumnSet}

Bulk insert for the record-builder insert path. Each row must have the same field set; use insert_default / insert_auto when a row should ask Postgres for a default without changing the shared column list.

insert_all_with_writer_returning

fun insert_all_with_writer_returning : Table cols -> Writer cols input -> List input -> cols -> Projection row -> Prepared row

Like insert_all_with_writer, but appends a RETURNING clause built from the projection callback (the table's columns, exactly like select). Yields a Prepared row with one row per inserted row; run it with Db.all. An empty list is a no-op that Db.all short-circuits to Ok [] (no round trip).

insert_all_returning

fun insert_all_returning : Table cols -> List (InsertOf insert_row) -> cols -> Projection row -> Prepared row where {cols: ColumnSet}

Like insert_all, but appends a RETURNING clause.

insert_with_writer_on_conflict_do_nothing

fun insert_with_writer_on_conflict_do_nothing : Table cols -> Writer cols input -> input -> cols -> List ColRef -> Prepared Unit

INSERT ... ON CONFLICT (<target>) DO NOTHING — insert the row unless it would collide on the target columns, in which case skip it silently. The target callback names the conflict columns with Db.ref (e.g. fun u -> [Db.ref u.email]).

insert_on_conflict_do_nothing

fun insert_on_conflict_do_nothing : Table cols -> InsertOf row -> cols -> List ColRef -> Prepared Unit where {cols: ColumnSet}

INSERT ... ON CONFLICT (<target>) DO NOTHING for InsertOf.

upsert_with_writer

fun upsert_with_writer : Table cols -> Writer cols input -> input -> cols -> List ColRef -> Prepared Unit

Upsert: INSERT ... ON CONFLICT (<target>) DO UPDATE SET <rest> = EXCLUDED.<rest>. On a collision on the target columns, overwrite every other inserted column with the value from this insert. The target callback names the conflict columns with Db.ref. Panics at build time if the target covers every inserted column (nothing left to update — use insert_on_conflict_do_nothing).

upsert

fun upsert : Table cols -> InsertOf row -> cols -> List ColRef -> Prepared Unit where {cols: ColumnSet}

Upsert for InsertOf.

insert_with_writer_on_conflict_do_nothing_returning

fun insert_with_writer_on_conflict_do_nothing_returning : Table cols -> Writer cols input -> input -> cols -> List ColRef -> cols -> Projection row -> Prepared row

Like insert_on_conflict_do_nothing, but appends a RETURNING clause. Note a skipped (conflicting) row produces no returned row, so Db.one yields Ok Nothing on conflict.

insert_on_conflict_do_nothing_returning

fun insert_on_conflict_do_nothing_returning : Table cols -> InsertOf insert_row -> cols -> List ColRef -> cols -> Projection row -> Prepared row where {cols: ColumnSet}

Returning variant of insert_on_conflict_do_nothing.

upsert_with_writer_returning

fun upsert_with_writer_returning : Table cols -> Writer cols input -> input -> cols -> List ColRef -> cols -> Projection row -> Prepared row

Like upsert, but appends a RETURNING clause built from the projection callback. Both the inserted and the updated row are returned, so Db.one always yields the resulting row.

upsert_returning

fun upsert_returning : Table cols -> InsertOf insert_row -> cols -> List ColRef -> cols -> Projection row -> Prepared row where {cols: ColumnSet}

Returning variant of upsert.

upsert_set_with_writer

fun upsert_set_with_writer : Table cols -> Writer cols input -> input -> cols -> ConflictTarget -> cols -> List SetExpr -> Prepared Unit

Upsert with an explicit DO UPDATE SET: update only the columns you list, to arbitrary expressions over the existing row, the proposed row (Db.excluded), and literals — e.g. a counter Db.assign u.count (Db.add u.count 1) or a merge Db.assign u.total (Db.add_sql u.total (Db.excluded u.total)). The conflict target is a Db.ConflictTarget (Db.on_columns [Db.ref u.id] or Db.on_constraint "…"). For the "overwrite every other column with EXCLUDED" default, use upsert instead.

upsert_set

fun upsert_set : Table cols -> InsertOf row -> cols -> ConflictTarget -> cols -> List SetExpr -> Prepared Unit where {cols: ColumnSet}

InsertOf variant of upsert_set.

upsert_set_with_writer_returning

fun upsert_set_with_writer_returning : Table cols -> Writer cols input -> input -> cols -> ConflictTarget -> cols -> List SetExpr -> cols -> Projection row -> Prepared row

Like upsert_set, but appends a RETURNING clause built from the projection callback. Yields the resulting row (inserted or updated) via Db.one.

upsert_set_returning

fun upsert_set_returning : Table cols -> InsertOf insert_row -> cols -> ConflictTarget -> cols -> List SetExpr -> cols -> Projection row -> Prepared row where {cols: ColumnSet}

Returning variant of upsert_set.

update

fun update : Table cols -> cols -> Unit needs {Update} -> Prepared Unit

Build an UPDATE statement. Columns are referenced through the callback's column record; set!/where_! describe the assignments and row filter.

update_returning

fun update_returning : Table cols -> cols -> Unit needs {Update} -> cols -> Projection row -> Prepared row

Like update, but appends a RETURNING clause built from the projection callback. Returns a Prepared row; run it with Db.all / Db.one.

update_all

fun update_all : Table cols -> Writer cols row -> row -> Prepared Unit where {cols: ColumnSet}

Save a whole entity: UPDATE <table> SET <every non-key column> WHERE <pk>. The entity is the domain record as-is (read → modify → save, no conversion); the key columns come from the table's primary_key and form the WHERE, the rest become the SET. The supplied writer ties the accepted entity type to the table's columns.

delete

fun delete : Table cols -> cols -> Expr -> Prepared Unit

Build a DELETE statement. The predicate callback receives the table's columns.

delete_returning

fun delete_returning : Table cols -> cols -> Expr -> cols -> Projection row -> Prepared row

Like delete, but appends a RETURNING clause built from the projection callback. Returns a Prepared row; run it with Db.all / Db.one.