diff --git a/dialyzer.ignore-warnings b/dialyzer.ignore-warnings index 3e04453513..3fafc505b3 100644 --- a/dialyzer.ignore-warnings +++ b/dialyzer.ignore-warnings @@ -69,13 +69,13 @@ riak_kv_vnode.erl:1886: Function delete_from_hashtree/3 has no local return riak_kv_vnode.erl:1890: The call riak_kv_index_hashtree:async_delete(Items::[{'object',{_,_}},...],Trees::'undefined' | pid()) breaks the contract ({binary(),binary()} | [{binary(),binary()}],pid()) -> 'ok' riak_kv_vnode.erl:1893: The call riak_kv_index_hashtree:delete(Items::[{'object',{_,_}},...],Trees::'undefined' | pid()) breaks the contract ([{binary(),binary()}],pid()) -> 'ok' riak_kv_vnode.erl:2029: Function update_index_delete_stats/1 will never be called -riak_kv_wm_counter.erl:186: The call riak_core_security:check_permission({[46 | 95 | 97 | 101 | 103 | 105 | 107 | 112 | 114 | 116 | 117 | 118,...],{<<_:56>>,_}},Security::any()) breaks the contract (Permission::permission(),Context::context()) -> {'true',context()} | {'false',binary(),context()} +riak_kv_wm_counter.erl:184: The call riak_core_security:check_permission({[46 | 95 | 97 | 101 | 103 | 105 | 107 | 112 | 114 | 116 | 117 | 118,...],{<<_:56>>,_}},Security::any()) breaks the contract (Permission::permission(),Context::context()) -> {'true',context()} | {'false',binary(),context()} riak_kv_wm_crdt.erl:387: Function produce_json/2 has no local return riak_kv_wm_crdt.erl:391: The call riak_kv_crdt_json:fetch_response_to_json(Type::'counter' | 'flag' | 'map' | 'register' | 'set' | 'undefined',Value::any(),'undefined' | binary(),[{'counter','riak_dt_pncounter'} | {'flag','riak_dt_od_flag'} | {'map','riak_dt_map'} | {'register','riak_dt_lwwreg'} | {'set','riak_dt_orswot'},...]) does not have an opaque term of type riak_kv_crdt_json:context() as 3rd argument riak_kv_wm_index.erl:135: The call riak_core_security:check_permission({[46 | 95 | 97 | 100 | 101 | 105 | 107 | 110 | 114 | 118 | 120,...],{<<_:56>>,binary()}},any()) breaks the contract (Permission::permission(),Context::context()) -> {'true',context()} | {'false',binary(),context()} riak_kv_wm_index.erl:214: Guard test is_integer(NormStart::'undefined' | binary()) can never succeed -riak_kv_wm_keylist.erl:137: The call riak_core_security:check_permission({[46 | 95 | 97 | 101 | 105 | 107 | 108 | 114 | 115 | 116 | 118 | 121,...],{<<_:56>>,_}},any()) breaks the contract (Permission::permission(),Context::context()) -> {'true',context()} | {'false',binary(),context()} -riak_kv_wm_utils.erl:283: The pattern {Scheme, _, Host, Port, _, _} can never match the type {'error','no_scheme' | {_,atom(),_}} +riak_kv_wm_keylist.erl:135: The call riak_core_security:check_permission({[46 | 95 | 97 | 101 | 105 | 107 | 108 | 114 | 115 | 116 | 118 | 121,...],{<<_:56>>,_}},any()) breaks the contract (Permission::permission(),Context::context()) -> {'true',context()} | {'false',binary(),context()} +riak_kv_wm_utils.erl:288: The pattern {Scheme, _, Host, Port, _, _} can never match the type {'error','no_scheme' | {_,atom(),_}} cluster_info:dump_all_connected/1 cluster_info:dump_nodes/2 cluster_info:format/3 @@ -103,4 +103,3 @@ Unknown types: riak_core_apl:preflist2/0 riak_dt:operation/0 riak_dt:value/0 - wrq:reqdata/0 diff --git a/src/riak_kv_wm_bucket_type.erl b/src/riak_kv_wm_bucket_type.erl index 78a422efdf..7d05ed0ebf 100644 --- a/src/riak_kv_wm_bucket_type.erl +++ b/src/riak_kv_wm_bucket_type.erl @@ -61,7 +61,6 @@ accept_bucket_type_body/2 ]). -%% @type context() = term() -record(ctx, {bucket_type, %% binary() - Bucket type (from uri) client, %% riak_client() - the store client prefix, %% string() - prefix for resource uris @@ -71,11 +70,12 @@ api_version, %% non_neg_integer() - old or new http api security %% security context }). +-type context() :: #ctx{}. -include_lib("webmachine/include/webmachine.hrl"). -include("riak_kv_wm_raw.hrl"). -%% @spec init(proplist()) -> {ok, context()} +-spec init(proplists:proplist()) -> {ok, context()}. %% @doc Initialize this resource. This function extracts the %% 'prefix' and 'riak' properties from the dispatch args. init(Props) -> @@ -86,8 +86,8 @@ init(Props) -> bucket_type=proplists:get_value(bucket_type, Props) }}. -%% @spec service_available(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} +-spec service_available(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Determine whether or not a connection to Riak can be %% established. This function also takes this opportunity to extract %% the 'bucket' bindings from the dispatch. @@ -163,15 +163,15 @@ forbidden_check_bucket_type(RD, Ctx) -> {false, RD, Ctx}. -%% @spec allowed_methods(reqdata(), context()) -> -%% {[method()], reqdata(), context()} +-spec allowed_methods(#wm_reqdata{}, context()) -> + {[atom()], #wm_reqdata{}, context()}. %% @doc Get the list of methods this resource supports. %% Properties allows HEAD, GET, and PUT. allowed_methods(RD, Ctx) when Ctx#ctx.api_version =:= 3 -> {['HEAD', 'GET', 'PUT'], RD, Ctx}. -%% @spec malformed_request(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} +-spec malformed_request(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Determine whether query parameters, request headers, %% and request body are badly-formed. %% Body format is checked to be valid JSON, including @@ -181,8 +181,8 @@ malformed_request(RD, Ctx) when Ctx#ctx.method =:= 'PUT' -> malformed_request(RD, Ctx) -> {false, RD, Ctx}. -%% @spec malformed_bucket_put(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} +-spec malformed_props(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Check the JSON format of a bucket-level PUT. %% Must be a valid JSON object, containing a "props" object. malformed_props(RD, Ctx) -> @@ -198,9 +198,9 @@ malformed_props(RD, Ctx) -> {true, props_format_message(RD), Ctx} end. -%% @spec bucket_format_message(reqdata()) -> reqdata() +-spec props_format_message(#wm_reqdata{}) -> #wm_reqdata{}. %% @doc Put an error about the format of the bucket-PUT body -%% in the response body of the reqdata(). +%% in the response body of the #wm_reqdata{}. props_format_message(RD) -> wrq:append_to_resp_body( ["bucket type PUT must be a JSON object of the form:\n", @@ -211,29 +211,30 @@ props_format_message(RD) -> resource_exists(RD, Ctx) -> {riak_kv_wm_utils:bucket_type_exists(Ctx#ctx.bucket_type), RD, Ctx}. -%% @spec content_types_provided(reqdata(), context()) -> -%% {[{ContentType::string(), Producer::atom()}], reqdata(), context()} +-spec content_types_provided(#wm_reqdata{}, context()) -> + {[{ContentType::string(), Producer::atom()}], #wm_reqdata{}, context()}. %% @doc List the content types available for representing this resource. %% "application/json" is the content-type for props requests. content_types_provided(RD, Ctx) -> {[{"application/json", produce_bucket_type_body}], RD, Ctx}. -%% @spec encodings_provided(reqdata(), context()) -> -%% {[{Encoding::string(), Producer::function()}], reqdata(), context()} +-spec encodings_provided(#wm_reqdata{}, context()) -> + {[{Encoding::string(), Producer::function()}], #wm_reqdata{}, context()}. %% @doc List the encodings available for representing this resource. %% "identity" and "gzip" are available for props requests. encodings_provided(RD, Ctx) -> {riak_kv_wm_utils:default_encodings(), RD, Ctx}. -%% @spec content_types_accepted(reqdata(), context()) -> -%% {[{ContentType::string(), Acceptor::atom()}], -%% reqdata(), context()} +-spec content_types_accepted(#wm_reqdata{}, context()) -> + {[{ContentType::string(), Acceptor::atom()}], + #wm_reqdata{}, context()}. %% @doc Get the list of content types this resource will accept. %% "application/json" is the only type accepted for props PUT. content_types_accepted(RD, Ctx) -> {[{"application/json", accept_bucket_type_body}], RD, Ctx}. -%% @spec produce_bucket_body(reqdata(), context()) -> {binary(), reqdata(), context()} +-spec produce_bucket_type_body(#wm_reqdata{}, context()) -> + {binary(), #wm_reqdata{}, context()}. %% @doc Produce the bucket properties as JSON. produce_bucket_type_body(RD, Ctx) -> Props = riak_core_bucket_type:get(Ctx#ctx.bucket_type), @@ -245,7 +246,8 @@ produce_bucket_type_body(RD, Ctx) -> ]}), {JsonProps, RD, Ctx}. -%% @spec accept_bucket_body(reqdata(), context()) -> {true, reqdata(), context()} +-spec accept_bucket_type_body(#wm_reqdata{}, context()) -> + {true, #wm_reqdata{}, context()}. %% @doc Modify the bucket properties according to the body of the %% bucket-level PUT request. accept_bucket_type_body(RD, Ctx=#ctx{bucket_type=T, bucketprops=Props}) -> diff --git a/src/riak_kv_wm_buckets.erl b/src/riak_kv_wm_buckets.erl index e75bf48dd0..7c5e37a280 100644 --- a/src/riak_kv_wm_buckets.erl +++ b/src/riak_kv_wm_buckets.erl @@ -49,7 +49,6 @@ malformed_request/2 ]). -%% @type context() = term() -record(ctx, { bucket_type, %% binary() - bucket type (from uri) api_version, %% integer() - Determine which version of the API to use. @@ -60,13 +59,14 @@ timeout, %% integer() - list buckets timeout security %% security context }). +-type context() :: #ctx{}. -include_lib("webmachine/include/webmachine.hrl"). -include("riak_kv_wm_raw.hrl"). -define(DEFAULT_TIMEOUT, 5 * 60000). -%% @spec init(proplist()) -> {ok, context()} +-spec init(proplists:proplist()) -> {ok, context()}. %% @doc Initialize this resource. This function extracts the %% 'prefix' and 'riak' properties from the dispatch args. init(Props) -> @@ -78,8 +78,8 @@ init(Props) -> }}. -%% @spec service_available(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} +-spec service_available(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Determine whether or not a connection to Riak %% can be established. This function also takes this %% opportunity to extract the 'bucket' and 'key' path @@ -137,16 +137,16 @@ forbidden(RD, Ctx) -> end end. -%% @spec content_types_provided(reqdata(), context()) -> -%% {[{ContentType::string(), Producer::atom()}], reqdata(), context()} +-spec content_types_provided(#wm_reqdata{}, context()) -> + {[{ContentType::string(), Producer::atom()}], #wm_reqdata{}, context()}. %% @doc List the content types available for representing this resource. %% "application/json" is the content-type for bucket lists. content_types_provided(RD, Ctx) -> {[{"application/json", produce_bucket_list}], RD, Ctx}. -%% @spec encodings_provided(reqdata(), context()) -> -%% {[{Encoding::string(), Producer::function()}], reqdata(), context()} +-spec encodings_provided(#wm_reqdata{}, context()) -> + {[{Encoding::string(), Producer::function()}], #wm_reqdata{}, context()}. %% @doc List the encodings available for representing this resource. %% "identity" and "gzip" are available for bucket lists. encodings_provided(RD, Ctx) -> @@ -155,8 +155,8 @@ encodings_provided(RD, Ctx) -> malformed_request(RD, Ctx) -> malformed_timeout_param(RD, Ctx). -%% @spec malformed_timeout_param(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} +-spec malformed_timeout_param(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Check that the timeout parameter is are a %% string-encoded integer. Store the integer value %% in context() if so. @@ -183,7 +183,8 @@ malformed_timeout_param(RD, Ctx) -> resource_exists(RD, #ctx{bucket_type=BType}=Ctx) -> {riak_kv_wm_utils:bucket_type_exists(BType), RD, Ctx}. -%% @spec produce_bucket_list(reqdata(), context()) -> {binary(), reqdata(), context()} +-spec produce_bucket_list(#wm_reqdata{}, context()) -> + {binary(), #wm_reqdata{}, context()}. %% @doc Produce the JSON response to a bucket-level GET. %% Includes a list of known buckets if the "buckets=true" query %% param is specified. diff --git a/src/riak_kv_wm_counter.erl b/src/riak_kv_wm_counter.erl index ac19aa932c..c85728ef8a 100644 --- a/src/riak_kv_wm_counter.erl +++ b/src/riak_kv_wm_counter.erl @@ -84,7 +84,6 @@ to_text/2 ]). -%% @type context() = term() -record(ctx, {api_version, %% integer() - Determine which version of the API to use. bucket, %% binary() - Bucket name (from uri) key, %% binary() - Key (from uri) @@ -105,15 +104,14 @@ counter_op :: integer() | undefined, %% The amount to add to the counter security %% security context }). -%% @type link() = {{Bucket::binary(), Key::binary()}, Tag::binary()} -%% @type index_field() = {Key::string(), Value::string()} +-type context() :: #ctx{}. -include_lib("webmachine/include/webmachine.hrl"). -include("riak_kv_wm_raw.hrl"). -include("riak_kv_types.hrl"). -%% @spec init(proplist()) -> {ok, context()} +-spec init(proplists:proplist()) -> {ok, context()}. %% @doc Initialize this resource. This function extracts the %% 'prefix' and 'riak' properties from the dispatch args. init(Props) -> diff --git a/src/riak_kv_wm_index.erl b/src/riak_kv_wm_index.erl index f1e5fa403d..671fd7c85b 100644 --- a/src/riak_kv_wm_index.erl +++ b/src/riak_kv_wm_index.erl @@ -63,7 +63,6 @@ produce_index_results/2 ]). -%% @type context() = term() -record(ctx, { client, %% riak_client() - the store client riak, %% local | {node(), atom()} - params for riak client @@ -76,6 +75,7 @@ pagination_sort :: boolean() | undefined, security %% security context }). +-type context() :: #ctx{}. -define(ALL_2I_RESULTS, all). @@ -83,7 +83,7 @@ -include("riak_kv_wm_raw.hrl"). -include("riak_kv_index.hrl"). -%% @spec init(proplist()) -> {ok, context()} +-spec init(proplists:proplist()) -> {ok, context()}. %% @doc Initialize this resource. init(Props) -> {ok, #ctx{ @@ -92,8 +92,8 @@ init(Props) -> }}. -%% @spec service_available(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} +-spec service_available(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Determine whether or not a connection to Riak %% can be established. Also, extract query params. service_available(RD, Ctx0=#ctx{riak=RiakProps}) -> @@ -145,8 +145,8 @@ forbidden(RD, Ctx) -> end end. -%% @spec malformed_request(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} +-spec malformed_request(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Determine whether query parameters are badly-formed. %% Specifically, we check that the index operation is of %% a known type. @@ -296,16 +296,16 @@ normalize_boolean("true") -> normalize_boolean(_) -> malformed. -%% @spec content_types_provided(reqdata(), context()) -> -%% {[{ContentType::string(), Producer::atom()}], reqdata(), context()} +-spec content_types_provided(#wm_reqdata{}, context()) -> + {[{ContentType::string(), Producer::atom()}], #wm_reqdata{}, context()}. %% @doc List the content types available for representing this resource. %% "application/json" is the content-type for bucket lists. content_types_provided(RD, Ctx) -> {[{"application/json", produce_index_results}], RD, Ctx}. -%% @spec encodings_provided(reqdata(), context()) -> -%% {[{Encoding::string(), Producer::function()}], reqdata(), context()} +-spec encodings_provided(#wm_reqdata{}, context()) -> + {[{Encoding::string(), Producer::function()}], #wm_reqdata{}, context()}. %% @doc List the encodings available for representing this resource. %% "identity" and "gzip" are available for bucket lists. encodings_provided(RD, Ctx) -> @@ -315,7 +315,8 @@ encodings_provided(RD, Ctx) -> resource_exists(RD, #ctx{bucket_type=BType}=Ctx) -> {riak_kv_wm_utils:bucket_type_exists(BType), RD, Ctx}. -%% @spec produce_index_results(reqdata(), context()) -> {binary(), reqdata(), context()} +-spec produce_index_results(#wm_reqdata{}, context()) -> + {binary(), #wm_reqdata{}, context()}. %% @doc Produce the JSON response to an index lookup. produce_index_results(RD, Ctx) -> case wrq:get_qs_value("stream", "false", RD) of diff --git a/src/riak_kv_wm_keylist.erl b/src/riak_kv_wm_keylist.erl index 1f242b8aaf..40cfbe2f66 100644 --- a/src/riak_kv_wm_keylist.erl +++ b/src/riak_kv_wm_keylist.erl @@ -56,7 +56,6 @@ malformed_request/2 ]). -%% @type context() = term() -record(ctx, {api_version, %% integer() - Determine which version of the API to use. bucket_type, %% binary() - Bucket type (from uri) bucket, %% binary() - Bucket name (from uri) @@ -67,13 +66,12 @@ timeout, %% integer() - list keys timeout security %% security context }). -%% @type link() = {{Bucket::binary(), Key::binary()}, Tag::binary()} -%% @type index_field() = {Key::string(), Value::string()} +-type context() :: #ctx{}. -include_lib("webmachine/include/webmachine.hrl"). -include("riak_kv_wm_raw.hrl"). -%% @spec init(proplist()) -> {ok, context()} +-spec init(proplists:proplist()) -> {ok, context()}. %% @doc Initialize this resource. This function extracts the %% 'prefix' and 'riak' properties from the dispatch args. init(Props) -> @@ -84,8 +82,8 @@ init(Props) -> bucket_type=proplists:get_value(bucket_type, Props) }}. -%% @spec service_available(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} +-spec service_available(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Determine whether or not a connection to Riak %% can be established. This function also takes this %% opportunity to extract the 'bucket' and 'key' path @@ -147,16 +145,16 @@ forbidden(RD, Ctx) -> end end. -%% @spec content_types_provided(reqdata(), context()) -> -%% {[{ContentType::string(), Producer::atom()}], reqdata(), context()} +-spec content_types_provided(#wm_reqdata{}, context()) -> + {[{ContentType::string(), Producer::atom()}], #wm_reqdata{}, context()}. %% @doc List the content types available for representing this resource. %% "application/json" is the content-type for listing keys. content_types_provided(RD, Ctx) -> %% bucket-level: JSON description only {[{"application/json", produce_bucket_body}], RD, Ctx}. -%% @spec encodings_provided(reqdata(), context()) -> -%% {[{Encoding::string(), Producer::function()}], reqdata(), context()} +-spec encodings_provided(#wm_reqdata{}, context()) -> + {[{Encoding::string(), Producer::function()}], #wm_reqdata{}, context()}. %% @doc List the encodings available for representing this resource. %% "identity" and "gzip" are available for listing keys. encodings_provided(RD, Ctx) -> @@ -166,8 +164,8 @@ encodings_provided(RD, Ctx) -> malformed_request(RD, Ctx) -> malformed_timeout_param(RD, Ctx). -%% @spec malformed_timeout_param(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} +-spec malformed_timeout_param(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Check that the timeout parameter is are a %% string-encoded integer. Store the integer value %% in context() if so. @@ -194,7 +192,8 @@ malformed_timeout_param(RD, Ctx) -> resource_exists(RD, Ctx) -> {riak_kv_wm_utils:bucket_type_exists(Ctx#ctx.bucket_type), RD, Ctx}. -%% @spec produce_bucket_body(reqdata(), context()) -> {binary(), reqdata(), context()} +-spec produce_bucket_body(#wm_reqdata{}, context()) -> + {binary(), #wm_reqdata{}, context()}. %% @doc Produce the JSON response to a bucket-level GET. %% Includes the keys of the documents in the bucket unless the %% "keys=false" query param is specified. If "keys=stream" query param diff --git a/src/riak_kv_wm_link_walker.erl b/src/riak_kv_wm_link_walker.erl index ae7336dcb8..3a38f9e343 100644 --- a/src/riak_kv_wm_link_walker.erl +++ b/src/riak_kv_wm_link_walker.erl @@ -137,7 +137,6 @@ -include_lib("webmachine/include/webmachine.hrl"). -include("riak_kv_wm_raw.hrl"). -%% @type context() = term() -record(ctx, {api_version, %% integer() - Determine which version of the API to use. prefix, %% string() - prefix for resource urls riak, %% local | {node(), atom()} - params for riak client @@ -149,10 +148,15 @@ cache_secs, %% integer() - number of seconds to add for expires header client %% riak_client() - the store client }). +-type context() :: #ctx{}. -%% @spec mapreduce_linkfun({error, notfound}|riak_object(), term(), {binary(), binary()}) -> -%% [link()] -%% @type link() = {{Bucket::binary(), Key::binary()}, Tag::binary()} +-type link() :: {{Bucket::binary(), Key::binary()}, Tag::binary()}. +-type linkquery() :: {Bucket::binary()|'_', Tag::binary()|'_', Acc::boolean()}. +-type tokenizedlink() :: [string()]. + +-spec mapreduce_linkfun({error, notfound}|riak_object:riak_object(), term(), + {binary(), binary()}) -> + [link()]. %% @doc Extract the links from Object that match {Bucket, Tag}. %% Set this function as the bucket property linkfun to enable %% {link, Bucket, Key, Acc} syntax in mapreduce queries on the bucket. @@ -162,7 +166,7 @@ mapreduce_linkfun({error, notfound}, _, _) -> []; mapreduce_linkfun(Object, _, {Bucket, Tag}) -> links(Object, Bucket, Tag). -%% @spec links(riak_object()) -> [link()] +-spec links(riak_object:riak_object()) -> [link()]. %% @doc Get all of the links that Object has. links(Object) -> MDs = riak_object:get_metadatas(Object), @@ -174,7 +178,8 @@ links(Object) -> end || MD <- MDs ]). -%% @spec links(riak_object(), binary()|'_', binary()|'_') -> [link()] +-spec links(riak_object:riak_object(), binary()|'_', binary()|'_') -> + [link()]. %% @doc Get all of the links Object has that match Bucket and Tag. %% Pass binaries for Bucket or Tag to match the bucket or %% tag of the link exactly. Pass the atom '_' to match any @@ -182,7 +187,7 @@ links(Object) -> links(Object, Bucket, Tag) -> lists:filter(link_match_fun(Bucket, Tag), links(Object)). -%% @spec link_match_fun(binary()|'_', binary()|'_') -> function() +-spec link_match_fun(binary()|'_', binary()|'_') -> function(). %% @doc Create a function suitable for lists:filter/2 for filtering %% links by Bucket and Tag. link_match_fun('_', '_') -> @@ -194,7 +199,7 @@ link_match_fun(Bucket, '_') -> link_match_fun(Bucket, Tag) -> fun([B, _K, T]) -> Bucket == B andalso Tag == T end. -%% @spec init(proplist()) -> {ok, context()} +-spec init(proplists:proplist()) -> {ok, context()}. %% @doc Initialize the resource. This function extacts the 'prefix', %% 'riak', and 'chache_secs' properties from the dispatch args. init(Props) -> @@ -205,8 +210,8 @@ init(Props) -> bucket_type=proplists:get_value(bucket_type, Props) }}. -%% @spec malformed_request(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} +-spec malformed_request(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Parse link walk query and determine if it's %% valid. malformed_request(RD, Ctx) -> @@ -225,8 +230,8 @@ malformed_request(RD, Ctx) -> end. -%% @spec service_available(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} +-spec service_available(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Determine whether or not a connection to Riak %% can be established. This function also takes this %% opportunity to extract the 'bucket' and 'key' path @@ -275,8 +280,8 @@ forbidden(RD, Ctx) -> end end. -%% @spec allowed_methods(reqdata(), context()) -> -%% {[method()], reqdata(), context()} +-spec allowed_methods(#wm_reqdata{}, context()) -> + {[atom()], #wm_reqdata{}, context()}. %% @doc Get the list of methods this resource supports. %% HEAD, GET, and POST are supported. POST does nothing, %% though, and is only exposed for browser-cache-clearing @@ -284,8 +289,8 @@ forbidden(RD, Ctx) -> allowed_methods(RD, Ctx) -> {['GET', 'HEAD', 'POST'], RD, Ctx}. -%% @spec content_types_provided(reqdata(), context()) -> -%% {[{ContentType::string(), Producer::atom()}], reqdata(), context()} +-spec content_types_provided(#wm_reqdata{}, context()) -> + {[{ContentType::string(), Producer::atom()}], #wm_reqdata{}, context()}. %% @doc List the content types available for representing this %% resource. Currently only multipart/mixed is supported. content_types_provided(RD, Ctx) -> @@ -297,7 +302,8 @@ expires(RD, Ctx=#ctx{cache_secs=Secs}) -> calendar:universal_time())), RD, Ctx}. -%% @spec resource_exists(reqdata(), context()) -> {boolean(), reqdata(), context()} +-spec resource_exists(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc This resource exists if Riak returns {ok, riak_object()} from %% a get of the starting document. resource_exists(RD, Ctx=#ctx{bucket=B, key=K, client=C}) -> @@ -308,7 +314,8 @@ resource_exists(RD, Ctx=#ctx{bucket=B, key=K, client=C}) -> {false, RD, Ctx} end. -%% @spec to_multipart_mixed(reqdata(), context()) -> {iolist(), reqdata(), context()} +-spec to_multipart_mixed(#wm_reqdata{}, context()) -> + {iolist(), #wm_reqdata{}, context()}. %% @doc Execute the link walking query, and build the response body. %% This function has to explicitly set the Content-Type header, %% because Webmachine doesn't know to add the "boundary" parameter to it. @@ -322,9 +329,8 @@ to_multipart_mixed(RD, Ctx=#ctx{linkquery=Query, start=Start}) -> RD), Ctx}. -%% @spec execute_query([riak_object()], [linkquery()]) -> -%% [[riak_object()]] -%% @type linkquery() = {Bucket::binary()|'_', Tag::binary()|'_', Acc::boolean()} +-spec execute_query([riak_object:riak_object()], [linkquery()]) -> + [[riak_object:riak_object()]]. %% @doc Execute the link query. Return a list of link step results, %% each link step result being a list of Riak objects. Link %% step results are only returns for those steps that specify @@ -348,8 +354,8 @@ execute_query(StartObjects, [{Bucket, Tag, Acc}|RestQuery]) -> end, [SegResults|execute_query(SegResults,Leftover)]. -%% @spec execute_segment([bkeytag()], [linkquery()]) -> -%% [riak_object()] +-spec execute_segment([BKeyTag :: term()], [linkquery()]) -> + [riak_object:riak_object()]. %% @doc Execute a string of link steps, where only the last step's %% result will be kept for later. execute_segment(Start, Steps) -> @@ -366,7 +372,7 @@ execute_segment(Start, Steps) -> [], Objects)). -%% @spec extract_query(reqdata()) -> [linkquery()] +-spec extract_query(#wm_reqdata{}) -> [linkquery()]. %% @doc Extract the link-walking query from the URL chunk after the %% bucket and key. extract_query(RD) -> @@ -374,9 +380,8 @@ extract_query(RD) -> Parts = [ string:tokens(P, ",") || P <- string:tokens(Path, "/") ], parts_to_query(Parts, []). -%% @spec parts_to_query([toeknizedlink()], [linkquery()]) -> -%% [linkquery()] -%% @type tokenizedlink() = [string()] +-spec parts_to_query([tokenizedlink()], [linkquery()]) -> + [linkquery()]. %% @doc Translate each token-ized string link query to the real link %% query format. parts_to_query([], Acc) -> lists:reverse(Acc); @@ -397,13 +402,16 @@ parts_to_query([[B,T,A]|Rest], Acc) -> end} |Acc]). -%% @spec process_post(reqdata(), context()) -> {true, reqdata(), context()} +-spec process_post(#wm_reqdata{}, context()) -> + {true, #wm_reqdata{}, context()}. %% @doc do nothing with POST %% just allow client to use it to invalidate browser cache process_post(RD, Ctx) -> {true, RD, Ctx}. -%% @spec multipart_mixed_encode([riak_object()]|[[riak_object()]], string(), context()) -> iolist() +-spec multipart_mixed_encode([riak_object:riak_object()]| + [[riak_object:riak_object()]], + string(), context()) -> iolist(). %% @doc Encode the list of result lists, or a single result list in a %% multipart body. multipart_mixed_encode(WalkResults, Boundary, Ctx) -> @@ -411,7 +419,9 @@ multipart_mixed_encode(WalkResults, Boundary, Ctx) -> || R <- WalkResults], "\r\n--",Boundary,"--\r\n"]. -%% @spec multipart_encode_body(riak_object()|[riak_object()], context()) -> iolist() +-spec multipart_encode_body(riak_object:riak_object()| + [riak_object:riak_object()], context()) -> + iolist(). %% @doc Encode a riak object (as an HTTP response much like what riak_kv_wm_object %% would produce) or a result list (as a multipart/mixed document). %% Riak object body will include a Location header to describe where to find diff --git a/src/riak_kv_wm_mapred.erl b/src/riak_kv_wm_mapred.erl index 722dd58b12..f0ce801d5b 100644 --- a/src/riak_kv_wm_mapred.erl +++ b/src/riak_kv_wm_mapred.erl @@ -94,8 +94,8 @@ forbidden(RD, State) -> allowed_methods(RD, State) -> {['GET','HEAD','POST'], RD, State}. --spec known_content_type(wrq:reqdata(), state()) -> - {boolean(), wrq:reqdata(), state()}. +-spec known_content_type(#wm_reqdata{}, state()) -> + {boolean(), #wm_reqdata{}, state()}. known_content_type(RD, State) -> {ctype_ok(RD), RD, State}. @@ -125,13 +125,13 @@ format_error({error, Error}) when is_list(Error) -> format_error(_Error) -> mochijson2:encode({struct, [{error, map_reduce_error}]}). --spec ctype_ok(wrq:reqdata()) -> boolean(). +-spec ctype_ok(#wm_reqdata{}) -> boolean(). %% @doc Return true if the content type from %% this request is appropriate. ctype_ok(RD) -> valid_ctype(get_base_ctype(RD)). --spec get_base_ctype(wrq:reqdata()) -> string(). +-spec get_base_ctype(#wm_reqdata{}) -> string(). %% @doc Return the "base" content-type, that %% is, not including the subtype parameters get_base_ctype(RD) -> diff --git a/src/riak_kv_wm_object.erl b/src/riak_kv_wm_object.erl index c19091bfb0..921e8d2e30 100644 --- a/src/riak_kv_wm_object.erl +++ b/src/riak_kv_wm_object.erl @@ -127,7 +127,6 @@ delete_resource/2 ]). -%% @type context() = term() -record(ctx, {api_version, %% integer() - Determine which version of the API to use. bucket_type, %% binary() - Bucket type (from uri) bucket, %% binary() - Bucket name (from uri) @@ -153,15 +152,16 @@ timeout, %% integer() - passed-in timeout value in ms security %% security context }). -%% @type link() = {{Bucket::binary(), Key::binary()}, Tag::binary()} -%% @type index_field() = {Key::string(), Value::string()} +-type context() :: #ctx{}. + +-type link() :: {{Bucket::binary(), Key::binary()}, Tag::binary()}. -define(DEFAULT_TIMEOUT, 60000). -include_lib("webmachine/include/webmachine.hrl"). -include("riak_kv_wm_raw.hrl"). -%% @spec init(proplist()) -> {ok, context()} +-spec init(proplists:proplist()) -> {ok, context()}. %% @doc Initialize this resource. This function extracts the %% 'prefix' and 'riak' properties from the dispatch args. init(Props) -> @@ -170,8 +170,8 @@ init(Props) -> riak=proplists:get_value(riak, Props), bucket_type=proplists:get_value(bucket_type, Props)}}. -%% @spec service_available(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} +-spec service_available(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Determine whether or not a connection to Riak %% can be established. This function also takes this %% opportunity to extract the 'bucket' and 'key' path @@ -298,21 +298,21 @@ forbidden_check_bucket_type(RD, Ctx) -> handle_common_error(bucket_type_unknown, RD, Ctx) end. -%% @spec allowed_methods(reqdata(), context()) -> -%% {[method()], reqdata(), context()} +-spec allowed_methods(#wm_reqdata{}, context()) -> + {[atom()], #wm_reqdata{}, context()}. %% @doc Get the list of methods this resource supports. allowed_methods(RD, Ctx) -> {['HEAD', 'GET', 'POST', 'PUT', 'DELETE'], RD, Ctx}. -%% @spec allow_missing_post(reqdata(), context()) -> -%% {true, reqdata(), context()} +-spec allow_missing_post(#wm_reqdata{}, context()) -> + {true, #wm_reqdata{}, context()}. %% @doc Makes POST and PUT equivalent for creating new %% bucket entries. allow_missing_post(RD, Ctx) -> {true, RD, Ctx}. -%% @spec malformed_request(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} +-spec malformed_request(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Determine whether query parameters, request headers, %% and request body are badly-formed. %% Body format is checked to be valid JSON, including @@ -341,7 +341,7 @@ malformed_request(RD, Ctx) -> %% @doc Given a list of 2-arity funs, threads through the request data %% and context, returning as soon as a single fun discovers a %% malformed request or halts. -%% -spec malformed_request([fun()], wrq:reqdata(), #ctx{}) -> {boolean() | {halt, non_neg_integer()}, wrq:reqdata(), #ctx{}}. +-spec malformed_request([fun()], #wm_reqdata{}, #ctx{}) -> {boolean() | {halt, non_neg_integer()}, #wm_reqdata{}, #ctx{}}. malformed_request([], RD, Ctx) -> {false, RD, Ctx}; malformed_request([H|T], RD, Ctx) -> @@ -361,8 +361,8 @@ malformed_content_type(RD, Ctx) -> _ -> {false, RD, Ctx} end. -%% @spec malformed_timeout_param(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} +-spec malformed_timeout_param(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Check that the timeout parameter is are a %% string-encoded integer. Store the integer value %% in context() if so. @@ -386,8 +386,8 @@ malformed_timeout_param(RD, Ctx) -> end end. -%% @spec malformed_rw_params(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} +-spec malformed_rw_params(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Check that r, w, dw, and rw query parameters are %% string-encoded integers. Store the integer values %% in context() if so. @@ -407,12 +407,12 @@ malformed_rw_params(RD, Ctx) -> {#ctx.notfound_ok, "notfound_ok", "default"}, {#ctx.asis, "asis", "false"}]). -%% @spec malformed_rw_param({Idx::integer(), Name::string(), Default::string()}, -%% {boolean(), reqdata(), context()}) -> -%% {boolean(), reqdata(), context()} +-spec malformed_rw_param({Idx::integer(), Name::string(), Default::string()}, + {boolean(), #wm_reqdata{}, context()}) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Check that a specific r, w, dw, or rw query param is a %% string-encoded integer. Store its result in context() if it -%% is, or print an error message in reqdata() if it is not. +%% is, or print an error message in #wm_reqdata{} if it is not. malformed_rw_param({Idx, Name, Default}, {Result, RD, Ctx}) -> case catch normalize_rw_param(wrq:get_qs_value(Name, Default, RD)) of P when (is_atom(P) orelse is_integer(P)) -> @@ -427,12 +427,12 @@ malformed_rw_param({Idx, Name, Default}, {Result, RD, Ctx}) -> Ctx} end. -%% @spec malformed_boolean_param({Idx::integer(), Name::string(), Default::string()}, -%% {boolean(), reqdata(), context()}) -> -%% {boolean(), reqdata(), context()} +-spec malformed_boolean_param({Idx::integer(), Name::string(), Default::string()}, + {boolean(), #wm_reqdata{}, context()}) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Check that a specific query param is a %% string-encoded boolean. Store its result in context() if it -%% is, or print an error message in reqdata() if it is not. +%% is, or print an error message in #wm_reqdata{} if it is not. malformed_boolean_param({Idx, Name, Default}, {Result, RD, Ctx}) -> case string:to_lower(wrq:get_qs_value(Name, Default, RD)) of "true" -> @@ -456,11 +456,11 @@ normalize_rw_param("quorum") -> quorum; normalize_rw_param("all") -> all; normalize_rw_param(V) -> list_to_integer(V). -%% @spec malformed_link_headers(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} +-spec malformed_link_headers(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Check that the Link header in the request() is valid. %% Store the parsed links in context() if the header is valid, -%% or print an error in reqdata() if it is not. +%% or print an error in #wm_reqdata{} if it is not. %% A link header should be of the form: %% </Prefix/Bucket/Key>; riaktag="Tag",... malformed_link_headers(RD, Ctx) -> @@ -485,12 +485,11 @@ malformed_link_headers(RD, Ctx) -> end. -%% @spec malformed_index_headers(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} -%% +-spec malformed_index_headers(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Check that the Index headers (HTTP headers prefixed with index_") %% are valid. Store the parsed headers in context() if valid, -%% or print an error in reqdata() if not. +%% or print an error in #wm_reqdata{} if not. %% An index field should be of the form "index_fieldname_type" malformed_index_headers(RD, Ctx) -> %% Get a list of index_headers... @@ -509,8 +508,7 @@ malformed_index_headers(RD, Ctx) -> Ctx} end. -%% @spec extract_index_fields(reqdata()) -> proplist(). -%% +-spec extract_index_fields(#wm_reqdata{}) -> proplists:proplist(). %% @doc Extract fields from headers prefixed by "x-riak-index-" in the %% client's PUT request, to be indexed at write time. extract_index_fields(RD) -> @@ -536,8 +534,8 @@ extract_index_fields(RD) -> end, lists:foldl(F, [], mochiweb_headers:to_list(wrq:req_headers(RD))). -%% @spec content_types_provided(reqdata(), context()) -> -%% {[{ContentType::string(), Producer::atom()}], reqdata(), context()} +-spec content_types_provided(#wm_reqdata{}, context()) -> + {[{ContentType::string(), Producer::atom()}], #wm_reqdata{}, context()}. %% @doc List the content types available for representing this resource. %% The content-type for a key-level request is the content-type that %% was used in the PUT request that stored the document in Riak. @@ -556,9 +554,9 @@ content_types_provided(RD, Ctx0) -> {"multipart/mixed", produce_multipart_body}], RD, DocCtx} end. -%% @spec charsets_provided(reqdata(), context()) -> -%% {no_charset|[{Charset::string(), Producer::function()}], -%% reqdata(), context()} +-spec charsets_provided(#wm_reqdata{}, context()) -> + {no_charset|[{Charset::string(), Producer::function()}], + #wm_reqdata{}, context()}. %% @doc List the charsets available for representing this resource. %% The charset for a key-level request is the charset that was used %% in the PUT request that stored the document in Riak (none if @@ -590,8 +588,8 @@ charsets_provided(RD, Ctx0) -> {no_charset, RD, DocCtx} end. -%% @spec encodings_provided(reqdata(), context()) -> -%% {[{Encoding::string(), Producer::function()}], reqdata(), context()} +-spec encodings_provided(#wm_reqdata{}, context()) -> + {[{Encoding::string(), Producer::function()}], #wm_reqdata{}, context()}. %% @doc List the encodings available for representing this resource. %% The encoding for a key-level request is the encoding that was %% used in the PUT request that stored the document in Riak, or @@ -615,9 +613,9 @@ encodings_provided(RD, Ctx0) -> {riak_kv_wm_utils:default_encodings(), RD, DocCtx} end. -%% @spec content_types_accepted(reqdata(), context()) -> -%% {[{ContentType::string(), Acceptor::atom()}], -%% reqdata(), context()} +-spec content_types_accepted(#wm_reqdata{}, context()) -> + {[{ContentType::string(), Acceptor::atom()}], + #wm_reqdata{}, context()}. %% @doc Get the list of content types this resource will accept. %% Whatever content type is specified by the Content-Type header %% of a key-level PUT request will be accepted by this resource. @@ -647,7 +645,8 @@ content_types_accepted(RD, Ctx) -> end end. -%% @spec resource_exists(reqdata(), context()) -> {boolean(), reqdata(), context()} +-spec resource_exists(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Determine whether or not the requested item exists. %% Documents exists if a read request to Riak returns {ok, riak_object()}, %% and either no vtag query parameter was specified, or the value of the @@ -673,7 +672,8 @@ resource_exists(RD, Ctx0) -> {false, RD, DocCtx} end. -%% @spec post_is_create(reqdata(), context()) -> {boolean(), reqdata(), context()} +-spec post_is_create(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc POST is considered a document-creation operation for bucket-level %% requests (this makes webmachine call create_path/2, where the key %% for the created document will be chosen). @@ -684,7 +684,8 @@ post_is_create(RD, Ctx) -> %% key-POST is not create {false, RD, Ctx}. -%% @spec create_path(reqdata(), context()) -> {string(), reqdata(), context()} +-spec create_path(#wm_reqdata{}, context()) -> + {string(), #wm_reqdata{}, context()}. %% @doc Choose the Key for the document created during a bucket-level POST. %% This function also sets the Location header to generate a %% 201 Created response. @@ -696,12 +697,14 @@ create_path(RD, Ctx=#ctx{prefix=P, bucket_type=T, bucket=B, api_version=V}) -> RD), Ctx#ctx{key=list_to_binary(K)}}. -%% @spec process_post(reqdata(), context()) -> {true, reqdata(), context()} +-spec process_post(#wm_reqdata{}, context()) -> + {true, #wm_reqdata{}, context()}. %% @doc Pass-through for key-level requests to allow POST to function %% as PUT for clients that do not support PUT. process_post(RD, Ctx) -> accept_doc_body(RD, Ctx). -%% @spec accept_doc_body(reqdata(), context()) -> {true, reqdat(), context()} +-spec accept_doc_body(#wm_reqdata{}, context()) -> + {true, #wm_reqdata{}, context()}. %% @doc Store the data the client is PUTing in the document. %% This function translates the headers and body of the HTTP request %% into their final riak_object() form, and executes the Riak put. @@ -779,8 +782,8 @@ add_conditional_headers(RD, Ctx) -> httpd_util:rfc1123_date(calendar:universal_time_to_local_time(LM)), RD4), {RD5,Ctx3}. -%% @spec extract_content_type(reqdata()) -> -%% {ContentType::string(), Charset::string()|undefined} +-spec extract_content_type(#wm_reqdata{}) -> + {ContentType::string(), Charset::string()|undefined}. %% @doc Interpret the Content-Type header in the client's PUT request. %% This function extracts the content type and charset for use %% in subsequent GET requests. @@ -794,7 +797,7 @@ extract_content_type(RD) -> {CType, proplists:get_value("charset", Params)} end. -%% @spec extract_user_meta(reqdata()) -> proplist() +-spec extract_user_meta(#wm_reqdata{}) -> proplists:proplist(). %% @doc Extract headers prefixed by X-Riak-Meta- in the client's PUT request %% to be returned by subsequent GET requests. extract_user_meta(RD) -> @@ -805,8 +808,8 @@ extract_user_meta(RD) -> end, mochiweb_headers:to_list(wrq:req_headers(RD))). -%% @spec multiple_choices(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} +-spec multiple_choices(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Determine whether a document has siblings. If the user has %% specified a specific vtag, the document is considered not to %% have sibling versions. This is a safe assumption, because @@ -841,7 +844,8 @@ multiple_choices(RD, Ctx) -> throw({unexpected_code_path, ?MODULE, multiple_choices, multiple_choices}) end. -%% @spec produce_doc_body(reqdata(), context()) -> {binary(), reqdata(), context()} +-spec produce_doc_body(#wm_reqdata{}, context()) -> + {binary(), #wm_reqdata{}, context()}. %% @doc Extract the value of the document, and place it in the %% response body of the request. This function also adds the %% Link, X-Riak-Meta- headers, and X-Riak-Index- headers to the @@ -888,8 +892,8 @@ produce_doc_body(RD, Ctx) -> throw({unexpected_code_path, ?MODULE, produce_doc_body, multiple_choices}) end. -%% @spec produce_sibling_message_body(reqdata(), context()) -> -%% {iolist(), reqdata(), context()} +-spec produce_sibling_message_body(#wm_reqdata{}, context()) -> + {iolist(), #wm_reqdata{}, context()}. %% @doc Produce the text message informing the user that there are multiple %% values for this document, and giving that user the vtags of those %% values so they can get to them with the vtag query param. @@ -901,8 +905,8 @@ produce_sibling_message_body(RD, Ctx=#ctx{doc={ok, Doc}}) -> encode_vclock_header(RD, Ctx)), Ctx}. -%% @spec produce_multipart_body(reqdata(), context()) -> -%% {iolist(), reqdata(), context()} +-spec produce_multipart_body(#wm_reqdata{}, context()) -> + {iolist(), #wm_reqdata{}, context()}. %% @doc Produce a multipart body representation of an object with multiple %% values (siblings), each sibling being one part of the larger %% document. @@ -919,7 +923,8 @@ produce_multipart_body(RD, Ctx=#ctx{doc={ok, Doc}, bucket=B, prefix=P}) -> Ctx}. -%% @spec select_doc(context()) -> {metadata(), value()}|multiple_choices +-spec select_doc(context()) -> + {Metadata :: term(), Value :: term()}|multiple_choices. %% @doc Selects the "proper" document: %% - chooses update-value/metadata if update-value is set %% - chooses only val/md if only one exists @@ -944,7 +949,7 @@ select_doc(#ctx{doc={ok, Doc}, vtag=Vtag}) -> {riak_object:get_update_metadata(Doc), UpdateValue} end. -%% @spec encode_vclock_header(reqdata(), context()) -> reqdata() +-spec encode_vclock_header(#wm_reqdata{}, context()) -> #wm_reqdata{}. %% @doc Add the X-Riak-Vclock header to the response. encode_vclock_header(RD, #ctx{doc={ok, Doc}}) -> {Head, Val} = riak_object:vclock_header(Doc), @@ -953,7 +958,7 @@ encode_vclock_header(RD, #ctx{doc={error, {deleted, VClock}}}) -> BinVClock = riak_object:encode_vclock(VClock), wrq:set_resp_header(?HEAD_VCLOCK, binary_to_list(base64:encode(BinVClock)), RD). -%% @spec decode_vclock_header(reqdata()) -> vclock() +-spec decode_vclock_header(#wm_reqdata{}) -> vclock:vclock(). %% @doc Translate the X-Riak-Vclock header value from the request into %% its Erlang representation. If no vclock header exists, a fresh %% vclock is returned. @@ -963,7 +968,7 @@ decode_vclock_header(RD) -> Head -> riak_object:decode_vclock(base64:decode(Head)) end. -%% @spec ensure_doc(context()) -> context() +-spec ensure_doc(context()) -> context(). %% @doc Ensure that the 'doc' field of the context() has been filled %% with the result of a riak_client:get request. This is a %% convenience for memoizing the result of a get so it can be @@ -984,7 +989,8 @@ ensure_doc(Ctx=#ctx{doc=undefined, bucket_type=T, bucket=B, key=K, client=C, end; ensure_doc(Ctx) -> Ctx. -%% @spec delete_resource(reqdata(), context()) -> {true, reqdata(), context()} +-spec delete_resource(#wm_reqdata{}, context()) -> + {true, #wm_reqdata{}, context()}. %% @doc Delete the document specified. delete_resource(RD, Ctx=#ctx{bucket_type=T, bucket=B, key=K, client=C}) -> Options = make_options([], Ctx), @@ -1009,8 +1015,8 @@ md5(Bin) -> crypto:md5(Bin). -endif. -%% @spec generate_etag(reqdata(), context()) -> -%% {undefined|string(), reqdata(), context()} +-spec generate_etag(#wm_reqdata{}, context()) -> + {undefined|string(), #wm_reqdata{}, context()}. %% @doc Get the etag for this resource. %% Documents will have an etag equal to their vtag. For documents with %% siblings when no vtag is specified, this will be an etag derived from @@ -1026,8 +1032,8 @@ generate_etag(RD, Ctx) -> {riak_core_util:integer_to_list(ETag, 62), RD, Ctx} end. -%% @spec last_modified(reqdata(), context()) -> -%% {undefined|datetime(), reqdata(), context()} +-spec last_modified(#wm_reqdata{}, context()) -> + {undefined|calendar:datetime(), #wm_reqdata{}, context()}. %% @doc Get the last-modified time for this resource. %% Documents will have the last-modified time specified by the riak_object. %% For documents with siblings, this is the last-modified time of the latest @@ -1043,7 +1049,7 @@ last_modified(RD, Ctx) -> {lists:max(LMDates), RD, Ctx} end. -%% @spec normalize_last_modified(dict()) -> calendar:datetime() +-spec normalize_last_modified(dict()) -> calendar:datetime(). %% @doc Extract and convert the Last-Modified metadata into a normalized form %% for use in the last_modified/2 callback. normalize_last_modified(MD) -> @@ -1054,7 +1060,7 @@ normalize_last_modified(MD) -> httpd_util:convert_request_date(Rfc1123) end. -%% @spec get_link_heads(reqdata(), context()) -> [link()] +-spec get_link_heads(#wm_reqdata{}, context()) -> [link()]. %% @doc Extract the list of links from the Link request header. %% This function will die if an invalid link header format %% is found. @@ -1122,7 +1128,7 @@ extract_links_1([LinkHeader|Rest], BucketRegex, KeyRegex, BucketAcc, KeyAcc) -> extract_links_1([], _BucketRegex, _KeyRegex, BucketAcc, KeyAcc) -> {BucketAcc, KeyAcc}. -%% @spec get_ctype(dict(), term()) -> string() +-spec get_ctype(dict(), term()) -> string(). %% @doc Work out the content type for this object - use the metadata if provided get_ctype(MD,V) -> case dict:find(?MD_CTYPE, MD) of diff --git a/src/riak_kv_wm_props.erl b/src/riak_kv_wm_props.erl index e1bea1f094..cc2fc0b348 100644 --- a/src/riak_kv_wm_props.erl +++ b/src/riak_kv_wm_props.erl @@ -72,7 +72,6 @@ delete_resource/2 ]). -%% @type context() = term() -record(ctx, {bucket_type, %% binary() - Bucket type (from uri) bucket, %% binary() - Bucket name (from uri) client, %% riak_client() - the store client @@ -83,11 +82,12 @@ api_version, %% non_neg_integer() - old or new http api security %% security context }). +-type context() :: #ctx{}. -include_lib("webmachine/include/webmachine.hrl"). -include("riak_kv_wm_raw.hrl"). -%% @spec init(proplist()) -> {ok, context()} +-spec init(proplists:proplist()) -> {ok, context()}. %% @doc Initialize this resource. This function extracts the %% 'prefix' and 'riak' properties from the dispatch args. init(Props) -> @@ -98,8 +98,8 @@ init(Props) -> bucket_type=proplists:get_value(bucket_type, Props) }}. -%% @spec service_available(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} +-spec service_available(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Determine whether or not a connection to Riak can be %% established. This function also takes this opportunity to extract %% the 'bucket' bindings from the dispatch. @@ -169,8 +169,8 @@ forbidden(RD, Ctx=#ctx{security=Security}) -> end end. -%% @spec allowed_methods(reqdata(), context()) -> -%% {[method()], reqdata(), context()} +-spec allowed_methods(#wm_reqdata{}, context()) -> + {[atom()], #wm_reqdata{}, context()}. %% @doc Get the list of methods this resource supports. %% Properties allows HEAD, GET, and PUT. allowed_methods(RD, Ctx) when Ctx#ctx.api_version =:= 1 -> @@ -179,8 +179,8 @@ allowed_methods(RD, Ctx) when Ctx#ctx.api_version =:= 2; Ctx#ctx.api_version =:= 3 -> {['HEAD', 'GET', 'PUT', 'DELETE'], RD, Ctx}. -%% @spec malformed_request(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} +-spec malformed_request(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Determine whether query parameters, request headers, %% and request body are badly-formed. %% Body format is checked to be valid JSON, including @@ -190,8 +190,8 @@ malformed_request(RD, Ctx) when Ctx#ctx.method =:= 'PUT' -> malformed_request(RD, Ctx) -> {false, RD, Ctx}. -%% @spec malformed_bucket_put(reqdata(), context()) -> -%% {boolean(), reqdata(), context()} +-spec malformed_bucket_put(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Check the JSON format of a bucket-level PUT. %% Must be a valid JSON object, containing a "props" object. malformed_bucket_put(RD, Ctx) -> @@ -207,9 +207,9 @@ malformed_bucket_put(RD, Ctx) -> {true, bucket_format_message(RD), Ctx} end. -%% @spec bucket_format_message(reqdata()) -> reqdata() +-spec bucket_format_message(#wm_reqdata{}) -> #wm_reqdata{}. %% @doc Put an error about the format of the bucket-PUT body -%% in the response body of the reqdata(). +%% in the response body of the #wm_reqdata{}. bucket_format_message(RD) -> wrq:append_to_resp_body( ["bucket PUT must be a JSON object of the form:\n", @@ -220,29 +220,30 @@ bucket_format_message(RD) -> resource_exists(RD, Ctx) -> {riak_kv_wm_utils:bucket_type_exists(Ctx#ctx.bucket_type), RD, Ctx}. -%% @spec content_types_provided(reqdata(), context()) -> -%% {[{ContentType::string(), Producer::atom()}], reqdata(), context()} +-spec content_types_provided(#wm_reqdata{}, context()) -> + {[{ContentType::string(), Producer::atom()}], #wm_reqdata{}, context()}. %% @doc List the content types available for representing this resource. %% "application/json" is the content-type for props requests. content_types_provided(RD, Ctx) -> {[{"application/json", produce_bucket_body}], RD, Ctx}. -%% @spec encodings_provided(reqdata(), context()) -> -%% {[{Encoding::string(), Producer::function()}], reqdata(), context()} +-spec encodings_provided(#wm_reqdata{}, context()) -> + {[{Encoding::string(), Producer::function()}], #wm_reqdata{}, context()}. %% @doc List the encodings available for representing this resource. %% "identity" and "gzip" are available for props requests. encodings_provided(RD, Ctx) -> {riak_kv_wm_utils:default_encodings(), RD, Ctx}. -%% @spec content_types_accepted(reqdata(), context()) -> -%% {[{ContentType::string(), Acceptor::atom()}], -%% reqdata(), context()} +-spec content_types_accepted(#wm_reqdata{}, context()) -> + {[{ContentType::string(), Acceptor::atom()}], + #wm_reqdata{}, context()}. %% @doc Get the list of content types this resource will accept. %% "application/json" is the only type accepted for props PUT. content_types_accepted(RD, Ctx) -> {[{"application/json", accept_bucket_body}], RD, Ctx}. -%% @spec produce_bucket_body(reqdata(), context()) -> {binary(), reqdata(), context()} +-spec produce_bucket_body(#wm_reqdata{}, context()) -> + {binary(), #wm_reqdata{}, context()}. %% @doc Produce the bucket properties as JSON. produce_bucket_body(RD, Ctx) -> Client = Ctx#ctx.client, @@ -257,7 +258,7 @@ get_bucket_props_json(Client, Bucket) -> Props2 = lists:map(fun riak_kv_wm_utils:jsonify_bucket_prop/1, Props1), {?JSON_PROPS, {struct, Props2}}. -%% @spec accept_bucket_body(reqdata(), context()) -> {true, reqdata(), context()} +-spec accept_bucket_body(#wm_reqdata{}, context()) -> {true, #wm_reqdata{}, context()}. %% @doc Modify the bucket properties according to the body of the %% bucket-level PUT request. accept_bucket_body(RD, Ctx=#ctx{bucket_type=T, bucket=B, client=C, bucketprops=Props}) -> @@ -271,7 +272,8 @@ accept_bucket_body(RD, Ctx=#ctx{bucket_type=T, bucket=B, client=C, bucketprops=P {{halt, 400}, RD2, Ctx} end. -%% @spec delete_resource(reqdata(), context()) -> {boolean, reqdata(), context()} +-spec delete_resource(#wm_reqdata{}, context()) -> + {boolean(), #wm_reqdata{}, context()}. %% @doc Reset the bucket properties back to the default values delete_resource(RD, Ctx=#ctx{bucket_type=T, bucket=B, client=C}) -> C:reset_bucket({T,B}), diff --git a/src/riak_kv_wm_stats.erl b/src/riak_kv_wm_stats.erl index 347173bc15..56da4f1506 100644 --- a/src/riak_kv_wm_stats.erl +++ b/src/riak_kv_wm_stats.erl @@ -36,12 +36,13 @@ -include_lib("webmachine/include/webmachine.hrl"). -record(ctx, {}). +-type context() :: #ctx{}. init(_) -> {ok, #ctx{}}. -%% @spec encodings_provided(webmachine:wrq(), context()) -> -%% {[encoding()], webmachine:wrq(), context()} +-spec encodings_provided(#wm_reqdata{}, context()) -> + {[term()], #wm_reqdata{}, context()}. %% @doc Get the list of encodings this resource provides. %% "identity" is provided for all methods, and "gzip" is %% provided for GET as well @@ -54,8 +55,8 @@ encodings_provided(ReqData, Context) -> {[{"identity", fun(X) -> X end}], ReqData, Context} end. -%% @spec content_types_provided(webmachine:wrq(), context()) -> -%% {[ctype()], webmachine:wrq(), context()} +-spec content_types_provided(#wm_reqdata{}, context()) -> + {[term()], #wm_reqdata{}, context()}. %% @doc Get the list of content types this resource provides. %% "application/json" and "text/plain" are both provided %% for all requests. "text/plain" is a "pretty-printed" @@ -76,8 +77,8 @@ produce_body(ReqData, Ctx) -> Body = mochijson2:encode({struct, get_stats()}), {Body, ReqData, Ctx}. -%% @spec pretty_print(webmachine:wrq(), context()) -> -%% {string(), webmachine:wrq(), context()} +-spec pretty_print(#wm_reqdata{}, context()) -> + {string(), #wm_reqdata{}, context()}. %% @doc Format the respons JSON object is a "pretty-printed" style. pretty_print(RD1, C1=#ctx{}) -> {Json, RD2, C2} = produce_body(RD1, C1), diff --git a/src/riak_kv_wm_utils.erl b/src/riak_kv_wm_utils.erl index f311aaf585..a29062b4c7 100644 --- a/src/riak_kv_wm_utils.erl +++ b/src/riak_kv_wm_utils.erl @@ -47,6 +47,10 @@ -include_lib("webmachine/include/webmachine.hrl"). -include("riak_kv_wm_raw.hrl"). +-type jsonpropvalue() :: integer()|string()|boolean()|{struct,[jsonmodfun()]}. +-type jsonmodfun() :: {ModBinary :: term(), binary()}|{FunBinary :: term(), binary()}. +-type erlpropvalue() :: integer()|string()|boolean(). + maybe_decode_uri(RD, Val) -> case application:get_env(riak_kv, http_url_encoding) of {ok, on} -> @@ -60,8 +64,8 @@ maybe_decode_uri(RD, Val) -> end end. -%% @spec get_riak_client(local|{node(),Cookie::atom()}, term()) -> -%% {ok, riak_client()} | error() +-spec get_riak_client(local|{node(),Cookie::atom()}, term()) -> + {ok, RiakClient :: term()} | {error, term()}. %% @doc Get a riak_client. get_riak_client(local, ClientId) -> riak:local_client(ClientId); @@ -69,7 +73,7 @@ get_riak_client({Node, Cookie}, ClientId) -> erlang:set_cookie(node(), Cookie), riak:client_connect(Node, ClientId). -%% @spec get_client_id(reqdata()) -> term() +-spec get_client_id(#wm_reqdata{}) -> term(). %% @doc Extract the request's preferred client id from the %% X-Riak-ClientId header. Return value will be: %% 'undefined' if no header was found @@ -88,13 +92,14 @@ get_client_id(RD) -> end. -%% @spec default_encodings() -> [{Encoding::string(), Producer::function()}] +-spec default_encodings() -> [{Encoding::string(), Producer::function()}]. %% @doc The default encodings available: identity and gzip. default_encodings() -> [{"identity", fun(X) -> X end}, {"gzip", fun(X) -> zlib:gzip(X) end}]. -%% @spec multipart_encode_body(string(), binary(), {dict(), binary()}) -> iolist() +-spec multipart_encode_body(string(), binary(), {dict(), binary()}, term()) -> + iolist(). %% @doc Produce one part of a multipart body, representing one sibling %% of a multi-valued document. multipart_encode_body(Prefix, Bucket, {MD, V}, APIVersion) -> @@ -195,7 +200,7 @@ format_uri(Type, Bucket, Key, _Prefix, 3) -> io_lib:format("/types/~s/buckets/~s/keys/~s", [Type, Bucket, Key]). -%% @spec get_ctype(dict(), term()) -> string() +-spec get_ctype(dict(), term()) -> string(). %% @doc Work out the content type for this object - use the metadata if provided get_ctype(MD,V) -> case dict:find(?MD_CTYPE, MD) of @@ -207,7 +212,7 @@ get_ctype(MD,V) -> "application/x-erlang-binary" end. -%% @spec encode_value(term()) -> binary() +-spec encode_value(term()) -> binary(). %% @doc Encode the object value as a binary - content type can be used %% to decode encode_value(V) when is_binary(V) -> @@ -215,7 +220,7 @@ encode_value(V) when is_binary(V) -> encode_value(V) -> term_to_binary(V). -%% @spec accept_value(string(), binary()) -> term() +-spec accept_value(string(), binary()) -> term(). %% @doc Accept the object value as a binary - content type can be used %% to decode accept_value("application/x-erlang-binary",V) -> @@ -287,12 +292,9 @@ referer_tuple(RD) -> end end. -%% @spec jsonify_bucket_prop({Property::atom(), erlpropvalue()}) -> -%% {Property::binary(), jsonpropvalue()} -%% @type erlpropvalue() = integer()|string()|boolean()| +-spec jsonify_bucket_prop({Property::atom(), erlpropvalue()}) -> + {Property::binary(), jsonpropvalue()}. %% {modfun, atom(), atom()}|{atom(), atom()} -%% @type jsonpropvalue() = integer()|string()|boolean()|{struct,[jsonmodfun()]} -%% @type jsonmodfun() = {mod_binary(), binary()}|{fun_binary(), binary()} %% @doc Convert erlang bucket properties to JSON bucket properties. %% Property names are converted from atoms to binaries. %% Integer, string, and boolean property values are left as integer, @@ -352,8 +354,8 @@ jsonify_bucket_prop({name, {_T, B}}) -> jsonify_bucket_prop({Prop, Value}) -> {atom_to_binary(Prop, utf8), Value}. -%% @spec erlify_bucket_prop({Property::binary(), jsonpropvalue()}) -> -%% {Property::atom(), erlpropvalue()} +-spec erlify_bucket_prop({Property::binary(), jsonpropvalue()}) -> + {Property::atom(), erlpropvalue()}. %% @doc The reverse of jsonify_bucket_prop/1. Converts JSON representation %% of bucket properties to their Erlang form. erlify_bucket_prop({?JSON_DATATYPE, Type}) when is_binary(Type) -> diff --git a/src/riak_object.erl b/src/riak_object.erl index ff38a9c834..5a6a55da38 100644 --- a/src/riak_object.erl +++ b/src/riak_object.erl @@ -626,7 +626,6 @@ set_vclock(Object=#r_object{}, VClock) -> Object#r_object{vclock=VClock}. %% @doc Increment the entry for ClientId in O's vclock. -spec increment_vclock(riak_object(), vclock:vclock_node()) -> riak_object(). -%% @spec increment_vclock(riak_object(), vclock:vclock_node()) -> riak_object() increment_vclock(Object=#r_object{bucket=B}, ClientId) -> NewClock = vclock:increment(ClientId, Object#r_object.vclock), {ok, Dot} = vclock:get_dot(ClientId, NewClock), @@ -734,7 +733,7 @@ assemble_index_specs(Indexes, IndexOp) -> set_contents(Object=#r_object{}, MVs) when is_list(MVs) -> Object#r_object{contents=[#r_content{metadata=M,value=V} || {M, V} <- MVs]}. -%% @spec vclock_header(riak_object()) -> {Name::string(), Value::string()} +-spec vclock_header(riak_object()) -> {Name::string(), Value::string()}. %% @doc Transform the Erlang representation of the document's vclock %% into something suitable for an HTTP header vclock_header(Doc) ->