diff options
author | Garren Smith <garren.smith@gmail.com> | 2019-08-14 17:18:56 +0200 |
---|---|---|
committer | Paul J. Davis <paul.joseph.davis@gmail.com> | 2019-09-23 12:23:49 -0500 |
commit | bc6d9f3609b1f11e23315cd260877320b27feeb3 (patch) | |
tree | 394d00b6898794f245c94754f7f2d2642977c34d | |
parent | 01a9228c91a42b5a99bd1478a9ad8c578b09b70f (diff) | |
download | couchdb-bc6d9f3609b1f11e23315cd260877320b27feeb3.tar.gz |
Add couch_eval abstraction layer
-rw-r--r-- | rebar.config.script | 1 | ||||
-rw-r--r-- | rel/reltool.config | 2 | ||||
-rw-r--r-- | src/couch_eval/README.md | 5 | ||||
-rw-r--r-- | src/couch_eval/rebar.config | 14 | ||||
-rw-r--r-- | src/couch_eval/src/couch_eval.app.src | 23 | ||||
-rw-r--r-- | src/couch_eval/src/couch_eval.erl | 97 |
6 files changed, 142 insertions, 0 deletions
diff --git a/rebar.config.script b/rebar.config.script index c1d519f06..ba7b754ff 100644 --- a/rebar.config.script +++ b/rebar.config.script @@ -74,6 +74,7 @@ SubDirs = [ "src/couch_log", "src/chttpd", "src/couch", + "src/couch_eval", "src/couch_event", "src/mem3", "src/couch_index", diff --git a/rel/reltool.config b/rel/reltool.config index 907b2418b..e2ae71c43 100644 --- a/rel/reltool.config +++ b/rel/reltool.config @@ -40,6 +40,7 @@ couch_plugins, couch_replicator, couch_stats, + couch_eval, couch_event, couch_peruser, couch_views, @@ -93,6 +94,7 @@ {app, config, [{incl_cond, include}]}, {app, couch, [{incl_cond, include}]}, {app, couch_epi, [{incl_cond, include}]}, + {app, couch_eval, [{incl_cond, include}]}, {app, couch_jobs, [{incl_cond, include}]}, {app, couch_index, [{incl_cond, include}]}, {app, couch_log, [{incl_cond, include}]}, diff --git a/src/couch_eval/README.md b/src/couch_eval/README.md new file mode 100644 index 000000000..048a165fb --- /dev/null +++ b/src/couch_eval/README.md @@ -0,0 +1,5 @@ +couch_eval +===== + +An an initial abstraction layer for evaluating user provided code. So far +this is only used by `couch_views` to provide map function support. Currently this is implemented in `couch_js` by reusing the existing `couchjs` mechanics. diff --git a/src/couch_eval/rebar.config b/src/couch_eval/rebar.config new file mode 100644 index 000000000..362c8785e --- /dev/null +++ b/src/couch_eval/rebar.config @@ -0,0 +1,14 @@ +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +{cover_enabled, true}. +{cover_print_enabled, true}. diff --git a/src/couch_eval/src/couch_eval.app.src b/src/couch_eval/src/couch_eval.app.src new file mode 100644 index 000000000..87193d806 --- /dev/null +++ b/src/couch_eval/src/couch_eval.app.src @@ -0,0 +1,23 @@ +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +{application, couch_eval, [ + {description, "An OTP application"}, + {vsn, git}, + {registered, []}, + {applications, [ + kernel, + stdlib, + couch_log, + config + ]} + ]}. diff --git a/src/couch_eval/src/couch_eval.erl b/src/couch_eval/src/couch_eval.erl new file mode 100644 index 000000000..23ca263ab --- /dev/null +++ b/src/couch_eval/src/couch_eval.erl @@ -0,0 +1,97 @@ +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + + +-module(couch_eval). + + +-export([ + acquire_map_context/6, + release_map_context/1, + map_docs/2 +]). + + +-include_lib("couch/include/couch_db.hrl"). + + +-type db_name() :: binary(). +-type doc_id() :: binary(). +-type ddoc_id() :: binary(). +-type language() :: binary(). +-type sig() :: binary(). +-type lib() :: any(). +-type map_fun() :: binary(). +-type map_funs() :: [map_fun()]. +-type result() :: {doc_id(), [[{any(), any()}]]}. +-type api_mod() :: atom(). +-type context() :: {api_mod(), any()}. + +-type context_opts() :: #{ + db_name := db_name(), + ddoc_id => ddoc_id(), + language => language(), + sig => sig(), + lib => lib(), + map_funs => map_funs(), + api_mod => api_mod() +}. + + +-callback acquire_map_context(context_opts()) -> {ok, any()} | {error, any()}. +-callback release_map_context(context()) -> ok | {error, any()}. +-callback map_docs(context(), [doc()]) -> {ok, [result()]} | {error, any()}. + + +-spec acquire_map_context( + db_name(), + ddoc_id(), + language(), + sig(), + lib(), + map_funs() + ) -> {ok, context()} | {error, any()}. +acquire_map_context(DbName, DDocId, Language, Sig, Lib, MapFuns) -> + ApiMod = get_api_mod(Language), + CtxOpts = #{ + db_name => DbName, + ddoc_id => DDocId, + language => Language, + sig => Sig, + lib => Lib, + map_funs => MapFuns + }, + {ok, Ctx} = ApiMod:acquire_map_context(CtxOpts), + {ok, {ApiMod, Ctx}}. + + +-spec release_map_context(context()) -> ok | {error, any()}. +release_map_context({ApiMod, Ctx}) -> + ApiMod:release_map_context(Ctx). + + +-spec map_docs(context(), [doc()]) -> {ok, result()} | {error, any()}. +map_docs({ApiMod, Ctx}, Docs) -> + ApiMod:map_docs(Ctx, Docs). + + +get_api_mod(Language) when is_binary(Language) -> + try + LangStr = binary_to_list(Language), + ModStr = config:get("couch_eval.languages", LangStr), + if ModStr /= undefined -> ok; true -> + erlang:error({unknown_eval_api_language, Language}) + end, + list_to_existing_atom(ModStr) + catch error:badarg -> + erlang:error({invalid_eval_api_mod, Language}) + end. |