defmodule Meilisearch.Search do
@moduledoc """
Search into your Meilisearch indexes.
[Search API](https://www.meilisearch.com/docs/reference/api/search)
"""
use Ecto.Schema
@primary_key false
embedded_schema do
field(:hits, {:array, :map})
field(:offset, :integer)
field(:limit, :integer)
field(:estimatedTotalHits, :integer)
field(:totalHits, :integer)
field(:totalPages, :integer)
field(:hitsPerPage, :integer)
field(:page, :integer)
field(:facetDistribution, :map)
field(:facetStats, :map)
field(:processingTimeMs, :integer)
field(:query, :string)
end
@type t(item) :: %__MODULE__{
hits: list(item),
offset: integer(),
limit: integer(),
estimatedTotalHits: integer(),
totalHits: integer(),
totalPages: integer(),
hitsPerPage: integer(),
page: integer(),
facetDistribution: map(),
facetStats: map(),
processingTimeMs: integer(),
query: String.t()
}
def cast(data) when is_map(data) do
%__MODULE__{}
|> Ecto.Changeset.cast(data, [
:hits,
:offset,
:limit,
:estimatedTotalHits,
:totalHits,
:totalPages,
:hitsPerPage,
:page,
:facetDistribution,
:facetStats,
:processingTimeMs,
:query
])
|> Ecto.Changeset.apply_changes()
end
@type search_params() :: %{
q: String.t(),
offset: integer(),
limit: integer(),
hitsPerPage: integer(),
page: integer(),
filter: String.t() | list(String.t()) | nil,
facets: list(String.t()) | nil,
attributesToRetrieve: list(String.t()),
attributesToCrop: list(String.t()) | nil,
cropLength: integer(),
cropMarker: String.t(),
attributesToHighlight: list(String.t()) | nil,
highlightPreTag: String.t(),
highlightPostTag: String.t(),
showMatchesPosition: boolean(),
sort: list(String.t()) | nil,
matchingStrategy: String.t() | :last | :all
}
@doc """
Search into your Meilisearch indexes using a POST request.
[Meilisearch documentation](https://www.meilisearch.com/docs/reference/api/search#search-in-an-index-with-post)
## Examples
iex> client = Meilisearch.Client.new(endpoint: "http://localhost:7700", key: "master_key_test")
iex> Meilisearch.Search.search(client, "movies", q: "space")
{:ok, %{
offset: 0,
limit: 20,
estimatedTotalHits: 1,
totalHits: 1,
totalPages: 1,
totalPages: 1,
page: 1,
facetDistribution: %{
"genres" => %{
"action" => 273,
"animation" => 118,
"adventure" => 132,
"fantasy" => 67,
"comedy" => 475,
"mystery" => 70,
"thriller" => 217
}
},
processingTimeMs: 11,
query: "space",
hits: [%{
"id" => 2001,
"title" => "2001: A Space Odyssey"
}]
}}
"""
@spec search(
Tesla.Client.t(),
String.t(),
q: String.t(),
offset: integer(),
limit: integer(),
hitsPerPage: integer(),
page: integer(),
filter: String.t() | list(String.t()) | nil,
facets: list(String.t()) | nil,
attributesToRetrieve: list(String.t()),
attributesToCrop: list(String.t()) | nil,
cropLength: integer(),
cropMarker: String.t(),
attributesToHighlight: list(String.t()) | nil,
highlightPreTag: String.t(),
highlightPostTag: String.t(),
showMatchesPosition: boolean(),
sort: list(String.t()) | nil,
matchingStrategy: String.t() | :last | :all
) ::
{:ok, __MODULE__.t(Meilisearch.Document.t())}
| {:error, Meilisearch.Client.error()}
def search(client, index_uid, params \\ [])
def search(client, index_uid, params) when is_list(params),
do: search(client, index_uid, Enum.into(params, %{}))
def search(client, index_uid, params) when is_map(params) do
with {:ok, data} <-
client
|> Tesla.post("/indexes/:index_uid/search", params,
opts: [path_params: [index_uid: index_uid]]
)
|> Meilisearch.Client.handle_response() do
{:ok, __MODULE__.cast(data)}
end
end
end