-
-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Managing schema registry's schema references #50
Managing schema registry's schema references #50
Conversation
78b8e3b
to
6fd72f7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for your effort the code looks much cleaner now 👍🏼
In addition to specific points, I have a few recommendations about the code style:
- Please don't prefix variables, we have a file context and it should cover that need
- Please don't use 1-2 char variables, it makes code harder to read and it's acceptable in few cases when a shorter name will give some benefits.
- Please run
mix format
to align the code with project formatting rules (they are pretty standard, except the line length)
lib/avrora/storage/registry.ex
Outdated
@@ -33,7 +33,7 @@ defmodule Avrora.Storage.Registry do | |||
{:ok, id} <- Map.fetch(response, "id"), | |||
{:ok, version} <- Map.fetch(response, "version"), | |||
{:ok, schema} <- Map.fetch(response, "schema"), | |||
{:ok, schema} <- Schema.parse(schema) do | |||
{:ok, schema} <- Schema.parse(schema, csr_references_lookup_function(response)) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this function is local and will be called on each reference we should apply a few adjustments:
- Rename
csr_references_lookup_function
tomake_references_lookup_fun
because the scope of the whole module is CSR so no need to mention it in any name here - All the references must be prepared in advance otherwise (like in the current implementation) they will be extracted on each function call
As an idea:
{:ok, schema} <- Schema.parse(schema, csr_references_lookup_function(response)) do | |
{:ok, references} <- extract_references(response), | |
{:ok, schema} <- Schema.parse(schema, make_references_lookup_fun(references)) do |
where references is a Map
lib/avrora/storage/registry.ex
Outdated
@@ -93,10 +93,26 @@ defmodule Avrora.Storage.Registry do | |||
@spec configured?() :: true | false | |||
def configured?, do: !is_nil(registry_url()) | |||
|
|||
defp csr_references_lookup_function(response) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To comply with typespec of reference lookup function from Avrora.Schema we should always return a function with interface like
@type reference_lookup_fun :: (String.t() -> {:ok, String.t()} | {:error, term()})
which means for us that we can re-use the default lookup function Avrora.Schema.reference_lookup/1
lib/avrora/storage/registry.ex
Outdated
case Map.fetch(response, "references") do | ||
{:ok, csr_references} -> | ||
references = Enum.reduce(csr_references, %{}, fn(cr, map) -> | ||
{:ok, schema_map} = get(cr["subject"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will throw a matching error, but what if we can use case
+ throw
to take control over it and return {:error, ...}
instead. Also would be nice to cover it with a test of something like "reference can't be obtained"
lib/avrora/storage/registry.ex
Outdated
fn(r) -> | ||
json_schema = Map.get(references, r) | ||
{:ok, json_schema} | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fn(r) -> | |
json_schema = Map.get(references, r) | |
{:ok, json_schema} | |
end | |
{:ok, &Map.fetch(references, &1)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Strech thank you for your review, I'm a newbie in Elixir so any correction is very important for me.
I think I've applied all your corrections in last commit. Please take a look and if I missed something please let me know. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the refactoring, let's improve the reference extraction and we will be good to go 🚀
lib/avrora/storage/registry.ex
Outdated
end | ||
end | ||
|
||
defp make_references_lookup_fun(references) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a general correction for the whole file - reference_lookup
because it's a function to resolve 1 reference at a time. So better to name it
{:error, subject_not_found_parsed_error()} | ||
end) | ||
|
||
assert catch_throw(Registry.get("io.confluent.Account") == :unknown_subject) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it was a bit of misunderstanding, this assertion should look like this
assert catch_throw(Registry.get("io.confluent.Account") == :unknown_subject) | |
assert Registry.get("io.confluent.Account") == {:error, :unknown_reference_subject} |
lib/avrora/storage/registry.ex
Outdated
end | ||
end | ||
|
||
defp get_reference_schema(map, subject) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method should be inlined (i.e removed) back to the extract_references/1
lib/avrora/storage/registry.ex
Outdated
defp extract_references(response) do | ||
case Map.fetch(response, "references") do | ||
{:ok, references} -> | ||
references_map = | ||
Enum.reduce(references, %{}, fn cr, map -> | ||
get_reference_schema(map, cr["subject"]) | ||
end) | ||
|
||
{:ok, references_map} | ||
|
||
:error -> | ||
{:ok, :schema_without_references} | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By using throw I mean that we need to exit from the inner loop with error, but not throw it to outside, throw
it's just a control flow in this case.
I would like to suggest something like this
defp extract_references(response) do | |
case Map.fetch(response, "references") do | |
{:ok, references} -> | |
references_map = | |
Enum.reduce(references, %{}, fn cr, map -> | |
get_reference_schema(map, cr["subject"]) | |
end) | |
{:ok, references_map} | |
:error -> | |
{:ok, :schema_without_references} | |
end | |
end | |
defp extract_references(response) do | |
references = | |
response | |
|> Map.get("references", []) | |
|> Enum.reduce(%{}, fn reference, memo -> | |
case get(reference["subject"]) do | |
{:ok, schema} -> Map.put(memo, schema.full_name, schema.json) | |
{:error, error} -> throw(error) | |
end | |
end) | |
{:ok, references} | |
catch | |
{:error, :unknown_subject} -> {:error, :unknown_reference_subject} | |
error -> {:error, error} | |
end |
lib/avrora/storage/registry.ex
Outdated
@@ -33,7 +33,8 @@ defmodule Avrora.Storage.Registry do | |||
{:ok, id} <- Map.fetch(response, "id"), | |||
{:ok, version} <- Map.fetch(response, "version"), | |||
{:ok, schema} <- Map.fetch(response, "schema"), | |||
{:ok, schema} <- Schema.parse(schema) do | |||
{:ok, references} <- extract_references(response), | |||
{:ok, schema} <- Schema.parse(schema, make_references_lookup_fun(references)) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rename make_references_lookup_fun
to make_reference_lookup_fun
(see below)
lib/avrora/storage/registry.ex
Outdated
defp make_references_lookup_fun(references) do | ||
case references do | ||
:schema_without_references -> &Avrora.Schema.reference_lookup/1 | ||
_ -> &Map.fetch(references, &1) | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why the credo
silent about it, but for such a case if/else
should be used
if references == :no_references,
do: &Avrora.Schema.reference_lookup/1
else: &Map.fetch(references, &1)
And then we can return {:ok, %{}}
in extract_references
and use the same if/else
if references == %{},
do: &Avrora.Schema.reference_lookup/1
else: &Map.fetch(references, &1)
end
and from here we can go to pattern matching
defp make_references_lookup_fun(references) do | |
case references do | |
:schema_without_references -> &Avrora.Schema.reference_lookup/1 | |
_ -> &Map.fetch(references, &1) | |
end | |
end | |
def make_reference_lookup_function(%{}), do: &Avrora.Schema.reference_lookup/1 | |
def make_reference_lookup_function(references), do: &Map.fetch(references, &1) |
89d412d
to
e4963e1
Compare
@Strech I applied your advices. Thanks :) |
@FrancescoPessina Wanna say thanks for amazing contribution 🎉 . I will merge your PR, but the version release will be together with #47 If it will take too long (week+) for Klarna to release klarna/erlavro#104 then I would make preparations and release the next version without nil fix. |
@Strech thank you very much for your precise review :) Thanks again |
Hey, @FrancescoPessina a heads-up! The new 0.14 release was published on the Hex. Thanks a lot for your help, I appreciate it! |
This PR enables Avro schema parsing with new schema registry's schema references feature, introducing a dedicated lookup function for references got from CSR.
Changes in this PR comes from the discussion of the deprecated #49 pull request.
cc @Strech