Search documentation of Plushie

# Plushie.State (Plushie v0.7.2)

Copy Markdown View Source

Path-based state management with revision tracking and transactions.

A lightweight wrapper around a plain map that tracks a monotonically increasing revision number on every mutation. Useful for detecting changes and implementing optimistic concurrency.

## Transactions

`begin_transaction/1` captures a snapshot of the current data and revision. Subsequent mutations increment the revision as usual. `commit_transaction/1` finalises the transaction (bumping the revision once from the pre-transaction value). `rollback_transaction/1` restores the snapshot exactly.

## Example

    state = Plushie.State.new(%{count: 0})
    state = Plushie.State.put(state, [:count], 5)
    Plushie.State.get(state, [:count])
    #=> 5
    Plushie.State.revision(state)
    #=> 1

## Summary

### Types

t()

### Functions

begin_transaction(state)

Begins a transaction by capturing the current data and revision.

commit_transaction(state)

Commits the active transaction, setting the revision to one past the pre-transaction value.

delete(state, path)

Removes the key at the end of `path`, incrementing the revision.

get(state, path)

Reads the value at `path` in the state data.

new(data)

Creates a new state container wrapping `data`.

put(state, path, value)

Sets the value at `path` to `value`, incrementing the revision.

revision(state)

Returns the current revision number.

rollback_transaction(state)

Rolls back the active transaction, restoring the data and revision to their pre-transaction values.

update(state, path, fun)

Applies `fun` to the value at `path`, incrementing the revision.

## Types

# t()

    @type t() :: %Plushie.State{
      data: map(),
      revision: non_neg_integer(),
      transaction: map() | nil
    }

## Functions

# begin_transaction(state)

    @spec begin_transaction(state :: t()) :: t() | {:error, :transaction_already_active}

Begins a transaction by capturing the current data and revision.

Returns `{:error, :transaction_already_active}` if a transaction is already in progress.

# commit_transaction(state)

    @spec commit_transaction(state :: t()) :: t()

Commits the active transaction, setting the revision to one past the pre-transaction value.

# delete(state, path)

    @spec delete(state :: t(), path :: list()) :: t()

Removes the key at the end of `path`, incrementing the revision.

Uses `Kernel.pop_in/2` to remove the key. If the path doesn't exist, the revision is still incremented for consistency.

# get(state, path)

    @spec get(state :: t(), path :: list()) :: term()

Reads the value at `path` in the state data.

An empty path returns the entire data map. Path elements are keys passed to `Kernel.get_in/2`.

# new(data)

    @spec new(data :: map()) :: t()

Creates a new state container wrapping `data`.

The initial revision is 0.

# put(state, path, value)

    @spec put(state :: t(), path :: list(), value :: term()) :: t()

Sets the value at `path` to `value`, incrementing the revision.

# revision(state)

    @spec revision(state :: t()) :: non_neg_integer()

Returns the current revision number.

# rollback_transaction(state)

    @spec rollback_transaction(state :: t()) :: t()

Rolls back the active transaction, restoring the data and revision to their pre-transaction values.

# update(state, path, fun)

    @spec update(state :: t(), path :: list(), fun :: (term() -> term())) :: t()

Applies `fun` to the value at `path`, incrementing the revision.

`fun` receives the current value and must return the new value.