You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ga...@apache.org on 2021/04/06 08:56:46 UTC

[couchdb] 01/02: Validate ddoc uses couch_eval

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

garren pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 8736b9846f1b6d388977a4c1a34033781c26a883
Author: garren smith <ga...@gmail.com>
AuthorDate: Tue Mar 30 14:49:09 2021 +0200

    Validate ddoc uses couch_eval
    
    Change the validate ddoc check to use couch_eval.
    Also add in some extra functions in couch_eval so that the try_compile
    will work.
---
 src/couch/test/exunit/fabric_test.exs              |  2 +-
 src/couch_eval/src/couch_eval.erl                  | 51 +++++++++++++++++++++-
 src/couch_js/src/couch_js.erl                      | 17 +++++++-
 src/couch_mrview/src/couch_mrview.erl              | 23 +++-------
 .../test/eunit/couch_replicator_test_helper.erl    |  2 +-
 src/fabric/src/fabric2_db.erl                      |  2 +-
 src/fabric/test/fabric2_doc_crud_tests.erl         |  2 +-
 src/mango/src/mango_eval.erl                       | 17 +++++++-
 test/elixir/lib/setup/common.ex                    |  4 +-
 9 files changed, 94 insertions(+), 26 deletions(-)

diff --git a/src/couch/test/exunit/fabric_test.exs b/src/couch/test/exunit/fabric_test.exs
index bdb84e9..4cbd26b 100644
--- a/src/couch/test/exunit/fabric_test.exs
+++ b/src/couch/test/exunit/fabric_test.exs
@@ -15,7 +15,7 @@ defmodule Couch.Test.Fabric do
   def with_db(context, setup) do
     setup =
       setup
-      |> Setup.Common.with_db()
+      |> Setup.Common.with_db([:couch_js])
       |> Setup.run()
 
     context =
diff --git a/src/couch_eval/src/couch_eval.erl b/src/couch_eval/src/couch_eval.erl
index 3541a5b..a6e5965 100644
--- a/src/couch_eval/src/couch_eval.erl
+++ b/src/couch_eval/src/couch_eval.erl
@@ -17,7 +17,9 @@
 -export([
     acquire_map_context/6,
     release_map_context/1,
-    map_docs/2
+    map_docs/2,
+    with_context/2,
+    try_compile/4
 ]).
 
 
@@ -35,6 +37,10 @@
 -type result() :: {doc_id(), [[{any(), any()}]]}.
 -type api_mod() :: atom().
 -type context() :: {api_mod(), any()}.
+-type function_type() :: binary().
+-type function_name() :: binary().
+-type function_src() :: binary().
+-type error(_Error) :: no_return().
 
 -type context_opts() :: #{
     db_name := db_name(),
@@ -46,10 +52,17 @@
     api_mod => api_mod()
 }.
 
+-type with_context_opts() :: #{
+    language := language()
+}.
+
 
 -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()}.
+-callback acquire_context() -> {ok, any()} | {error, any()}.
+-callback release_context(context()) -> ok | {error, any()}.
+-callback try_compile(context(), function_type(), function_name(), function_src()) -> ok.
 
 
 -spec acquire_map_context(
@@ -59,7 +72,10 @@
         sig(),
         lib(),
         map_funs()
-    ) -> {ok, context()} | {error, any()}.
+    ) ->
+    {ok, context()}
+    | error({invalid_eval_api_mod, Language :: binary()})
+    | error({unknown_eval_api_language, Language :: binary()}).
 acquire_map_context(DbName, DDocId, Language, Sig, Lib, MapFuns) ->
     ApiMod = get_api_mod(Language),
     CtxOpts = #{
@@ -87,6 +103,37 @@ map_docs({ApiMod, Ctx}, Docs) ->
     ApiMod:map_docs(Ctx, Docs).
 
 
