update
This commit is contained in:
8
phoenix/deps/ecto_sqlite3/.formatter.exs
Normal file
8
phoenix/deps/ecto_sqlite3/.formatter.exs
Normal file
@@ -0,0 +1,8 @@
|
||||
# Used by "mix format"
|
||||
[
|
||||
inputs: [
|
||||
"{mix,.formatter}.exs",
|
||||
"{lib,test,bench}/**/*.{ex,exs}"
|
||||
],
|
||||
line_length: 88
|
||||
]
|
||||
BIN
phoenix/deps/ecto_sqlite3/.hex
Normal file
BIN
phoenix/deps/ecto_sqlite3/.hex
Normal file
Binary file not shown.
21
phoenix/deps/ecto_sqlite3/LICENSE
Normal file
21
phoenix/deps/ecto_sqlite3/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Matthew A. Johnston
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
106
phoenix/deps/ecto_sqlite3/README.md
Normal file
106
phoenix/deps/ecto_sqlite3/README.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# Ecto SQLite3 Adapter
|
||||
|
||||
[](https://github.com/elixir-sqlite/ecto_sqlite3/actions)
|
||||
[](https://hex.pm/packages/ecto_sqlite3)
|
||||
[](https://hexdocs.pm/ecto_sqlite3)
|
||||
|
||||
An Ecto SQLite3 Adapter. Uses [Exqlite](https://github.com/elixir-sqlite/exqlite)
|
||||
as the driver to communicate with sqlite3.
|
||||
|
||||
## Caveats and limitations
|
||||
|
||||
See [Limitations](https://hexdocs.pm/ecto_sqlite3/Ecto.Adapters.SQLite3.html#module-limitations-and-caveats)
|
||||
in Hexdocs.
|
||||
|
||||
## Installation
|
||||
|
||||
```elixir
|
||||
defp deps do
|
||||
[
|
||||
{:ecto_sqlite3, "~> 0.17"}
|
||||
]
|
||||
end
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Define your repo similar to this.
|
||||
|
||||
```elixir
|
||||
defmodule MyApp.Repo do
|
||||
use Ecto.Repo, otp_app: :my_app, adapter: Ecto.Adapters.SQLite3
|
||||
end
|
||||
```
|
||||
|
||||
Configure your repository similar to the following. If you want to know more
|
||||
about the possible options to pass the repository, checkout the documentation
|
||||
for [`Ecto.Adapters.SQLite`](https://hexdocs.pm/ecto_sqlite3/). It will have
|
||||
more information on what is configurable.
|
||||
|
||||
```elixir
|
||||
config :my_app,
|
||||
ecto_repos: [MyApp.Repo]
|
||||
|
||||
config :my_app, MyApp.Repo,
|
||||
database: "path/to/my/database.db"
|
||||
```
|
||||
|
||||
## Type Extensions
|
||||
|
||||
Type extensions allow custom data types to be stored and retrieved from an SQLite3 database.
|
||||
|
||||
This is done by implementing a module with the `Ecto.Adapters.SQLite3.TypeExtension` behaviour which maps types to encoder and decoder functions. Type extensions are activated by adding them to the `ecto_sqlite3` configuration as a list of type extention modules assigned to the `type_extensions` key:
|
||||
|
||||
```elixir
|
||||
config :exqlite:
|
||||
type_extensions: [MyApp.TypeExtension]
|
||||
|
||||
config :ecto_sqlite3,
|
||||
type_extensions: [MyApp.TypeExtension]
|
||||
```
|
||||
|
||||
## Database Encryption
|
||||
|
||||
As of version 0.9, `exqlite` supports loading database engines at runtime rather than compiling `sqlite3.c` itself.
|
||||
This can be used to support database level encryption via alternate engines such as [SQLCipher](https://www.zetetic.net/sqlcipher/design)
|
||||
or the [Official SEE extension](https://www.sqlite.org/see/doc/trunk/www/readme.wiki). Once you have either of those projects installed
|
||||
on your system, use the following environment variables during compilation:
|
||||
|
||||
```bash
|
||||
# tell exqlite that we wish to use some other sqlite installation. this will prevent sqlite3.c and friends from compiling
|
||||
export EXQLITE_USE_SYSTEM=1
|
||||
|
||||
# Tell exqlite where to find the `sqlite3.h` file
|
||||
export EXQLITE_SYSTEM_CFLAGS=-I/usr/local/include/sqlcipher
|
||||
|
||||
# tell exqlite which sqlite implementation to use
|
||||
export EXQLITE_SYSTEM_LDFLAGS=-L/usr/local/lib -lsqlcipher
|
||||
```
|
||||
|
||||
Once you have `exqlite` configured, you can use the `:key` option in the database config to enable encryption:
|
||||
|
||||
```elixir
|
||||
config :my_app, MyApp.Repo,
|
||||
database: "path/to/my/encrypted-database.db",
|
||||
key: "supersecret'
|
||||
```
|
||||
|
||||
## Benchmarks
|
||||
|
||||
We have some benchmarks comparing it against the `MySQL` and `Postgres` adapters.
|
||||
|
||||
You can read more about those at [bench/README.md](bench/README.md).
|
||||
|
||||
## Running Tests
|
||||
|
||||
Running unit tests
|
||||
|
||||
```sh
|
||||
mix test
|
||||
```
|
||||
|
||||
Running integration tests
|
||||
|
||||
```sh
|
||||
EXQLITE_INTEGRATION=true mix test
|
||||
```
|
||||
39
phoenix/deps/ecto_sqlite3/hex_metadata.config
Normal file
39
phoenix/deps/ecto_sqlite3/hex_metadata.config
Normal file
@@ -0,0 +1,39 @@
|
||||
{<<"links">>,
|
||||
[{<<"GitHub">>,<<"https://github.com/elixir-sqlite/ecto_sqlite3">>},
|
||||
{<<"docs">>,<<"https://hexdocs.pm/ecto_sqlite3">>}]}.
|
||||
{<<"name">>,<<"ecto_sqlite3">>}.
|
||||
{<<"version">>,<<"0.22.0">>}.
|
||||
{<<"description">>,<<"An SQLite3 Ecto3 adapter.">>}.
|
||||
{<<"elixir">>,<<"~> 1.15">>}.
|
||||
{<<"app">>,<<"ecto_sqlite3">>}.
|
||||
{<<"files">>,
|
||||
[<<"lib">>,<<"lib/ecto">>,<<"lib/ecto/adapters">>,
|
||||
<<"lib/ecto/adapters/sqlite3">>,<<"lib/ecto/adapters/sqlite3/codec.ex">>,
|
||||
<<"lib/ecto/adapters/sqlite3/data_type.ex">>,
|
||||
<<"lib/ecto/adapters/sqlite3/connection.ex">>,
|
||||
<<"lib/ecto/adapters/sqlite3/type_extension.ex">>,
|
||||
<<"lib/ecto/adapters/sqlite3.ex">>,<<".formatter.exs">>,<<"mix.exs">>,
|
||||
<<"README.md">>,<<"LICENSE">>]}.
|
||||
{<<"licenses">>,[<<"MIT">>]}.
|
||||
{<<"requirements">>,
|
||||
[[{<<"name">>,<<"decimal">>},
|
||||
{<<"app">>,<<"decimal">>},
|
||||
{<<"optional">>,false},
|
||||
{<<"requirement">>,<<"~> 1.6 or ~> 2.0">>},
|
||||
{<<"repository">>,<<"hexpm">>}],
|
||||
[{<<"name">>,<<"ecto_sql">>},
|
||||
{<<"app">>,<<"ecto_sql">>},
|
||||
{<<"optional">>,false},
|
||||
{<<"requirement">>,<<"~> 3.13.0">>},
|
||||
{<<"repository">>,<<"hexpm">>}],
|
||||
[{<<"name">>,<<"ecto">>},
|
||||
{<<"app">>,<<"ecto">>},
|
||||
{<<"optional">>,false},
|
||||
{<<"requirement">>,<<"~> 3.13.0">>},
|
||||
{<<"repository">>,<<"hexpm">>}],
|
||||
[{<<"name">>,<<"exqlite">>},
|
||||
{<<"app">>,<<"exqlite">>},
|
||||
{<<"optional">>,false},
|
||||
{<<"requirement">>,<<"~> 0.22">>},
|
||||
{<<"repository">>,<<"hexpm">>}]]}.
|
||||
{<<"build_tools">>,[<<"mix">>]}.
|
||||
602
phoenix/deps/ecto_sqlite3/lib/ecto/adapters/sqlite3.ex
Normal file
602
phoenix/deps/ecto_sqlite3/lib/ecto/adapters/sqlite3.ex
Normal file
@@ -0,0 +1,602 @@
|
||||
defmodule Ecto.Adapters.SQLite3 do
|
||||
@moduledoc """
|
||||
Adapter module for SQLite3.
|
||||
|
||||
It uses `Exqlite` for communicating to the database.
|
||||
|
||||
## Options
|
||||
|
||||
The adapter supports a superset of the options provided by the
|
||||
underlying `Exqlite` driver.
|
||||
|
||||
### Provided options
|
||||
|
||||
* `:database` - The path to the database. In memory is allowed. You can use
|
||||
`:memory` or `":memory:"` to designate that.
|
||||
* `:default_transaction_mode` - one of `:deferred` (default), `:immediate`, or
|
||||
`:exclusive`. If a mode is not specified in a call to `Repo.transaction/2`, this
|
||||
will be the default transaction mode.
|
||||
* `:journal_mode` - Sets the journal mode for the sqlite connection. Can be one of
|
||||
the following `:delete`, `:truncate`, `:persist`, `:memory`, `:wal`, or `:off`.
|
||||
Defaults to `:wal`.
|
||||
* `:temp_store` - Sets the storage used for temporary tables. Default is `:default`.
|
||||
Allowed values are `:default`, `:file`, `:memory`.
|
||||
* `:synchronous` - Can be `:extra`, `:full`, `:normal`, or `:off`. Defaults to `:normal`.
|
||||
* `:foreign_keys` - Sets if foreign key checks should be enforced or not. Can be
|
||||
`:on` or `:off`. Default is `:on`.
|
||||
* `:cache_size` - Sets the cache size to be used for the connection. This is an odd
|
||||
setting as a positive value is the number of pages in memory to use and a negative
|
||||
value is the size in kilobytes to use. Default is `-64000`.
|
||||
* `:cache_spill` - The cache_spill pragma enables or disables the ability of the
|
||||
pager to spill dirty cache pages to the database file in the middle of a
|
||||
transaction. By default it is `:on`, and for most applications, it should remain
|
||||
so.
|
||||
* `:case_sensitive_like` - whether LIKE is case-sensitive or not. Can be
|
||||
`:off` or `:on`. Defaults to `:off`.
|
||||
* `:auto_vacuum` - Defaults to `:none`. Can be `:none`, `:full` or `:incremental`.
|
||||
Depending on the database size, `:incremental` may be beneficial.
|
||||
* `:locking_mode` - Defaults to `:normal`. Allowed values are `:normal` or
|
||||
`:exclusive`. See [sqlite documentation][1] for more information.
|
||||
* `:secure_delete` - Defaults to `:off`. Can be `:off` or `:on`. If `:on`, it will
|
||||
cause SQLite3 to overwrite records that were deleted with zeros.
|
||||
* `:wal_auto_check_point` - Sets the write-ahead log auto-checkpoint interval.
|
||||
Default is `1000`. Setting the auto-checkpoint size to zero or a negative value
|
||||
turns auto-checkpointing off.
|
||||
* `:busy_timeout` - Sets the busy timeout in milliseconds for a connection.
|
||||
Default is `2000`.
|
||||
* `:pool_size` - the size of the connection pool. Defaults to `5`.
|
||||
* `:binary_id_type` - Defaults to `:string`. Determines how binary IDs are stored in
|
||||
the database and the type of `:binary_id` columns. See the
|
||||
[section on binary ID types](#module-binary-id-types) for more details.
|
||||
* `:uuid_type` - Defaults to `:string`. Determines the type of `:uuid` columns.
|
||||
Possible values and column types are the same as for
|
||||
[binary IDs](#module-binary-id-types).
|
||||
* `:map_type` - Defaults to `:string`. Determines the type of `:map` columns.
|
||||
Set to `:binary` to use the [JSONB](https://sqlite.org/jsonb.html)
|
||||
storage format.
|
||||
* `:array_type` - Defaults to `:string`. Determines the type of `:array` columns.
|
||||
Arrays are serialized using JSON. Set to `:binary` to use the
|
||||
[JSONB](https://sqlite.org/jsonb.html) storage format.
|
||||
* `:datetime_type` - Defaults to `:iso8601`. Determines how datetime fields are
|
||||
stored in the database. The allowed values are `:iso8601` and `:text_datetime`.
|
||||
`:iso8601` corresponds to a string of the form `YYYY-MM-DDThh:mm:ss` and
|
||||
`:text_datetime` corresponds to a string of the form `YYYY-MM-DD hh:mm:ss`
|
||||
* `:load_extensions` - list of paths identifying extensions to load. Defaults to `[]`.
|
||||
The provided list will be merged with the global extensions list, set on
|
||||
`:exqlite, :load_extensions`. Be aware that the path should handle pointing to a
|
||||
library compiled for the current architecture. See `Exqlite.Connection.connect/1`
|
||||
for more.
|
||||
|
||||
For more information about the options above, see [sqlite documentation][1]
|
||||
|
||||
### Differences between SQLite and Ecto SQLite defaults
|
||||
|
||||
For the most part, the defaults we provide above match the defaults that SQLite usually
|
||||
ships with. However, SQLite has conservative defaults due to its need to be strictly
|
||||
backwards compatible, so some of them do not necessarily match "best practices". Below
|
||||
are the defaults we provide above that differ from the normal SQLite defaults, along
|
||||
with rationale.
|
||||
|
||||
* `:journal_mode` - we use `:wal`, as it is vastly superior
|
||||
for concurrent access. SQLite usually defaults to `:delete`.
|
||||
See [SQLite documentation][2] for more info.
|
||||
* `:temp_store` - we use `:memory`, which increases performance a bit.
|
||||
SQLite usually defaults to `:file`.
|
||||
* `:foreign_keys` - we set it to `:on`, for better relational guarantees.
|
||||
This is also the default of the underlying `Exqlite` driver.
|
||||
SQLite usually defaults to `:off` for backwards compat.
|
||||
* `:busy_timeout` - we set it to `2000`, to better enable concurrent access.
|
||||
This is also the default of `Exqlite`. SQLite usually defaults to `0`.
|
||||
* `:cache_size` - we set it to `-64000`, to speed up access of data.
|
||||
SQLite usually defaults to `-2000`.
|
||||
|
||||
These defaults can of course be overridden, as noted above, to suit other needs.
|
||||
|
||||
[1]: https://www.sqlite.org/pragma.html
|
||||
[2]: https://sqlite.org/wal.html
|
||||
|
||||
### Binary ID types
|
||||
|
||||
The `:binary_id_type` configuration option allows configuring how `:binary_id` fields
|
||||
are stored in the database as well as the type of the column in which these IDs will
|
||||
be stored. The possible values are:
|
||||
|
||||
* `:string` - IDs are stored as strings, and the type of the column is `TEXT`. This is
|
||||
the default.
|
||||
* `:binary` - IDs are stored in their raw binary form, and the type of the column is `BLOB`.
|
||||
|
||||
The main differences between the two formats are as follows:
|
||||
* When stored as binary, UUIDs require much less space in the database. IDs stored as
|
||||
strings require 36 bytes each, while IDs stored as binary only require 16 bytes.
|
||||
* Because SQLite does not have a dedicated UUID type, most clients cannot represent
|
||||
UUIDs stored as binary in a human readable format. Therefore, IDs stored as strings
|
||||
may be easier to work with if manual manipulation is required.
|
||||
|
||||
## Limitations and caveats
|
||||
|
||||
There are some limitations when using Ecto with SQLite that one needs
|
||||
to be aware of. The ones listed below are specific to Ecto usage, but it
|
||||
is encouraged to also view the guidance on [when to use SQLite][4] provided
|
||||
by the SQLite documentation, as well.
|
||||
|
||||
### In memory robustness
|
||||
|
||||
When using the Ecto SQLite3 adapter with the database set to `:memory` it
|
||||
is possible that a crash in a process performing a query in the Repo will
|
||||
cause the database to be destroyed. This makes the `:memory` function
|
||||
unsuitable when it is expected to survive potential process crashes (for
|
||||
example a crash in a Phoenix request)
|
||||
|
||||
### Async Sandbox testing
|
||||
|
||||
The Ecto SQLite3 adapter does not support async tests when used with
|
||||
`Ecto.Adapters.SQL.Sandbox`. This is due to SQLite only allowing up one write
|
||||
transaction at a time, which often does not work with the Sandbox approach of wrapping
|
||||
each test in a transaction.
|
||||
|
||||
### LIKE match on BLOB columns
|
||||
|
||||
We have the `SQLITE_LIKE_DOESNT_MATCH_BLOBS` compile-time definition option set to true,
|
||||
as [recommended by SQLite][3]. This means you cannot do `LIKE` queries on `BLOB` columns.
|
||||
|
||||
### Case sensitivity
|
||||
|
||||
Case sensitivity for `LIKE` is off by default, and controlled by the `:case_sensitive_like`
|
||||
option outlined above.
|
||||
|
||||
However, for equality comparison, case sensitivity is always _on_.
|
||||
If you want to make a column not be case sensitive, for email storage for example, you
|
||||
can make it case insensitive by using the [`COLLATE NOCASE`][6] option in SQLite. This
|
||||
is configured via the `:collate` option.
|
||||
|
||||
So instead of:
|
||||
|
||||
add :email, :string
|
||||
|
||||
You would do:
|
||||
|
||||
add :email, :string, collate: :nocase
|
||||
|
||||
### Check constraints
|
||||
|
||||
SQLite3 supports specifying check constraints on the table or on the column definition.
|
||||
We currently only support adding a check constraint via a column definition, since the
|
||||
table definition approach only works at table-creation time and cannot be added at
|
||||
table-alter time. You can see more information in the SQLite3
|
||||
[CREATE TABLE documentation](https://sqlite.org/lang_createtable.html).
|
||||
|
||||
Because of this, you cannot add a constraint via the normal `Ecto.Migration.constraint/3`
|
||||
method, as that operates via `ALTER TABLE ADD CONSTRAINT`, and this type of `ALTER TABLE`
|
||||
operation SQLite3 does not support. You can however get the full functionality by
|
||||
adding a constraint at the column level, specifying the name and expression. Per the
|
||||
SQLite3 documentation, there is no _functional_ difference between a column or table
|
||||
constraint.
|
||||
|
||||
Thus, adding a check constraint for a new column is as simple as:
|
||||
|
||||
add :email, :string, check: %{name: "test_constraint", expr: "email != 'test@example.com'"}
|
||||
|
||||
### Handling foreign key constraints in changesets
|
||||
|
||||
Unfortunately, unlike other databases, SQLite3 does not provide the precise name of
|
||||
the constraint violated, but only the columns within that constraint (if it provides
|
||||
any information at all). Because of this, changeset functions like
|
||||
`Ecto.Changeset.foreign_key_constraint/3` may not work at all.
|
||||
|
||||
This is because the above functions depend on the Ecto Adapter returning the name of
|
||||
the violated constraint, which you annotate in your changeset so that Ecto can convert
|
||||
the constraint violation into the correct updated changeset when the constraint is hit
|
||||
during a `c:Ecto.Repo.update/2` or `c:Ecto.Repo.insert/2` operation. Since we cannot
|
||||
get the name of the violated constraint back from SQLite3 at `INSERT` or `UPDATE`
|
||||
time, there is no way to effectively use these changeset functions. This is a SQLite3
|
||||
limitation.
|
||||
|
||||
See [this GitHub issue](https://github.com/elixir-sqlite/ecto_sqlite3/issues/42) for
|
||||
more details.
|
||||
|
||||
### Schemaless queries
|
||||
|
||||
Using [schemaless Ecto queries][7] will not work well with SQLite. This is because
|
||||
the Ecto SQLite adapter relies heavily on the schema to support a rich array of Elixir
|
||||
types, despite the fact SQLite only has [five storage classes][5]. The query will still
|
||||
work and return data, but you will need to do this mapping on your own.
|
||||
|
||||
### Transaction mode
|
||||
|
||||
By default, [SQLite transactions][8] run in `DEFERRED` mode. However, in
|
||||
web applications with a balanced load of reads and writes, using `IMMEDIATE`
|
||||
mode may yield better performance.
|
||||
|
||||
Here are several ways to specify a different transaction mode:
|
||||
|
||||
**Pass `mode: :immediate` to `Repo.transaction/2`:** Use this approach to set
|
||||
the transaction mode for individual transactions.
|
||||
|
||||
Multi.new()
|
||||
|> Multi.run(:example, fn _repo, _changes_so_far ->
|
||||
# ... do some work ...
|
||||
end)
|
||||
|> Repo.transaction(mode: :immediate)
|
||||
|
||||
**Define custom transaction functions:** Create wrappers, such as
|
||||
`Repo.immediate_transaction/2` or `Repo.deferred_transaction/2`, to easily
|
||||
apply different modes where needed.
|
||||
|
||||
defmodule MyApp.Repo do
|
||||
def immediate_transaction(fun_or_multi) do
|
||||
transaction(fun_or_multi, mode: :immediate)
|
||||
end
|
||||
|
||||
def deferred_transaction(fun_or_multi) do
|
||||
transaction(fun_or_multi, mode: :deferred)
|
||||
end
|
||||
end
|
||||
|
||||
**Set a global default:** Configure `:default_transaction_mode` to apply a
|
||||
preferred mode for all transactions, unless explicitly passed a different
|
||||
`:mode` to `Repo.transaction/2`.
|
||||
|
||||
config :my_app, MyApp.Repo,
|
||||
database: "path/to/my/database.db",
|
||||
default_transaction_mode: :immediate
|
||||
|
||||
[3]: https://www.sqlite.org/compile.html
|
||||
[4]: https://www.sqlite.org/whentouse.html
|
||||
[5]: https://www.sqlite.org/datatype3.html
|
||||
[6]: https://www.sqlite.org/datatype3.html#collating_sequences
|
||||
[7]: https://hexdocs.pm/ecto/schemaless-queries.html
|
||||
[8]: https://www.sqlite.org/lang_transaction.html#deferred_immediate_and_exclusive_transactions
|
||||
"""
|
||||
|
||||
use Ecto.Adapters.SQL,
|
||||
driver: :exqlite
|
||||
|
||||
@behaviour Ecto.Adapter.Storage
|
||||
@behaviour Ecto.Adapter.Structure
|
||||
|
||||
alias Ecto.Adapters.SQLite3.Codec
|
||||
|
||||
@impl Ecto.Adapter.Storage
|
||||
def storage_down(options) do
|
||||
db_path = Keyword.fetch!(options, :database)
|
||||
|
||||
case File.rm(db_path) do
|
||||
:ok ->
|
||||
File.rm(db_path <> "-shm")
|
||||
File.rm(db_path <> "-wal")
|
||||
:ok
|
||||
|
||||
_otherwise ->
|
||||
{:error, :already_down}
|
||||
end
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter.Storage
|
||||
def storage_status(options) do
|
||||
db_path = Keyword.fetch!(options, :database)
|
||||
|
||||
if File.exists?(db_path) do
|
||||
:up
|
||||
else
|
||||
:down
|
||||
end
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter.Storage
|
||||
def storage_up(options) do
|
||||
database = Keyword.get(options, :database)
|
||||
pool_size = Keyword.get(options, :pool_size)
|
||||
|
||||
cond do
|
||||
is_nil(database) ->
|
||||
raise ArgumentError,
|
||||
"""
|
||||
No SQLite database path specified. Please check the configuration for your Repo.
|
||||
Your config/*.exs file should have something like this in it:
|
||||
|
||||
config :my_app, MyApp.Repo,
|
||||
adapter: Ecto.Adapters.SQLite3,
|
||||
database: "/path/to/sqlite/database"
|
||||
"""
|
||||
|
||||
File.exists?(database) ->
|
||||
{:error, :already_up}
|
||||
|
||||
database == ":memory:" && pool_size != 1 ->
|
||||
raise ArgumentError, """
|
||||
In memory databases must have a pool_size of 1
|
||||
"""
|
||||
|
||||
true ->
|
||||
{:ok, state} = Exqlite.Connection.connect(options)
|
||||
:ok = Exqlite.Connection.disconnect(:normal, state)
|
||||
end
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter.Migration
|
||||
def supports_ddl_transaction?, do: true
|
||||
|
||||
@impl Ecto.Adapter.Migration
|
||||
def lock_for_migrations(_meta, _options, fun) do
|
||||
fun.()
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter.Structure
|
||||
def structure_dump(default, config) do
|
||||
path = config[:dump_path] || Path.join(default, "structure.sql")
|
||||
|
||||
with {:ok, contents} <- dump_schema(config),
|
||||
{:ok, versions} <- dump_versions(config) do
|
||||
File.mkdir_p!(Path.dirname(path))
|
||||
File.write!(path, contents <> versions)
|
||||
{:ok, path}
|
||||
else
|
||||
err -> err
|
||||
end
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter.Structure
|
||||
def structure_load(default, config) do
|
||||
path = config[:dump_path] || Path.join(default, "structure.sql")
|
||||
|
||||
case run_with_cmd("sqlite3", [config[:database], ".read #{path}"]) do
|
||||
{_output, 0} -> {:ok, path}
|
||||
{output, _} -> {:error, output}
|
||||
end
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter.Structure
|
||||
def dump_cmd(args, opts \\ [], config) when is_list(config) and is_list(args) do
|
||||
run_with_cmd("sqlite3", ["-init", "/dev/null", config[:database] | args], opts)
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter.Schema
|
||||
def autogenerate(:id), do: nil
|
||||
def autogenerate(:embed_id), do: Ecto.UUID.generate()
|
||||
|
||||
def autogenerate(:binary_id) do
|
||||
case Application.get_env(:ecto_sqlite3, :binary_id_type, :string) do
|
||||
:string -> Ecto.UUID.generate()
|
||||
:binary -> Ecto.UUID.bingenerate()
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
## Loaders
|
||||
##
|
||||
|
||||
@default_datetime_type :iso8601
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def loaders(:boolean, type) do
|
||||
[&Codec.bool_decode/1, type]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def loaders(:naive_datetime_usec, type) do
|
||||
[&Codec.naive_datetime_decode/1, type]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def loaders(:time, type) do
|
||||
[&Codec.time_decode/1, type]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def loaders(:utc_datetime_usec, type) do
|
||||
[&Codec.utc_datetime_decode/1, type]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def loaders(:utc_datetime, type) do
|
||||
[&Codec.utc_datetime_decode/1, type]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def loaders(:naive_datetime, type) do
|
||||
[&Codec.naive_datetime_decode/1, type]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def loaders(:date, type) do
|
||||
[&Codec.date_decode/1, type]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def loaders({:map, _}, type) do
|
||||
[&Codec.json_decode/1, &Ecto.Type.embedded_load(type, &1, :json)]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def loaders({:array, _}, type) do
|
||||
[&Codec.json_decode/1, type]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def loaders(:map, type) do
|
||||
[&Codec.json_decode/1, type]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def loaders(:float, type) do
|
||||
[&Codec.float_decode/1, type]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def loaders(:decimal, type) do
|
||||
[&Codec.decimal_decode/1, type]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def loaders(:binary_id, type) do
|
||||
case Application.get_env(:ecto_sqlite3, :binary_id_type, :string) do
|
||||
:string -> [type]
|
||||
:binary -> [Ecto.UUID, type]
|
||||
end
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def loaders(:uuid, type) do
|
||||
case Application.get_env(:ecto_sqlite3, :uuid_type, :string) do
|
||||
:string -> []
|
||||
:binary -> [type]
|
||||
end
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def loaders(primitive_type, ecto_type) do
|
||||
loader_from_extension(primitive_type, ecto_type)
|
||||
end
|
||||
|
||||
##
|
||||
## Dumpers
|
||||
##
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def dumpers(:binary, type) do
|
||||
[type, &Codec.blob_encode/1]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def dumpers(:boolean, type) do
|
||||
[type, &Codec.bool_encode/1]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def dumpers(:decimal, type) do
|
||||
[type, &Codec.decimal_encode/1]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def dumpers(:binary_id, type) do
|
||||
case Application.get_env(:ecto_sqlite3, :binary_id_type, :string) do
|
||||
:string -> [type]
|
||||
:binary -> [type, Ecto.UUID]
|
||||
end
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def dumpers(:uuid, type) do
|
||||
case Application.get_env(:ecto_sqlite3, :uuid_type, :string) do
|
||||
:string -> []
|
||||
:binary -> [type]
|
||||
end
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def dumpers(:time, type) do
|
||||
[type, &Codec.time_encode/1]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def dumpers(:utc_datetime, type) do
|
||||
dt_type = Application.get_env(:ecto_sqlite3, :datetime_type, @default_datetime_type)
|
||||
[type, &Codec.utc_datetime_encode(&1, dt_type)]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def dumpers(:utc_datetime_usec, type) do
|
||||
dt_type = Application.get_env(:ecto_sqlite3, :datetime_type, @default_datetime_type)
|
||||
[type, &Codec.utc_datetime_encode(&1, dt_type)]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def dumpers(:naive_datetime, type) do
|
||||
dt_type = Application.get_env(:ecto_sqlite3, :datetime_type, @default_datetime_type)
|
||||
[type, &Codec.naive_datetime_encode(&1, dt_type)]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def dumpers(:naive_datetime_usec, type) do
|
||||
dt_type = Application.get_env(:ecto_sqlite3, :datetime_type, @default_datetime_type)
|
||||
[type, &Codec.naive_datetime_encode(&1, dt_type)]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def dumpers({:array, _}, type) do
|
||||
[type, &Codec.json_encode/1]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def dumpers({:map, _}, type) do
|
||||
[&Ecto.Type.embedded_dump(type, &1, :json), &Codec.json_encode/1]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def dumpers(:map, type) do
|
||||
[type, &Codec.json_encode/1]
|
||||
end
|
||||
|
||||
@impl Ecto.Adapter
|
||||
def dumpers(primitive_type, ecto_type) do
|
||||
dumper_from_extension(primitive_type, ecto_type)
|
||||
end
|
||||
|
||||
##
|
||||
## HELPERS
|
||||
##
|
||||
|
||||
defp dump_versions(config) do
|
||||
table = config[:migration_source] || "schema_migrations"
|
||||
|
||||
# `.dump` command also returns CREATE TABLE which will clash with CREATE we already run in dump_schema
|
||||
# So we set mode to insert which makes every SELECT statement to issue the result
|
||||
# as the INSERT statements instead of pure text data.
|
||||
case run_with_cmd("sqlite3", [
|
||||
config[:database],
|
||||
".mode insert #{table}",
|
||||
"SELECT * FROM #{table}"
|
||||
]) do
|
||||
{output, 0} -> {:ok, output}
|
||||
{output, _} -> {:error, output}
|
||||
end
|
||||
end
|
||||
|
||||
defp dump_schema(config) do
|
||||
case run_with_cmd("sqlite3", [config[:database], ".schema"]) do
|
||||
{output, 0} -> {:ok, output}
|
||||
{output, _} -> {:error, output}
|
||||
end
|
||||
end
|
||||
|
||||
defp run_with_cmd(cmd, args, cmd_opts \\ []) do
|
||||
unless System.find_executable(cmd) do
|
||||
raise "could not find executable `#{cmd}` in path, " <>
|
||||
"please guarantee it is available before running ecto commands"
|
||||
end
|
||||
|
||||
cmd_opts = Keyword.put_new(cmd_opts, :stderr_to_stdout, true)
|
||||
|
||||
System.cmd(cmd, args, cmd_opts)
|
||||
end
|
||||
|
||||
defp extensions do
|
||||
Application.get_env(:ecto_sqlite3, :type_extensions, [])
|
||||
end
|
||||
|
||||
defp loader_from_extension(primitive_type, ecto_type) do
|
||||
loader_from_extension(extensions(), primitive_type, ecto_type)
|
||||
end
|
||||
|
||||
defp loader_from_extension([], _primitive_type, ecto_type), do: [ecto_type]
|
||||
|
||||
defp loader_from_extension([extension | other_extensions], primitive_type, ecto_type) do
|
||||
case extension.loaders(primitive_type, ecto_type) do
|
||||
nil -> loader_from_extension(other_extensions, primitive_type, ecto_type)
|
||||
loader -> loader
|
||||
end
|
||||
end
|
||||
|
||||
defp dumper_from_extension(primitive_type, ecto_type) do
|
||||
dumper_from_extension(extensions(), primitive_type, ecto_type)
|
||||
end
|
||||
|
||||
defp dumper_from_extension([], _primitive_type, ecto_type), do: [ecto_type]
|
||||
|
||||
defp dumper_from_extension([extension | other_extensions], primitive_type, ecto_type) do
|
||||
case extension.dumpers(primitive_type, ecto_type) do
|
||||
nil -> dumper_from_extension(other_extensions, primitive_type, ecto_type)
|
||||
dumper -> dumper
|
||||
end
|
||||
end
|
||||
end
|
||||
150
phoenix/deps/ecto_sqlite3/lib/ecto/adapters/sqlite3/codec.ex
Normal file
150
phoenix/deps/ecto_sqlite3/lib/ecto/adapters/sqlite3/codec.ex
Normal file
@@ -0,0 +1,150 @@
|
||||
defmodule Ecto.Adapters.SQLite3.Codec do
|
||||
@moduledoc false
|
||||
|
||||
def bool_decode(0), do: {:ok, false}
|
||||
def bool_decode("0"), do: {:ok, false}
|
||||
def bool_decode("FALSE"), do: {:ok, false}
|
||||
def bool_decode(1), do: {:ok, true}
|
||||
def bool_decode("1"), do: {:ok, true}
|
||||
def bool_decode("TRUE"), do: {:ok, true}
|
||||
def bool_decode(v), do: {:ok, v}
|
||||
|
||||
def json_decode(v) when is_binary(v) do
|
||||
case Application.get_env(:ecto_sqlite3, :json_library, Jason).decode(v) do
|
||||
{:ok, decoded} -> {:ok, decoded}
|
||||
{:error, _reason} -> :error
|
||||
end
|
||||
end
|
||||
|
||||
def json_decode(v), do: {:ok, v}
|
||||
|
||||
def float_decode(%Decimal{} = decimal), do: {:ok, Decimal.to_float(decimal)}
|
||||
def float_decode(x) when is_integer(x), do: {:ok, x / 1}
|
||||
def float_decode(x), do: {:ok, x}
|
||||
|
||||
def decimal_decode(nil), do: {:ok, nil}
|
||||
|
||||
def decimal_decode(x) when is_float(x) do
|
||||
{:ok, Decimal.from_float(x)}
|
||||
catch
|
||||
Decimal.Error -> :error
|
||||
end
|
||||
|
||||
def decimal_decode(x) when is_binary(x) or is_integer(x) do
|
||||
{:ok, Decimal.new(x)}
|
||||
catch
|
||||
Decimal.Error -> :error
|
||||
end
|
||||
|
||||
def decimal_decode(_), do: :error
|
||||
|
||||
def utc_datetime_decode(nil), do: {:ok, nil}
|
||||
|
||||
def utc_datetime_decode(val) do
|
||||
with {:ok, naive} <- NaiveDateTime.from_iso8601(val),
|
||||
{:ok, dt} <- DateTime.from_naive(naive, "Etc/UTC") do
|
||||
{:ok, dt}
|
||||
else
|
||||
_ -> :error
|
||||
end
|
||||
end
|
||||
|
||||
def naive_datetime_decode(nil), do: {:ok, nil}
|
||||
|
||||
def naive_datetime_decode(val) do
|
||||
case NaiveDateTime.from_iso8601(val) do
|
||||
{:ok, dt} -> {:ok, dt}
|
||||
_ -> :error
|
||||
end
|
||||
end
|
||||
|
||||
def date_decode(nil), do: {:ok, nil}
|
||||
|
||||
def date_decode(val) do
|
||||
case Date.from_iso8601(val) do
|
||||
{:ok, d} -> {:ok, d}
|
||||
_ -> :error
|
||||
end
|
||||
end
|
||||
|
||||
def date_encode(val), do: date_encode(val, :iso8601)
|
||||
|
||||
def date_encode(%Date{} = val, :iso8601) do
|
||||
case Date.to_iso8601(val) do
|
||||
date when is_bitstring(date) -> {:ok, date}
|
||||
_ -> :error
|
||||
end
|
||||
end
|
||||
|
||||
def time_decode(nil), do: {:ok, nil}
|
||||
|
||||
def time_decode(%Time{} = value) do
|
||||
{:ok, value}
|
||||
end
|
||||
|
||||
def time_decode(value) do
|
||||
case Time.from_iso8601(value) do
|
||||
{:ok, _time} = result -> result
|
||||
{:error, _} -> :error
|
||||
end
|
||||
end
|
||||
|
||||
def json_encode(value) when is_bitstring(value), do: {:ok, value}
|
||||
|
||||
def json_encode(value) do
|
||||
{:ok, Application.get_env(:ecto_sqlite3, :json_library, Jason).encode!(value)}
|
||||
rescue
|
||||
_err -> :error
|
||||
end
|
||||
|
||||
def blob_encode(nil), do: {:ok, nil}
|
||||
def blob_encode(value), do: {:ok, {:blob, value}}
|
||||
|
||||
def bool_encode(nil), do: {:ok, nil}
|
||||
def bool_encode(false), do: {:ok, 0}
|
||||
def bool_encode(true), do: {:ok, 1}
|
||||
|
||||
def decimal_encode(nil), do: {:ok, nil}
|
||||
|
||||
def decimal_encode(%Decimal{} = x) do
|
||||
{:ok, Decimal.to_string(x, :normal)}
|
||||
end
|
||||
|
||||
def time_encode(value) do
|
||||
{:ok, value}
|
||||
end
|
||||
|
||||
@text_datetime_format "%Y-%m-%d %H:%M:%S"
|
||||
|
||||
def utc_datetime_encode(nil, :iso8601), do: {:ok, nil}
|
||||
def utc_datetime_encode(nil, :text_datetime), do: {:ok, nil}
|
||||
|
||||
def utc_datetime_encode(%DateTime{time_zone: "Etc/UTC"} = value, :iso8601) do
|
||||
{:ok, DateTime.to_iso8601(value)}
|
||||
end
|
||||
|
||||
def utc_datetime_encode(%{time_zone: "Etc/UTC"} = value, :text_datetime) do
|
||||
{:ok, Calendar.strftime(value, @text_datetime_format)}
|
||||
end
|
||||
|
||||
def utc_datetime_encode(%{time_zone: "Etc/UTC"}, type) do
|
||||
raise ArgumentError,
|
||||
"expected datetime type to be either `:iso8601` or `:text_datetime`, but received #{inspect(type)}"
|
||||
end
|
||||
|
||||
def naive_datetime_encode(nil, :iso8601), do: {:ok, nil}
|
||||
def naive_datetime_encode(nil, :text_datetime), do: {:ok, nil}
|
||||
|
||||
def naive_datetime_encode(value, :iso8601) do
|
||||
{:ok, NaiveDateTime.to_iso8601(value)}
|
||||
end
|
||||
|
||||
def naive_datetime_encode(value, :text_datetime) do
|
||||
{:ok, Calendar.strftime(value, @text_datetime_format)}
|
||||
end
|
||||
|
||||
def naive_datetime_encode(_value, type) do
|
||||
raise ArgumentError,
|
||||
"expected datetime type to be either `:iso8601` or `:text_datetime`, but received `#{inspect(type)}`"
|
||||
end
|
||||
end
|
||||
1990
phoenix/deps/ecto_sqlite3/lib/ecto/adapters/sqlite3/connection.ex
Normal file
1990
phoenix/deps/ecto_sqlite3/lib/ecto/adapters/sqlite3/connection.ex
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,95 @@
|
||||
defmodule Ecto.Adapters.SQLite3.DataType do
|
||||
@moduledoc false
|
||||
|
||||
# Simple column types. Note that we ignore options like :size, :precision,
|
||||
# etc. because columns do not have types, and SQLite will not coerce any
|
||||
# stored value. Thus, "strings" are all text and "numerics" have arbitrary
|
||||
# precision regardless of the declared column type. Decimals are the
|
||||
# only exception.
|
||||
|
||||
@spec column_type(atom(), Keyword.t()) :: String.t()
|
||||
def column_type(:id, _opts), do: "INTEGER"
|
||||
def column_type(:serial, _opts), do: "INTEGER"
|
||||
def column_type(:bigserial, _opts), do: "INTEGER"
|
||||
def column_type(:boolean, _opts), do: "INTEGER"
|
||||
def column_type(:integer, _opts), do: "INTEGER"
|
||||
def column_type(:bigint, _opts), do: "INTEGER"
|
||||
def column_type(:string, _opts), do: "TEXT"
|
||||
def column_type(:float, _opts), do: "NUMERIC"
|
||||
def column_type(:binary, _opts), do: "BLOB"
|
||||
def column_type(:date, _opts), do: "TEXT"
|
||||
def column_type(:utc_datetime, _opts), do: "TEXT"
|
||||
def column_type(:utc_datetime_usec, _opts), do: "TEXT"
|
||||
def column_type(:naive_datetime, _opts), do: "TEXT"
|
||||
def column_type(:naive_datetime_usec, _opts), do: "TEXT"
|
||||
def column_type(:time, _opts), do: "TEXT"
|
||||
def column_type(:time_usec, _opts), do: "TEXT"
|
||||
def column_type(:timestamp, _opts), do: "TEXT"
|
||||
def column_type(:decimal, nil), do: "DECIMAL"
|
||||
|
||||
def column_type(:decimal, opts) do
|
||||
# We only store precision and scale for DECIMAL.
|
||||
precision = Keyword.get(opts, :precision)
|
||||
scale = Keyword.get(opts, :scale, 0)
|
||||
|
||||
if precision do
|
||||
"DECIMAL(#{precision},#{scale})"
|
||||
else
|
||||
"DECIMAL"
|
||||
end
|
||||
end
|
||||
|
||||
def column_type(:array, _opts) do
|
||||
case Application.get_env(:ecto_sqlite3, :array_type, :string) do
|
||||
:string -> "TEXT"
|
||||
:binary -> "BLOB"
|
||||
end
|
||||
end
|
||||
|
||||
def column_type({:array, _}, _opts) do
|
||||
case Application.get_env(:ecto_sqlite3, :array_type, :string) do
|
||||
:string -> "TEXT"
|
||||
:binary -> "BLOB"
|
||||
end
|
||||
end
|
||||
|
||||
def column_type(:binary_id, _opts) do
|
||||
case Application.get_env(:ecto_sqlite3, :binary_id_type, :string) do
|
||||
:string -> "TEXT"
|
||||
:binary -> "BLOB"
|
||||
end
|
||||
end
|
||||
|
||||
def column_type(:map, _opts) do
|
||||
case Application.get_env(:ecto_sqlite3, :map_type, :string) do
|
||||
:string -> "TEXT"
|
||||
:binary -> "BLOB"
|
||||
end
|
||||
end
|
||||
|
||||
def column_type({:map, _}, _opts) do
|
||||
case Application.get_env(:ecto_sqlite3, :map_type, :string) do
|
||||
:string -> "TEXT"
|
||||
:binary -> "BLOB"
|
||||
end
|
||||
end
|
||||
|
||||
def column_type(:uuid, _opts) do
|
||||
case Application.get_env(:ecto_sqlite3, :uuid_type, :string) do
|
||||
:string -> "TEXT"
|
||||
:binary -> "BLOB"
|
||||
end
|
||||
end
|
||||
|
||||
def column_type(type, _) when is_atom(type) do
|
||||
type
|
||||
|> Atom.to_string()
|
||||
|> String.upcase()
|
||||
end
|
||||
|
||||
def column_type(type, _) do
|
||||
raise ArgumentError,
|
||||
"unsupported type `#{inspect(type)}`. The type can either be an atom, a string " <>
|
||||
"or a tuple of the form `{:map, t}` or `{:array, t}` where `t` itself follows the same conditions."
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,31 @@
|
||||
defmodule Ecto.Adapters.SQLite3.TypeExtension do
|
||||
@moduledoc """
|
||||
A behaviour that defines the API for extensions providing custom data loaders and dumpers
|
||||
for Ecto schemas.
|
||||
"""
|
||||
|
||||
@type primitive_type :: atom | {:map, type :: atom}
|
||||
@type ecto_type :: atom
|
||||
|
||||
@doc """
|
||||
Takes a primitive type and, if it knows how to decode it into an
|
||||
appropriate Elixir data structure, returns a two-element list in
|
||||
the form `[(db_data :: any -> term), elixir_type :: atom]`.
|
||||
|
||||
The function that is the first element will be called whenever
|
||||
the `primitive_type` appears in a schema and data is fetched from
|
||||
the database for it.
|
||||
"""
|
||||
@callback loaders(primitive_type, ecto_type) :: list | nil
|
||||
|
||||
@doc """
|
||||
Takes a primitive type and, if it knows how to encode it for storage
|
||||
in the database, returns a two-element list in
|
||||
the form `[elixir_type :: atom, (term -> db_data :: any)]`.
|
||||
|
||||
The function that is the second element will be called whenever
|
||||
the `primitive_type` appears in a schema and data is about to be
|
||||
sent to the database for storage.
|
||||
"""
|
||||
@callback dumpers(ecto_type, primitive_type) :: list | nil
|
||||
end
|
||||
99
phoenix/deps/ecto_sqlite3/mix.exs
Normal file
99
phoenix/deps/ecto_sqlite3/mix.exs
Normal file
@@ -0,0 +1,99 @@
|
||||
defmodule EctoSQLite3.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
@version "0.22.0"
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :ecto_sqlite3,
|
||||
version: @version,
|
||||
elixir: "~> 1.15",
|
||||
start_permanent: Mix.env() == :prod,
|
||||
source_url: "https://github.com/elixir-sqlite/ecto_sqlite3",
|
||||
homepage_url: "https://github.com/elixir-sqlite/ecto_sqlite3",
|
||||
deps: deps(),
|
||||
package: package(),
|
||||
description: description(),
|
||||
test_paths: test_paths(System.get_env("EXQLITE_INTEGRATION")),
|
||||
elixirc_paths: elixirc_paths(Mix.env()),
|
||||
aliases: aliases(),
|
||||
|
||||
# Docs
|
||||
name: "Ecto SQLite3",
|
||||
docs: docs()
|
||||
]
|
||||
end
|
||||
|
||||
# Run "mix help compile.app" to learn about applications.
|
||||
def application do
|
||||
[
|
||||
extra_applications: [:logger]
|
||||
]
|
||||
end
|
||||
|
||||
# Run "mix help deps" to learn about dependencies.
|
||||
defp deps do
|
||||
[
|
||||
{:decimal, "~> 1.6 or ~> 2.0"},
|
||||
{:ecto_sql, "~> 3.13.0"},
|
||||
{:ecto, "~> 3.13.0"},
|
||||
{:exqlite, "~> 0.22"},
|
||||
{:ex_doc, "~> 0.27", only: [:dev], runtime: false},
|
||||
{:jason, ">= 0.0.0", only: [:dev, :test, :docs]},
|
||||
{:temp, "~> 0.4", only: [:test]},
|
||||
{:credo, "~> 1.6", only: [:dev, :test, :docs]},
|
||||
|
||||
# Benchmarks
|
||||
{:benchee, "~> 1.0", only: :dev},
|
||||
{:benchee_markdown, "~> 0.2", only: :dev},
|
||||
{:postgrex, "~> 0.15", only: :dev},
|
||||
{:myxql, "~> 0.6", only: :dev}
|
||||
]
|
||||
end
|
||||
|
||||
defp description do
|
||||
"An SQLite3 Ecto3 adapter."
|
||||
end
|
||||
|
||||
defp package do
|
||||
[
|
||||
files: ~w(
|
||||
lib
|
||||
.formatter.exs
|
||||
mix.exs
|
||||
README.md
|
||||
LICENSE
|
||||
),
|
||||
name: "ecto_sqlite3",
|
||||
licenses: ["MIT"],
|
||||
links: %{
|
||||
"GitHub" => "https://github.com/elixir-sqlite/ecto_sqlite3",
|
||||
"docs" => "https://hexdocs.pm/ecto_sqlite3"
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
defp docs do
|
||||
[
|
||||
main: "Ecto.Adapters.SQLite3",
|
||||
source_ref: "v#{@version}",
|
||||
source_url: "https://github.com/elixir-sqlite/ecto_sqlite3"
|
||||
]
|
||||
end
|
||||
|
||||
defp elixirc_paths(:test), do: ["lib", "test/support"]
|
||||
defp elixirc_paths(_), do: ["lib"]
|
||||
|
||||
defp test_paths(nil), do: ["test"]
|
||||
defp test_paths(_any), do: ["integration_test"]
|
||||
|
||||
defp aliases do
|
||||
[
|
||||
lint: [
|
||||
"format --check-formatted",
|
||||
"deps.unlock --check-unused",
|
||||
"credo --all --strict"
|
||||
]
|
||||
]
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user