Typesense client for Elixir with support for your Ecto schemas.
Note: Breaking changes if you're upgrading from 0.3.x
to upcoming 0.5.x
version.
- creating collection using auto schema detection
- implement multisearch
- implement geosearch
- implement curation
- implement synonyms
ExTypesense requires Elixir ~> 1.14.x
. Read the Changelog for all available releases and requirements. This library is published to both Hex.pm and GitHub repository.
Add :ex_typesense
to your list of dependencies in the Elixir project config file, mix.exs
:
def deps do
[
# From default Hex package manager
{:ex_typesense, "~> 0.4"}
# Or from GitHub repository, if you want to latest greatest from main branch
{:ex_typesense, git: "https://github.com/jaeyson/ex_typesense.git"}
]
end
docker compose up -d
More info on spinning a local instance: https://typesense.org/docs/guide/install-typesense
After you have setup a local Typesense or Cloud hosted instance, there are 2 ways to set the credentials:
You can set the following config details to the config file:
config :ex_typesense,
api_key: "xyz",
host: "localhost",
port: 8108,
scheme: "http"
For Cloud hosted, you can generate and obtain the credentials from cluster instance admin interface:
config :ex_typesense,
api_key: "credential", # Admin API key
host: "111222333aaabbbcc-9.x9.typesense.net" # Nodes
port: 443,
scheme: "https"
By default you don't need to pass connections every time you use a function, if you use "Option 1" above.
You may have a Connection
Ecto schema in your app and want to pass your own creds dynamically.
defmodule MyApp.Credential do
schema "credentials" do
field :node, :string
field :secret_key, :string
field :port, :integer
end
end
credential = MyApp.Credential |> where(id: ^8888) |> Repo.one()
# using Connection struct
conn = %ExTypesense.Connection{
host: credential.node,
api_key: credential.secret_key,
port: credential.port,
scheme: "https"
}
# or maps, as long as the keys matches in ExTypesense.Connection.t()
conn = %{
host: credential.node,
api_key: credential.secret_key,
port: credential.port,
scheme: "https"
}
# or convert your struct to map, as long as the keys matches in ExTypesense.Connection.t()
conn = Map.from_struct(MyApp.Credential)
# or you don't want to change the fields in your schema, thus you convert it to map
conn = %Credential{
node: "localhost",
secret_key: "xyz",
port: 8108,
scheme: "http"
}
conn =
conn
|> Map.from_struct()
|> Map.drop([:node, :secret_key])
|> Map.put(:host, conn.node)
|> Map.put(:api_key, conn.secret_key)
ExTypesense.search(conn, collection_name, query)
There are 2 ways to create a collection, either via Ecto schema or using map (an Elixir data type):
In this example, we're adding person_id
that points to the id of persons
schema.
defmodule Person do
use Ecto.Schema
defimpl Jason.Encoder, for: __MODULE__ do
def encode(value, opts) do
value
|> Map.take([:id, :person_id, :name, :country])
|> Enum.map(fn {key, val} ->
cond do
key === :id -> {key, to_string(Map.get(value, :id))}
key === :person_id -> {key, Map.get(value, :id)}
true -> {key, val}
end
end)
|> Enum.into(%{})
|> Jason.Encode.map(opts)
end
end
schema "persons" do
field(:name, :string)
field(:country, :string)
field(:person_id, :integer, virtual: true)
end
def get_field_types do
%{
default_sorting_field: "person_id",
fields: [
%{name: "person_id", type: "int32"},
%{name: "name", type: "string"},
%{name: "country", type: "string"}
]
}
end
end
Next, create the collection from a module name.
ExTypesense.create_collection(Person)
schema = %{
name: "companies",
fields: [
%{name: "company_name", type: "string"},
%{name: "company_id", type: "int32"},
%{name: "country", type: "string"}
],
default_sorting_field: "company_id"
}
ExTypesense.create_collection(schema)
For multiple documents:
Post |> Repo.all() |> ExTypesense.index_multiple_documents()
For single document:
Post |> Repo.get!(123) |> ExTypesense.create_document()
params = %{q: "John Doe", query_by: "name"}
ExTypesense.search(schema.name, params)
ExTypesense.search(Person, params)
Check Cheatsheet for more usage examples.
Copyright (c) 2021 Jaeyson Anthony Y.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE