Skip to content

Add Exqlite.TypeExtensions to allow more types to be stored in the database #333

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,17 @@ end
### Runtime Configuration

```elixir
config :exqlite, default_chunk_size: 100
config :exqlite,
default_chunk_size: 100,
type_extensions: [MyApp.TypeExtension]
```

* `default_chunk_size` - The chunk size that is used when multi-stepping when
not specifying the chunk size explicitly.

* `type_extensions`: An optional list of modules that implement the
Exqlite.TypeExtension behaviour, allowing types beyond the default set that
can be stored and retrieved from the database.

### Compile-time Configuration

In `config/config.exs`,
Expand Down
25 changes: 24 additions & 1 deletion lib/exqlite/sqlite3.ex
Original file line number Diff line number Diff line change
Expand Up @@ -481,5 +481,28 @@ defmodule Exqlite.Sqlite3 do
raise ArgumentError, "#{inspect(datetime)} is not in UTC"
end

defp convert(val), do: val
defp convert(val) do
convert_with_type_extensions(type_extensions(), val)
end

defp convert_with_type_extensions(nil, val), do: val
defp convert_with_type_extensions([], val), do: val

defp convert_with_type_extensions([extension | other_extensions], val) do
case extension.convert(val) do
nil ->
convert_with_type_extensions(other_extensions, val)

{:ok, converted} ->
converted

{:error, reason} ->
raise ArgumentError,
"Failed conversion by TypeExtension #{extension}: #{inspect(val)}. Reason: #{inspect(reason)}."
end
end

defp type_extensions do
Application.get_env(:exqlite, :type_extensions)
end
end
14 changes: 14 additions & 0 deletions lib/exqlite/type_extension.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
defmodule Exqlite.TypeExtension do
@moduledoc """
A behaviour that defines the API for extensions providing custom data loaders and dumpers
for Ecto schemas.
"""

@doc """
Takes a value and convers it to data suitable for storage in the database.

Returns a tagged :ok/:error tuple. If the value is not convertable by this
extension, returns nil.
"""
@callback convert(value :: term) :: {:ok, term} | {:error, reason :: term} | nil
end