+-spec with_context(with_context_opts(), function()) -> 
+    any() 
+    | error({invalid_eval_api_mod, Language :: binary()})
+    | error({unknown_eval_api_language, Language :: binary()}).
+with_context(#{language := Language}, Fun) ->
+    {ok, Ctx} = acquire_context(Language),
+    try 
+        Fun(Ctx)
+    after
+        release_context(Ctx)
+    end.
+
+
+-spec try_compile(context(), function_type(), function_name(), function_src()) -> ok.
+try_compile({ApiMod, Ctx}, FuncType, FuncName, FuncSrc) -> 
+    ApiMod:try_compile(Ctx, FuncType, FuncName, FuncSrc).
+
+
+acquire_context(Language) ->
+    ApiMod = get_api_mod(Language),
+    {ok, Ctx} = ApiMod:acquire_context(),
+    {ok, {ApiMod, Ctx}}.
+
+
+release_context(nil) ->
+    ok;
+
+release_context({ApiMod, Ctx}) ->
+    ApiMod:release_context(Ctx).
+
+
 get_api_mod(Language) when is_binary(Language) ->
     try
         LangStr = binary_to_list(Language),
diff --git a/src/couch_js/src/couch_js.erl b/src/couch_js/src/couch_js.erl
index 1bc0f19..a9c974e 100644
--- a/src/couch_js/src/couch_js.erl
+++ b/src/couch_js/src/couch_js.erl
@@ -18,7 +18,10 @@
 -export([
     acquire_map_context/1,
     release_map_context/1,
-    map_docs/2
+    map_docs/2,
+    acquire_context/0,
+    release_context/1,
+    try_compile/4
 ]).
 
 
@@ -49,3 +52,15 @@ map_docs(Proc, Docs) ->
         end, Results),
         {Doc#doc.id, Tupled}
     end, Docs)}.
