diff --git a/guides/cheatsheet.cheatmd b/guides/cheatsheet.cheatmd index 4c8b867..5426958 100644 --- a/guides/cheatsheet.cheatmd +++ b/guides/cheatsheet.cheatmd @@ -93,6 +93,7 @@ iex> ExTypesense.create_collection(schema) ```elixir iex> ExTypesense.list_collections() ``` +{: .wrap} ### Update a collection @@ -140,8 +141,6 @@ iex> ExTypesense.create_document(post, :create) } ``` -{: .wrap} - ### Update a document ```elixir @@ -159,8 +158,6 @@ iex> ExTypesense.update_document(post, 0) } ``` -{: .wrap} - ### Delete a document @@ -177,8 +174,6 @@ iex> ExTypesense.delete_document(Post, 0) } ``` -{: .wrap} - ### Indexes multiple documents ```elixir @@ -187,13 +182,14 @@ iex> ExTypesense.index_multiple_documents(posts, :post_id, :upsert) {:ok, [%{"success" => true}, %{"success" => true}]} ``` -## Search +## How to use search {: .col-2} +### Search using Ecto schema (struct) + ```elixir iex> params = %{q: "test", query_by: "title"} - iex> ExTypesense.search(Post, params) {:ok, %{ @@ -205,3 +201,31 @@ iex> ExTypesense.search(Post, params) } } ``` + +### Multi search + +```elixir +iex> ExTypesense.multisearch(Catalog) +``` + +### Search using collection name (string) + +```elixir +iex> params = %{q: "test", query_by: "title"} +iex> ExTypesense.search("posts", params) +{:ok, + %{ + "id" => "0", + "collection_name" => "posts", + "post_id" => 34, + "title" => "test", + "description" => "lorem ipsum" + } +} +``` + +### Federated search + +```elixir +iex> ExTypesense.multisearch(Catalog) +``` diff --git a/lib/ex_typesense/search.ex b/lib/ex_typesense/search.ex index f5ea648..4677746 100644 --- a/lib/ex_typesense/search.ex +++ b/lib/ex_typesense/search.ex @@ -14,14 +14,15 @@ defmodule ExTypesense.Search do @documents_path "documents" @search_path "search" @multi_search_path "/multi_search" - @type response :: Ecto.Query.t() | {:ok, map()} | {:error, map()} + @type response :: {:ok, map()} | {:error, map()} @doc """ - Search from a document. + Search from a document or Ecto Schema. + Search params can be found [here](https://typesense.org/docs/latest/api/search.html#search-parameters). ## Examples iex> params = %{q: "umbrella", query_by: "title,description"} - iex> ExTypesense.search(Something, params) + iex> ExTypesense.search(Catalog, params) {:ok, %{ "facet_counts" => [], @@ -30,7 +31,26 @@ defmodule ExTypesense.Search do "out_of" => 0, "page" => 1, "request_params" => %{ - "collection_name" => "something", + "collection_name" => "catalogs", + "per_page" => 10, + "q" => "umbrella" + }, + "search_cutoff" => false, + "search_time_ms" => 5 + } + } + + iex> params = %{q: "umbrella", query_by: "title,description"} + iex> ExTypesense.search("catalogs", params) + {:ok, + %{ + "facet_counts" => [], + "found" => 0, + "hits" => [], + "out_of" => 0, + "page" => 1, + "request_params" => %{ + "collection_name" => "catalogs", "per_page" => 10, "q" => "umbrella" }, @@ -41,7 +61,7 @@ defmodule ExTypesense.Search do """ @doc since: "0.1.0" - @spec search(Connection.t(), module() | String.t(), map()) :: response() + @spec search(Connection.t(), module() | String.t(), map()) :: Ecto.Query.t() | response() def search(conn \\ Connection.new(), module_or_collection_name, params) def search(conn, module_name, params) when is_atom(module_name) and is_map(params) do @@ -75,13 +95,25 @@ defmodule ExTypesense.Search do end @doc """ - Perform multiple searches at once. + Perform [multiple/federated](https://typesense.org/docs/latest/api/federated-multi-search.html) + searches at once. + Search params can be found [here](https://typesense.org/docs/latest/api/search.html#search-parameters). + + > This is especially useful to avoid round-trip network latencies + > incurred otherwise if each of these requests are sent in separate + > HTTP requests. + + > You can also use this feature to do a federated search across + > multiple collections in a single HTTP request. For eg: in an + > ecommerce products dataset, you can show results from both a + > "products" collection, and a "brands" collection to the user, by + > searching them in parallel with a multi_search request. ## Examples iex> searches = [ - ...> %{collection: "companies", params: %{q: "umbrella"}}, - ...> %{collection: "companies", params: %{q: "rain"}}, - ...> %{collection: "companies", params: %{q: "sun"}} + ...> %{collection: "companies", q: "Loca Cola"}, + ...> %{collection: Company, q: "Burgler King"}, + ...> %{collection: Catalog, q: "umbrella"} ...> ] iex> ExTypesense.multi_search(searches) {:ok, @@ -95,7 +127,7 @@ defmodule ExTypesense.Search do "request_params" => %{ "collection_name" => "companies", "per_page" => 10, - "q" => "umbrella" + "q" => "Loca Cola" }, "search_cutoff" => false, "search_time_ms" => 5 @@ -109,7 +141,7 @@ defmodule ExTypesense.Search do "request_params" => %{ "collection_name" => "companies", "per_page" => 10, - "q" => "rain" + "q" => "Burgler King" }, "search_cutoff" => false, "search_time_ms" => 5 @@ -123,7 +155,7 @@ defmodule ExTypesense.Search do "request_params" => %{ "collection_name" => "companies", "per_page" => 10, - "q" => "sun" + "q" => "umbrella" }, "search_cutoff" => false, "search_time_ms" => 5 @@ -135,16 +167,24 @@ defmodule ExTypesense.Search do def multi_search(conn \\ Connection.new(), searches) do path = @multi_search_path - response = - HttpClient.request( - conn, - %{ - method: :post, - path: path, - body: Jason.encode!(%{searches: searches}) - } - ) - - response + searches = + Enum.map(searches, fn %{collection: name} = search -> + collection_name = + case is_binary(name) do + true -> name + false -> name.__schema__(:source) + end + + Map.put(search, :collection, collection_name) + end) + + HttpClient.request( + conn, + %{ + method: :post, + path: path, + body: Jason.encode!(%{searches: searches}) + } + ) end end diff --git a/test/search_test.exs b/test/search_test.exs index c56fca0..baeca01 100644 --- a/test/search_test.exs +++ b/test/search_test.exs @@ -78,7 +78,11 @@ defmodule SearchTest do assert {:ok, %{"found" => 0, "hits" => []}} = ExTypesense.search(schema.name, params) end - # test "success: multi_search Ecto", %{schema: schema} do + # test "success: multi_search Ecto", %{catalog: catalog} do + # assert nil == true + # end + + # test "success: multi_search contains string or module name as collection name", %{schema: schema} do # assert nil == true # end