From 51267a5fd170c865cba795b5af3f7d3f348caed5 Mon Sep 17 00:00:00 2001 From: Robert Newson Date: Wed, 10 May 2023 10:21:35 +0100 Subject: Improve nouveau mango integration 1) Fix sorting on strings and numbers 2) use 'string' type for string fields 3) use 'text' type for the default field --- src/mango/src/mango_cursor_nouveau.erl | 10 ++++++- src/mango/src/mango_error.erl | 11 ++++++++ src/mango/src/mango_idx_nouveau.erl | 2 ++ src/mango/src/mango_native_proc.erl | 15 +++++++++- test/elixir/test/config/nouveau.elixir | 3 ++ test/elixir/test/nouveau_test.exs | 51 ++++++++++++++++++++++++++++++---- 6 files changed, 85 insertions(+), 7 deletions(-) diff --git a/src/mango/src/mango_cursor_nouveau.erl b/src/mango/src/mango_cursor_nouveau.erl index 7cdad20cd..1758e5dcc 100644 --- a/src/mango/src/mango_cursor_nouveau.erl +++ b/src/mango/src/mango_cursor_nouveau.erl @@ -222,7 +222,15 @@ sort_query(Opts, Selector) -> {Field, <<"desc">>} -> {desc, Field}; Field when is_binary(Field) -> {asc, Field} end, - SField = mango_selector_text:append_sort_type(RawSortField, Selector), + SField0 = mango_selector_text:append_sort_type(RawSortField, Selector), + %% ugly fixup below + SField = + case SField0 of + <">> -> + <">>; + Else -> + Else + end, case Dir of asc -> SField; diff --git a/src/mango/src/mango_error.erl b/src/mango/src/mango_error.erl index 22cb37106..a8b5bfa4b 100644 --- a/src/mango/src/mango_error.erl +++ b/src/mango/src/mango_error.erl @@ -94,6 +94,17 @@ info(mango_cursor_nouveau, {nouveau_search_error, {error, Error}}) -> <<"nouveau_search_error">>, fmt("~p", [Error]) }; +info(mango_idx_nouveau, {invalid_index_fields_definition, Def}) -> + { + 400, + <<"invalid_index_fields_definition">>, + fmt( + "Text Index field definitions must be of the form\n" + " {\"name\": \"non-empty fieldname\", \"type\":\n" + " \"boolean,number,string or text\"}. Def: ~p", + [Def] + ) + }; info(mango_fields, {invalid_fields_json, BadFields}) -> { 400, diff --git a/src/mango/src/mango_idx_nouveau.erl b/src/mango/src/mango_idx_nouveau.erl index 074a755ee..0816898a1 100644 --- a/src/mango/src/mango_idx_nouveau.erl +++ b/src/mango/src/mango_idx_nouveau.erl @@ -181,6 +181,8 @@ validate_field_name(Else) when is_binary(Else) -> validate_field_name(_) -> throw(invalid_field_name). +validate_field_type(<<"text">>) -> + <<"text">>; validate_field_type(<<"string">>) -> <<"string">>; validate_field_type(<<"number">>) -> diff --git a/src/mango/src/mango_native_proc.erl b/src/mango/src/mango_native_proc.erl index 8e04ab4b8..7982fc787 100644 --- a/src/mango/src/mango_native_proc.erl +++ b/src/mango/src/mango_native_proc.erl @@ -254,7 +254,10 @@ add_default_text_field(Fields) -> add_default_text_field([], Acc) -> Acc; add_default_text_field([{_Name, <<"string">>, Value} | Rest], Acc) -> - NewAcc = [{<<"$default">>, <<"string">>, Value} | Acc], + NewAcc = [{<<"$default">>, <<"text">>, Value} | Acc], + add_default_text_field(Rest, NewAcc); +add_default_text_field([{_Name, <<"text">>, Value} | Rest], Acc) -> + NewAcc = [{<<"$default">>, <<"text">>, Value} | Acc], add_default_text_field(Rest, NewAcc); add_default_text_field([_ | Rest], Acc) -> add_default_text_field(Rest, Acc). @@ -310,6 +313,8 @@ get_text_field_type(<<"number">>) -> <<"number">>; get_text_field_type(<<"boolean">>) -> <<"boolean">>; +get_text_field_type(<<"text">>) -> + <<"text">>; get_text_field_type(_) -> <<"string">>. @@ -357,6 +362,14 @@ convert_to_nouveau_string_field([Name, Value, []]) when is_binary(Name), is_bina convert_nouveau_fields([]) -> []; convert_nouveau_fields([{Name, <<"string">>, Value} | Rest]) -> + Field = + {[ + {<<"@type">>, <<"string">>}, + {<<"name">>, Name}, + {<<"value">>, Value} + ]}, + [Field | convert_nouveau_fields(Rest)]; +convert_nouveau_fields([{Name, <<"text">>, Value} | Rest]) -> Field = {[ {<<"@type">>, <<"text">>}, diff --git a/test/elixir/test/config/nouveau.elixir b/test/elixir/test/config/nouveau.elixir index 5c13aac2b..a580581e6 100644 --- a/test/elixir/test/config/nouveau.elixir +++ b/test/elixir/test/config/nouveau.elixir @@ -15,6 +15,9 @@ "ranges (open)", "mango search by number", "mango search by string", + "mango search by text", + "mango sort by number", + "mango sort by string", "search GET (partitioned)", "search POST (partitioned)", "mango (partitioned)" diff --git a/test/elixir/test/nouveau_test.exs b/test/elixir/test/nouveau_test.exs index 3bea874d9..ad48e58ea 100644 --- a/test/elixir/test/nouveau_test.exs +++ b/test/elixir/test/nouveau_test.exs @@ -11,10 +11,10 @@ defmodule NouveauTest do resp = Couch.post("/#{db_name}/_bulk_docs", headers: ["Content-Type": "application/json"], body: %{:docs => [ - %{"_id" => "doc4", "foo" => "foo", "bar" => 42}, - %{"_id" => "doc3", "foo" => "bar", "bar" => 12.0}, - %{"_id" => "doc1", "foo" => "baz", "bar" => 0}, - %{"_id" => "doc2", "foo" => "foobar", "bar" => 100}, + %{"_id" => "doc4", "foo" => "foo", "bar" => 42, "baz" => "hello there"}, + %{"_id" => "doc3", "foo" => "bar", "bar" => 12.0, "baz" => "hello"}, + %{"_id" => "doc1", "foo" => "baz", "bar" => 0, "baz" => "there"}, + %{"_id" => "doc2", "foo" => "foobar", "bar" => 100, "baz" => "hi"}, ]} ) assert resp.status_code in [201] @@ -61,13 +61,15 @@ defmodule NouveauTest do index: %{ fields: [ %{name: "foo", type: "string"}, - %{name: "bar", type: "number"} + %{name: "bar", type: "number"}, + %{name: "baz", type: "string"}, ] } } resp = Couch.post("/#{db_name}/_index", body: body) assert resp.status_code in [200] + resp.body end def get_ids(resp) do @@ -303,6 +305,45 @@ defmodule NouveauTest do assert ids == ["doc4"] end + @tag :with_db + test "mango search by text", context do + db_name = context[:db_name] + create_search_docs(db_name) + create_mango_index(db_name) + + url = "/#{db_name}/_find" + resp = Couch.post(url, body: %{selector: %{"$text": "hello"}}) + assert_status_code(resp, 200) + ids = get_mango_ids(resp) + assert ids == ["doc4", "doc3"] + end + + @tag :with_db + test "mango sort by number", context do + db_name = context[:db_name] + create_search_docs(db_name) + create_mango_index(db_name) + + url = "/#{db_name}/_find" + resp = Couch.post(url, body: %{sort: [%{"bar:number": "asc"}], selector: %{bar: %{"$gt": 5}}}) + assert_status_code(resp, 200) + ids = get_mango_ids(resp) + assert ids == ["doc3", "doc4", "doc2"] + end + + @tag :with_db + test "mango sort by string", context do + db_name = context[:db_name] + create_search_docs(db_name) + create_mango_index(db_name) + + url = "/#{db_name}/_find" + resp = Couch.post(url, body: %{sort: [%{"foo:string": "asc"}], selector: %{bar: %{"$gte": 0}}}) + assert_status_code(resp, 200) + ids = get_mango_ids(resp) + assert ids == ["doc3", "doc1", "doc4", "doc2"] + end + @tag :with_partitioned_db test "search GET (partitioned)", context do db_name = context[:db_name] -- cgit v1.2.1