You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2019/08/23 16:20:21 UTC

[couchdb] 01/05: Add couch_eval abstraction layer

This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch prototype/fdb-layer-couch-eval
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 48d5aab3ed9cc7c1b232499ecb067057c2eea5dc
Author: Garren Smith <ga...@gmail.com>
AuthorDate: Wed Aug 14 17:18:56 2019 +0200

    Add couch_eval abstraction layer
---
 rebar.config.script                   |  1 +
 rel/reltool.config                    |  2 +
 src/couch_eval/README.md              |  5 ++
 src/couch_eval/rebar.config           | 14 +++++
 src/couch_eval/src/couch_eval.app.src | 23 +++++++++
 src/couch_eval/src/couch_eval.erl     | 97 +++++++++++++++++++++++++++++++++++
 6 files changed, 142 insertions(+)

diff --git a/rebar.config.script b/rebar.config.script
index c1d519f..ba7b754 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 907b241..e2ae71c 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 0000000..048a165
--- /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 0000000..362c878
--- /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 0000000..87193d8
--- /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 0000000..23ca263
--- /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.