@@ -133,36 +133,55 @@ defmodule Schemecto do
133133 defp build_changeset ( fields ) do
134134 { types , defaults , metadata_validations } = extract_field_info ( fields )
135135
136- changeset = Ecto.Changeset . change ( { defaults , types } , % { } )
136+ changeset = Ecto.Changeset . change ( { Map . new ( defaults ) , types } , % { } )
137137 % { changeset | validations: metadata_validations ++ changeset . validations }
138138 end
139139
140140 # Extracts types, defaults, and metadata validations from field definitions
141141 defp extract_field_info ( fields ) do
142- Enum . reduce ( fields , { % { } , % { } , [ ] } , fn field , { types_acc , defaults_acc , metadata_acc } ->
142+ Enum . reduce ( fields , { % { } , [ ] , [ ] } , fn field , { types_acc , defaults_acc , metadata_acc } ->
143143 name = Map . fetch! ( field , :name )
144144 type = Map . fetch! ( field , :type )
145145
146- # Add to types map
146+ if Map . has_key? ( types_acc , name ) do
147+ raise ArgumentError , "duplicate field #{ inspect ( name ) } given to Schemecto"
148+ end
149+
147150 types_acc = Map . put ( types_acc , name , type )
148151
149- # Add to defaults if present
150152 defaults_acc =
151- case Map . fetch ( field , :default ) do
152- { :ok , default } -> Map . put ( defaults_acc , name , default )
153- :error -> defaults_acc
153+ case field do
154+ % { default: default } -> [ { name , default } | defaults_acc ]
155+ % { } -> defaults_acc
154156 end
155157
156- # Build metadata map for this field
157- metadata = % { }
158- metadata = if Map . has_key? ( field , :description ) , do: Map . put ( metadata , :description , field . description ) , else: metadata
159- metadata = if Map . has_key? ( field , :title ) , do: Map . put ( metadata , :title , field . title ) , else: metadata
160- metadata = if Map . has_key? ( field , :deprecated ) , do: Map . put ( metadata , :deprecated , field . deprecated ) , else: metadata
158+ metadata =
159+ Enum . flat_map ( field , fn
160+ { :name , name } when is_atom ( name ) ->
161+ [ ]
162+
163+ { :type , _type } ->
164+ [ ]
165+
166+ { :default , _ } ->
167+ [ ]
168+
169+ { :deprecated , boolean } when is_boolean ( boolean ) ->
170+ [ { :deprecated , boolean } ]
171+
172+ { :title , string } when is_binary ( string ) ->
173+ [ { :title , string } ]
174+
175+ { :description , string } when is_binary ( string ) ->
176+ [ { :description , string } ]
177+
178+ { name , _value } ->
179+ raise ArgumentError , "unknown key #{ inspect ( name ) } in #{ inspect ( field ) } "
180+ end )
161181
162- # Add metadata validation if there's any metadata
163182 metadata_acc =
164- if map_size ( metadata ) > 0 do
165- [ { name , { :schemecto_metadata , metadata } } | metadata_acc ]
183+ if metadata != [ ] do
184+ [ { name , { :schemecto_metadata , Map . new ( metadata ) } } | metadata_acc ]
166185 else
167186 metadata_acc
168187 end
@@ -220,6 +239,10 @@ defmodule Schemecto do
220239 end
221240 end
222241
242+ # For compatibility with Ecto earlier than v3.12
243+ defp type_to_json_schema ( { :parameterized , mod , arg } ) ,
244+ do: type_to_json_schema ( { :parameterized , { mod , arg } } )
245+
223246 defp type_to_json_schema ( { :parameterized , { Ecto.Enum , params } } = type ) do
224247 Ecto.Enum . type ( params )
225248 |> type_to_json_schema ( )
0 commit comments