# `LivePanels.Canvas.LayoutStore.Ecto`
[🔗](https://github.com/livepanels/livepanels/blob/v0.1.0/lib/livepanels/canvas/layout_store/ecto.ex#L1)

Ecto-backed `LivePanels.Canvas.LayoutStore` adapter.

Use this module to define an application layout store backed by an Ecto repo
and schema:

    defmodule MyApp.CanvasLayouts do
      use LivePanels.Canvas.LayoutStore.Ecto,
        repo: MyApp.Repo,
        schema: MyApp.LivePanelsCanvasLayout
    end

The schema needs a unique canvas id field and a layout field that stores the
versioned layout list unchanged. With PostgreSQL, `{:array, :map}` is the
direct fit for LivePanels layout payloads:

    defmodule MyApp.LivePanelsCanvasLayout do
      use Ecto.Schema

      schema "livepanels_canvas_layouts" do
        field :canvas_id, :string
        field :layout, {:array, :map}, default: []

        timestamps(type: :utc_datetime_usec)
      end
    end

Migration:

    create table(:livepanels_canvas_layouts) do
      add :canvas_id, :string, null: false
      add :layout, {:array, :map}, null: false, default: []

      timestamps(type: :utc_datetime_usec)
    end

    create unique_index(:livepanels_canvas_layouts, [:canvas_id])

Then wire the generated store into a local or distributed shared backend:

    use LivePanels.Canvas,
      pubsub: MyApp.PubSub,
      session: [
        mode: :shared,
        id: {:param, "board_id"},
        backend:
          {LivePanels.Canvas.Shared.Local,
           layout_store: MyApp.CanvasLayouts}
      ]

The generated store uses `repo.insert_all/3` with `on_conflict` for saves and
`repo.get_by/2` for loads. The adapter intentionally avoids compile-time Ecto
references so LivePanels can ship the adapter without forcing Ecto into every
installation. Because `insert_all/3` bypasses schema changesets, this table is
LivePanels-owned: out-of-band writers are validated at layout load time, not
when rows are written.

> #### `use LivePanels.Canvas.LayoutStore.Ecto` {: .info}
>
> When you `use LivePanels.Canvas.LayoutStore.Ecto`, the module sets the
> `LivePanels.Canvas.LayoutStore` behaviour and defines the required `save/2`
> and `load/1` callbacks backed by the configured repo, schema, fields, and
> timestamp options.

## Options

  * `:repo` - required Ecto repo module.
  * `:schema` - required Ecto schema module.
  * `:canvas_id_field` - schema field used as the unique canvas key.
    Defaults to `:canvas_id`.
  * `:layout_field` - schema field that stores the layout list. Defaults to
    `:layout`.
  * `:timestamps` - when true, save writes `inserted_at` and `updated_at`.
    Defaults to true.
  * `:inserted_at_field` - timestamp field for inserted rows. Defaults to
    `:inserted_at`.
  * `:updated_at_field` - timestamp field replaced on conflict. Defaults to
    `:updated_at`.

# `option`

```elixir
@type option() ::
  {:repo, module()}
  | {:schema, module()}
  | {:canvas_id_field, atom()}
  | {:layout_field, atom()}
  | {:timestamps, boolean()}
  | {:inserted_at_field, atom()}
  | {:updated_at_field, atom()}
```

# `options`

```elixir
@type options() :: [option()]
```

# `__using__`
*macro* 

Defines an Ecto-backed layout store module.

---

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