# `AshScylla.PreparedStatementCache`
[🔗](https://github.com/ohhi-vn/ash_scylla/blob/main/lib/ash_scylla/prepared_statement_cache.ex#L15)

ETS-based prepared statement cache for ScyllaDB/Cassandra queries.

Caches prepared statements keyed by `{repo, cql, keyspace, opts}` to
eliminate repeated query parsing overhead on ScyllaDB. This is especially
impactful for high-throughput workloads where the same queries are executed
repeatedly.

All ETS operations are routed through the GenServer to avoid race
conditions when multiple processes access the cache concurrently.

## Usage

    AshScylla.PreparedStatementCache.prepare(repo, "SELECT * FROM users WHERE id = ?")

## Starting the Cache

Add to your supervision tree:

    children = [
      AshScylla.PreparedStatementCache,
      # ... other children
    ]

Or start manually:

    AshScylla.PreparedStatementCache.start_link([])

## Limits

- Max cache size: 10,000 entries
- Cleanup interval: 5 minutes
- Registered locally as `__MODULE__` by default

# `cache_entry`

```elixir
@type cache_entry() :: {term(), term()}
```

# `cache_key`

```elixir
@type cache_key() :: {module(), String.t(), String.t(), keyword()}
```

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `clear`

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

Clears all cached prepared statements.

# `evict_oldest`

```elixir
@spec evict_oldest(:ets.tid(), non_neg_integer()) :: :ok
```

Evicts the oldest `count` entries from the cache.

Exposed for testing the eviction logic.

# `invalidate`

```elixir
@spec invalidate(String.t()) :: :ok
```

Invalidates a specific cached statement by CQL string.

# `max_cache_size`

```elixir
@spec max_cache_size() :: non_neg_integer()
```

Returns the configured maximum cache size.

Exposed for testing.

# `prepare`

```elixir
@spec prepare(module(), String.t(), keyword()) :: {:ok, term()} | {:error, term()}
```

Prepares a CQL statement, using the cache if available.

Returns `{:ok, stmt}` on success or `{:error, reason}` on failure.

# `size`

```elixir
@spec size() :: non_neg_integer()
```

Returns the number of cached statements.

# `start_link`

```elixir
@spec start_link(keyword()) :: GenServer.on_start()
```

Starts the prepared statement cache.

When no `:name` option is given, the GenServer is registered locally
as `__MODULE__` so that each node runs its own per-node cache. This is
required in a clustered deployment (libcluster + K8s/gossip), where a
global name would be contested by every node and cause repeated
`:reached_max_restart_intensity` crashes.

Pass a `{:global, name}` tuple to register globally, or a custom local
name to register under a different local name.

# `table`

```elixir
@spec table() :: :ets.tid() | nil
```

Returns the ETS table tid for inspection/testing.

---

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