How to dynamically cast and validate embedded Ecto schemas based on a field type in Elixir?

I have an Elixir application using Ecto, and I need to dynamically cast and validate embedded schemas based on a type field. My Discount schema has a field discount_params that can be different structures depending on the value of the type field.

I don’t want to change the field type from :map and want to leave it as it is.

Here is the base function:

defmodule Discounts.Discount do

  schema "discounts" do
    field :type, :string
    field :global, :boolean
    field :discount, :integer
    field :discount_params, :map
    field :latest_event, :string, virtual: true, default: ""

    has_many :event_discounts, EventDiscount, on_replace: :delete
    has_many :events, through: [:event_discounts, :event]

    timestamps()
  end

  @type id_t() :: String.t() | non_neg_integer()
  @type t ::
          %__MODULE__{
            id: non_neg_integer(),
            type: String.t(),
            global: boolean(),
            discount: non_neg_integer(),
            discount_params: %{String.t() => String.t() | non_neg_integer()},
            inserted_at: Date.t(),
            event_discounts: [EventDiscount.t()],
            events: [Event.t()]
          }
          | %__MODULE__{}

  @required_params ~w(type discount discount_params)a
  @optional_params ~w(global)a

  defp changeset(discount, params) do
    discount
    |> cast(params, @required_params ++ @optional_params)
    |> cast_assoc(:event_discounts)
    |> validate_required(@required_params)
    |> validate_inclusion(:type, ["Package", "Volume"])
    |> cast_discount_params(params)
  end

  defp cast_discount_params(changeset, params) do
    type = get_field(changeset, :type)

    schema_module = Module.concat(Discounts.DiscountType, DiscountParams.schema(type))
     # return example Discounts.DiscountType.Volume.Params

    if schema_module do
      embed_params = Map.get(params, "discount_params", %{})
      embed_changeset = schema_module.changeset(%schema_module{}, embed_params)

      if embed_changeset.valid? do
        params = apply_changes(embed_changeset)
        change(changeset, discount_params: params)
      else
        Enum.reduce(embed_changeset.errors, changeset, fn {field, error}, acc ->
          add_error(acc, field, error)
        end)
      end
    else
      changeset
    end
  end

And I have two discount types:

defmodule SG.Shop.Discounts.DiscountType.Package do
  use SG.Shop.Discounts.DiscountType

  alias SG.Shop.Discounts.Discount
  alias SG.Shop.Events.ProductType

  @name DiscountType.name(__MODULE__)

  defmodule Params do
    use DiscountParams

    @primary_key false
    embedded_schema do
      field :product_type_a, :string
      field :product_type_b, :string
    end

    @required_params ~w(product_type_a product_type_b)a
    @optional_params ~w()a

    def changeset(discount_params, params \ %{}) do
      discount_params
      |> cast(params, @required_params ++ @optional_params)
      |> validate_required(@required_params)
      |> validate_inclusion(:product_type_a, ProductType.all_types())
      |> validate_inclusion(:product_type_b, ProductType.all_types())
    end
  end
end

   
    
defmodule SG.Shop.Discounts.DiscountType.Package do
  use SG.Shop.Discounts.DiscountType

  alias SG.Shop.Discounts.Discount
  alias SG.Shop.Events.ProductType

  @name DiscountType.name(__MODULE__)

  defmodule Params do
    use DiscountParams

    @primary_key false
    embedded_schema do
      field :product_type_a, :string
      field :product_type_b, :string
    end

    @required_params ~w(product_type_a product_type_b)a
    @optional_params ~w()a

    def changeset(discount_params, params \ %{}) do
      discount_params
      |> cast(params, @required_params ++ @optional_params)
      |> validate_required(@required_params)
      |> validate_inclusion(:product_type_a, ProductType.all_types())
      |> validate_inclusion(:product_type_b, ProductType.all_types())
    end
  end
end

I have tried the above approach, but I am facing issues with dynamically setting the schema_module. How can I achieve this so the validation goes through the embedded schema based on the type we get? And discounts discount_type is created only with this fields not with all given from params

    defmodule Discounts.DiscountType.Volume do
      
      defmodule Params do
        use DiscountParams
    
        @primary_key false
        embedded_schema do
          field(:n, :integer)
          field(:product_type, :string)
        end
    
        @required_params ~w(n product_type)a
        @optional_params ~w()a
    
        def changeset(discount_params, params \ %{}) do
          discount_params
          |> cast(params, @required_params ++ @optional_params)
          |> validate_required(@required_params)
          |> validate_inclusion(:product_type, ProductType.all_types())
          |> validate_number(:n, greater_than: 0, less_than_or_equal_to: 100)
        end
      end
    end 

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật