Skip to content

Zurga/ecto_sync

Repository files navigation

EctoSync

TLDR;

Subscribe to events emitted by EctoWatch, cache the result, allow subscribers to sync.

Use cases

Schema:

Post <-> PostsTags <-> Tag

Subscribe to alterations of assocs of loaded rows (in a LiveView for example):

application.ex

children = [
  ...,
  {EctoSync,
   repo: MyRepo,
   pub_sub: MyPubSub,
   watchers: EctoSync.all_events(Posts, assocs: true)

PostLive.ex

alias MyApp.Posts.Post
alias MyApp.Posts.Tag

def mount(params, session, socket) do
  posts = list_posts(preload: [:tags])
  if connected?(socket) do
    EctoSync.subscribe_all(Post)
  end

  {:ok, assign(socket, posts: posts)}
end

def handle_info({{Tag, _event}, sync_args}, socket) do
  {:ok, posts} = EctoSync.sync(socket.assigns.posts, sync_args)
  {:noreply, assign(socket, posts: posts)}
end
  1. When a Tag is updated, all posts that contain that tag will be updated.
  2. When a Tag is inserted, the tag will automatically be added to the corresponding post.

The tag is loaded from the database once for each event handled by EctoSync. The result is then cached and this cached version will be used when other processes call EctoSync.sync/2 with the args provided in handle_info.

Subscribe to insertions of assocs that can be used for row creation:

PostForm.ex

def mount(params, session, socket) do
  tags = list_tags()
  if connected?(socket) do
    EctoSync.subscribe_assocs(Post)
  end

  {:ok, assign(socket, tags: tags)}
end

def render(assigns) do
  ~F"""
  <.simple_form for={@form}>
    <input name="name" placeholder="Post name" />
    <select multiple name="tags">
      <option :for={tag <- @tags} value={tag.id}>{tag.name}</option>
    </select>
  </.simple_form>
  """
end

def handle_info({{Tag, _event}, sync_args}, socket) do
  {:ok, tags} = EctoSync.sync(socket.assigns.tags, sync_args)
  {:noreply, assign(socket, tags: tags)
end

Installation

If available in Hex, the package can be installed by adding ecto_sync to your list of dependencies in mix.exs:

def deps do
  [
    {:ecto_sync, "~> 0.1.0"}
  ]
end

Modify lib/my_app/application.ex

children = [
  ...,
  {EctoSync,
   repo: MyRepo,
   pub_sub: MyPubSub,
   watchers:
     EctoSync.all_events(Schema)
     |> EctoSync.all_events(OtherSchema, assocs: :some_assocs)
     |> EctoSync.all_events(AnotherSchema, extra_columns: [:test_id])},
  ]

Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/ecto_sync.

About

Cache the EctoWatch events and sync your rows

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages