# The operations every entity gets

Every entity gets these operations, called through the entity's name, as
`Todo.get(todo_id)`. Only actions in the entity's own domain may call the
ones that write. Other domains call that domain's public actions instead.

| Operation | Does |
|---|---|
| `Todo.get(todo_id)` | reads one visible record, or fails `TodoNotFound` |
| `Todo.create { set: { ... } }` | adds a record |
| `Todo.update(todo) { set: { ... } }` | changes fields of a record loaded earlier in the action |
| `Todo.update(todo) { patch: input }` | changes only the fields a request supplied |
| `Todo.update(todo_id) { set: { ... } }` | changes the record with that `id` in one step (counters, below) |
| `Todo.delete(todo)` | removes the record, or runs the lifecycle's `delete` transition |
| `User.disable(user)` | runs a lifecycle transition, named after it |

An `update`, `delete` or transition takes either the record the action
loaded earlier or its `id`. By `id`, it fails with the entity's not-found
failure when no record has that `id`.

An update gives its fields in `set:`, or the request's changes with
`patch:`, never both. `when_supplied:` goes with `patch:` (both are below).

A create and an update give back the record as stored; a delete gives
nothing. Each fills the fields the store owns: a new version 7 UUID as the
`id` on create (`Ctx::new_id`, from the invocation's seed), and the
operation's time in each generated field, `on_create` once and `on_change`
on every update.

Every write joins the action's transaction. In the compiler's graph of the
program, a `writes` edge runs from the action or function to the entity.

In this action, `attempt User.get(owner_id)` gives the user, or passes on
`UserNotFound`. `Project.create` sets every field but `id` and the
generated ones:

```jadpo
// domains/planning/actions/start_project.jadpo
action start_project(owner_id: User.id, name: Project.name) fails UserNotFound -> Project {
    var owner: User = attempt User.get(owner_id)  // the user, or UserNotFound
    return Project.create {
        set: {
            owner_id: owner.id  // every field but `id` and the generated ones
            name: name
        }
    }
}
```

## Transitions

A transition ([Lifecycle](lifecycle.md)) is an update of the
fields its `set:` gives. Like an update, it runs on the record loaded
earlier or by `id`, and gives back the record as stored; a `delete`
transition gives nothing. Its block takes only `conflict:`, since what it
changes is fixed in the lifecycle.

Like every update and delete, a transition reaches only a record that
`visible:` lets through, so a hidden record is the entity's not-found
failure. A `when:` that asks more than `visible:` can refuse a record that
is there. Map that refusal in `conflict:`, as you would a rule, keyed by
the transition. Here `UserDisabled` is what the action fails with when
`disable`'s `when:` doesn't hold:

```jadpo
// domains/planning/actions/disable_user.jadpo
action disable_user(user_id: User.id) fails UserNotFound, UserDisabled -> User {
    return attempt User.disable(user_id) {
        conflict: {
            User.disable: UserDisabled  // its `when:` doesn't hold
        }
    }
}
```

The statement is `UPDATE "user" SET "stage" = $1, "disabled_at" = $2
WHERE "id" = $3 AND "stage" = $4`, with the stages bound as their column
holds them, `'disabled'` and `'active'`
([Every boundary through the contract](every-boundary-through-the-contract.md)).
When it changes no row, a second statement asks whether the user is there
and visible, which tells `UserDisabled` from `UserNotFound`.
`jadpo sql disable_user` shows both.

## The not-found failure

Nothing else is an entity operation: `Todo.fetch(todo_id)` is
`semantic.unknown_callee`. `Todo.title(value)` still builds a value of the
field's type ([Creating values](creating-values.md)).

`TodoNotFound` is the domain's failure of that name in `failures/`. When
the domain declares none, the compiler provides one: kind `not_found`,
public, with no fields, placed at the entity in the graph. When a declared
one has a field typed `<Entity>.id`, a read or write that fails fills it
with the `id` it looked for. A write that can't fail needs no `attempt`
([Attempt](attempt.md)).

This domain declares no `TodoNotFound`, so the compiler provides it:

```jadpo
// domains/planning/actions/reschedule_todo.jadpo
action reschedule_todo(todo_id: Todo.id, due_at: DueAt) fails TodoNotFound, DueDateInPast -> Todo {
    var todo: Todo = attempt Todo.get(todo_id)  // TodoNotFound: provided
    if (due_at <= clock.now) {
        reject DueDateInPast
    }
    return Todo.update(todo) {
        set: {
            due_at: due_at
            reminder_sent_at: none
        }
    }
}
```

## Patches from a request

A patch takes an `Input` whose fields are optional and match the
entity's. A field the request left out keeps its value, and one sent as
`none` is cleared ([Values that may be missing](absent-values.md)).
`when_supplied:` sets further fields when a given field was supplied: here
a new `due_at` also clears `reminder_sent_at`. A patch with no fields
changes nothing and succeeds, as a JSON Merge Patch does, so there is no
`empty:` failure.

```jadpo
type TodoChanges = Input {
    pick: [Todo.title, Todo.due_at]
    optional: all
}

action edit_todo(todo: Todo, amendment: TodoChanges) -> Todo {
    return Todo.update(todo) {
        patch: amendment
        when_supplied: {
            due_at: {
                reminder_sent_at: none
            }
        }
    }
}
```

The statement's text is fixed: each field of the input is written
`CASE WHEN <supplied> THEN <value> ELSE <column> END`, and an `on_change`
field changes only when a field was supplied.

A value built without one of its optional `Input` fields remembers that
the field was left out. Only a patch reads that, and the value still
equals one given `none`.

A field whose type can't be `none` (`title` above) can't be cleared, so
`none` given to it is the same as leaving it out, and the patch keeps the
stored value. That isn't an error, since passing an optional value on
into an optional field, such as a page's `next` cursor, is ordinary code.
