Skip to content

Commit 2389b7b

Browse files
authored
Merge pull request #1 from zmstone/feat-add-map-store
Feat add map store
2 parents 7972f1e + 805edac commit 2389b7b

5 files changed

+65
-23
lines changed

changelog.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
* 2.10.0
2+
- Add map as avro store, and use it as default.
3+
- Changed to store type aliases as type's full name index, so the type store map (or dict) is less bloated.
14
* 2.9.10
25
- Optimize avro:is_same_type/2
36
- Upgrade jsone to 1.8.1

src/avro_schema_store.erl

+52-17
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@
6262

6363
-include("avro_internal.hrl").
6464

65-
-opaque store() :: ets:tab() | {dict, dict:dict()}.
66-
-type option_key() :: access | name | dict.
65+
-type store() :: ets:tab() | {dict, dict:dict()} | map().
66+
-type option_key() :: access | name | dict | map.
6767
-type options() :: [option_key() | {option_key(), term()}].
6868
-type filename() :: file:filename_all().
6969

@@ -81,12 +81,20 @@ new() -> new([]).
8181
%% mode in ets:new and defines what processes can have access to
8282
%% * `{name, atom()}' - used to create a named ets table.
8383
%% * `dict' - use dict as store backend, ignore `access' and `name' options
84+
%% * `map' - use map as store backend, ignore `access' and `name' options
8485
%% @end
8586
-spec new(options()) -> store().
8687
new(Options) ->
8788
case proplists:get_bool(dict, Options) of
88-
true -> {dict, dict:new()};
89-
false -> new_ets(Options)
89+
true ->
90+
{dict, dict:new()};
91+
false ->
92+
case proplists:get_bool(map, Options) of
93+
true ->
94+
#{};
95+
false ->
96+
new_ets(Options)
97+
end
9098
end.
9199

92100
%% @doc Create a new schema store and improt the given schema JSON files.
@@ -98,6 +106,7 @@ new(Options, Files) ->
98106
%% @doc Return true if the given arg is a schema store.
99107
-spec is_store(term()) -> boolean().
100108
is_store({dict, _}) -> true;
109+
is_store(Map) when is_map(Map) -> true;
101110
is_store(T) -> is_integer(T) orelse is_atom(T) orelse is_reference(T).
102111

103112
%% @doc Make a schema lookup function from store.
@@ -143,12 +152,13 @@ import_schema_json(Json, Store) ->
143152
%% @doc Delete the ets table.
144153
-spec close(store()) -> ok.
145154
close({dict, _}) -> ok;
155+
close(Map) when is_map(Map) -> ok;
146156
close(Store) ->
147157
ets:delete(Store),
148158
ok.
149159

150160
%% @doc To make dialyzer happy.
151-
-spec ensure_store(atom() | integer() | reference() | {dict, dict:dict()}) ->
161+
-spec ensure_store(atom() | integer() | reference() | store()) ->
152162
store().
153163
ensure_store(Store) ->
154164
true = is_store(Store),
@@ -194,6 +204,7 @@ get_all_types(Store) ->
194204

195205
-spec to_list(store()) -> [{name(), avro_type()}].
196206
to_list({dict, Dict}) -> dict:to_list(Dict);
207+
to_list(Map) when is_map(Map) -> maps:to_list(Map);
197208
to_list(Store) -> ets:tab2list(Store).
198209

199210
-spec new_ets(options()) -> store().
@@ -212,8 +223,8 @@ new_ets(Options) ->
212223
-spec add_by_assigned_name(undefined | name_raw(),
213224
type_or_name(), store()) -> store().
214225
add_by_assigned_name(undefined, _Type, Store) -> Store;
215-
add_by_assigned_name(AssignedName, Type, Store) ->
216-
do_add_type_by_names([?NAME(AssignedName)], Type, Store).
226+
add_by_assigned_name(AssignedName, TypeOrName, Store) ->
227+
add_type_by_name(?NAME(AssignedName), TypeOrName, Store).
217228

218229
%% @private Parse file basename. try to strip ".avsc" or ".json" extension.
219230
-spec parse_basename(filename()) -> name().
@@ -241,13 +252,19 @@ import_schema_json(AssignedName, Json, Store) ->
241252
do_add_type(Type, Store) ->
242253
FullName = avro:get_type_fullname(Type),
243254
Aliases = avro:get_aliases(Type),
244-
do_add_type_by_names([FullName|Aliases], Type, Store).
255+
Store1 = add_type_by_name(FullName, Type, Store),
256+
add_aliases(Aliases, FullName, Store1).
257+
258+
add_aliases([], _FullName, Store) ->
259+
Store;
260+
add_aliases([Alias | More], FullName, Store) ->
261+
NewStore = put_type_to_store(Alias, FullName, Store),
262+
add_aliases(More, FullName, NewStore).
245263

246264
%% @private
247-
-spec do_add_type_by_names([fullname()], avro_type(), store()) ->
265+
-spec add_type_by_name([fullname()], avro_type(), store()) ->
248266
store() | no_return().
249-
do_add_type_by_names([], _Type, Store) -> Store;
250-
do_add_type_by_names([Name|Rest], Type, Store) ->
267+
add_type_by_name(Name, Type, Store) ->
251268
case get_type_from_store(Name, Store) of
252269
{ok, Type} ->
253270
Store;
@@ -257,27 +274,45 @@ do_add_type_by_names([Name|Rest], Type, Store) ->
257274
%% old / new types.
258275
erlang:error({name_clash, Name, Type, OtherType});
259276
false ->
260-
Store1 = put_type_to_store(Name, Type, Store),
261-
do_add_type_by_names(Rest, Type, Store1)
277+
put_type_to_store(Name, Type, Store)
262278
end.
263279

264280
%% @private
265-
-spec put_type_to_store(fullname(), avro_type(), store()) -> store().
281+
-spec put_type_to_store(fullname(), name() | avro_type(), store()) -> store().
266282
put_type_to_store(Name, Type, {dict, Dict}) ->
267283
NewDict = dict:store(Name, Type, Dict),
268284
{dict, NewDict};
285+
put_type_to_store(Name, Type, Map) when is_map(Map) ->
286+
Map#{Name => Type};
269287
put_type_to_store(Name, Type, Store) ->
270288
true = ets:insert(Store, {Name, Type}),
271289
Store.
272290

273-
%% @private
291+
%% @private Get type by name or alias.
274292
-spec get_type_from_store(fullname(), store()) -> false | {ok, avro_type()}.
275-
get_type_from_store(Name, {dict, Dict}) ->
293+
get_type_from_store(NameRef, Store) ->
294+
case do_get_type_from_store(NameRef, Store) of
295+
false ->
296+
false;
297+
{ok, FullName} when is_binary(FullName) ->
298+
do_get_type_from_store(FullName, Store);
299+
{ok, Type} ->
300+
{ok, Type}
301+
end.
302+
303+
%% @private
304+
-spec do_get_type_from_store(fullname(), store()) -> false | {ok, fullname() | avro_type()}.
305+
do_get_type_from_store(Name, {dict, Dict}) ->
276306
case dict:find(Name, Dict) of
277307
error -> false;
278308
{ok, Type} -> {ok, Type}
279309
end;
280-
get_type_from_store(Name, Store) ->
310+
do_get_type_from_store(Name, Map) when is_map(Map) ->
311+
case maps:find(Name, Map) of
312+
error -> false;
313+
{ok, Type} -> {ok, Type}
314+
end;
315+
do_get_type_from_store(Name, Store) ->
281316
case ets:lookup(Store, Name) of
282317
[] -> false;
283318
[{Name, Type}] -> {ok, Type}

src/avro_util.erl

+2-2
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,10 @@ ensure_lkup_fun(Sc) ->
8383
false -> make_lkup_fun(?ASSIGNED_NAME, Sc)
8484
end.
8585

86-
%% @doc Make a schema store (dict based) and wrap it in a lookup fun.
86+
%% @doc Make a schema store (map based) and wrap it in a lookup fun.
8787
-spec make_lkup_fun(name_raw(), avro_type()) -> lkup().
8888
make_lkup_fun(AssignedName, Type) ->
89-
Store0 = avro_schema_store:new([dict]),
89+
Store0 = avro_schema_store:new([map]),
9090
Store = avro_schema_store:add_type(AssignedName, Type, Store0),
9191
avro_schema_store:to_lookup_fun(Store).
9292

test/avro_schema_store_tests.erl

+7-3
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,13 @@ get_all_types_test() ->
3535
ok = avro_schema_store:close(Store)
3636
end,
3737
ok = TestFun(avro_schema_store:new([{name, ?MODULE}])),
38-
ok = TestFun(avro_schema_store:new([dict])).
38+
ok = TestFun(avro_schema_store:new([dict])),
39+
ok = TestFun(avro_schema_store:new([map])).
3940

4041
is_store_test() ->
4142
?assertNot(avro_schema_store:is_store(<<"json">>)),
4243
?assert(avro_schema_store:is_store(avro_schema_store:new([dict]))),
44+
?assert(avro_schema_store:is_store(avro_schema_store:new([map]))),
4345
?assert(avro_schema_store:is_store(avro_schema_store:new([]))).
4446

4547
ensure_store_test() ->
@@ -52,7 +54,8 @@ ensure_store_test() ->
5254
?assertEqual(1, avro_schema_store:ensure_store(1)),
5355
?assertEqual(atom, avro_schema_store:ensure_store(atom)),
5456
?assertEqual({dict, dict:new()},
55-
avro_schema_store:ensure_store({dict, dict:new()})).
57+
avro_schema_store:ensure_store({dict, dict:new()})),
58+
?assertEqual(#{}, avro_schema_store:ensure_store(#{})).
5659

5760
flatten_type_test() ->
5861
Type = avro_array:type(test_record()),
@@ -81,7 +84,8 @@ add_type_test() ->
8184
ok = avro_schema_store:close(Store1)
8285
end,
8386
ok = TestFun(avro_schema_store:new()),
84-
ok = TestFun(avro_schema_store:new([dict])).
87+
ok = TestFun(avro_schema_store:new([dict])),
88+
ok = TestFun(avro_schema_store:new([map])).
8589

8690
lookup(Name, Store) ->
8791
avro_schema_store:lookup_type(Name, Store).

test/avro_tests.erl

+1-1
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ wrapped_union_cast_test() ->
337337
Rec1 = avro_record:type("rec1", [avro_record:define_field("f1", int)]),
338338
Rec2 = avro_record:type("rec2", [avro_record:define_field("f1", int)]),
339339
Union = avro_union:type(["rec1", "rec2"]),
340-
Store0 = avro_schema_store:new([dict]),
340+
Store0 = avro_schema_store:new([map]),
341341
Store1 = avro_schema_store:add_type(Rec1, Store0),
342342
Store = avro_schema_store:add_type(Rec2, Store1),
343343
Lkup = avro_util:ensure_lkup_fun(Store),

0 commit comments

Comments
 (0)