Skip to content

:map type in Schemaless Changeset.cast/3 only accepts single type #4271

Description

@ozthegnp

Elixir version

1.14.4

Database and Version

n/a

Ecto Versions

3.9.5

Database Adapter and Versions (postgrex, myxql, etc)

n/a

Current behavior

This works, and it means that all keys in the map must be strings.

types = %{foo: {:map, :string}}
cs = cast({%{}, types}, %{foo: %{bar: "hello", baz: "world"}}, Map.keys(types))
IO.inspect(cs.valid?)IO.inspect(cs.valid?)
# true

This also works to detect non-string fields within the nested map.

types = %{foo: {:map, :string}}
cs = cast({%{}, types}, %{foo: %{bar: 3}}, Map.keys(types))
IO.inspect(cs.valid?)
# false
IO.inspect(cs.errors)
# errors: [foo: {"is invalid", [type: {:map, :string}, validation: :cast]}]

However, when we try to define a specific type of the nested key, an error is raised.

types = %{foo: {:map, %{bar: :string}}}
Ecto.Changeset.cast({%{}, types}, %{foo: %{bar: "hello}}, Map.keys(types))
# ** (FunctionClauseError) no function clause matching in Ecto.Type.cast_fun/1

# The following arguments were given to Ecto.Type.cast_fun/1:

#     # 1
#     %{bar: :string}

It seems we are limited to uniform types exclusively.

Expected behavior

We should be able to define custom types for each key in the map. e.g:

types = %{foo: {:map, %{bar: :string, baz: :integer}}}
Ecto.Changeset.cast({%{}, types}, %{foo: %{bar: "hello", baz: 1}}, Map.keys(types))
IO.inspect(cs.valid?)
# true

Thank you

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions