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
Comment on lines +484 to +489
Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Comment on lines +9 to +13
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I know it's just an atom, but perhaps :unsupported is more clear than nil?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The reason I didn't use a more "expressive" atom is one ends up having to remember all the various names for "this is not something that is happening" return values. nil is convenient in that it is the least surprising (at least for me) and widely used to mean "nothing here".

If you prefer, I can change it to :unsupported, but as a library user I lean towards "common and therefore predictable" in these cases.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

No that's a fine justification.

end