summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarren Smith <garren.smith@gmail.com>2019-08-14 17:18:56 +0200
committerPaul J. Davis <paul.joseph.davis@gmail.com>2019-09-23 12:23:49 -0500
commitbc6d9f3609b1f11e23315cd260877320b27feeb3 (patch)
tree394d00b6898794f245c94754f7f2d2642977c34d
parent01a9228c91a42b5a99bd1478a9ad8c578b09b70f (diff)
downloadcouchdb-bc6d9f3609b1f11e23315cd260877320b27feeb3.tar.gz
Add couch_eval abstraction layer
-rw-r--r--rebar.config.script1
-rw-r--r--rel/reltool.config2
-rw-r--r--src/couch_eval/README.md5
-rw-r--r--src/couch_eval/rebar.config14
-rw-r--r--src/couch_eval/src/couch_eval.app.src23
-rw-r--r--src/couch_eval/src/couch_eval.erl97
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.