Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
24 changes: 23 additions & 1 deletion lib/exqlite/sqlite3.ex
Original file line number Diff line number Diff line change
Expand Up @@ -481,5 +481,27 @@ 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([], val), do: val
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going back and fourth on allowing type_extensions to be nil.

On one hand, letting it default to nil, will make the pattern match be faster than matching with an empty list.

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

And then changing Application.get_env(:exqlite, :type_extensions, []) to be Application.get_env(:exqlite, :type_extensions).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went back and forth as well .. I'm not sure the speed gain is really going to be noticeable, but it's easy enough to do.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See 704c9bd


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