Skip to content

Commit 70caf73

Browse files
whatyouhidetony612
authored andcommitted
Raise on non-existing fields in Protobuf.Builder.new/2 (#77)
* Raise on non-existing fields in Protobuf.Builder.new/2 * Use new!/2 * Generate new! when "use Protobuf" is called
1 parent 87bc43a commit 70caf73

File tree

3 files changed

+44
-25
lines changed

3 files changed

+44
-25
lines changed

lib/protobuf.ex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ defmodule Protobuf do
1616
def new(attrs) do
1717
Protobuf.Builder.new(__MODULE__, attrs)
1818
end
19+
20+
def new!(attrs) do
21+
Protobuf.Builder.new!(__MODULE__, attrs)
22+
end
1923
end
2024
end
2125

lib/protobuf/builder.ex

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,46 @@ defmodule Protobuf.Builder do
44
end
55

66
def new(mod, attrs) do
7+
new_maybe_strict(mod, attrs, _strict? = false)
8+
end
9+
10+
def new!(mod, attrs) do
11+
new_maybe_strict(mod, attrs, _strict? = true)
12+
end
13+
14+
def field_default(_, %{default: default}) when not is_nil(default), do: default
15+
def field_default(_, %{repeated?: true}), do: []
16+
def field_default(_, %{map?: true}), do: %{}
17+
def field_default(:proto3, props), do: type_default(props.type)
18+
def field_default(_, _), do: nil
19+
20+
def type_default(:int32), do: 0
21+
def type_default(:int64), do: 0
22+
def type_default(:uint32), do: 0
23+
def type_default(:uint64), do: 0
24+
def type_default(:sint32), do: 0
25+
def type_default(:sint64), do: 0
26+
def type_default(:bool), do: false
27+
def type_default({:enum, _}), do: 0
28+
def type_default(:fixed32), do: 0
29+
def type_default(:sfixed32), do: 0
30+
def type_default(:fixed64), do: 0
31+
def type_default(:sfixed64), do: 0
32+
def type_default(:float), do: 0.0
33+
def type_default(:double), do: 0.0
34+
def type_default(:bytes), do: <<>>
35+
def type_default(:string), do: ""
36+
def type_default(_), do: nil
37+
38+
defp new_maybe_strict(mod, attrs, strict?) do
739
case attrs do
840
%{__struct__: _} ->
941
attrs
1042

1143
_ ->
12-
msg = struct(mod.__default_struct__(), attrs)
1344
props = mod.__message_props__()
45+
default_struct = mod.__default_struct__()
46+
msg = if strict?, do: struct!(default_struct, attrs), else: struct(default_struct, attrs)
1447

1548
Enum.reduce(props.embedded_fields, msg, fn k, acc ->
1649
case msg do
@@ -36,28 +69,4 @@ defmodule Protobuf.Builder do
3669
end)
3770
end
3871
end
39-
40-
def field_default(_, %{default: default}) when not is_nil(default), do: default
41-
def field_default(_, %{repeated?: true}), do: []
42-
def field_default(_, %{map?: true}), do: %{}
43-
def field_default(:proto3, props), do: type_default(props.type)
44-
def field_default(_, _), do: nil
45-
46-
def type_default(:int32), do: 0
47-
def type_default(:int64), do: 0
48-
def type_default(:uint32), do: 0
49-
def type_default(:uint64), do: 0
50-
def type_default(:sint32), do: 0
51-
def type_default(:sint64), do: 0
52-
def type_default(:bool), do: false
53-
def type_default({:enum, _}), do: 0
54-
def type_default(:fixed32), do: 0
55-
def type_default(:sfixed32), do: 0
56-
def type_default(:fixed64), do: 0
57-
def type_default(:sfixed64), do: 0
58-
def type_default(:float), do: 0.0
59-
def type_default(:double), do: 0.0
60-
def type_default(:bytes), do: <<>>
61-
def type_default(:string), do: ""
62-
def type_default(_), do: nil
6372
end

test/protobuf/builder_test.exs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,10 @@ defmodule Protobuf.BuilderTest do
4949
msg = %Foo{}
5050
assert msg == Foo.new(msg)
5151
end
52+
53+
test "new!/2 raises for fields that don't exist in the schema" do
54+
assert_raise KeyError, fn ->
55+
Foo.new!(nonexisting_field: "foo")
56+
end
57+
end
5258
end

0 commit comments

Comments
 (0)