Packages

A comprehensive state management library for Phoenix LiveView with DSL, type checking, and deep Phoenix integration.

Current section

Files

Jump to
live_schema lib live_schema.ex
Raw

lib/live_schema.ex

defmodule LiveSchema do
@moduledoc """
A comprehensive state management library for Phoenix LiveView.
LiveSchema provides a DSL for defining typed state structures with automatic
setter generation, action-based state transitions, and deep Phoenix integration.
## Quick Start
Define a state schema:
defmodule MyApp.PostsState do
use LiveSchema
schema do
field :posts, {:list, Post}, default: []
field :selected, {:nullable, Post}
field :loading, :boolean, default: false
embeds_one :filter do
field :status, {:enum, [:all, :active]}, default: :all
field :query, :string, default: ""
end
end
action :select_post, [:id] do
post = Enum.find(state.posts, &(&1.id == id))
set_selected(state, post)
end
end
## Features
- **Schema DSL** - Define your state structure declaratively
- **Type System** - Built-in types with optional runtime validation
- **Auto-generated Setters** - Reduce boilerplate
- **Actions** - Elm-style state transitions
- **Embeds** - Nested state structures
- **Phoenix Integration** - Works with LiveView and Components
## Configuration
Configure LiveSchema in your `config.exs`:
config :live_schema,
validate_at: :runtime, # :runtime | :none
on_error: :log # :log | :raise | :ignore
"""
@doc false
defmacro __using__(opts) do
quote do
import LiveSchema.Schema,
only: [
schema: 1,
field: 2,
field: 3,
embeds_one: 2,
embeds_one: 3,
embeds_many: 2,
embeds_many: 3
]
import LiveSchema.Action,
only: [action: 2, action: 3, async_action: 2, async_action: 3, reaction: 2, reaction: 3]
import LiveSchema.Middleware, only: [before_action: 1, after_action: 1]
@live_schema_opts unquote(opts)
Module.register_attribute(__MODULE__, :live_schema_fields, accumulate: true)
Module.register_attribute(__MODULE__, :live_schema_embeds, accumulate: true)
Module.register_attribute(__MODULE__, :live_schema_actions, accumulate: true)
Module.register_attribute(__MODULE__, :live_schema_before_hooks, accumulate: true)
Module.register_attribute(__MODULE__, :live_schema_after_hooks, accumulate: true)
@before_compile LiveSchema.Compiler
end
end
@doc """
Computes the difference between two states.
Returns a map describing what changed between the old and new state.
## Example
{:changed, diff} = LiveSchema.diff(old_state, new_state)
# diff = %{
# changed: [:posts, :selected],
# added: %{selected: post},
# removed: %{},
# nested: %{filter: %{changed: [:status]}}
# }
"""
defdelegate diff(old_state, new_state), to: LiveSchema.Diff
end