Packages
SQL provides state-of-the-art, high-performance SQL integration for Elixir, built to handle extreme concurrency with unmatched expressiveness and ergonomic query composition. Write safe, composable, parameterized queries directly, without translating to Ecto or any ORM.
Current section
Files
Jump to
Current section
Files
lib/mix/tasks/sql.get.ex
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: 2025 DBVisor
defmodule Mix.Tasks.Sql.Get do
use Mix.Task
import SQL
import Mix.Generator
@moduledoc since: "0.3.0"
@shortdoc "Generates a sql.lock"
def run(args) do
app = Mix.Project.config()[:app]
Application.load(app)
Mix.Task.run("app.config", args)
Application.ensure_all_started(:sql, :permanent)
create_file("sql.lock", gen_template(), force: true)
end
def gen_template() do
Application.ensure_all_started(:sql, :permanent)
lock_template(lock: Enum.reduce(Application.get_env(:sql, :pools), [], &(get(&1)++&2)))
end
def get({name, %{adapter: SQL.Adapters.Postgres}}) do
SQL.transaction do
~SQL"""
select
table_schema::text,
table_name::text,
column_name::text,
data_type::text,
is_nullable = 'YES',
COALESCE(character_maximum_length, 0)::int4,
COALESCE(numeric_precision, 0)::int4,
COALESCE(numeric_scale, 0)::int4,
COALESCE(datetime_precision, 0)::int4,
udt_name::text,
is_identity = 'YES',
ordinal_position::int4
from information_schema.columns
order by table_schema, table_name, ordinal_position
"""
|> SQL.map(fn row -> Map.new(row) end)
|> Map.put(:pool, name)
|> Enum.to_list()
end
end
def get({name, opts}), do: get({name, Map.new(opts)})
def columns({name, %{adapter: SQL.Adapters.Postgres}}) do
SQL.transaction do
~SQL"""
SELECT
table_catalog::text,
table_schema::text,
table_name::text,
ARRAY_AGG(column_name::text ORDER BY ordinal_position) AS columns,
HSTORE(ARRAY_AGG(column_name::text ORDER BY ordinal_position), ARRAY_AGG(data_type::text ORDER BY ordinal_position)) AS table_info
FROM
information_schema.columns
GROUP BY
table_catalog,
table_schema,
table_name
"""
|> SQL.map(fn row -> Map.new(row) end)
|> Map.put(:pool, name)
|> Enum.to_list()
end
end
def enums({name, %{adapter: SQL.Adapters.Postgres}}) do
SQL.transaction do
~SQL"""
SELECT
n.nspname::text,
t.typname::text,
ARRAY_AGG(e.enumlabel::text ORDER BY e.enumsortorder) AS values
FROM
pg_type t
JOIN
pg_enum e ON t.oid = e.enumtypid
JOIN
pg_namespace n ON n.oid = t.typnamespace
WHERE
t.typtype = 'e'
GROUP BY
n.nspname,
t.typname
ORDER BY
n.nspname,
t.typname
"""
|> SQL.map(fn row -> Map.new(row) end)
|> Map.put(:pool, name)
|> Enum.to_list()
end
end
def oids({name, %{adapter: SQL.Adapters.Postgres}}) do
SQL.transaction do
~SQL"""
SELECT
base_type.typname::text AS type,
ARRAY_AGG(derived.oid::int4) AS oids
FROM
pg_type base_type
JOIN
pg_type derived ON derived.typname = base_type.typname and base_type.typtype != 'e'
WHERE
base_type.typtype = 'b'
GROUP BY
base_type.typname
ORDER BY
base_type.typname
"""
|> SQL.map(fn
[{:type, "_" <> type}, {:oids, oids}] -> {{:array, :"#{type}"}, oids}
[{:type, type}, {:oids, oids}] -> {:"#{type}", oids}
end)
|> Map.put(:pool, name)
|> Enum.to_list()
|> Map.new()
end
end
def functions({name, %{adapter: SQL.Adapters.Postgres}}) do
SQL.transaction do
~SQL"""
SELECT
n.nspname::text AS schema,
p.proname::text AS name,
pg_get_function_arguments(p.oid)::text AS arguments,
pg_get_function_result(p.oid)::text AS return_type,
l.lanname::text AS language
FROM pg_proc p
JOIN pg_namespace n ON n.oid = p.pronamespace
JOIN pg_language l ON l.oid = p.prolang
ORDER BY schema, name
"""
|> Map.put(:pool, name)
|> Enum.to_list()
end
end
# ~SQL"select * from information_schema.columns where table_schema not in ('information_schema', 'pg_catalog')"
# ~SQL"select * from information_schema.columns where table_schema not in ('mysql', 'performance_schema', 'sys')"
# ~SQL"select * from sqlite_master join pragma_table_info (sqlite_master.name)"
embed_template(:lock, """
%{
columns: <%= inspect @lock, pretty: true, limit: :infinity %>,
validate: fn
<%= for %{table_name: table, column_name: column} <- @lock do %>
<%= inspect String.to_charlist(table) %>, nil -> true
<%= inspect String.to_charlist(table) %>, <%= inspect String.to_charlist(column) %> -> true
<% end %>
_, _ -> false
end
}
""")
end