Initial commit
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
require_dependency 'carto/db/view'
|
||||
require_dependency 'carto/db/function'
|
||||
require_dependency 'carto/db/trigger'
|
||||
require_dependency 'carto/db/role'
|
||||
|
||||
module Carto
|
||||
module Db
|
||||
class Database
|
||||
|
||||
def self.build_with_user(user)
|
||||
Database.new(user.database_name, user.in_database)
|
||||
end
|
||||
|
||||
def initialize(database_name, conn)
|
||||
@database_name = database_name
|
||||
@conn = conn
|
||||
end
|
||||
|
||||
# Attempts to create a new database schema
|
||||
# Does not raise exception if the schema already exists
|
||||
def create_schema(schema, role = nil)
|
||||
if role
|
||||
@conn.run(%{CREATE SCHEMA "#{schema}" AUTHORIZATION "#{role}"})
|
||||
else
|
||||
@conn.run(%{CREATE SCHEMA "#{schema}"})
|
||||
end
|
||||
rescue Sequel::DatabaseError => e
|
||||
raise unless e.message =~ /schema .* already exists/
|
||||
end
|
||||
|
||||
def triggers(schema)
|
||||
query = %{
|
||||
select table_catalog, table_schema, relname, tgname, tgtype, proname, tgdeferrable, tginitdeferred, tgnargs,
|
||||
tgattr, tgargs from (pg_trigger join pg_class on tgrelid=pg_class.oid)
|
||||
join pg_proc on (tgfoid=pg_proc.oid) join information_schema.tables ist on relname = table_name
|
||||
where table_schema = '#{schema}'
|
||||
and table_catalog = '#{@database_name}'
|
||||
}
|
||||
|
||||
execute_query(@conn, query).map do |t|
|
||||
t = t.deep_symbolize_keys
|
||||
Trigger.new(
|
||||
database_name: t[:table_catalog],
|
||||
database_schema: t[:table_schema],
|
||||
table_name: t[:table_name],
|
||||
trigger_name: t[:tgname]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def materialized_views(schema, owner_role)
|
||||
views(schema, owner_role, 'm')
|
||||
end
|
||||
|
||||
# relkind: 'm' (materialized view) or 'v' (view). Default: 'v'.
|
||||
def views(schema, owner_role, relkind = 'v')
|
||||
query = %{
|
||||
select ns.nspname as schemaname,
|
||||
pc.relname as matviewname,
|
||||
string_agg(atr.attname ||' '||pg_catalog.format_type(atr.atttypid, NULL), ', ') as columns
|
||||
from pg_class pc
|
||||
join pg_namespace ns on pc.relnamespace = ns.oid
|
||||
join pg_attribute atr
|
||||
on atr.attrelid = pc.oid
|
||||
and atr.attnum > 0
|
||||
and not atr.attisdropped
|
||||
join pg_roles
|
||||
on pc.relowner = pg_roles.oid
|
||||
where pc.relkind = '#{relkind}'
|
||||
and ns.nspname = '#{schema}'
|
||||
and rolname = '#{owner_role}'
|
||||
group by ns.nspname, pc.relname;
|
||||
}
|
||||
execute_query(@conn, query).map do |v|
|
||||
v = v.deep_symbolize_keys
|
||||
View.new(
|
||||
database_name: @database_name,
|
||||
database_schema: v[:schemaname],
|
||||
name: v[:matviewname],
|
||||
relkind: relkind
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def functions(schema, owner_role)
|
||||
query = %{
|
||||
SELECT n.nspname,
|
||||
p.proname,
|
||||
pg_catalog.pg_get_function_identity_arguments(p.oid) as argument_data_types
|
||||
FROM pg_catalog.pg_proc p
|
||||
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
|
||||
JOIN pg_roles
|
||||
on p.proowner = pg_roles.oid
|
||||
WHERE pg_catalog.pg_function_is_visible(p.oid)
|
||||
AND n.nspname = '#{schema}'
|
||||
AND rolname = '#{owner_role}'
|
||||
}
|
||||
execute_query(@conn, query).map do |f|
|
||||
f = f.deep_symbolize_keys
|
||||
Function.new(
|
||||
database_name: @database_name,
|
||||
database_schema: f[:nspname],
|
||||
name: f[:proname],
|
||||
argument_data_types: f[:argument_data_types]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def roles
|
||||
execute_query(@conn, "SELECT usename from pg_user").map do |r|
|
||||
r = r.deep_symbolize_keys
|
||||
Role.new(database_name: @database_name, name: r[:usename])
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def execute_query(conn, query)
|
||||
activerecord_connection?(conn) ? conn.select_all(query) : conn[query].all
|
||||
end
|
||||
|
||||
def activerecord_connection?(conn)
|
||||
## Right now we have two kind of connections from Sequel and from AR
|
||||
conn.is_a? ActiveRecord::ConnectionAdapters::AbstractAdapter
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user