Imagine modelling this is Riak pre2.0? Look at user.erl, where are the merge functions? There aren't any.
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
{ | |
"profile": { | |
"guid": "12345", | |
"created": "2008-08-26T23:35:16Z", | |
"familyName": "Edgerton", | |
"givenName": "Samantha", | |
"image": { | |
"height": 225, | |
"url": "http://img.avatars.yahoo.com/users/1YfXUc4vMAAEB9IFDbJ_vk45UmUYE==.large.png", | |
"width": 150 | |
}, | |
"Interests": { | |
"Hobbies": [ | |
"Pottery", | |
"Tennis", | |
"Skiing", | |
"Hiking", | |
"Travel", | |
"picnics" | |
], | |
"Films": [ | |
"Ratatouille", | |
"TheIncredibles" | |
], | |
"Books": [] | |
}, | |
"nickname": "Sam" | |
}, | |
"searches": 100, | |
"views": 10, | |
"liked": 8, | |
"active": true | |
} |
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
Eshell V5.10.3 (abort with ^G) | |
1> f(Pid), {ok, Pid} = riakc_pb_socket:start_link("localhost", 8087). | |
{ok,<0.34.0>} | |
2> Key = <<"0987">>. | |
<<"0987">> | |
3> {ok, U} = user:create_user(Pid, Key, <<"Bob">>, <<"Dobalina">>, <<"bodo">>). | |
{ok,{map,[{{<<"active">>,flag},true}, | |
{{<<"likes">>,counter},0}, | |
{{<<"profile">>,map}, | |
[{{<<"nickName">>,register},<<"bodo">>}, | |
{{<<"interests">>,map}, | |
[{{<<"hobbies">>,set},[]}, | |
{{<<"films">>,set},[]}, | |
{{<<"books">>,set},[]}]}, | |
{{<<"image">>,map}, | |
[{{<<"width">>,register},<<>>}, | |
{{<<"url">>,register},<<>>}, | |
{{<<"height">>,register},<<>>}]}, | |
{{<<"guid">>,register},<<"0987">>}, | |
{{<<"givenName">>,register},<<"Bob">>}, | |
{{<<"familyName">>,register},<<"Dobalina">>}]}, | |
{{<<"searches">>,counter},0}, | |
{{<<"views">>,counter},0}], | |
[],[],[], | |
<<77,1,0,0,0,113,131,108,0,0,0,5,104,2,100,0,14,114,105, | |
97,107,...>>}} | |
4> user:add_image(Pid, Key, <<"125">>, <<"150">>, <<"http://not.reallybobd.info/bodb.png">>). | |
{ok,{map,[{{<<"active">>,flag},true}, | |
{{<<"likes">>,counter},0}, | |
{{<<"profile">>,map}, | |
[{{<<"nickName">>,register},<<"bodo">>}, | |
{{<<"interests">>,map}, | |
[{{<<"hobbies">>,set},[]}, | |
{{<<"films">>,set},[]}, | |
{{<<"books">>,set},[]}]}, | |
{{<<"image">>,map}, | |
[{{<<"width">>,register},<<"150">>}, | |
{{<<"url">>,register}, | |
<<"http://not.reallybobd.info/bodb.png">>}, | |
{{<<"height">>,register},<<"125">>}]}, | |
{{<<"guid">>,register},<<"0987">>}, | |
{{<<"givenName">>,register},<<"Bob">>}, | |
{{<<"familyName">>,register},<<"Dobalina">>}]}, | |
{{<<"searches">>,counter},0}, | |
{{<<"views">>,counter},0}], | |
[],[],[], | |
<<77,1,0,0,0,113,131,108,0,0,0,5,104,2,100,0,14,114,105, | |
97,107,...>>}} | |
5> user:add_hobbies(Pid, Key, [<<"fishing">>, <<"skiing">>, <<"cycling">>, <<"knitting">>]). | |
{ok,{map,[{{<<"active">>,flag},true}, | |
{{<<"likes">>,counter},0}, | |
{{<<"profile">>,map}, | |
[{{<<"nickName">>,register},<<"bodo">>}, | |
{{<<"interests">>,map}, | |
[{{<<"hobbies">>,set}, | |
[<<"cycling">>,<<"fishing">>,<<"knitting">>,<<"skiing">>]}, | |
{{<<"films">>,set},[]}, | |
{{<<"books">>,set},[]}]}, | |
{{<<"image">>,map}, | |
[{{<<"width">>,register},<<"150">>}, | |
{{<<"url">>,register}, | |
<<"http://not.reallybobd.info/bodb.png">>}, | |
{{<<"height">>,register},<<"125">>}]}, | |
{{<<"guid">>,register},<<"0987">>}, | |
{{<<"givenName">>,register},<<"Bob">>}, | |
{{<<"familyName">>,register},<<"Dobalina">>}]}, | |
{{<<"searches">>,counter},0}, | |
{{<<"views">>,counter},0}], | |
[],[],[], | |
<<77,1,0,0,0,113,131,108,0,0,0,5,104,2,100,0,14,114,105, | |
97,107,...>>}} | |
6> user:add_films(Pid, Key, [<<"bambi">>, <<"The Incredibles">>, <<"Enter The Dragon">>, <<"Cocolat">>]). | |
{ok,{map,[{{<<"active">>,flag},true}, | |
{{<<"likes">>,counter},0}, | |
{{<<"profile">>,map}, | |
[{{<<"nickName">>,register},<<"bodo">>}, | |
{{<<"interests">>,map}, | |
[{{<<"hobbies">>,set}, | |
[<<"cycling">>,<<"fishing">>,<<"knitting">>,<<"skiing">>]}, | |
{{<<"films">>,set}, | |
[<<"Cocolat">>,<<"Enter The Dragon">>,<<"The Incredibles">>, | |
<<"bambi">>]}, | |
{{<<"books">>,set},[]}]}, | |
{{<<"image">>,map}, | |
[{{<<"width">>,register},<<"150">>}, | |
{{<<"url">>,register}, | |
<<"http://not.reallybobd.info/bodb.png">>}, | |
{{<<"height">>,register},<<"125">>}]}, | |
{{<<"guid">>,register},<<"0987">>}, | |
{{<<"givenName">>,register},<<"Bob">>}, | |
{{<<"familyName">>,register},<<"Dobalina">>}]}, | |
{{<<"searches">>,counter},0}, | |
{{<<"views">>,counter},0}], | |
[],[],[], | |
<<77,1,0,0,0,113,131,108,0,0,0,5,104,2,100,0,14,114,105, | |
97,107,...>>}} | |
7> {ok, U2} = user:remove_films(Pid, Key, [<<"bambi">>]). | |
{ok,{map,[{{<<"active">>,flag},true}, | |
{{<<"likes">>,counter},0}, | |
{{<<"profile">>,map}, | |
[{{<<"nickName">>,register},<<"bodo">>}, | |
{{<<"interests">>,map}, | |
[{{<<"hobbies">>,set}, | |
[<<"cycling">>,<<"fishing">>,<<"knitting">>,<<"skiing">>]}, | |
{{<<"films">>,set}, | |
[<<"Cocolat">>,<<"Enter The Dragon">>, | |
<<"The Incredibles">>]}, | |
{{<<"books">>,set},[]}]}, | |
{{<<"image">>,map}, | |
[{{<<"width">>,register},<<"150">>}, | |
{{<<"url">>,register}, | |
<<"http://not.reallybobd.info/bodb.png">>}, | |
{{<<"height">>,register},<<"125">>}]}, | |
{{<<"guid">>,register},<<"0987">>}, | |
{{<<"givenName">>,register},<<"Bob">>}, | |
{{<<"familyName">>,register},<<"Dobalina">>}]}, | |
{{<<"searches">>,counter},0}, | |
{{<<"views">>,counter},0}], | |
[],[],[], | |
<<77,1,0,0,0,113,131,108,0,0,0,5,104,2,100,0,14,114,105, | |
97,107,...>>}} | |
8> riakc_map:value(U2). | |
[{{<<"active">>,flag},true}, | |
{{<<"likes">>,counter},0}, | |
{{<<"profile">>,map}, | |
[{{<<"nickName">>,register},<<"bodo">>}, | |
{{<<"interests">>,map}, | |
[{{<<"hobbies">>,set}, | |
[<<"cycling">>,<<"fishing">>,<<"knitting">>,<<"skiing">>]}, | |
{{<<"films">>,set}, | |
[<<"Cocolat">>,<<"Enter The Dragon">>, | |
<<"The Incredibles">>]}, | |
{{<<"books">>,set},[]}]}, | |
{{<<"image">>,map}, | |
[{{<<"width">>,register},<<"150">>}, | |
{{<<"url">>,register}, | |
<<"http://not.reallybobd.info/bodb.png">>}, | |
{{<<"height">>,register},<<"125">>}]}, | |
{{<<"guid">>,register},<<"0987">>}, | |
{{<<"givenName">>,register},<<"Bob">>}, | |
{{<<"familyName">>,register},<<"Dobalina">>}]}, | |
{{<<"searches">>,counter},0}, | |
{{<<"views">>,counter},0}] | |
9> |
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
%%%------------------------------------------------------------------- | |
%%% @author Russell Brown <russelldb@basho.com> | |
%%% @copyright (C) 2013, Russell Brown | |
%%% @doc | |
%%% | |
%%% @end | |
%%% Created : 28 Oct 2013 by Russell Brown <russelldb@basho.com> | |
%%%------------------------------------------------------------------- | |
-module('user'). | |
%% API | |
-compile([export_all]). | |
-define(USERS_BUCKET, {<<"maps">>, <<"user">>}). | |
%% Field names | |
-define(PROFILE, <<"profile">>). | |
-define(GUID, <<"guid">>). | |
-define(GIVEN_NAME, <<"givenName">>). | |
-define(FAMILY_NAME, <<"familyName">>). | |
-define(NICK, <<"nickName">>). | |
-define(IMAGE, <<"image">>). | |
-define(INTERESTS, <<"interests">>). | |
-define(HOBBIES, <<"hobbies">>). | |
-define(FILMS, <<"films">>). | |
-define(BOOKS, <<"books">>). | |
-define(URL, <<"url">>). | |
-define(HEIGHT, <<"height">>). | |
-define(WIDTH, <<"width">>). | |
%%%=================================================================== | |
%%% API | |
%%%=================================================================== | |
%%-------------------------------------------------------------------- | |
%% @doc | |
%% | |
%% @end | |
%%-------------------------------------------------------------------- | |
create_user(Pid, Key, GivenName, FamilyName, Nickname) -> | |
riakc_pb_socket:modify_type(Pid, fun(Map) -> create(Map, Key, GivenName, FamilyName, Nickname) end, | |
?USERS_BUCKET, Key, [create, return_body]). | |
%% No need to fetch before just adding to a set | |
add_hobbies(Pid, Key, Hobbies) -> | |
add_interests(Pid, Key, ?HOBBIES, Hobbies). | |
%% Ensure the context is included by doing a fetch, update, send | |
remove_hobbies(Pid, Key, Hobbies) -> | |
remove_interests(Pid, Key, ?HOBBIES, Hobbies). | |
add_films(Pid, Key, Films) -> | |
add_interests(Pid, Key, ?FILMS, Films). | |
remove_films(Pid, Key, Films) -> | |
remove_interests(Pid, Key, ?FILMS, Films). | |
add_books(Pid, Key, Books) -> | |
add_interests(Pid, Key, ?BOOKS, Books). | |
remove_books(Pid, Key, Books) -> | |
remove_interests(Pid, Key, ?BOOKS, Books). | |
%% No need to fetch before updating a bunch of registers | |
add_image(Pid, Key, Height, Width, Url) -> | |
Image = lists:foldl(fun({Name, Val}, Map) -> | |
riakc_map:update({Name, register}, | |
fun(Current) -> | |
riakc_register:set(Val, Current) end, | |
Map) end, | |
riakc_map:new(), | |
[{?URL, Url}, | |
{?HEIGHT, Height}, | |
{?WIDTH, Width}]), | |
Profile = riakc_map:update({?IMAGE, map}, fun(_) -> Image end, riakc_map:new()), | |
User = riakc_map:update({?PROFILE, map}, fun(_N) -> Profile end, riakc_map:new()), | |
riakc_pb_socket:update_type(Pid, ?USERS_BUCKET, Key, riakc_map:to_op(User), [return_body]). | |
%% Just send the minimal op, no fetch needed | |
update_counter(Pid, Key, Counter, Amt) -> | |
User = riakc_map:update({Counter, counter}, fun(C) -> | |
riakc_counter:increment(Amt, C) end, | |
riakc_map:new()), | |
riakc_pb_socket:update_type(Pid, ?USERS_BUCKET, Key, riakc_map:to_op(User), [return_body]). | |
%%%=================================================================== | |
%%% Internal functions | |
%%%=================================================================== | |
create(User, UID, GivenName, FamilyName, NickName) -> | |
CreateProfile = fun(Profile) -> | |
Prof = lists:foldl(fun({Name, Val}, Map) -> | |
riakc_map:update({Name, register}, | |
fun(Current) -> | |
riakc_register:set(Val, Current) end, | |
Map) end, | |
Profile, | |
[{?GUID, UID}, | |
{?GIVEN_NAME, GivenName}, | |
{?FAMILY_NAME, FamilyName}, | |
{?NICK, NickName}]), | |
ProfImage = riakc_map:update({?IMAGE, map}, fun create_image/1, Prof), | |
riakc_map:update({?INTERESTS, map}, fun create_interests/1, ProfImage) | |
end, | |
%% Add profile map | |
UserProf = riakc_map:update({?PROFILE, map}, CreateProfile, User), | |
%% Add counters | |
User1 = lists:foldl(fun(Name, Map) -> riakc_map:add({Name, counter}, Map) end, | |
UserProf, | |
[<<"searches">>, <<"views">>, <<"likes">>]), | |
%% set active | |
riakc_map:update({<<"active">>, flag}, fun(F) -> riakc_flag:enable(F) end, User1). | |
create_image(Image) -> | |
lists:foldl(fun(Name, Map) -> | |
riakc_map:add({Name, register}, Map) end, | |
Image, | |
[?HEIGHT, ?WIDTH, ?URL]). | |
create_interests(Interests) -> | |
lists:foldl(fun(Name, Map) -> | |
riakc_map:add({Name, set}, Map) end, | |
Interests, | |
[?HOBBIES, <<"books">>, <<"films">>]). | |
add_interests(Pid, Key, Interest, Interests) -> | |
Interests1 = lists:foldl(fun(I, Set) -> | |
riakc_set:add_element(I, Set) end, | |
riakc_set:new(), | |
Interests), | |
Interests2 = riakc_map:update({Interest, set}, fun(_S) -> Interests1 end, riakc_map:new()), | |
Profile = riakc_map:update({?INTERESTS, map}, fun(_) -> Interests2 end, riakc_map:new()), | |
User = riakc_map:update({?PROFILE, map}, fun(_N) -> Profile end, riakc_map:new()), | |
riakc_pb_socket:update_type(Pid, ?USERS_BUCKET, Key, riakc_map:to_op(User), [return_body]). | |
%% Ensure the context is included by doing a fetch, update, send | |
remove_interests(Pid, Key, Interest, Interests) -> | |
riakc_pb_socket:modify_type(Pid, fun(Map) -> | |
remove_interests(Map, Interest, Interests) end, | |
?USERS_BUCKET, | |
Key, | |
[return_body]). | |
%% OK, this looks pretty bad, but we're working with sets within maps within maps within maps | |
%% There are other ways, grab the map and context, generate the ops | |
%% and ship them back | |
remove_interests(Map, Interest, Interests) -> | |
riakc_map:update({?PROFILE, map}, | |
fun(P) -> | |
riakc_map:update({?INTERESTS, map}, | |
fun(I) -> | |
riakc_map:update({Interest, set}, | |
fun(S) -> | |
lists:foldl(fun(ToRem, Set) -> | |
riakc_set:del_element(ToRem, Set) end, | |
S, | |
Interests) end, | |
I) end, | |
P) end, | |
Map). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment