Created
October 13, 2016 08:33
-
-
Save zhongwencool/11b511e02ac24c667703db7b112411a4 to your computer and use it in GitHub Desktop.
[test] mnesia find object without transaction.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(mnesia_read_test). | |
-include_lib("stdlib/include/ms_transform.hrl"). | |
-include_lib("stdlib/include/qlc.hrl"). | |
%% API | |
-compile(export_all). | |
-record(person, {name, sex, age, height}). | |
-define(PERSON, person). | |
init_table() -> | |
mnesia:start(), | |
random:seed(), | |
mnesia:create_table(?PERSON, | |
[{attributes, record_info(fields, ?PERSON)}, | |
{ram_copies, [erlang:node()]}, | |
{index, [age]}, | |
{majority, true}]), | |
create_persons(1000). | |
%% 1. accord primary key to read one object | |
find_person_by_name(Name) -> | |
mnesia:dirty_read(?PERSON, Name). | |
%% 2. accord index to read objects | |
find_person_by_age(Age) -> | |
mnesia:dirty_index_read(?PERSON, Age, #person.age). | |
%% 3. Match Pattern | |
%% The function mnesia:match_object/3 automatically uses indexes if these exist. However, no heuristics are performed to select the best index. | |
find_person_by_age2(Age) -> | |
mnesia:dirty_match_object(?PERSON, {person, '_', '_', Age, '_'}). | |
%% 4. assign index's Match Pattern | |
find_person_by_age3(Age) -> | |
mnesia:dirty_index_match_object(?PERSON, {person, '_', '_', Age, '_'}, #person.age). | |
%% 5. select | |
find_name_by_age_range(MinAge, MaxAge) -> | |
MatchSpec = ets:fun2ms(fun(#person{age = Age, name = Name}) when Age >= MinAge andalso Age =< MaxAge -> {Age, Name} end), | |
mnesia:dirty_select(?PERSON, MatchSpec). | |
%% 6. foldl Iterates over the table | |
find_name_by_age_range2(MinAge, MaxAge) -> | |
Fun = fun(#person{age = Age, name = Name}, Acc) when Age >= MinAge andalso Age =< MaxAge -> [{Age, Name}|Acc]; | |
(_, Acc) -> Acc | |
end, | |
mnesia:async_dirty(fun() -> mnesia:foldl(Fun, [], ?PERSON) end). | |
%% 7. first/next Iterates over the table | |
find_name_by_age_range3(MinAge, MaxAge) -> | |
case mnesia:dirty_first(?PERSON) of | |
'$end_of_table' -> []; | |
First -> | |
[Person] = mnesia:dirty_read({person, First}), | |
Persons = | |
if Person#person.age >= MinAge andalso Person#person.age =< MaxAge -> | |
[{Person#person.age, Person#person.name}]; | |
true -> [] | |
end, | |
read_next(First, MinAge, MaxAge, Persons) | |
end. | |
%% 8. qlc | |
find_name_by_age_range4(MinAge, MaxAge) -> | |
Fun = fun() -> | |
qlc:e(qlc:q([{X#person.age, X#person.name} || X <- mnesia:table(?PERSON), | |
X#person.age >= MinAge, | |
X#person.age =< MaxAge])) | |
end, | |
mnesia:async_dirty(Fun). | |
test() -> | |
init_table(), | |
Res0 = [P0|_] = find_person_by_name("zhongwencool100"), | |
io:format("dirty_read find_person_by_name Number:~p~nSample:~p~n", [length(Res0), P0]), | |
Res1 = [P1|_] = find_person_by_age(21), | |
io:format("dirty_index_read find_person_by_age Number:~p~nSample:~p~n", [length(Res1), P1]), | |
Res2 = [P2|_] = find_person_by_age2(21), | |
io:format("dirty_match_object find_person_by_age2 Number:~p~nSample:~p~n", [length(Res2), P2]), | |
Res3 = [P3|_] = find_person_by_age3(21), | |
io:format("dirty_index_match_object find_person_by_age3 Number:~p~nSample:~p~n", [length(Res3), P3]), | |
Res4 = [P4|_] = find_name_by_age_range(10, 20), | |
io:format("dirty_select find_name_by_age_range Number:~p~nSample:~p~n", [length(Res4), P4]), | |
Res5 = [P5|_] = find_name_by_age_range2(10, 20), | |
io:format("foldl find_name_by_age_range2 Number:~p~nSample:~p~n", [length(Res5), P5]), | |
Res6 = [P6|_] = find_name_by_age_range3(10, 20), | |
io:format("first/next find_name_by_age_range3 Number:~p~nSample:~p~n", [length(Res6), P6]), | |
Res7 = [P7|_] = find_name_by_age_range4(10, 20), | |
io:format("qlc find_name_by_age_range4 Number:~p~nSample:~p~n", [length(Res7), P7]), | |
io:format("verify result :~p~n", [{Res1 == Res2, Res2 == Res3, Res4 == Res5, Res5 == Res6, lists:sort(Res6) == lists:sort(Res7)}]), | |
ok. | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
%% Local Function | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
create_person(Person)when is_record(Person, person) -> | |
{atomic, ok} = mnesia:transaction(fun() -> mnesia:write(Person) end). | |
create_persons(Num)when is_integer(Num) -> | |
Fun = | |
fun() -> | |
[begin | |
Person = #person{name = "zhongwencool" ++ integer_to_list(Index), | |
sex = random_sex(), | |
age = random_age(), | |
height = Index + 120}, | |
mnesia:write(Person) | |
end|| Index <-lists:seq(1, Num)], | |
ok | |
end, | |
{atomic, ok} = mnesia:transaction(Fun). | |
read_next(Current, MinAge, MaxAge, Acc) -> | |
case mnesia:dirty_next(person, Current) of | |
'$end_of_table' -> Acc; | |
Next -> | |
[Person] = mnesia:dirty_read({person, Next}), | |
Persons = | |
if Person#person.age >= MinAge andalso Person#person.age =< MaxAge -> | |
[{Person#person.age, Person#person.name}|Acc]; | |
true -> Acc | |
end, | |
read_next(Next, MinAge, MaxAge, Persons) | |
end. | |
random_age() -> | |
Age = lists:nth(random:uniform(9), [10, 20, 30, 40, 50, 60, 70, 80, 90]), | |
Age + random:uniform(10) - 1. | |
random_sex() -> | |
case random:uniform(2) of | |
1 -> male; | |
2 -> female | |
end. |
Author
zhongwencool
commented
Oct 13, 2016
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment