Files
firezone/elixir/apps/domain/lib/domain.ex
Jamil cce21a8dea fix(portal): handle jsonb for embedded schemas (#9882)
In #9664, we introduced the `Domain.struct_from_params/2` function which
converts a set of params containing string keys into a provided struct
representing a schema module. This is used to broadcast actual structs
pertaining to WAL data as opposed to simple string encodings of the
data.

The problem is that function was a bit too naive and failed to properly
cast embedded schemas, resulting in all embedded schema on the root
struct being `nil` or `[]`.

To fix this, we need to do two things:

1. We now decode JSON/JSONB fields from binaries (strings) into actual
lists and maps in the replication consumer module for downstream
processors to use
2. We update our `struct_from_params/2` function to properly cast
embedded schemas from these lists and maps using Ecto.Changeset's
`apply_changes` function, which uses the same logic to instantiate the
schemas as if we were saving a form or API request.

Lastly, tests are added to ensure this works under various scenarios,
including nested embedded schemas which we use in some places.

Fixes #9835

---------

Signed-off-by: Jamil <jamilbk@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-15 23:50:27 +00:00

44 lines
897 B
Elixir

defmodule Domain do
@moduledoc """
This module provides a common interface for all the domain modules,
making sure our code structure is consistent and predictable.
"""
def schema do
quote do
use Ecto.Schema
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
@timestamps_opts [type: :utc_datetime_usec]
@type id :: binary()
end
end
def changeset do
quote do
import Ecto.Changeset
import Domain.Repo.Changeset
import Domain.Repo, only: [valid_uuid?: 1]
end
end
def query do
quote do
import Ecto.Query
import Domain.Repo.Query
@behaviour Domain.Repo.Query
end
end
@doc """
When used, dispatch to the appropriate schema/context/changeset/query/etc.
"""
defmacro __using__(which) when is_atom(which) do
apply(__MODULE__, which, [])
end
end