# `Dala.State`
[🔗](https://github.com/manhvu/dala/blob/main/lib/dala/state.ex#L1)

Persistent key-value store for app state.

Backed by `:dets` — Erlang's disk-based term storage, part of OTP stdlib.
State survives app kills and restarts. Any Elixir term can be stored as a
value; no serialisation step required.

## When to use this vs. Ecto

- **`Dala.State`** — app preferences, UI choices, small per-user settings.
  Think: selected theme, onboarding complete flag, last-opened tab, cached
  user ID. Designed for O(dozens) of keys, not O(thousands) of rows.

- **Your Ecto Repo** — user records, structured data, anything you'd query,
  filter, or paginate. Use migrations and schemas for that.

## Usage

    # Store anything — atoms, maps, lists, nested structures.
    Dala.State.put(:theme, :citrus)
    Dala.State.put(:onboarded, true)
    Dala.State.put(:last_position, %{lat: 43.7, lng: -79.4})

    # Read back on next launch — returns `default` if not yet set.
    Dala.State.get(:theme, :obsidian)   #=> :citrus
    Dala.State.get(:missing_key, 0)     #=> 0

    # Remove a key.
    Dala.State.delete(:last_position)

## Lifecycle

Started automatically by `Dala.App.start/0` — no setup required.
The backing file is stored at `dala_DATA_DIR/dala_state.dets` on device,
or `priv/repo/dala_state.dets` in local dev (same directory as the SQLite DB).

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `delete`

```elixir
@spec delete(term()) :: :ok
```

Delete a key.

No-op if the key is absent. The deletion is synchronised to disk before
this function returns.

    Dala.State.delete(:theme)
    Dala.State.get(:theme, :obsidian)   #=> :obsidian

# `get`

```elixir
@spec get(term(), term()) :: term()
```

Read a persisted value.

Returns `default` if the key has never been written. `default` is `nil`
unless explicitly provided.

    iex> Dala.State.get(:theme, :obsidian)
    :obsidian

    iex> Dala.State.put(:theme, :citrus)
    iex> Dala.State.get(:theme, :obsidian)
    :citrus

Reads go directly to the underlying `:dets` table without going through
the GenServer, so they never queue behind in-flight writes.

# `put`

```elixir
@spec put(term(), term()) :: :ok
```

Persist a key-value pair to disk.

Any Elixir term is accepted for both key and value. Backed by `:dets`
(Erlang's disk-based term storage) with a `sync` after each write, so the
value is on disk before this function returns and survives an immediate
`SIGKILL` (Android OOM kill, iOS termination under memory pressure).

    Dala.State.put(:theme, :citrus)
    Dala.State.put(:onboarded, true)
    Dala.State.put({:last_seen, :home}, DateTime.utc_now())
    Dala.State.put(:prefs, %{font_size: 16, notifications: true})

Calling `put/2` with an existing key overwrites the previous value.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
