# `Electric.ShapeCache.ShapeStatus`
[🔗](https://github.com/electric-sql/electric/tree/%40core/sync-service%401.6.2/packages/sync-service/lib/electric/shape_cache/shape_status.ex#L1)

Keeps track of shape state.

Can recover basic persisted shape metadata from shape storage to repopulate
the in-memory cache.

The shape cache then loads this and starts processes (storage and consumer)
for each `{shape_handle, %Shape{}}` pair. These then use their attached storage
to recover the status information for the shape (snapshot xmin and latest
offset).

The ETS metadata table name is part of the config because we need to be able
to access the data in the ETS from anywhere, so there's an internal api,
using the full state and an external api using just the table name.

# `shape_counts`

```elixir
@type shape_counts() :: %{
  total: non_neg_integer(),
  indexed: non_neg_integer(),
  unindexed: non_neg_integer()
}
```

# `shape_handle`

```elixir
@type shape_handle() :: Electric.shape_handle()
```

# `stack_id`

```elixir
@type stack_id() :: Electric.stack_id()
```

# `add_shape`

```elixir
@spec add_shape(stack_id(), Electric.Shapes.Shape.t()) ::
  {:ok, shape_handle()} | {:error, term()}
```

# `count_shapes`

```elixir
@spec count_shapes(stack_id()) :: non_neg_integer()
```

# `fetch_handle_by_shape`

```elixir
@spec fetch_handle_by_shape(stack_id(), Electric.Shapes.Shape.t()) ::
  {:ok, shape_handle()} | :error
```

# `fetch_handle_by_shape_critical`

```elixir
@spec fetch_handle_by_shape_critical(stack_id(), Electric.Shapes.Shape.t()) ::
  {:ok, shape_handle()} | :error
```

Where as `fetch_handle_by_shape/2` *may* under high-write load return stale
data -- not finding a shape that has been written -- due to SQLite's
cross-connection durability when in WAL mode, where a connection reads
against a snapshot of the data, this version does the lookup via the write
connection, which is guaranteed to see all writes (SQLite connections can
always see their own writes).

This guarantees that will will return consistent restults at the cost of slower
lookups as we're contending with access to the single write connection.

# `fetch_shape_by_handle`

```elixir
@spec fetch_shape_by_handle(stack_id(), shape_handle()) ::
  {:ok, Electric.Shapes.Shape.t()} | :error
```

# `has_shape_handle?`

# `initialize`

```elixir
@spec initialize(stack_id()) :: :ok | {:error, term()}
```

Runs a validation step on the existing Shape data.

The database path is dependent on both `@version` above and
`ShapeDb.Connection`'s `@schema_version`.

A change to either of those, or to the OTP release, will result in an empty
database.

# `least_recently_used`

# `list_shape_handles_for_relations`

```elixir
@spec list_shape_handles_for_relations(stack_id(), [Electric.oid_relation()]) :: [
  shape_handle()
]
```

# `list_shapes`

```elixir
@spec list_shapes(stack_id()) :: [{shape_handle(), Electric.Shapes.Shape.t()}]
```

# `mark_snapshot_complete`

```elixir
@spec mark_snapshot_complete(stack_id(), shape_handle()) :: :ok | :error
```

# `mark_snapshot_started`

```elixir
@spec mark_snapshot_started(stack_id(), shape_handle()) :: :ok | :error
```

# `reduce_shapes`

# `refresh`

```elixir
@spec refresh(stack_id()) :: :ok | {:error, term()}
```

Refresh the shape meta table from SQLite without recreating it.

Used on lock acquisition to pick up any shapes that were created/deleted
by a previous instance while we were in read-only mode.

# `remove_shape`

```elixir
@spec remove_shape(stack_id(), shape_handle()) :: :ok | {:error, term()}
```

# `reset`

```elixir
@spec reset(stack_id()) :: :ok
```

# `shape_counts`

```elixir
@spec shape_counts(stack_id()) :: shape_counts() | :error
```

# `shape_has_been_activated?`

```elixir
@spec shape_has_been_activated?(stack_id(), shape_handle()) :: boolean()
```

# `snapshot_started?`

# `update_last_read_time`

Sets the last read time for the given shape to the provided time.

Used for tests, otherwise prefer `update_last_read_time_to_now/2`.

# `update_last_read_time_to_now`

Updates the last read time for the given shape to the current time.

# `validate_shape_handle`

```elixir
@spec validate_shape_handle(stack_id(), shape_handle(), Electric.Shapes.Shape.t()) ::
  :ok | :error
```

Cheaply validate that a shape handle matches the shape definition by matching
the shape's saved hash against the provided shape's hash.

# `version`

```elixir
@spec version() :: pos_integer()
```

---

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