Few little things to work directly with Postgrex
.
res = Postgrex.query!(conn, "select x, y from table", [])
[%{"x" => x, "y" => y}, ...] = Exql.Query.result_to_map(res)
This function can be used to get rid of the query positional parameters and use named ones.
# positional parameters:
Postgrex.query!(conn, "insert into a_table (x, y1, y2) values ($1, $2, $2)", ["X", "Y"])
# named parameters:
{:ok, q, p} = Exql.Query.named_params("insert into a_table (x, y1, y2) values (:x, :y, :y)", %{x: "X", y: "Y"})
Postgrex.query!(conn, q, p)
You may define a convenient wrapper around the two functions above:
def query!(conn, stmt, args \\ %{}, opts \\ []) do
{:ok, q, p} = Exql.Query.named_params(stmt, args)
res = Postgrex.query!(conn, q, p, opts)
Query.result_to_map(res)
end
And just write:
query!("insert into a_table (x, y1, y2) values (:x, :y, :y)", %{x: "X", y: "Y"})
A minimalist executor for Postgres schema migration scripts.
Define your ordered list of SQL migrations under priv/migrations/*.sql
and add Exql.Migration
to you app supervisor.
The migration task will execute the *.sql
scripts not already applied to the target DB.
The execution order follows the scripts filename alphabetic order.
If a migration script fails, the Exql.Migration
executor stops the application.
If you have n instances of your app deployed, each of them can safely run the migration task since every migration runs
in a transaction and acquire a 'LOCK ... SHARE MODE'
ensuring that one and only migration execution can run at a time.
In your application you can call the Exql.Migration.create_db
and Exql.Migration.migrate
functions:
Exql.Migration.create_db(postgres_credentials, "db_name")
Exql.Migration.migrate(mydb_credentials, "priv/migrations/db_name")
Check the sample app under ./sample_app
for more details.
docker run -d --rm -e POSTGRES_PASSWORD=postgres -p 5432:5432 postgres:alpine
mix deps.get
mix format
mix credo --strict --all
mix dialyzer
mix coveralls