diff --git a/lib/live_sync/replication_test.exs b/lib/live_sync/replication_test.exs index ed3d665..f661a22 100644 --- a/lib/live_sync/replication_test.exs +++ b/lib/live_sync/replication_test.exs @@ -7,7 +7,7 @@ defmodule LiveSync.ReplicationTest do alias LiveSync.Replication alias LiveSync.Repo - @moduletag cleanup: ["ignored", "examples"] + @moduletag cleanup: ["example_tags", "ignored", "examples"] setup do LiveSync.start_link(repo: Repo, otp_app: :live_sync) diff --git a/lib/live_sync/socket.ex b/lib/live_sync/socket.ex index 6c0e3fe..8432988 100644 --- a/lib/live_sync/socket.ex +++ b/lib/live_sync/socket.ex @@ -69,10 +69,10 @@ defmodule LiveSync.Socket do :delete %{} = value -> - {schema, id} = LiveSync.lookup_info(value) + lookup = LiveSync.lookup_info(value) Enum.find_value(operations, fn {op, record} -> - if record.__struct__ == schema and record.id == id do + if LiveSync.lookup_info(record) == lookup do op end end) @@ -206,9 +206,9 @@ defmodule LiveSync.Socket do update.__struct__ == assoc.related and Map.get(update, assoc.related_key) != Map.get(parent, assoc.owner_key) end) - |> Enum.map(fn {_lookup, {_op, update}} -> update.id end) + |> Enum.map(fn {lookup, {_op, _update}} -> lookup end) - Enum.filter(list, &(is_map(&1) && &1.id not in records_to_remove)) + Enum.filter(list, &(is_map(&1) && LiveSync.lookup_info(&1) not in records_to_remove)) end defp maybe_remove_from_association(record, _parent, _assoc, _updates), do: record diff --git a/lib/live_sync/socket_test.exs b/lib/live_sync/socket_test.exs index fe63d5c..7e6610e 100644 --- a/lib/live_sync/socket_test.exs +++ b/lib/live_sync/socket_test.exs @@ -2,6 +2,7 @@ defmodule LiveSync.SocketTest do use LiveSync.ConnCase alias LiveSync.Example + alias LiveSync.ExampleTag alias LiveSync.Ignored alias LiveSync.Repo @@ -179,6 +180,25 @@ defmodule LiveSync.SocketTest do ] == Floki.find(parsed_html, ".data-child-name") end + test "works with associations without an id", %{conn: conn} do + example = Repo.insert!(%Example{organization_id: 1, name: "replication", enabled: false}) + Repo.insert!(%ExampleTag{name: "tag", example_id: example.id}) + + {:ok, view, html} = conn |> get("/#{example.id}") |> live() + + parsed_html = Floki.parse_document!(html) + assert parsed_html |> Floki.find(".data-tag-name") |> Floki.text() == "tag" + + Repo.update!(change(example, name: "more replication")) + + assert_receive :synced + html = render(view) + + parsed_html = Floki.parse_document!(html) + assert parsed_html |> Floki.find("#data-name") |> Floki.text() == "more replication" + assert parsed_html |> Floki.find(".data-tag-name") |> Floki.text() == "tag" + end + test "ignores non-watched schemas", %{conn: conn} do example = Repo.insert!(%Example{organization_id: 1, name: "replication", enabled: false}) ignore = Repo.insert!(%Ignored{organization_id: 1, name: "ignore", example_id: example.id}) diff --git a/lib/test_helper.exs b/lib/test_helper.exs index 0554f2a..9aaffac 100644 --- a/lib/test_helper.exs +++ b/lib/test_helper.exs @@ -1,6 +1,7 @@ LiveSync.Repo.start_link() LiveSync.Endpoint.start_link() +LiveSync.Repo.query!("DROP TABLE IF EXISTS example_tags;") LiveSync.Repo.query!("DROP TABLE IF EXISTS ignored;") LiveSync.Repo.query!("DROP TABLE IF EXISTS examples;") LiveSync.Repo.query("DROP PUBLICATION live_sync;") @@ -28,6 +29,14 @@ CREATE TABLE ignored ( ); """) +LiveSync.Repo.query!(""" +CREATE TABLE example_tags ( + name text, + example_id bytea REFERENCES examples(id), + PRIMARY KEY (name, example_id) +); +""") + Ecto.Migration.Runner.run(LiveSync.Repo, LiveSync.Repo.config(), 1, LiveSync.Migration, :forward, :up, :up, []) ExUnit.start(capture_log: true) diff --git a/mix.exs b/mix.exs index be990dd..1af102e 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule LiveSync.MixProject do def project do [ app: :live_sync, - version: "0.1.11", + version: "0.1.12", elixir: "~> 1.17", elixirc_paths: elixirc_paths(Mix.env()), start_permanent: Mix.env() == :prod, diff --git a/test/support/example.ex b/test/support/example.ex index cd3c379..31b98ef 100644 --- a/test/support/example.ex +++ b/test/support/example.ex @@ -26,6 +26,7 @@ defmodule LiveSync.Example do belongs_to :parent, LiveSync.Example, type: :binary_id, foreign_key: :parent_id has_many :children, LiveSync.Example, foreign_key: :parent_id has_many :ignored, LiveSync.Ignored, foreign_key: :example_id + has_many :example_tags, LiveSync.ExampleTag, foreign_key: :example_id end def changeset(struct \\ %__MODULE__{}, params) do diff --git a/test/support/example_tag.ex b/test/support/example_tag.ex new file mode 100644 index 0000000..24697f4 --- /dev/null +++ b/test/support/example_tag.ex @@ -0,0 +1,13 @@ +defmodule LiveSync.ExampleTag do + @moduledoc false + use Ecto.Schema + + # a join style schema with a composite primary key and no `id` field + @primary_key false + + schema "example_tags" do + field :name, :string, primary_key: true + + belongs_to :example, LiveSync.Example, type: :binary_id, foreign_key: :example_id, primary_key: true + end +end diff --git a/test/support/live_page.ex b/test/support/live_page.ex index 5e48ff1..09b5190 100644 --- a/test/support/live_page.ex +++ b/test/support/live_page.ex @@ -12,7 +12,7 @@ defmodule LiveSync.LivePage do alias LiveSync.Repo def mount(%{"id" => id}, session, socket) do - data = LiveSync.Example |> Repo.get!(id) |> Repo.preload([:parent, :children, :ignored]) + data = LiveSync.Example |> Repo.get!(id) |> Repo.preload([:parent, :children, :ignored, :example_tags]) {:ok, assign(socket, examples: [data], data: data, test: session["test"])} end @@ -36,6 +36,7 @@ defmodule LiveSync.LivePage do
{@data.parent.name}
{child.name}
{ignored.name}
+{tag.name}