Skip to content

Commit f4bf2a4

Browse files
committed
Relax Ecto dependency, validate all fields
1 parent f807000 commit f4bf2a4

2 files changed

Lines changed: 39 additions & 16 deletions

File tree

lib/schemecto.ex

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -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()

mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ defmodule Schemecto.MixProject do
2727

2828
defp deps do
2929
[
30-
{:ecto, "~> 3.12"},
30+
{:ecto, "~> 3.7"},
3131
{:ex_doc, "~> 0.34", only: :docs}
3232
]
3333
end

0 commit comments

Comments
 (0)