Skip to content

Commit

Permalink
Merge pull request #8 from talko/fixes/query
Browse files Browse the repository at this point in the history
Expose additional APIs
  • Loading branch information
joelreymont committed May 7, 2012
2 parents beab1f2 + 3d8fa35 commit e05455e
Showing 1 changed file with 76 additions and 15 deletions.
91 changes: 76 additions & 15 deletions src/ddb.erl
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,14 @@
key_type/2, key_type/4,
key_value/2, key_value/4,
create_table/4, describe_table/1, remove_table/1,
get/2, put/2, update/3, update/4,
get/2, get/3, put/2, update/3, update/4,
delete/2, delete/3,
cond_put/3,
cond_update/4, cond_update/5,
cond_delete/3, cond_delete/4,
now/0, find/3, find/4]).
now/0, find/3, find/4,
q/3, q/4,
range_key_condition/1]).

-define(DDB_DOMAIN, "dynamodb.us-east-1.amazonaws.com").
-define(DDB_ENDPOINT, "http://" ++ ?DDB_DOMAIN ++ "/").
Expand Down Expand Up @@ -79,6 +82,8 @@
-type update_attr() :: {binary(), binary(), type(), 'put' | 'add'} | {binary(), 'delete'}.
-type returns() :: 'none' | 'all_old' | 'updated_old' | 'all_new' | 'updated_new'.
-type update_cond() :: {'does_not_exist', binary()} | {'exists', binary(), binary(), type()}.
-type json_parameter() :: {binary(), term()}.
-type json_parameters() :: [json_parameter()].

%%% Set temporary credentials, use ddb_iam:token/1 to fetch from AWS.

Expand Down Expand Up @@ -176,6 +181,18 @@ put(Name, Attributes)
{<<"Item">>, format_put_attrs(Attributes)}],
request(?TG_PUT_ITEM, JSON).

%%% Conditionally put item attributes into table

-spec cond_put(tablename(), [put_attr()], update_cond()) -> json_reply().

cond_put(Name, Attributes, Condition)
when is_binary(Name),
is_list(Attributes) ->
JSON = [{<<"TableName">>, Name},
{<<"Item">>, format_put_attrs(Attributes)}]
++ format_update_cond(Condition),
request(?TG_PUT_ITEM, JSON).

%%% Create a key value, either hash or hash and range.

-spec key_value(binary(), type()) -> json().
Expand Down Expand Up @@ -286,6 +303,18 @@ get(Name, Keys)
JSON = [{<<"TableName">>, Name}] ++ Keys,
request(?TG_GET_ITEM, JSON).

%%% get with additional parameters

-spec get(tablename(), key_json(), json_parameters()) -> json_reply().

get(Name, Keys, Parameters)
when is_binary(Name),
is_list(Keys) ->
JSON = [{<<"TableName">>, Name}]
++ Keys
++ Parameters,
request(?TG_GET_ITEM, JSON).

%%% Fetch all item attributes from table using a condition.

-spec find(tablename(), key_value(), find_cond()) -> json_reply().
Expand All @@ -297,11 +326,23 @@ find(Name, HashKey, RangeKeyCond) ->

-spec find(tablename(), key_value(), find_cond(), json() | 'none') -> json_reply().

find(Name, {HashKeyValue, HashKeyType}, {Condition, RangeKeyType, RangeKeyValues}, StartKey)
find(Name, {HashKeyValue, HashKeyType}, RangeKeyCond, StartKey)
when is_binary(Name),
is_binary(HashKeyValue),
is_atom(HashKeyType),
is_atom(Condition),
is_atom(HashKeyType) ->
JSON = [{<<"TableName">>, Name},
{<<"HashKeyValue">>,
[{type(HashKeyType), HashKeyValue}]},
range_key_condition(RangeKeyCond)]
++ start_key(StartKey),

request(?TG_QUERY, JSON).

%%% Create a range key condition parameter

-spec range_key_condition(find_cond()) -> json_parameter().
range_key_condition({Condition, RangeKeyType, RangeKeyValues})
when is_atom(Condition),
is_atom(RangeKeyType),
is_list(RangeKeyValues) ->
{Op, Values} = case Condition of
Expand All @@ -312,22 +353,41 @@ find(Name, {HashKeyValue, HashKeyType}, {Condition, RangeKeyType, RangeKeyValues
'equal' ->
{<<"EQ">>, [[{type(RangeKeyType), hd(RangeKeyValues)}]]}
end,
{<<"RangeKeyCondition">>, [{<<"AttributeValueList">>, Values},
{<<"ComparisonOperator">>, Op}]}.

%%% Query a table

-spec q(tablename(), key_value(), json_parameters()) -> json_reply().

q(Name, HashKey, Parameters) ->
q(Name, HashKey, Parameters, 'none').

%% Query a table with pagination

-spec q(tablename(), key_value(), json_parameters(), json() | 'none') -> json_reply().

q(Name, {HashKeyValue, HashKeyType}, Parameters, StartKey)
when is_binary(Name),
is_binary(HashKeyValue),
is_atom(HashKeyType),
is_list(Parameters) ->
JSON = [{<<"TableName">>, Name},
{<<"HashKeyValue">>,
[{type(HashKeyType), HashKeyValue}]},
{<<"RangeKeyCondition">>,
[{<<"AttributeValueList">>, Values},
{<<"ComparisonOperator">>, Op}]}],
JSON1 = case StartKey of
'none' -> JSON;
_ -> [{<<"ExclusiveStartKey">>, StartKey}|JSON]
end,
request(?TG_QUERY, JSON1).
{<<"HashKeyValue">>, [{type(HashKeyType), HashKeyValue}]}]
++ Parameters
++ start_key(StartKey),
request(?TG_QUERY, JSON).

%%%
%%% Helper functions
%%%

-spec start_key(json() | 'none') -> json_parameters().
start_key('none') ->
[];
start_key(StartKey) ->
[{<<"ExclusiveStartKey">>, StartKey}].

-spec format_put_attrs([put_attr()]) -> json().

format_put_attrs(Attributes) ->
Expand Down Expand Up @@ -378,6 +438,7 @@ update_action('delete') -> <<"DELETE">>.

request(Target, JSON) ->
Body = jsx:term_to_json(JSON),
ok = lager:debug("REQUEST BODY ~n~p", [Body]),
Headers = headers(Target, Body),
Opts = [{'response_format', 'binary'}],
F = fun() -> ibrowse:send_req(?DDB_ENDPOINT, [{'Content-type', ?CONTENT_TYPE} | Headers], 'post', Body, Opts) end,
Expand Down

0 comments on commit e05455e

Please sign in to comment.