Skip to content

Commit 8aa1675

Browse files
authored
feat: support global and per-connection opts extension loading (#247)
1 parent a1e1acd commit 8aa1675

File tree

1 file changed

+53
-1
lines changed

1 file changed

+53
-1
lines changed

lib/exqlite/connection.ex

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ defmodule Exqlite.Connection do
2828
alias Exqlite.Query
2929
alias Exqlite.Result
3030
alias Exqlite.Sqlite3
31+
require Logger
3132

3233
defstruct [
3334
:db,
@@ -128,6 +129,32 @@ defmodule Exqlite.Connection do
128129
* `:soft_heap_limit` - The size limit in bytes for the heap limit.
129130
* `:hard_heap_limit` - The size limit in bytes for the heap.
130131
* `:custom_pragmas` - A list of custom pragmas to set on the connection, for example to configure extensions.
132+
* `:load_extensions` - A list of paths identifying extensions to load. Defaults to `[]`.
133+
The provided list will be merged with the global extensions list, set on `:exqlite, :load_extensions`.
134+
Be aware that the path should handle pointing to a library compiled for the current architecture.
135+
Example configuration:
136+
137+
```
138+
arch_dir =
139+
System.cmd("uname", ["-sm"])
140+
|> elem(0)
141+
|> String.trim()
142+
|> String.replace(" ", "-")
143+
|> String.downcase() # => "darwin-arm64"
144+
145+
config :myapp, arch_dir: arch_dir
146+
147+
# global
148+
config :exqlite, load_extensions: [ "./priv/sqlite/\#{arch_dir}/rotate" ]
149+
150+
# per connection in a Phoenix app
151+
config :myapp, Myapp.Repo,
152+
database: "path/to/db",
153+
load_extensions: [
154+
"./priv/sqlite/\#{arch_dir}/vector0",
155+
"./priv/sqlite/\#{arch_dir}/vss0"
156+
]
157+
```
131158
132159
For more information about the options above, see [sqlite documentation][1]
133160
@@ -460,6 +487,30 @@ defmodule Exqlite.Connection do
460487
set_pragma(db, "busy_timeout", Pragma.busy_timeout(options))
461488
end
462489

490+
defp load_extensions(db, options) do
491+
global_extensions = Application.get_env(:exqlite, :load_extensions, [])
492+
493+
extensions =
494+
Keyword.get(options, :load_extensions, [])
495+
|> Enum.concat(global_extensions)
496+
|> Enum.uniq()
497+
498+
do_load_extensions(db, extensions)
499+
end
500+
501+
defp do_load_extensions(_db, []), do: :ok
502+
503+
defp do_load_extensions(db, extensions) do
504+
Sqlite3.enable_load_extension(db, true)
505+
506+
Enum.each(extensions, fn extension ->
507+
Logger.debug(fn -> "Exqlite: loading extension `#{extension}`" end)
508+
Sqlite3.execute(db, "SELECT load_extension('#{extension}')")
509+
end)
510+
511+
Sqlite3.enable_load_extension(db, false)
512+
end
513+
463514
defp do_connect(database, options) do
464515
with {:ok, directory} <- resolve_directory(database),
465516
:ok <- mkdir_p(directory),
@@ -480,7 +531,8 @@ defmodule Exqlite.Connection do
480531
:ok <- set_busy_timeout(db, options),
481532
:ok <- set_journal_size_limit(db, options),
482533
:ok <- set_soft_heap_limit(db, options),
483-
:ok <- set_hard_heap_limit(db, options) do
534+
:ok <- set_hard_heap_limit(db, options),
535+
:ok <- load_extensions(db, options) do
484536
state = %__MODULE__{
485537
db: db,
486538
directory: directory,

0 commit comments

Comments
 (0)