Store and change a record
You end with an entity, its migration, and actions that add, change and delete records.
On this page
A record your app keeps is an entity: think of a table, where each field is a column with a Jadpo type, and the entity also says who may create, read, change and delete its records. This guide stores books, then adds, changes and deletes them from actions. Jadpo writes the SQL and the migrations; you write neither.
You start from an app with one domain, books, holding a type for a
book's title.
domains/:
/// What a book is called: at least one character, at most 200.type BookTitle = Text { min_length: 1 max_length: 200}
Declare the entity
Entities have their own folder in a domain, entities/:
domains/:
use books/types { BookTitle }/// A book the library lends.entity Book { id: Uuid title: BookTitle isbn: Text { min_length: 10 max_length: 13 unique: true } on_loan: Bool added_at: Instant { generated: Generated.on_create } changed_at: Instant { generated: Generated.on_change } policy: { create: [Access.public] read: [Access.public] update: [Access.public] delete: [Access.public] }}
id: Uuidis the record's key. Every entity has one, and Jadpo makes a new one for each record.- A field's type carries its rules into the database:
titleis aBookTitle, andisbnis 10 to 13 characters. unique: truemakes the database refuse a second book with the same ISBN.generated:fields are filled by Jadpo, never by your code:on_createonce,on_changeon every update.policy:says who may do each thing.Access.publicmeans anyone, which keeps this guide short; a real app names its signed-in people, as Add sign-in shows.
Write the migration
A migration is the SQL that changes the database to match your entities.
jadpo check fails while they disagree, and jadpo migrate new writes
the next one, comparing the entities with the last migration:
jadpo migrate new initialcompared the entities with an empty database Book + table book new entity System tables + table jadpo_circuit_breakers system table for circuit breakers + table jadpo_deliveries system table for deliveries + table jadpo_handled_deliveries system table for handled deliveries + table jadpo_housekeeping system table for housekeeping + table jadpo_idempotency_keys system table for idempotency keys + table jadpo_operator_actions system table for operator actions + table jadpo_outbox system table for outboxWrote database/migrations/20261020T1400_initial/ snapshot.json the whole schema at this point postgres.sql 15 statements: create table, add unique rule, add reference, create indexnext: jadpo check confirms the migration matches the entities
Commit the folder it writes, and never edit it; yours is named after
the time you ran it. The jadpo_ tables are Jadpo's own bookkeeping,
kept in your database so that it commits or rolls back with your data.
Add a record
Every entity gets create, get, update and delete without your
writing them. A create gives every field but id and the generated
ones in set:, and gives back the record as stored.
The unique ISBN means a create can be refused. The compiler knows which
rules each write can break, and makes you map each one to a failure in
conflict:, so the caller gets a clear 409 rather than a database
error:
domains/:
/// Another book already has this ISBN.type IsbnTaken = Failure { kind: FailureKind.conflict message: "A book with that ISBN is already in the catalogue."}
domains/:
use books/entities { Book }use books/types { BookTitle }use books/failures { IsbnTaken }/// Adds a book to the catalogue.action add_book(title: BookTitle, isbn: Book.isbn) fails IsbnTaken -> Book { return attempt Book.create { set: { title: title isbn: isbn on_loan: false } conflict: { Book.isbn: IsbnTaken } }}
attempt passes the failure on to whoever called the action, which
fails IsbnTaken declares. Handle failures
says more.
Change a record
To change only the fields a caller sent, give update a patch: an
Input whose fields are all optional. A field the caller left out
keeps its value.
domains/:
use books/entities { Book }/// What a caller may change about a book: any of these, or none.type BookChanges = Input { pick: [Book.title, Book.on_loan] optional: all}
domains/:
use books/entities { Book, BookNotFound }use books/types { BookChanges }/// Changes the fields of a book that the caller sent.action change_book(book_id: Book.id, changes: BookChanges) fails BookNotFound -> Book { var book: Book = attempt Book.get(book_id) return Book.update(book) { patch: changes }}
Book.get reads one record or fails with BookNotFound, the failure
Jadpo declares for every entity; a route turns it into a 404. To set
fields from code rather than from a request, give set: in place of
patch:.
jadpo sql shows the SQL an action sends:
jadpo sql change_bookerror The entities have changed since the latest migration
--> domains/books/entities/book.jadpo:4:8
|4 | entity Book { | ^^^^ changed
- reason
jadpo checkcompares the database schema the entities ask for with the latest migration's snapshot (database/): fieldmigrations/ 20261020T1500_add_author/ snapshot.json Book.authorremoved.- next
- Run
jadpo migrate new retire_author(agent) - rule
- migration.
out_ of_ date - help
- https://jadpo.
dev/docs/errors/migration. out_ of_ date
Delete a record
domains/:
use books/entities { Book, BookNotFound }/// Takes a book out of the catalogue.action remove_book(book_id: Book.id) fails BookNotFound -> Unit { var book: Book = attempt Book.get(book_id) Book.delete(book)}
All or nothing
Every action is all or nothing: its writes commit together, or none of them do. Two people changing the same book at once don't overwrite each other's changes either. A write to a record the action loaded checks that nobody changed it in between, and if someone did, Jadpo runs the whole action again with fresh reads. You write nothing for either.
Change the entity later
Each time you add, change or remove a field, jadpo check fails until
you write the next migration, named for what it does. Here an optional
author: Text? field was added at the end of Book:
jadpo migrate new add_authorcompared the entities with 20261020T1400_initial Book + author text new fieldWrote database/migrations/20261020T1500_add_author/ snapshot.json the whole schema at this point postgres.sql 1 statement: add columnnext: jadpo check confirms the migration matches the entities
Read more
Entities and the id, Fields and their settings, Unique rules, Migrations, The operations every entity gets, When a write is refused and All-or-nothing actions and concurrent changes. To read records back, see Query records.
Markdown for agents: /guides/guide-store-and-change-a-record.md.Built from Jadpo main at e00e61f. Jadpo's CI compiles this guide's code and runs its tests.