Embeds in schemaless changesets

Hello everyone. I want to use schemaless changesets to validate external data. And I wonder how to properly use embeds with them.

Let’s assume I want to validate the nested map under the user key in my params payload. And I want my data to be a map in the end. So to get this work I managed to write this “hack”:

defmodule Params do
  import Ecto.Changeset

  @user_types %{id: :integer}

  @user_fields Map.keys(@user_types)

  @types %{
    name: :string,
    page: :integer,
    page_size: :integer,
    ages: {:array, :integer},
    user:
      {:embed,
       elem(
         Ecto.ParameterizedType.init(Ecto.Embedded,
           cardinality: :one,
           related: __MODULE__,
           field: :user
         ),
         2
       )}
  }

  @default %{
    page: 1,
    page_size: 10
  }

  @fields Map.keys(@types) -- [:user]

  def build(entity \\ @default, attrs \\ %{}) do
    entity
    |> changeset(attrs)
    |> apply_action(:insert)
  end

  def changeset(entity, attrs) do
    {entity, @types}
    |> cast(attrs, @fields)
    |> cast_embed(:user, with: &user_changeset/2)
  end

  def user_changeset(entity, attrs) do
    {entity, @user_types}
    |> cast(attrs, @user_fields)
  end

  def __schema__(:primary_key), do: []
  def __struct__, do: %{}
end

Although it’s kinda working doesn’t seems good. As I need to define __schema__/1 and __struct__/0 functons with custom behavior while setting related key to not being relation module, but parent module.

I want to know better approaches to how to validate nested data using schemaless changesets. Or maybe that’s not proper usage of schemaless changeset. And I need to use schema/embedded_schema to avoid “hacking” ?