You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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
-
23
21
Documentation is available at [hexdocs.pm/phoenix_sync](https://hexdocs.pm/phoenix_sync).
24
22
25
-
## Build real-time apps on locally synced data
23
+
## Build real-time apps on sync
24
+
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.
26
26
27
-
- sync data into Elixir, `LiveView` and frontend web and mobile applications
28
27
- 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
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
31
30
32
-
## Usage
31
+
There are four key APIs for [read-path sync](#read-path-sync) out of Postgres:
33
32
34
-
There are four key APIs:
33
+
-`Phoenix.Sync.Client.stream/2` for low level usage in Elixir
34
+
-`Phoenix.Sync.LiveView.sync_stream/4` to sync into a LiveView
35
+
-`Phoenix.Sync.Router.sync/2` macro to expose a shape in your Router
36
+
-`Phoenix.Sync.Controller.sync_render/3` to return shapes from a Controller
35
37
36
-
-[`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
38
+
And a `Phoenix.Sync.Writer` module for handling [write-path sync](#write-path-sync) back into Postgres.
39
+
40
+
## Read-path sync
40
41
41
42
### Low level usage in Elixir
42
43
43
-
Use [`Phoenix.Sync.Client.stream/2`](https://hexdocs.pm/phoenix_sync/Phoenix.Sync.Client.html#stream/2) to convert an `Ecto.Query` into an Elixir `Stream`:
44
+
Use `Phoenix.Sync.Client.stream/2` to convert an `Ecto.Query` into an Elixir `Stream`:
44
45
45
46
```elixir
46
47
stream =Phoenix.Sync.Client.stream(Todos.Todo)
@@ -52,7 +53,7 @@ stream =
52
53
53
54
### Sync into a LiveView stream
54
55
55
-
Swap out `Phoenix.LiveView.stream/3` for [`Phoenix.Sync.LiveView.sync_stream/4`](https://hexdocs.pm/phoenix_sync/Phoenix.Sync.LiveView.html#sync_stream/4) to automatically keep a LiveView up-to-date with the state of your Postgres database:
56
+
Swap out `Phoenix.LiveView.stream/3` for `Phoenix.Sync.LiveView.sync_stream/4` to automatically keep a LiveView up-to-date with the state of your Postgres database:
56
57
57
58
```elixir
58
59
defmoduleMyWeb.MyLivedo
@@ -75,7 +76,7 @@ This means you can build fully end-to-end real-time multi-user applications with
75
76
76
77
### Sync shapes through your Router
77
78
78
-
Use the [`Phoenix.Sync.Router.sync/2`](https://hexdocs.pm/phoenix_sync/Phoenix.Sync.Router.html#sync/2) macro to expose statically (compile-time) defined shapes in your Router:
79
+
Use the `Phoenix.Sync.Router.sync/2` macro to expose statically (compile-time) defined shapes in your Router:
79
80
80
81
```elixir
81
82
defmoduleMyWeb.Routerdo
@@ -98,7 +99,7 @@ Because the shapes are exposed through your Router, the client connects through
98
99
99
100
### Sync dynamic shapes from a Controller
100
101
101
-
Sync shapes from any standard Controller using the [`Phoenix.Sync.Controller.sync_render/3`](https://hexdocs.pm/phoenix_sync/Phoenix.Sync.Controller.html#sync_render/3) view function:
102
+
Sync shapes from any standard Controller using the `Phoenix.Sync.Controller.sync_render/3` view function:
See the Electric [demos](https://electric-sql.com/demos) and [documentation](https://electric-sql.com/docs) for more client-side usage examples.
154
155
156
+
## Write-path sync
157
+
158
+
The `Phoenix.Sync.Writer` 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 `Phoenix.Sync.Writer.allow/3` calls. These register functions against `Ecto.Schema`s (in this case `Projects.Project` and `Projects.Issue`):
165
+
166
+
```elixir
167
+
defmoduleMutationControllerdo
168
+
usePhoenix.Controller, formats: [:json]
169
+
170
+
aliasPhoenix.Sync.Writer
171
+
aliasPhoenix.Sync.Writer.Format
172
+
173
+
defmutate(conn, %{"transaction"=> transaction} =_params) do
For anything else more dyanamic, or to use Ecto queries, you should switch from using the `sync` macros in your router to using `sync_render/3` in a controller.
405
+
For anything else more dynamic, or to use Ecto queries, you should switch from using the `sync` macros in your router to using `sync_render/3` in a controller.
360
406
361
407
### Using a keyword list
362
408
@@ -372,4 +418,3 @@ The available options are:
372
418
-`replica` (optional). By default Electric will only send primary keys + changed columns on updates. Set `replica: :full` to receive the full row, not just the changed columns.
373
419
374
420
See the [Electric Shapes guide](https://electric-sql.com/docs/guides/shapes) for more information.
0 commit comments