# `Raxol.Core.Stores.Dets`
[🔗](https://github.com/DROOdotFOO/raxol/blob/v2.7.0/lib/raxol/core/stores/dets.ex#L1)

Shared DETS lifecycle for ETS-backed stores with optional disk persistence.

An ETS-backed store keeps its working set in one or more `:named_table`
ETS tables and, when configured, mirrors the canonical records to a DETS
file so they survive a process restart. This module covers:

- resolving the DETS path from start options or application config,
- opening (or creating) the file and replaying its records back into the
  caller's live ETS tables on boot,
- writing through to disk on each mutation,
- flushing and closing the file on shutdown.

The caller owns its ETS table topology and replay logic. The replay step
is supplied as a function so a store with secondary indices can re-index
every record as it is read back. A `nil` handle is a valid no-op
throughout, so a store with persistence disabled can call these helpers
unconditionally.

Pure: depends only on `:dets`, `File`, and `Path`.

# `handle`

```elixir
@type handle() :: :dets.tab_name() | nil
```

An open DETS handle, or `nil` when persistence is disabled.

# `clear`

```elixir
@spec clear(handle()) :: :ok
```

Wipe every persisted record. No-op when persistence is disabled.

# `close`

```elixir
@spec close(handle()) :: :ok
```

Flush and close the DETS file. No-op when persistence is disabled.

Intended for a store's `terminate/2`. A `SIGKILL` can still lose the most
recent write window; use a real database for stronger guarantees.

# `delete`

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

Delete a record from disk. No-op when persistence is disabled.

# `get`

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

Read a record straight from disk, or `default` when the key is absent.

For stores whose working set lives in ETS this is never needed (replay
covers boot); it exists for single-record stores with no ETS mirror, such
as a poller checkpoint. Returns `default` when persistence is disabled.

# `open!`

```elixir
@spec open!(atom(), binary(), ({term(), term()} -&gt; any())) :: handle()
```

Open (or create) the DETS file at `path` under table name `dets_name`,
replay every stored record through `replay_fun`, and return the handle.

`replay_fun` is called once per `{key, value}` record for its side effect
(re-inserting into the caller's ETS tables); its return value is ignored.

Raises when the parent directory cannot be created or the file cannot be
opened, so a misconfigured path surfaces at boot rather than degrading
silently to an in-memory store.

# `put`

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

Write a record through to disk. No-op when persistence is disabled.

# `resolve_path`

```elixir
@spec resolve_path(keyword(), atom(), atom()) :: binary() | nil
```

Resolve the configured DETS path, or `nil` when persistence is disabled.

An explicit `:dets_path` in `opts` always wins; otherwise the value falls
back to `Application.get_env(otp_app, config_key)`. Returns `nil` when
neither is set, signalling in-memory-only operation.

---

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