joelpaulkoch

joelpaulkoch

Call SQL function when dumping custom Ecto type with SQLite and virtual table

I have a custom Ecto type and want to call a SQL function when dumping a value of this type into a virtual table with SQLite.

I’m developing this library to use sqlite-vec with Elixir.

There are 3 vector types in sqlite-vec: float32, int8, and bit.
The most performant way to use sqlite-vec is to create a virtual table.
Then you can create vectors with SQL functions as constructors.

So, in SQL that would be something like this:

CREATE VIRTUAL TABLE vt USING vec0(id INTEGER PRIMARY KEY, embedding int8[2])

INSERT INTO vt(id, embedding) VALUES(1, vec_int8('[1, 2]'))

I’ve created a custom Ecto type for each of the three vector types, e.g. here for int8:

defmodule SqliteVec.Ecto.Int8 do
  @moduledoc """
  `Ecto.Type` for `SqliteVec.Int8`
  """
  use Ecto.Type

  def type, do: :binary

  def cast(value) do
    {:ok, SqliteVec.Int8.new(value)}
  end

  def load(data) do
    {:ok, SqliteVec.Int8.from_binary(data)}
  end

  def dump(%SqliteVec.Int8{} = vector) do
    {:ok, SqliteVec.Int8.to_binary(vector)}
  end

  def dump(_), do: :error
end

What I want to achieve is inserting vectors with regular Ecto.Repo functions.

For that, I define a schema:

defmodule VT do
  use Ecto.Schema

  schema "vt" do
    field(:embedding, SqliteVec.Ecto.Int8)
  end
end	

And now I want to insert using

MyApp.Repo.insert(%VT{
  embedding: SqliteVec.Int8.new([1, 2])
})  

The problem is that this fails as I’m dumping the binary data directly instead of calling the vec_int8 constructor function.
Actually, sqlite-vec interprets plain binary data as float32 (as if I would call the vec_f32 constructor function).
So it works for float32 vectors without constructor function but fails for int8 and bit vectors because the types don’t match.

What I’ve tried:

  • parameterized types, I don’t think they add any capabilities that would work here
  • changing the type of the custom type from :binary to :string and dump a string of the constructor function with interpolated arguments, e.g. “vec_int8(‘[1, 2]’)”

I also had a look at ecto_sqlite3 as I’m assuming that the correct place for this functionality would be the adapter, and in particular the codec.
I guess I would need a way to define my own codec for the custom types, and call the constructor function there, not sure if that would work though.

Thanks in advance for any input!

First Post!

rhcarvalho

rhcarvalho

I’m not sure it would work in this context, but have you considered using Ecto’s fragment/1?

https://hexdocs.pm/ecto/Ecto.Query.API.html#fragment/1

Where Next?

Popular in Questions Top

gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

Other popular topics Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> someth...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
Nvim
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
New

We're in Beta

About us Mission Statement