WIP: converting DbStructure
This commit is contained in:
+298
-258
@@ -27,9 +27,10 @@ import qualified Hasql.Session as H
|
|||||||
import PostgREST.Types
|
import PostgREST.Types
|
||||||
|
|
||||||
import GHC.Exts (groupWith)
|
import GHC.Exts (groupWith)
|
||||||
|
import GHC.Int (Int32)
|
||||||
import Prelude
|
import Prelude
|
||||||
|
|
||||||
getDbStructure :: Schema -> H.Session DbStructure
|
getDbStructure :: Schema -> H.Query () DbStructure
|
||||||
getDbStructure schema = do
|
getDbStructure schema = do
|
||||||
tabs <- allTables
|
tabs <- allTables
|
||||||
cols <- allColumns tabs
|
cols <- allColumns tabs
|
||||||
@@ -60,6 +61,48 @@ decodeTables =
|
|||||||
tblRow = Table <$> HD.value HD.text <*> HD.value HD.text
|
tblRow = Table <$> HD.value HD.text <*> HD.value HD.text
|
||||||
<*> HD.value HD.bool
|
<*> HD.value HD.bool
|
||||||
|
|
||||||
|
decodeColumns :: [Table] -> HD.Result [Column]
|
||||||
|
decodeColumns tables =
|
||||||
|
mapMaybe (columnFromRow tables) <$> HD.rowsList colRow
|
||||||
|
where
|
||||||
|
colRow =
|
||||||
|
(,,,,,,,,,,)
|
||||||
|
<$> HD.value HD.text <*> HD.value HD.text
|
||||||
|
<*> HD.value HD.text <*> HD.value HD.int4
|
||||||
|
<*> HD.value HD.bool <*> HD.value HD.text
|
||||||
|
<*> HD.value HD.bool
|
||||||
|
<*> HD.nullableValue HD.int4
|
||||||
|
<*> HD.nullableValue HD.int4
|
||||||
|
<*> HD.nullableValue HD.text
|
||||||
|
<*> HD.nullableValue HD.text
|
||||||
|
|
||||||
|
decodeRelations :: [Table] -> [Column] -> HD.Result [Relation]
|
||||||
|
decodeRelations tables cols =
|
||||||
|
mapMaybe (relationFromRow tables cols) <$> HD.rowsList relRow
|
||||||
|
where
|
||||||
|
relRow = (,,,,,)
|
||||||
|
<$> HD.value HD.text
|
||||||
|
<*> HD.value HD.text
|
||||||
|
<*> HD.value (HD.array $ HD.arrayValue HD.text)
|
||||||
|
<*> HD.value HD.text
|
||||||
|
<*> HD.value HD.text
|
||||||
|
<*> HD.value (HD.array $ HD.arrayValue HD.text)
|
||||||
|
|
||||||
|
decodePks :: [Table] -> HD.Result [PrimaryKey]
|
||||||
|
decodePks tables =
|
||||||
|
mapMaybe (pkFromRow tables) <$> HD.rowsList pkRow
|
||||||
|
where
|
||||||
|
pkRow = (,,) <$> HD.value HD.text <*> HD.value HD.text <*> HD.value HD.text
|
||||||
|
|
||||||
|
decodeSynonyms :: [Column] -> HD.Result [(Column,Column)]
|
||||||
|
decodeSynonyms cols =
|
||||||
|
mapMaybe (synonymFromRow cols) <$> HD.rowsList synRow
|
||||||
|
where
|
||||||
|
synRow = (,,,,,)
|
||||||
|
<$> HD.value HD.text <*> HD.value HD.text
|
||||||
|
<*> HD.value HD.text <*> HD.value HD.text
|
||||||
|
<*> HD.value HD.text <*> HD.value HD.text
|
||||||
|
|
||||||
doesProcExist :: H.Query QualifiedIdentifier Bool
|
doesProcExist :: H.Query QualifiedIdentifier Bool
|
||||||
doesProcExist =
|
doesProcExist =
|
||||||
H.statement sql encodeQi (HD.singleRow (HD.value HD.bool)) True
|
H.statement sql encodeQi (HD.singleRow (HD.value HD.bool)) True
|
||||||
@@ -209,151 +252,148 @@ allTables =
|
|||||||
GROUP BY table_schema, table_name, insertable
|
GROUP BY table_schema, table_name, insertable
|
||||||
ORDER BY table_schema, table_name |]
|
ORDER BY table_schema, table_name |]
|
||||||
|
|
||||||
tableFromRow :: (Text, Text, Bool) -> Table
|
allColumns :: [Table] -> H.Query () [Column]
|
||||||
tableFromRow (s, n, i) = Table s n i
|
|
||||||
|
|
||||||
allColumns :: [Table] -> H.Session [Column]
|
|
||||||
allColumns tabs = do
|
allColumns tabs = do
|
||||||
cols <- H.listEx $ [H.stmt|
|
H.statement sql HE.unit (decodeColumns tabs) True
|
||||||
SELECT DISTINCT
|
where
|
||||||
info.table_schema AS schema,
|
sql = [q|
|
||||||
info.table_name AS table_name,
|
SELECT DISTINCT
|
||||||
info.column_name AS name,
|
info.table_schema AS schema,
|
||||||
info.ordinal_position AS position,
|
info.table_name AS table_name,
|
||||||
info.is_nullable::boolean AS nullable,
|
info.column_name AS name,
|
||||||
info.data_type AS col_type,
|
info.ordinal_position AS position,
|
||||||
info.is_updatable::boolean AS updatable,
|
info.is_nullable::boolean AS nullable,
|
||||||
info.character_maximum_length AS max_len,
|
info.data_type AS col_type,
|
||||||
info.numeric_precision AS precision,
|
info.is_updatable::boolean AS updatable,
|
||||||
info.column_default AS default_value,
|
info.character_maximum_length AS max_len,
|
||||||
array_to_string(enum_info.vals, ',') AS enum
|
info.numeric_precision AS precision,
|
||||||
FROM (
|
info.column_default AS default_value,
|
||||||
/*
|
array_to_string(enum_info.vals, ',') AS enum
|
||||||
-- CTE based on information_schema.columns to remove the owner filter
|
FROM (
|
||||||
*/
|
/*
|
||||||
WITH columns AS (
|
-- CTE based on information_schema.columns to remove the owner filter
|
||||||
SELECT current_database()::information_schema.sql_identifier AS table_catalog,
|
*/
|
||||||
nc.nspname::information_schema.sql_identifier AS table_schema,
|
WITH columns AS (
|
||||||
c.relname::information_schema.sql_identifier AS table_name,
|
SELECT current_database()::information_schema.sql_identifier AS table_catalog,
|
||||||
a.attname::information_schema.sql_identifier AS column_name,
|
nc.nspname::information_schema.sql_identifier AS table_schema,
|
||||||
a.attnum::information_schema.cardinal_number AS ordinal_position,
|
c.relname::information_schema.sql_identifier AS table_name,
|
||||||
pg_get_expr(ad.adbin, ad.adrelid)::information_schema.character_data AS column_default,
|
a.attname::information_schema.sql_identifier AS column_name,
|
||||||
CASE
|
a.attnum::information_schema.cardinal_number AS ordinal_position,
|
||||||
WHEN a.attnotnull OR t.typtype = 'd'::"char" AND t.typnotnull THEN 'NO'::text
|
pg_get_expr(ad.adbin, ad.adrelid)::information_schema.character_data AS column_default,
|
||||||
ELSE 'YES'::text
|
CASE
|
||||||
END::information_schema.yes_or_no AS is_nullable,
|
WHEN a.attnotnull OR t.typtype = 'd'::"char" AND t.typnotnull THEN 'NO'::text
|
||||||
CASE
|
ELSE 'YES'::text
|
||||||
WHEN t.typtype = 'd'::"char" THEN
|
END::information_schema.yes_or_no AS is_nullable,
|
||||||
CASE
|
CASE
|
||||||
WHEN bt.typelem <> 0::oid AND bt.typlen = (-1) THEN 'ARRAY'::text
|
WHEN t.typtype = 'd'::"char" THEN
|
||||||
WHEN nbt.nspname = 'pg_catalog'::name THEN format_type(t.typbasetype, NULL::integer)
|
CASE
|
||||||
ELSE 'USER-DEFINED'::text
|
WHEN bt.typelem <> 0::oid AND bt.typlen = (-1) THEN 'ARRAY'::text
|
||||||
END
|
WHEN nbt.nspname = 'pg_catalog'::name THEN format_type(t.typbasetype, NULL::integer)
|
||||||
ELSE
|
ELSE 'USER-DEFINED'::text
|
||||||
CASE
|
END
|
||||||
WHEN t.typelem <> 0::oid AND t.typlen = (-1) THEN 'ARRAY'::text
|
ELSE
|
||||||
WHEN nt.nspname = 'pg_catalog'::name THEN format_type(a.atttypid, NULL::integer)
|
CASE
|
||||||
ELSE 'USER-DEFINED'::text
|
WHEN t.typelem <> 0::oid AND t.typlen = (-1) THEN 'ARRAY'::text
|
||||||
END
|
WHEN nt.nspname = 'pg_catalog'::name THEN format_type(a.atttypid, NULL::integer)
|
||||||
END::information_schema.character_data AS data_type,
|
ELSE 'USER-DEFINED'::text
|
||||||
information_schema._pg_char_max_length(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.cardinal_number AS character_maximum_length,
|
END
|
||||||
information_schema._pg_char_octet_length(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.cardinal_number AS character_octet_length,
|
END::information_schema.character_data AS data_type,
|
||||||
information_schema._pg_numeric_precision(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.cardinal_number AS numeric_precision,
|
information_schema._pg_char_max_length(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.cardinal_number AS character_maximum_length,
|
||||||
information_schema._pg_numeric_precision_radix(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.cardinal_number AS numeric_precision_radix,
|
information_schema._pg_char_octet_length(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.cardinal_number AS character_octet_length,
|
||||||
information_schema._pg_numeric_scale(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.cardinal_number AS numeric_scale,
|
information_schema._pg_numeric_precision(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.cardinal_number AS numeric_precision,
|
||||||
information_schema._pg_datetime_precision(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.cardinal_number AS datetime_precision,
|
information_schema._pg_numeric_precision_radix(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.cardinal_number AS numeric_precision_radix,
|
||||||
information_schema._pg_interval_type(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.character_data AS interval_type,
|
information_schema._pg_numeric_scale(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.cardinal_number AS numeric_scale,
|
||||||
NULL::integer::information_schema.cardinal_number AS interval_precision,
|
information_schema._pg_datetime_precision(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.cardinal_number AS datetime_precision,
|
||||||
NULL::character varying::information_schema.sql_identifier AS character_set_catalog,
|
information_schema._pg_interval_type(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.character_data AS interval_type,
|
||||||
NULL::character varying::information_schema.sql_identifier AS character_set_schema,
|
NULL::integer::information_schema.cardinal_number AS interval_precision,
|
||||||
NULL::character varying::information_schema.sql_identifier AS character_set_name,
|
NULL::character varying::information_schema.sql_identifier AS character_set_catalog,
|
||||||
CASE
|
NULL::character varying::information_schema.sql_identifier AS character_set_schema,
|
||||||
WHEN nco.nspname IS NOT NULL THEN current_database()
|
NULL::character varying::information_schema.sql_identifier AS character_set_name,
|
||||||
ELSE NULL::name
|
CASE
|
||||||
END::information_schema.sql_identifier AS collation_catalog,
|
WHEN nco.nspname IS NOT NULL THEN current_database()
|
||||||
nco.nspname::information_schema.sql_identifier AS collation_schema,
|
ELSE NULL::name
|
||||||
co.collname::information_schema.sql_identifier AS collation_name,
|
END::information_schema.sql_identifier AS collation_catalog,
|
||||||
CASE
|
nco.nspname::information_schema.sql_identifier AS collation_schema,
|
||||||
WHEN t.typtype = 'd'::"char" THEN current_database()
|
co.collname::information_schema.sql_identifier AS collation_name,
|
||||||
ELSE NULL::name
|
CASE
|
||||||
END::information_schema.sql_identifier AS domain_catalog,
|
WHEN t.typtype = 'd'::"char" THEN current_database()
|
||||||
CASE
|
ELSE NULL::name
|
||||||
WHEN t.typtype = 'd'::"char" THEN nt.nspname
|
END::information_schema.sql_identifier AS domain_catalog,
|
||||||
ELSE NULL::name
|
CASE
|
||||||
END::information_schema.sql_identifier AS domain_schema,
|
WHEN t.typtype = 'd'::"char" THEN nt.nspname
|
||||||
CASE
|
ELSE NULL::name
|
||||||
WHEN t.typtype = 'd'::"char" THEN t.typname
|
END::information_schema.sql_identifier AS domain_schema,
|
||||||
ELSE NULL::name
|
CASE
|
||||||
END::information_schema.sql_identifier AS domain_name,
|
WHEN t.typtype = 'd'::"char" THEN t.typname
|
||||||
current_database()::information_schema.sql_identifier AS udt_catalog,
|
ELSE NULL::name
|
||||||
COALESCE(nbt.nspname, nt.nspname)::information_schema.sql_identifier AS udt_schema,
|
END::information_schema.sql_identifier AS domain_name,
|
||||||
COALESCE(bt.typname, t.typname)::information_schema.sql_identifier AS udt_name,
|
current_database()::information_schema.sql_identifier AS udt_catalog,
|
||||||
NULL::character varying::information_schema.sql_identifier AS scope_catalog,
|
COALESCE(nbt.nspname, nt.nspname)::information_schema.sql_identifier AS udt_schema,
|
||||||
NULL::character varying::information_schema.sql_identifier AS scope_schema,
|
COALESCE(bt.typname, t.typname)::information_schema.sql_identifier AS udt_name,
|
||||||
NULL::character varying::information_schema.sql_identifier AS scope_name,
|
NULL::character varying::information_schema.sql_identifier AS scope_catalog,
|
||||||
NULL::integer::information_schema.cardinal_number AS maximum_cardinality,
|
NULL::character varying::information_schema.sql_identifier AS scope_schema,
|
||||||
a.attnum::information_schema.sql_identifier AS dtd_identifier,
|
NULL::character varying::information_schema.sql_identifier AS scope_name,
|
||||||
'NO'::character varying::information_schema.yes_or_no AS is_self_referencing,
|
NULL::integer::information_schema.cardinal_number AS maximum_cardinality,
|
||||||
'NO'::character varying::information_schema.yes_or_no AS is_identity,
|
a.attnum::information_schema.sql_identifier AS dtd_identifier,
|
||||||
NULL::character varying::information_schema.character_data AS identity_generation,
|
'NO'::character varying::information_schema.yes_or_no AS is_self_referencing,
|
||||||
NULL::character varying::information_schema.character_data AS identity_start,
|
'NO'::character varying::information_schema.yes_or_no AS is_identity,
|
||||||
NULL::character varying::information_schema.character_data AS identity_increment,
|
NULL::character varying::information_schema.character_data AS identity_generation,
|
||||||
NULL::character varying::information_schema.character_data AS identity_maximum,
|
NULL::character varying::information_schema.character_data AS identity_start,
|
||||||
NULL::character varying::information_schema.character_data AS identity_minimum,
|
NULL::character varying::information_schema.character_data AS identity_increment,
|
||||||
NULL::character varying::information_schema.yes_or_no AS identity_cycle,
|
NULL::character varying::information_schema.character_data AS identity_maximum,
|
||||||
'NEVER'::character varying::information_schema.character_data AS is_generated,
|
NULL::character varying::information_schema.character_data AS identity_minimum,
|
||||||
NULL::character varying::information_schema.character_data AS generation_expression,
|
NULL::character varying::information_schema.yes_or_no AS identity_cycle,
|
||||||
CASE
|
'NEVER'::character varying::information_schema.character_data AS is_generated,
|
||||||
WHEN c.relkind = 'r'::"char" OR (c.relkind = ANY (ARRAY['v'::"char", 'f'::"char"])) AND pg_column_is_updatable(c.oid::regclass, a.attnum, false) THEN 'YES'::text
|
NULL::character varying::information_schema.character_data AS generation_expression,
|
||||||
ELSE 'NO'::text
|
CASE
|
||||||
END::information_schema.yes_or_no AS is_updatable
|
WHEN c.relkind = 'r'::"char" OR (c.relkind = ANY (ARRAY['v'::"char", 'f'::"char"])) AND pg_column_is_updatable(c.oid::regclass, a.attnum, false) THEN 'YES'::text
|
||||||
FROM pg_attribute a
|
ELSE 'NO'::text
|
||||||
LEFT JOIN pg_attrdef ad ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum
|
END::information_schema.yes_or_no AS is_updatable
|
||||||
JOIN (pg_class c
|
FROM pg_attribute a
|
||||||
JOIN pg_namespace nc ON c.relnamespace = nc.oid) ON a.attrelid = c.oid
|
LEFT JOIN pg_attrdef ad ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum
|
||||||
JOIN (pg_type t
|
JOIN (pg_class c
|
||||||
JOIN pg_namespace nt ON t.typnamespace = nt.oid) ON a.atttypid = t.oid
|
JOIN pg_namespace nc ON c.relnamespace = nc.oid) ON a.attrelid = c.oid
|
||||||
LEFT JOIN (pg_type bt
|
JOIN (pg_type t
|
||||||
JOIN pg_namespace nbt ON bt.typnamespace = nbt.oid) ON t.typtype = 'd'::"char" AND t.typbasetype = bt.oid
|
JOIN pg_namespace nt ON t.typnamespace = nt.oid) ON a.atttypid = t.oid
|
||||||
LEFT JOIN (pg_collation co
|
LEFT JOIN (pg_type bt
|
||||||
JOIN pg_namespace nco ON co.collnamespace = nco.oid) ON a.attcollation = co.oid AND (nco.nspname <> 'pg_catalog'::name OR co.collname <> 'default'::name)
|
JOIN pg_namespace nbt ON bt.typnamespace = nbt.oid) ON t.typtype = 'd'::"char" AND t.typbasetype = bt.oid
|
||||||
WHERE NOT pg_is_other_temp_schema(nc.oid) AND a.attnum > 0 AND NOT a.attisdropped AND (c.relkind = ANY (ARRAY['r'::"char", 'v'::"char", 'f'::"char"]))
|
LEFT JOIN (pg_collation co
|
||||||
/*--AND (pg_has_role(c.relowner, 'USAGE'::text) OR has_column_privilege(c.oid, a.attnum, 'SELECT, INSERT, UPDATE, REFERENCES'::text))*/
|
JOIN pg_namespace nco ON co.collnamespace = nco.oid) ON a.attcollation = co.oid AND (nco.nspname <> 'pg_catalog'::name OR co.collname <> 'default'::name)
|
||||||
)
|
WHERE NOT pg_is_other_temp_schema(nc.oid) AND a.attnum > 0 AND NOT a.attisdropped AND (c.relkind = ANY (ARRAY['r'::"char", 'v'::"char", 'f'::"char"]))
|
||||||
SELECT
|
/*--AND (pg_has_role(c.relowner, 'USAGE'::text) OR has_column_privilege(c.oid, a.attnum, 'SELECT, INSERT, UPDATE, REFERENCES'::text))*/
|
||||||
table_schema,
|
)
|
||||||
table_name,
|
SELECT
|
||||||
column_name,
|
table_schema,
|
||||||
ordinal_position,
|
table_name,
|
||||||
is_nullable,
|
column_name,
|
||||||
data_type,
|
ordinal_position,
|
||||||
is_updatable,
|
is_nullable,
|
||||||
character_maximum_length,
|
data_type,
|
||||||
numeric_precision,
|
is_updatable,
|
||||||
column_default,
|
character_maximum_length,
|
||||||
udt_name
|
numeric_precision,
|
||||||
/*-- FROM information_schema.columns*/
|
column_default,
|
||||||
FROM columns
|
udt_name
|
||||||
WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
|
/*-- FROM information_schema.columns*/
|
||||||
) AS info
|
FROM columns
|
||||||
LEFT OUTER JOIN (
|
WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
|
||||||
SELECT
|
) AS info
|
||||||
n.nspname AS s,
|
LEFT OUTER JOIN (
|
||||||
t.typname AS n,
|
SELECT
|
||||||
array_agg(e.enumlabel ORDER BY e.enumsortorder) AS vals
|
n.nspname AS s,
|
||||||
FROM pg_type t
|
t.typname AS n,
|
||||||
JOIN pg_enum e ON t.oid = e.enumtypid
|
array_agg(e.enumlabel ORDER BY e.enumsortorder) AS vals
|
||||||
JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
|
FROM pg_type t
|
||||||
GROUP BY s,n
|
JOIN pg_enum e ON t.oid = e.enumtypid
|
||||||
) AS enum_info ON (info.udt_name = enum_info.n)
|
JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
|
||||||
ORDER BY schema, position
|
GROUP BY s,n
|
||||||
|]
|
) AS enum_info ON (info.udt_name = enum_info.n)
|
||||||
return $ mapMaybe (columnFromRow tabs) cols
|
ORDER BY schema, position |]
|
||||||
|
|
||||||
columnFromRow :: [Table] ->
|
columnFromRow :: [Table] ->
|
||||||
(Text, Text, Text,
|
(Text, Text, Text,
|
||||||
Int, Bool, Text,
|
Int32, Bool, Text,
|
||||||
Bool, Maybe Int, Maybe Int,
|
Bool, Maybe Int32, Maybe Int32,
|
||||||
Maybe Text, Maybe Text)
|
Maybe Text, Maybe Text)
|
||||||
-> Maybe Column
|
-> Maybe Column
|
||||||
columnFromRow tabs (s, t, n, pos, nul, typ, u, l, p, d, e) = buildColumn <$> table
|
columnFromRow tabs (s, t, n, pos, nul, typ, u, l, p, d, e) = buildColumn <$> table
|
||||||
@@ -363,9 +403,11 @@ columnFromRow tabs (s, t, n, pos, nul, typ, u, l, p, d, e) = buildColumn <$> tab
|
|||||||
parseEnum :: Maybe Text -> [Text]
|
parseEnum :: Maybe Text -> [Text]
|
||||||
parseEnum str = fromMaybe [] $ split (==',') <$> str
|
parseEnum str = fromMaybe [] $ split (==',') <$> str
|
||||||
|
|
||||||
allRelations :: [Table] -> [Column] -> H.Session [Relation]
|
allRelations :: [Table] -> [Column] -> H.Query () [Relation]
|
||||||
allRelations tabs cols = do
|
allRelations tabs cols = do
|
||||||
rels <- H.listEx $ [H.stmt|
|
H.statement sql HE.unit (decodeRelations tabs cols) True
|
||||||
|
where
|
||||||
|
sql = [q|
|
||||||
SELECT ns1.nspname AS table_schema,
|
SELECT ns1.nspname AS table_schema,
|
||||||
tab.relname AS table_name,
|
tab.relname AS table_name,
|
||||||
column_info.cols AS columns,
|
column_info.cols AS columns,
|
||||||
@@ -389,9 +431,7 @@ allRelations tabs cols = do
|
|||||||
LATERAL (SELECT * FROM pg_class WHERE pg_class.oid = confrelid) AS other,
|
LATERAL (SELECT * FROM pg_class WHERE pg_class.oid = confrelid) AS other,
|
||||||
LATERAL (SELECT * FROM pg_namespace WHERE pg_namespace.oid = other.relnamespace) AS ns2
|
LATERAL (SELECT * FROM pg_namespace WHERE pg_namespace.oid = other.relnamespace) AS ns2
|
||||||
WHERE confrelid != 0
|
WHERE confrelid != 0
|
||||||
ORDER BY (conrelid, column_info.nums)
|
ORDER BY (conrelid, column_info.nums) |]
|
||||||
|]
|
|
||||||
return $ mapMaybe (relationFromRow tabs cols) rels
|
|
||||||
|
|
||||||
relationFromRow :: [Table] -> [Column] -> (Text, Text, [Text], Text, Text, [Text]) -> Maybe Relation
|
relationFromRow :: [Table] -> [Column] -> (Text, Text, [Text], Text, Text, [Text]) -> Maybe Relation
|
||||||
relationFromRow allTabs allCols (rs, rt, rcs, frs, frt, frcs) =
|
relationFromRow allTabs allCols (rs, rt, rcs, frs, frt, frcs) =
|
||||||
@@ -404,119 +444,121 @@ relationFromRow allTabs allCols (rs, rt, rcs, frs, frt, frcs) =
|
|||||||
cols = mapM (findCol rs rt) rcs
|
cols = mapM (findCol rs rt) rcs
|
||||||
colsF = mapM (findCol frs frt) frcs
|
colsF = mapM (findCol frs frt) frcs
|
||||||
|
|
||||||
allPrimaryKeys :: [Table] -> H.Session [PrimaryKey]
|
allPrimaryKeys :: [Table] -> H.Query () [PrimaryKey]
|
||||||
allPrimaryKeys tabs = do
|
allPrimaryKeys tabs = do
|
||||||
pks <- H.listEx $ [H.stmt|
|
H.statement sql HE.unit (decodePks tabs) True
|
||||||
/*
|
where
|
||||||
-- CTE to replace information_schema.table_constraints to remove owner limit
|
sql = [q|
|
||||||
*/
|
/*
|
||||||
WITH tc AS (
|
-- CTE to replace information_schema.table_constraints to remove owner limit
|
||||||
SELECT current_database()::information_schema.sql_identifier AS constraint_catalog,
|
*/
|
||||||
nc.nspname::information_schema.sql_identifier AS constraint_schema,
|
WITH tc AS (
|
||||||
c.conname::information_schema.sql_identifier AS constraint_name,
|
SELECT current_database()::information_schema.sql_identifier AS constraint_catalog,
|
||||||
current_database()::information_schema.sql_identifier AS table_catalog,
|
nc.nspname::information_schema.sql_identifier AS constraint_schema,
|
||||||
nr.nspname::information_schema.sql_identifier AS table_schema,
|
c.conname::information_schema.sql_identifier AS constraint_name,
|
||||||
r.relname::information_schema.sql_identifier AS table_name,
|
current_database()::information_schema.sql_identifier AS table_catalog,
|
||||||
CASE c.contype
|
nr.nspname::information_schema.sql_identifier AS table_schema,
|
||||||
WHEN 'c'::"char" THEN 'CHECK'::text
|
r.relname::information_schema.sql_identifier AS table_name,
|
||||||
WHEN 'f'::"char" THEN 'FOREIGN KEY'::text
|
CASE c.contype
|
||||||
WHEN 'p'::"char" THEN 'PRIMARY KEY'::text
|
WHEN 'c'::"char" THEN 'CHECK'::text
|
||||||
WHEN 'u'::"char" THEN 'UNIQUE'::text
|
WHEN 'f'::"char" THEN 'FOREIGN KEY'::text
|
||||||
ELSE NULL::text
|
WHEN 'p'::"char" THEN 'PRIMARY KEY'::text
|
||||||
END::information_schema.character_data AS constraint_type,
|
WHEN 'u'::"char" THEN 'UNIQUE'::text
|
||||||
CASE
|
ELSE NULL::text
|
||||||
WHEN c.condeferrable THEN 'YES'::text
|
END::information_schema.character_data AS constraint_type,
|
||||||
ELSE 'NO'::text
|
CASE
|
||||||
END::information_schema.yes_or_no AS is_deferrable,
|
WHEN c.condeferrable THEN 'YES'::text
|
||||||
CASE
|
ELSE 'NO'::text
|
||||||
WHEN c.condeferred THEN 'YES'::text
|
END::information_schema.yes_or_no AS is_deferrable,
|
||||||
ELSE 'NO'::text
|
CASE
|
||||||
END::information_schema.yes_or_no AS initially_deferred
|
WHEN c.condeferred THEN 'YES'::text
|
||||||
FROM pg_namespace nc,
|
ELSE 'NO'::text
|
||||||
pg_namespace nr,
|
END::information_schema.yes_or_no AS initially_deferred
|
||||||
pg_constraint c,
|
FROM pg_namespace nc,
|
||||||
pg_class r
|
pg_namespace nr,
|
||||||
WHERE nc.oid = c.connamespace AND nr.oid = r.relnamespace AND c.conrelid = r.oid AND (c.contype <> ALL (ARRAY['t'::"char", 'x'::"char"])) AND r.relkind = 'r'::"char" AND NOT pg_is_other_temp_schema(nr.oid)
|
pg_constraint c,
|
||||||
/*--AND (pg_has_role(r.relowner, 'USAGE'::text) OR has_table_privilege(r.oid, 'INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER'::text) OR has_any_column_privilege(r.oid, 'INSERT, UPDATE, REFERENCES'::text))*/
|
pg_class r
|
||||||
UNION ALL
|
WHERE nc.oid = c.connamespace AND nr.oid = r.relnamespace AND c.conrelid = r.oid AND (c.contype <> ALL (ARRAY['t'::"char", 'x'::"char"])) AND r.relkind = 'r'::"char" AND NOT pg_is_other_temp_schema(nr.oid)
|
||||||
SELECT current_database()::information_schema.sql_identifier AS constraint_catalog,
|
/*--AND (pg_has_role(r.relowner, 'USAGE'::text) OR has_table_privilege(r.oid, 'INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER'::text) OR has_any_column_privilege(r.oid, 'INSERT, UPDATE, REFERENCES'::text))*/
|
||||||
nr.nspname::information_schema.sql_identifier AS constraint_schema,
|
UNION ALL
|
||||||
(((((nr.oid::text || '_'::text) || r.oid::text) || '_'::text) || a.attnum::text) || '_not_null'::text)::information_schema.sql_identifier AS constraint_name,
|
SELECT current_database()::information_schema.sql_identifier AS constraint_catalog,
|
||||||
current_database()::information_schema.sql_identifier AS table_catalog,
|
nr.nspname::information_schema.sql_identifier AS constraint_schema,
|
||||||
nr.nspname::information_schema.sql_identifier AS table_schema,
|
(((((nr.oid::text || '_'::text) || r.oid::text) || '_'::text) || a.attnum::text) || '_not_null'::text)::information_schema.sql_identifier AS constraint_name,
|
||||||
r.relname::information_schema.sql_identifier AS table_name,
|
current_database()::information_schema.sql_identifier AS table_catalog,
|
||||||
'CHECK'::character varying::information_schema.character_data AS constraint_type,
|
nr.nspname::information_schema.sql_identifier AS table_schema,
|
||||||
'NO'::character varying::information_schema.yes_or_no AS is_deferrable,
|
r.relname::information_schema.sql_identifier AS table_name,
|
||||||
'NO'::character varying::information_schema.yes_or_no AS initially_deferred
|
'CHECK'::character varying::information_schema.character_data AS constraint_type,
|
||||||
FROM pg_namespace nr,
|
'NO'::character varying::information_schema.yes_or_no AS is_deferrable,
|
||||||
pg_class r,
|
'NO'::character varying::information_schema.yes_or_no AS initially_deferred
|
||||||
pg_attribute a
|
FROM pg_namespace nr,
|
||||||
WHERE nr.oid = r.relnamespace AND r.oid = a.attrelid AND a.attnotnull AND a.attnum > 0 AND NOT a.attisdropped AND r.relkind = 'r'::"char" AND NOT pg_is_other_temp_schema(nr.oid)
|
pg_class r,
|
||||||
/*--AND (pg_has_role(r.relowner, 'USAGE'::text) OR has_table_privilege(r.oid, 'INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER'::text) OR has_any_column_privilege(r.oid, 'INSERT, UPDATE, REFERENCES'::text))*/
|
pg_attribute a
|
||||||
),
|
WHERE nr.oid = r.relnamespace AND r.oid = a.attrelid AND a.attnotnull AND a.attnum > 0 AND NOT a.attisdropped AND r.relkind = 'r'::"char" AND NOT pg_is_other_temp_schema(nr.oid)
|
||||||
/*
|
/*--AND (pg_has_role(r.relowner, 'USAGE'::text) OR has_table_privilege(r.oid, 'INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER'::text) OR has_any_column_privilege(r.oid, 'INSERT, UPDATE, REFERENCES'::text))*/
|
||||||
-- CTE to replace information_schema.key_column_usage to remove owner limit
|
),
|
||||||
*/
|
/*
|
||||||
kc AS (
|
-- CTE to replace information_schema.key_column_usage to remove owner limit
|
||||||
SELECT current_database()::information_schema.sql_identifier AS constraint_catalog,
|
*/
|
||||||
ss.nc_nspname::information_schema.sql_identifier AS constraint_schema,
|
kc AS (
|
||||||
ss.conname::information_schema.sql_identifier AS constraint_name,
|
SELECT current_database()::information_schema.sql_identifier AS constraint_catalog,
|
||||||
current_database()::information_schema.sql_identifier AS table_catalog,
|
ss.nc_nspname::information_schema.sql_identifier AS constraint_schema,
|
||||||
ss.nr_nspname::information_schema.sql_identifier AS table_schema,
|
ss.conname::information_schema.sql_identifier AS constraint_name,
|
||||||
ss.relname::information_schema.sql_identifier AS table_name,
|
current_database()::information_schema.sql_identifier AS table_catalog,
|
||||||
a.attname::information_schema.sql_identifier AS column_name,
|
ss.nr_nspname::information_schema.sql_identifier AS table_schema,
|
||||||
(ss.x).n::information_schema.cardinal_number AS ordinal_position,
|
ss.relname::information_schema.sql_identifier AS table_name,
|
||||||
CASE
|
a.attname::information_schema.sql_identifier AS column_name,
|
||||||
WHEN ss.contype = 'f'::"char" THEN information_schema._pg_index_position(ss.conindid, ss.confkey[(ss.x).n])
|
(ss.x).n::information_schema.cardinal_number AS ordinal_position,
|
||||||
ELSE NULL::integer
|
CASE
|
||||||
END::information_schema.cardinal_number AS position_in_unique_constraint
|
WHEN ss.contype = 'f'::"char" THEN information_schema._pg_index_position(ss.conindid, ss.confkey[(ss.x).n])
|
||||||
FROM pg_attribute a,
|
ELSE NULL::integer
|
||||||
( SELECT r.oid AS roid,
|
END::information_schema.cardinal_number AS position_in_unique_constraint
|
||||||
r.relname,
|
FROM pg_attribute a,
|
||||||
r.relowner,
|
( SELECT r.oid AS roid,
|
||||||
nc.nspname AS nc_nspname,
|
r.relname,
|
||||||
nr.nspname AS nr_nspname,
|
r.relowner,
|
||||||
c.oid AS coid,
|
nc.nspname AS nc_nspname,
|
||||||
c.conname,
|
nr.nspname AS nr_nspname,
|
||||||
c.contype,
|
c.oid AS coid,
|
||||||
c.conindid,
|
c.conname,
|
||||||
c.confkey,
|
c.contype,
|
||||||
c.confrelid,
|
c.conindid,
|
||||||
information_schema._pg_expandarray(c.conkey) AS x
|
c.confkey,
|
||||||
FROM pg_namespace nr,
|
c.confrelid,
|
||||||
pg_class r,
|
information_schema._pg_expandarray(c.conkey) AS x
|
||||||
pg_namespace nc,
|
FROM pg_namespace nr,
|
||||||
pg_constraint c
|
pg_class r,
|
||||||
WHERE nr.oid = r.relnamespace AND r.oid = c.conrelid AND nc.oid = c.connamespace AND (c.contype = ANY (ARRAY['p'::"char", 'u'::"char", 'f'::"char"])) AND r.relkind = 'r'::"char" AND NOT pg_is_other_temp_schema(nr.oid)) ss
|
pg_namespace nc,
|
||||||
WHERE ss.roid = a.attrelid AND a.attnum = (ss.x).x AND NOT a.attisdropped
|
pg_constraint c
|
||||||
/*--AND (pg_has_role(ss.relowner, 'USAGE'::text) OR has_column_privilege(ss.roid, a.attnum, 'SELECT, INSERT, UPDATE, REFERENCES'::text))*/
|
WHERE nr.oid = r.relnamespace AND r.oid = c.conrelid AND nc.oid = c.connamespace AND (c.contype = ANY (ARRAY['p'::"char", 'u'::"char", 'f'::"char"])) AND r.relkind = 'r'::"char" AND NOT pg_is_other_temp_schema(nr.oid)) ss
|
||||||
)
|
WHERE ss.roid = a.attrelid AND a.attnum = (ss.x).x AND NOT a.attisdropped
|
||||||
SELECT
|
/*--AND (pg_has_role(ss.relowner, 'USAGE'::text) OR has_column_privilege(ss.roid, a.attnum, 'SELECT, INSERT, UPDATE, REFERENCES'::text))*/
|
||||||
kc.table_schema,
|
)
|
||||||
kc.table_name,
|
SELECT
|
||||||
kc.column_name
|
kc.table_schema,
|
||||||
FROM
|
kc.table_name,
|
||||||
/*
|
kc.column_name
|
||||||
--information_schema.table_constraints tc,
|
FROM
|
||||||
--information_schema.key_column_usage kc
|
/*
|
||||||
*/
|
--information_schema.table_constraints tc,
|
||||||
tc, kc
|
--information_schema.key_column_usage kc
|
||||||
WHERE
|
*/
|
||||||
tc.constraint_type = 'PRIMARY KEY' AND
|
tc, kc
|
||||||
kc.table_name = tc.table_name AND
|
WHERE
|
||||||
kc.table_schema = tc.table_schema AND
|
tc.constraint_type = 'PRIMARY KEY' AND
|
||||||
kc.constraint_name = tc.constraint_name AND
|
kc.table_name = tc.table_name AND
|
||||||
kc.table_schema NOT IN ('pg_catalog', 'information_schema')
|
kc.table_schema = tc.table_schema AND
|
||||||
|]
|
kc.constraint_name = tc.constraint_name AND
|
||||||
return $ mapMaybe (pkFromRow tabs) pks
|
kc.table_schema NOT IN ('pg_catalog', 'information_schema') |]
|
||||||
|
|
||||||
pkFromRow :: [Table] -> (Schema, Text, Text) -> Maybe PrimaryKey
|
pkFromRow :: [Table] -> (Schema, Text, Text) -> Maybe PrimaryKey
|
||||||
pkFromRow tabs (s, t, n) = PrimaryKey <$> table <*> pure n
|
pkFromRow tabs (s, t, n) = PrimaryKey <$> table <*> pure n
|
||||||
where table = find (\tbl -> tableSchema tbl == s && tableName tbl == t) tabs
|
where table = find (\tbl -> tableSchema tbl == s && tableName tbl == t) tabs
|
||||||
|
|
||||||
allSynonyms :: [Column] -> H.Session [(Column,Column)]
|
allSynonyms :: [Column] -> H.Query () [(Column,Column)]
|
||||||
allSynonyms allCols = do
|
allSynonyms cols = do
|
||||||
syns <- H.listEx $ [H.stmt|
|
H.statement sql HE.unit (decodeSynonyms cols) True
|
||||||
|
where
|
||||||
|
sql = [q|
|
||||||
WITH synonyms AS (
|
WITH synonyms AS (
|
||||||
/*
|
/*
|
||||||
-- CTE to replace the view from information_schema because the information in it depended on the logged in role
|
-- CTE to replace the view from information_schema because the information in it depended on the logged in role
|
||||||
@@ -578,9 +620,7 @@ allSynonyms allCols = do
|
|||||||
syn_table_schema, syn_table_name,
|
syn_table_schema, syn_table_name,
|
||||||
(regexp_matches(view_definition, CONCAT('\.', src_column_name, '\sAS\s("?)(.+?)\1(,|$)'), 'gn'))[2] AS syn_column_name /* " <- for syntax highlighting */
|
(regexp_matches(view_definition, CONCAT('\.', src_column_name, '\sAS\s("?)(.+?)\1(,|$)'), 'gn'))[2] AS syn_column_name /* " <- for syntax highlighting */
|
||||||
FROM synonyms
|
FROM synonyms
|
||||||
)
|
) |]
|
||||||
|]
|
|
||||||
return $ mapMaybe (synonymFromRow allCols) syns
|
|
||||||
|
|
||||||
synonymFromRow :: [Column] -> (Text,Text,Text,Text,Text,Text) -> Maybe (Column,Column)
|
synonymFromRow :: [Column] -> (Text,Text,Text,Text,Text,Text) -> Maybe (Column,Column)
|
||||||
synonymFromRow allCols (s1,t1,c1,s2,t2,c2) = (,) <$> col1 <*> col2
|
synonymFromRow allCols (s1,t1,c1,s2,t2,c2) = (,) <$> col1 <*> col2
|
||||||
|
|||||||
Reference in New Issue
Block a user