+
+acquire_context() ->
+    Ctx = couch_query_servers:get_os_process(?JS),
+    {ok, Ctx}.
+
+
+release_context(Proc) ->
+    couch_query_servers:ret_os_process(Proc).
+
+
+try_compile(Proc, FunctionType, FunName, FunSrc) ->
+    couch_query_servers:try_compile(Proc, FunctionType, FunName, FunSrc).
diff --git a/src/couch_mrview/src/couch_mrview.erl b/src/couch_mrview/src/couch_mrview.erl
index 880dfa7..32f823d 100644
--- a/src/couch_mrview/src/couch_mrview.erl
+++ b/src/couch_mrview/src/couch_mrview.erl
@@ -188,8 +188,8 @@ validate(DbName, _IsDbPartitioned,  DDoc) ->
         (#mrview{reduce_funs = [{Name, _} | _]}) -> Name;
         (_) -> null
     end,
-    ValidateView = fun(Proc, #mrview{def=MapSrc, reduce_funs=Reds}=View) ->
-        couch_query_servers:try_compile(Proc, map, GetName(View), MapSrc),
+    ValidateView = fun(Ctx, #mrview{def=MapSrc, reduce_funs=Reds}=View) ->
+        couch_eval:try_compile(Ctx, map, GetName(View), MapSrc),
         lists:foreach(fun
             ({_RedName, <<"_sum", _/binary>>}) ->
                 ok;
@@ -203,7 +203,7 @@ validate(DbName, _IsDbPartitioned,  DDoc) ->
                 Msg = ["`", Bad, "` is not a supported reduce function."],
                 throw({invalid_design_doc, Msg});
             ({RedName, RedSrc}) ->
-                couch_query_servers:try_compile(Proc, reduce, RedName, RedSrc)
+                couch_eval:try_compile(Ctx, reduce, RedName, RedSrc)
         end, Reds)
     end,
     {ok, #mrst{
@@ -211,19 +211,10 @@ validate(DbName, _IsDbPartitioned,  DDoc) ->
         views = Views
     }} = couch_mrview_util:ddoc_to_mrst(DbName, DDoc),
 
-    try Views =/= [] andalso couch_query_servers:get_os_process(Lang) of
-        false ->
-            ok;
-        Proc ->
-            try
-                lists:foreach(fun(V) -> ValidateView(Proc, V) end, Views)
-            after
-                couch_query_servers:ret_os_process(Proc)
-            end
-    catch {unknown_query_language, _Lang} ->
-    %% Allow users to save ddocs written in unknown languages
-        ok
-    end.
+    Views =/= [] andalso couch_eval:with_context(#{language => Lang}, fun (Ctx) ->
+        lists:foreach(fun(V) -> ValidateView(Ctx, V) end, Views)
+    end),
+    ok.
 
 
 query_all_docs(Db, Args) ->
diff --git a/src/couch_replicator/test/eunit/couch_replicator_test_helper.erl b/src/couch_replicator/test/eunit/couch_replicator_test_helper.erl
index 2ac447e..39717dd 100644
--- a/src/couch_replicator/test/eunit/couch_replicator_test_helper.erl
+++ b/src/couch_replicator/test/eunit/couch_replicator_test_helper.erl
@@ -56,7 +56,7 @@
 
 
 start_couch() ->
-    Ctx = test_util:start_couch([fabric, chttpd, couch_replicator]),
+    Ctx = test_util:start_couch([fabric, chttpd, couch_replicator, couch_js]),
     Hashed = couch_passwords:hash_admin_password(?PASSWORD),
     ok = config:set("admins", ?USERNAME, ?b2l(Hashed), _Persist = false),
     Ctx.
diff --git a/src/fabric/src/fabric2_db.erl b/src/fabric/src/fabric2_db.erl
index 6d8bb72..4e0a9fd 100644
--- a/src/fabric/src/fabric2_db.erl
+++ b/src/fabric/src/fabric2_db.erl
@@ -2154,7 +2154,7 @@ validate_doc_update(Db, Doc, PrevDoc) ->
 
 validate_ddoc(Db, DDoc) ->
     try
-        ok = couch_index_server:validate(Db, couch_doc:with_ejson_body(DDoc))
+        ok = couch_mrview:validate(Db, couch_doc:with_ejson_body(DDoc))
     catch
         throw:{invalid_design_doc, Reason} ->
             throw({bad_request, invalid_design_doc, Reason});
diff --git a/src/fabric/test/fabric2_doc_crud_tests.erl b/src/fabric/test/fabric2_doc_crud_tests.erl
index 7a24b7d..bc78887 100644
--- a/src/fabric/test/fabric2_doc_crud_tests.erl
+++ b/src/fabric/test/fabric2_doc_crud_tests.erl
@@ -75,7 +75,7 @@ doc_crud_test_() ->
 
 
 setup() ->
-    Ctx = test_util:start_couch([fabric]),
+    Ctx = test_util:start_couch([fabric, couch_js]),
     {ok, Db} = fabric2_db:create(?tempdb(), [{user_ctx, ?ADMIN_USER}]),
     {Db, Ctx}.
 
diff --git a/src/mango/src/mango_eval.erl b/src/mango/src/mango_eval.erl
index 59d784b..7fd81df 100644
--- a/src/mango/src/mango_eval.erl
+++ b/src/mango/src/mango_eval.erl
@@ -18,7 +18,10 @@
 -export([
     acquire_map_context/1,
     release_map_context/1,
-    map_docs/2
+    map_docs/2,
+    acquire_context/0,
+    release_context/1,
+    try_compile/4
 ]).
 
 
@@ -60,6 +63,18 @@ map_docs(Indexes, Docs) ->
     end, Docs)}.
 
 
+acquire_context() ->
+    {ok, no_ctx}.
+
+
+release_context(_) ->
+    ok.
+
+
+try_compile(_Ctx, _FunType, _IndexName, IndexInfo) ->
+    mango_idx_view:validate_index_def(IndexInfo).
+
+
 index_doc(Indexes, Doc) ->
     lists:map(fun(Idx) ->
         {IdxDef} = mango_idx:def(Idx),
diff --git a/test/elixir/lib/setup/common.ex b/test/elixir/lib/setup/common.ex
index e81f109..65cd04f 100644
--- a/test/elixir/lib/setup/common.ex
+++ b/test/elixir/lib/setup/common.ex
@@ -19,9 +19,9 @@ defmodule Couch.Test.Setup.Common do
       |> Step.Create.DB.new(:db)
   end
 
-  def with_db(setup) do
+  def with_db(setup, apps \\ []) do
     setup
-      |> Step.Start.new(:start, extra_apps: [:fabric])
+      |> Step.Start.new(:start, extra_apps: [:fabric] ++ apps)
       |> Step.Create.DB.new(:db)
   end
 end
\ No newline at end of file