/src/riak_kv_mapred_term.erl

https://github.com/kellymclaughlin/riak_kv · Erlang · 115 lines · 68 code · 10 blank · 37 comment · 0 complexity · e8d629d46cb5de4f888e79f1d85945cd MD5 · raw file

  1. %% -------------------------------------------------------------------
  2. %%
  3. %% riak_mapred_term: Term parsing for mapreduce
  4. %%
  5. %% Copyright (c) 2007-2010 Basho Technologies, Inc. All Rights Reserved.
  6. %%
  7. %% This file is provided to you under the Apache License,
  8. %% Version 2.0 (the "License"); you may not use this file
  9. %% except in compliance with the License. You may obtain
  10. %% a copy of the License at
  11. %%
  12. %% http://www.apache.org/licenses/LICENSE-2.0
  13. %%
  14. %% Unless required by applicable law or agreed to in writing,
  15. %% software distributed under the License is distributed on an
  16. %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  17. %% KIND, either express or implied. See the License for the
  18. %% specific language governing permissions and limitations
  19. %% under the License.
  20. %%
  21. %% -------------------------------------------------------------------
  22. %% @doc Term parsing for mapreduce
  23. -module(riak_kv_mapred_term).
  24. -export([parse_request/1]).
  25. -define(DEFAULT_TIMEOUT, 60000).
  26. %%
  27. %% Parse a map/reduce request encoded as a property list
  28. %% [{'inputs', Inputs},
  29. %% {'query', Query},
  30. %% {'timeout', Timeout}].
  31. %%
  32. parse_request(BinReq) ->
  33. try
  34. Req = binary_to_term(BinReq),
  35. Timeout = proplists:get_value(timeout, Req, ?DEFAULT_TIMEOUT),
  36. Inputs = proplists:get_value(inputs, Req, undefined),
  37. Query = proplists:get_value('query', Req, undefined),
  38. case parse_inputs(Inputs) of
  39. {ok, Inputs1} ->
  40. case parse_query(Query) of
  41. {ok, Query1} ->
  42. {ok, Inputs1, Query1, Timeout};
  43. {error, Reason} ->
  44. {error, {'query', Reason}}
  45. end;
  46. {error, Reason} ->
  47. {error, {'inputs', Reason}}
  48. end
  49. catch
  50. _:Error ->
  51. {error, Error}
  52. end.
  53. %% Return ok if inputs are valid, {error, Reason} if not
  54. %% @type mapred_inputs() = [bucket_key()]
  55. %% |bucket()
  56. %% |{bucket(), list()}
  57. %% |{modfun, atom(), atom(), list()}
  58. parse_inputs(Bucket) when is_binary(Bucket) ->
  59. {ok, Bucket};
  60. parse_inputs(Targets) when is_list(Targets) ->
  61. case valid_input_targets(Targets) of
  62. ok -> {ok, Targets};
  63. {error, Reason} -> {error, Reason}
  64. end;
  65. parse_inputs(Inputs = {modfun, Module, Function, _Options})
  66. when is_atom(Module), is_atom(Function) ->
  67. {ok, Inputs};
  68. parse_inputs({index, Bucket, Index, Key}) ->
  69. case riak_index:parse_fields([{Index, Key}]) of
  70. {ok, [{Index1, Key1}]} ->
  71. {ok, {index, Bucket, Index1, Key1}};
  72. {error, Reasons} ->
  73. {error, Reasons}
  74. end;
  75. parse_inputs({index, Bucket, Index, StartKey, EndKey}) ->
  76. case riak_index:parse_fields([{Index, StartKey}, {Index, EndKey}]) of
  77. {ok, [{Index1, StartKey1}, {Index1, EndKey1}]} ->
  78. {ok, {index, Bucket, Index1, StartKey1, EndKey1}};
  79. {error, Reasons} ->
  80. {error, Reasons}
  81. end;
  82. parse_inputs(Inputs = {search, _Bucket, _Query}) ->
  83. {ok, Inputs};
  84. parse_inputs(Inputs = {search, _Bucket, _Query, _Filter}) ->
  85. {ok, Inputs};
  86. parse_inputs(Inputs = {Bucket, Filters}) when is_binary(Bucket), is_list(Filters) ->
  87. {ok, Inputs};
  88. parse_inputs(Invalid) ->
  89. {error, {"Inputs must be a binary bucket, a tuple of bucket and key-filters, a list of target tuples, or a search, index, or modfun tuple:", Invalid}}.
  90. %% @type bucket_key() = {binary(), binary()}
  91. %% |{{binary(), binary()}, term()}
  92. valid_input_targets([]) ->
  93. ok;
  94. valid_input_targets([{B,K}|Rest]) when is_binary(B), is_binary(K) ->
  95. valid_input_targets(Rest);
  96. valid_input_targets([{{B,K},_KeyData}|Rest]) when is_binary(B), is_binary(K) ->
  97. valid_input_targets(Rest);
  98. valid_input_targets(Invalid) ->
  99. {error, {"Inputs target tuples must be {B,K} or {{B,K},KeyData}:", Invalid}}.
  100. %% Return ok if query are valid, {error, Reason} if not. Not very strong validation
  101. %% done here as riak_kv_mapred_query will check this.
  102. parse_query(Query) when is_list(Query) ->
  103. {ok, Query};
  104. parse_query(Invalid) ->
  105. {error, {"Query takes a list of step tuples", Invalid}}.