WIP: converting DbStructure

This commit is contained in:
Joe Nelson
2016-01-24 18:09:18 -08:00
parent 2d5210464a
commit 4b515c5df4
+67 -27
View File
@@ -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,12 +252,11 @@ 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
where
sql = [q|
SELECT DISTINCT SELECT DISTINCT
info.table_schema AS schema, info.table_schema AS schema,
info.table_name AS table_name, info.table_name AS table_name,
@@ -346,14 +388,12 @@ allColumns tabs = do
JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
GROUP BY s,n GROUP BY s,n
) AS enum_info ON (info.udt_name = enum_info.n) ) AS enum_info ON (info.udt_name = enum_info.n)
ORDER BY schema, position ORDER BY schema, position |]
|]
return $ mapMaybe (columnFromRow tabs) cols
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,9 +444,11 @@ 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
sql = [q|
/* /*
-- CTE to replace information_schema.table_constraints to remove owner limit -- CTE to replace information_schema.table_constraints to remove owner limit
*/ */
@@ -506,17 +548,17 @@ allPrimaryKeys tabs = do
kc.table_name = tc.table_name AND kc.table_name = tc.table_name AND
kc.table_schema = tc.table_schema AND kc.table_schema = tc.table_schema AND
kc.constraint_name = tc.constraint_name AND kc.constraint_name = tc.constraint_name AND
kc.table_schema NOT IN ('pg_catalog', 'information_schema') kc.table_schema NOT IN ('pg_catalog', 'information_schema') |]
|]
return $ mapMaybe (pkFromRow tabs) pks
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