Recollect.DatabaseAdapter behaviour (recollect v0.5.1)

Copy Markdown View Source

Behaviour for database-specific implementations.

Recollect supports multiple database backends through this adapter pattern. Currently supported:

  • PostgreSQL with pgvector extension
  • libSQL (SQLite with native vector support)

Configure the adapter in your config.exs:

config :recollect, :database_adapter, Recollect.DatabaseAdapter.LibSQL
# or
config :recollect, :database_adapter, Recollect.DatabaseAdapter.Postgres

The adapter is used internally by Recollect to generate database-specific SQL, handle type mappings, and manage vector operations.

Summary

Callbacks

Returns SQL for creating the vector extension, or nil if not needed.

Returns the SQL dialect name.

Formats an embedding list for database insertion.

Formats a UUID for database insertion.

Converts an embedding from database format to Elixir list.

Returns SQL placeholder for parameterized queries.

Returns the module name for the Repo adapter.

Returns true if the adapter requires the pgvector package.

Returns true if the database supports recursive CTEs.

Returns true if the database supports vector indexes.

Returns SQL for approximate top-k vector search using index.

Returns the Ecto type for UUID fields.

Returns SQL expression for calculating cosine distance.

Returns the Ecto type atom for embedding fields.

Returns SQL for creating a vector index.

Returns SQL expression for calculating cosine similarity (1 - distance).

Returns the SQL type definition for a vector column.

Callbacks

create_vector_extension_sql()

@callback create_vector_extension_sql() :: String.t() | nil

Returns SQL for creating the vector extension, or nil if not needed.

dialect()

@callback dialect() :: :postgres | :sqlite | :libsql

Returns the SQL dialect name.

format_embedding(embedding)

@callback format_embedding(embedding :: [float()]) :: String.t() | [float()]

Formats an embedding list for database insertion.

Examples

iex> adapter.format_embedding([0.1, 0.2, 0.3])
"[0.1,0.2,0.3]"  # for libSQL
[0.1, 0.2, 0.3]  # for PostgreSQL (as Pgvector.Ecto.Vector)

format_uuid(uuid)

@callback format_uuid(uuid :: String.t() | binary()) :: String.t() | binary()

Formats a UUID for database insertion.

parse_embedding(data)

(optional)
@callback parse_embedding(data :: any()) :: [float()] | nil

Converts an embedding from database format to Elixir list.

placeholder(position)

@callback placeholder(position :: pos_integer()) :: String.t()

Returns SQL placeholder for parameterized queries.

PostgreSQL uses numbered parameters ($1, $2), while SQLite uses ?.

repo_adapter()

@callback repo_adapter() :: module()

Returns the module name for the Repo adapter.

Examples

iex> adapter.repo_adapter()
Ecto.Adapters.LibSQL  # for libSQL
Ecto.Adapters.Postgres  # for PostgreSQL

requires_pgvector?()

@callback requires_pgvector?() :: boolean()

Returns true if the adapter requires the pgvector package.

supports_recursive_ctes?()

@callback supports_recursive_ctes?() :: boolean()

Returns true if the database supports recursive CTEs.

supports_vector_index?()

@callback supports_vector_index?() :: boolean()

Returns true if the database supports vector indexes.

top_k_sql(table, index_name, query_vector, k)

(optional)
@callback top_k_sql(
  table :: atom(),
  index_name :: String.t(),
  query_vector :: String.t(),
  k :: pos_integer()
) :: String.t() | nil

Returns SQL for approximate top-k vector search using index.

Returns nil if not supported by the database.

uuid_type()

@callback uuid_type() :: atom()

Returns the Ecto type for UUID fields.

Examples

iex> adapter.uuid_type()
:binary_id  # libSQL uses binary IDs by default
:uuid       # PostgreSQL has native UUID

vector_distance_sql(column, query_ref)

@callback vector_distance_sql(column :: String.t(), query_ref :: String.t()) :: String.t()

Returns SQL expression for calculating cosine distance.

Examples

iex> adapter.vector_distance_sql("embedding", "query_vector")
"embedding <=> query_vector"  # PostgreSQL
"vector_distance_cos(embedding, query_vector)"  # libSQL

vector_ecto_type()

@callback vector_ecto_type() :: atom()

Returns the Ecto type atom for embedding fields.

Examples

iex> adapter.vector_ecto_type()
:string  # for libSQL (vectors stored as text representation)
Pgvector.Ecto.Vector  # for PostgreSQL

vector_index_sql(table, column, opts)

@callback vector_index_sql(table :: atom(), column :: atom(), opts :: keyword()) ::
  String.t()

Returns SQL for creating a vector index.

Examples

iex> adapter.vector_index_sql(:recollect_entries, :embedding, dimensions: 768)
"CREATE INDEX ... USING hnsw ..."  # PostgreSQL
"CREATE INDEX ... (libsql_vector_idx(embedding))"  # libSQL

vector_similarity_sql(column, query_ref)

@callback vector_similarity_sql(column :: String.t(), query_ref :: String.t()) ::
  String.t()

Returns SQL expression for calculating cosine similarity (1 - distance).

vector_type(dimensions)

@callback vector_type(dimensions :: pos_integer()) :: String.t()

Returns the SQL type definition for a vector column.

Examples

iex> adapter.vector_type(768)
"F32_BLOB(768)"  # for libSQL
"vector(768)"    # for PostgreSQL