Skip to content

Commit 0c2d208

Browse files
thruflomagnetised
andauthored
Revised writer docs. (#19)
@magnetised I've done a pass on the docs. I'm afraid that it does include renaming preflight to check and Changeset to validate. Give it a read with an open mind -- for me this is far clearer naming. https://funny-sable-3d7d09.netlify.app/readme.html https://funny-sable-3d7d09.netlify.app/phoenix.sync.writer --------- Co-authored-by: Garry Hill <garry@electric-sql.com>
1 parent 292769a commit 0c2d208

File tree

3 files changed

+252
-176
lines changed

3 files changed

+252
-176
lines changed

README.md

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
# Phoenix.Sync
22

3+
Real-time sync for Postgres-backed [Phoenix](https://www.phoenixframework.org/) applications.
4+
35
<p>
4-
<br />
56
<a href="https://hexdocs.pm/phoenix_sync" target="_blank">
67
<picture>
78
<img alt="Phoenix sync illustration"
89
src="https://github.com/electric-sql/phoenix_sync/raw/main/docs/phoenix-sync.png"
910
/>
1011
</picture>
1112
</a>
12-
<br />
1313
</p>
1414

1515
[![Hex.pm](https://img.shields.io/hexpm/v/phoenix_sync.svg)](https://hex.pm/packages/phoenix_sync)
@@ -18,25 +18,26 @@
1818
[![Status](https://img.shields.io/badge/status-beta-orange)](https://github.com/electric-sql/phoenix_sync)
1919
[![Discord](https://img.shields.io/discord/933657521581858818?color=5969EA&label=discord)](https://discord.electric-sql.com)
2020

21-
Sync is the best way of building modern apps. Phoenix.Sync enables real-time sync for Postgres-backed [Phoenix](https://www.phoenixframework.org/) applications.
22-
2321
Documentation is available at [hexdocs.pm/phoenix_sync](https://hexdocs.pm/phoenix_sync).
2422

25-
## Build real-time apps on locally synced data
23+
## Build real-time apps on sync
2624

27-
- sync data into Elixir, `LiveView` and frontend web and mobile applications
28-
- integrates with `Plug` and `Phoenix.{Controller, LiveView, Router, Stream}`
29-
- uses [ElectricSQL](https://electric-sql.com) for scalable data delivery and fan out
30-
- maps `Ecto` queries to [Shapes](https://electric-sql.com/docs/guides/shapes) for partial replication
25+
Phoenix.Sync is a library that adds real-time sync to Postgres-backed [Phoenix](https://www.phoenixframework.org/) applications. Use it to sync data into both LiveView and front-end web and mobile applications.
3126

32-
## Usage
27+
- integrates with `Plug` and `Phoenix.{Controller, LiveView, Router, Stream}`
28+
- uses [ElectricSQL](https://electric-sql.com) for core sync, fan-out and data delivery
29+
- maps `Ecto.Query`s to [Shapes](https://electric-sql.com/docs/guides/shapes) for partial replication
3330

34-
There are four key APIs:
31+
There are four key APIs for [read-path sync](#read-path-sync) out of Postgres:
3532

3633
- [`Phoenix.Sync.Client.stream/2`](https://hexdocs.pm/phoenix_sync/Phoenix.Sync.Client.html#stream/2) for low level usage in Elixir
37-
- [`Phoenix.Sync.LiveView.sync_stream/4`](https://hexdocs.pm/phoenix_sync/Phoenix.Sync.LiveView.html#sync_stream/4) to sync into a LiveView stream
38-
- [`Phoenix.Sync.Router.sync/2`](https://hexdocs.pm/phoenix_sync/Phoenix.Sync.Router.html#sync/2) macro to expose a statically defined shape in your Router
39-
- [`Phoenix.Sync.Controller.sync_render/3`](https://hexdocs.pm/phoenix_sync/Phoenix.Sync.Controller.html#sync_render/3) to expose dynamically constructed shapes from a Controller
34+
- [`Phoenix.Sync.LiveView.sync_stream/4`](https://hexdocs.pm/phoenix_sync/Phoenix.Sync.LiveView.html#sync_stream/4) to sync into a LiveView
35+
- [`Phoenix.Sync.Router.sync/2`](https://hexdocs.pm/phoenix_sync/Phoenix.Sync.Router.html#sync/2) macro to expose a shape in your Router
36+
- [`Phoenix.Sync.Controller.sync_render/3`](https://hexdocs.pm/phoenix_sync/Phoenix.Sync.Controller.html#sync_render/3) to return shapes from a Controller
37+
38+
And a [`Phoenix.Sync.Writer`](https://hexdocs.pm/phoenix_sync/Phoenix.Sync.Writer.html) module for handling [write-path sync](#write-path-sync) back into Postgres.
39+
40+
## Read-path sync
4041

4142
### Low level usage in Elixir
4243

@@ -152,6 +153,52 @@ const MyComponent = () => {
152153

153154
See the Electric [demos](https://electric-sql.com/demos) and [documentation](https://electric-sql.com/demos) for more client-side usage examples.
154155

156+
## Write-path sync
157+
158+
The [`Phoenix.Sync.Writer`](https://hexdocs.pm/phoenix_sync/Phoenix.Sync.Writer.html) module allows you to ingest batches of writes from the client.
159+
160+
The idea is that the front-end can batch up [local optimistic writes](https://electric-sql.com/docs/guides/writes). For example using a library like [@TanStack/optimistic](https://github.com/TanStack/optimistic) or by [monitoring changes to a local embedded database](https://electric-sql.com/docs/guides/writes#through-the-db).
161+
162+
These changes can be POSTed to a `Phoenix.Controller`, which then constructs a `Phoenix.Sync.Writer` instance. The writer instance authorizes and validates the writes before applying them to the database. Under the hood this uses `Ecto.Multi`, to ensure that transactions (batches of writes) are applied atomically.
163+
164+
For example, the controller below handles local writes made to a project management app. It constructs a writer instance and pipes it through a series of [`Writer.allow/3`](https://hexdocs.pm/phoenix_sync/Phoenix.Sync.Writer.html#allow/3) calls. These register functions against `Ecto.Schema`s (in this case `Projects.Project` and `Projects.Issue`):
165+
166+
```elixir
167+
defmodule MutationController do
168+
use Phoenix.Controller, formats: [:json]
169+
170+
alias Phoenix.Sync.Writer
171+
alias Phoenix.Sync.Writer.Format
172+
173+
def mutate(conn, %{"transaction" => transaction} = _params) do
174+
user_id = conn.assigns.user_id
175+
176+
{:ok, txid, _changes} =
177+
Phoenix.Sync.Writer.new(format: Format.TanstackOptimistic)
178+
|> Phoenix.Sync.Writer.allow(
179+
Projects.Project,
180+
check: reject_invalid_params/2,
181+
load: &Projects.load_for_user(&1, user_id),
182+
validate: &Projects.Project.changeset/2
183+
)
184+
|> Phoenix.Sync.Writer.allow(
185+
Projects.Issue,
186+
# Use the sensible defaults:
187+
# load: Ecto.Repo.get_by(Projects.Issue, id: ^issue_id)
188+
# validate: Projects.Issue.changeset/2
189+
# etc.
190+
)
191+
|> Phoenix.Sync.Writer.apply(transaction, Repo)
192+
193+
render(conn, :mutations, txid: txid)
194+
end
195+
end
196+
```
197+
198+
This facilitates incrementally adding bi-directional sync support to a Phoenix application, re-using your existing auth and schema/validation logic.
199+
200+
See the [`Phoenix.Sync.Writer`](https://hexdocs.pm/phoenix_sync/Phoenix.Sync.Writer.html) module docs for more information.
201+
155202
## Installation and configuration
156203

157204
`Phoenix.Sync` can be used in two modes:

0 commit comments

Comments
 (0)