mirror of
https://github.com/khibino/haskell-relational-record.git
synced 2025-01-07 13:46:41 +03:00
Update to get composite primary key from PostgreSQL system catalog.
This commit is contained in:
parent
508981afb4
commit
fccffe406a
@ -17,7 +17,8 @@ module Database.Relational.Schema.PostgreSQL (
|
|||||||
|
|
||||||
normalizeColumn, notNull, getType,
|
normalizeColumn, notNull, getType,
|
||||||
|
|
||||||
columnQuerySQL, primaryKeyQuerySQL
|
columnQuerySQL,
|
||||||
|
primaryKeyLengthQuerySQL, primaryKeyQuerySQL
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Prelude hiding (or)
|
import Prelude hiding (or)
|
||||||
@ -26,6 +27,7 @@ import Language.Haskell.TH (TypeQ)
|
|||||||
|
|
||||||
import Data.Int (Int16, Int32, Int64)
|
import Data.Int (Int16, Int32, Int64)
|
||||||
import Data.Char (toLower)
|
import Data.Char (toLower)
|
||||||
|
import Data.List (foldl1')
|
||||||
import Data.Map (Map, fromList)
|
import Data.Map (Map, fromList)
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import Data.Time
|
import Data.Time
|
||||||
@ -34,15 +36,15 @@ import Data.Time
|
|||||||
|
|
||||||
import Database.Relational.Query.Type (fromRelation)
|
import Database.Relational.Query.Type (fromRelation)
|
||||||
import Database.Relational.Query
|
import Database.Relational.Query
|
||||||
(Query, Relation, query, query', relation', expr,
|
(Query, Relation, query, query', relation', relation, union,
|
||||||
wheres, (.=.), (.>.), in', values, (!), just,
|
wheres, (.=.), (.>.), in', values, (!), expr, fst', snd',
|
||||||
placeholder, asc, value, unsafeProjectSql, (><))
|
placeholder, asc, value, unsafeProjectSql, (><))
|
||||||
|
|
||||||
import Database.Relational.Schema.PgCatalog.PgNamespace (pgNamespace)
|
import Database.Relational.Schema.PgCatalog.PgNamespace (pgNamespace)
|
||||||
import qualified Database.Relational.Schema.PgCatalog.PgNamespace as Namespace
|
import qualified Database.Relational.Schema.PgCatalog.PgNamespace as Namespace
|
||||||
import Database.Relational.Schema.PgCatalog.PgClass (pgClass)
|
import Database.Relational.Schema.PgCatalog.PgClass (pgClass)
|
||||||
import qualified Database.Relational.Schema.PgCatalog.PgClass as Class
|
import qualified Database.Relational.Schema.PgCatalog.PgClass as Class
|
||||||
import Database.Relational.Schema.PgCatalog.PgConstraint (pgConstraint)
|
import Database.Relational.Schema.PgCatalog.PgConstraint (PgConstraint, pgConstraint)
|
||||||
import qualified Database.Relational.Schema.PgCatalog.PgConstraint as Constraint
|
import qualified Database.Relational.Schema.PgCatalog.PgConstraint as Constraint
|
||||||
|
|
||||||
import Database.Relational.Schema.PgCatalog.PgAttribute (PgAttribute, pgAttribute)
|
import Database.Relational.Schema.PgCatalog.PgAttribute (PgAttribute, pgAttribute)
|
||||||
@ -159,20 +161,52 @@ columnRelation = relation' $ do
|
|||||||
columnQuerySQL :: Query (String, String) Column
|
columnQuerySQL :: Query (String, String) Column
|
||||||
columnQuerySQL = fromRelation columnRelation
|
columnQuerySQL = fromRelation columnRelation
|
||||||
|
|
||||||
|
-- | 'Relation' to query primary key length from schema name and table name.
|
||||||
|
primaryKeyLengthRelation :: Relation (String, String) Int32
|
||||||
|
primaryKeyLengthRelation = relation' $ do
|
||||||
|
(ph, reloid) <- query' relOidRelation
|
||||||
|
con <- query pgConstraint
|
||||||
|
|
||||||
|
wheres $ con ! Constraint.conrelid' .=. expr reloid
|
||||||
|
wheres $ con ! Constraint.contype' .=. value 'p' -- 'p': primary key constraint type
|
||||||
|
|
||||||
|
return (ph, unsafeProjectSql "array_length (conkey, 1)")
|
||||||
|
|
||||||
|
-- | Phantom typed 'Query' to get primary key length from schema name and table name.
|
||||||
|
primaryKeyLengthQuerySQL :: Query (String, String) Int32
|
||||||
|
primaryKeyLengthQuerySQL = fromRelation primaryKeyLengthRelation
|
||||||
|
|
||||||
|
-- | One column which is nth column of composite primary key.
|
||||||
|
constraintColRelation :: Int32 -> Relation () (PgConstraint, (Int16, Int32))
|
||||||
|
constraintColRelation i = relation $ do
|
||||||
|
con <- query pgConstraint
|
||||||
|
|
||||||
|
return $ con >< (unsafeProjectSql ("conkey[" ++ show i ++ "]") >< value i)
|
||||||
|
|
||||||
|
-- | Make composite primary key relation from primary key length.
|
||||||
|
constraintColExpandRelation :: Int32 -> Relation () (PgConstraint, (Int16, Int32))
|
||||||
|
constraintColExpandRelation n =
|
||||||
|
foldl1' union [constraintColRelation i | i <- [1..n] ]
|
||||||
|
|
||||||
-- | 'Relation' to query primary key name from schema name and table name.
|
-- | 'Relation' to query primary key name from schema name and table name.
|
||||||
primaryKeyRelation :: Relation (String, String) String
|
primaryKeyRelation :: Int32 -> Relation (String, String) String
|
||||||
primaryKeyRelation = relation' $ do
|
primaryKeyRelation n = relation' $ do
|
||||||
(ph, att) <- query' attributeRelation
|
(ph, att) <- query' attributeRelation
|
||||||
con <- query pgConstraint
|
conEx <- query (constraintColExpandRelation n)
|
||||||
|
|
||||||
|
let con = conEx ! fst'
|
||||||
|
col' = conEx ! snd'
|
||||||
|
keyIx = col' ! fst'
|
||||||
|
keyN = col' ! snd'
|
||||||
|
|
||||||
wheres $ con ! Constraint.conrelid' .=. att ! Attr.attrelid'
|
wheres $ con ! Constraint.conrelid' .=. att ! Attr.attrelid'
|
||||||
wheres $ unsafeProjectSql "conkey[1]" .=. att ! Attr.attnum'
|
wheres $ keyIx .=. att ! Attr.attnum'
|
||||||
wheres $ just (att ! Attr.attnotnull')
|
|
||||||
wheres $ con ! Constraint.contype' .=. value 'p' -- 'p': primary key constraint type
|
wheres $ con ! Constraint.contype' .=. value 'p' -- 'p': primary key constraint type
|
||||||
wheres $ unsafeProjectSql "array_length (conkey, 1)" .=. value (1 :: Int32)
|
|
||||||
|
asc $ keyN
|
||||||
|
|
||||||
return (ph, att ! Attr.attname')
|
return (ph, att ! Attr.attname')
|
||||||
|
|
||||||
-- | Phantom typed 'Query' to get primary key name from schema name and table name.
|
-- | Phantom typed 'Query' to get primary key name from schema name and table name.
|
||||||
primaryKeyQuerySQL :: Query (String, String) String
|
primaryKeyQuerySQL :: Int32 -> Query (String, String) String
|
||||||
primaryKeyQuerySQL = fromRelation primaryKeyRelation
|
primaryKeyQuerySQL = fromRelation . primaryKeyRelation
|
||||||
|
@ -32,7 +32,8 @@ import Database.HDBC.Record.Query (runQuery')
|
|||||||
import Database.HDBC.Record.Persistable ()
|
import Database.HDBC.Record.Persistable ()
|
||||||
|
|
||||||
import Database.Relational.Schema.PostgreSQL
|
import Database.Relational.Schema.PostgreSQL
|
||||||
(normalizeColumn, notNull, getType, columnQuerySQL, primaryKeyQuerySQL)
|
(normalizeColumn, notNull, getType, columnQuerySQL,
|
||||||
|
primaryKeyLengthQuerySQL, primaryKeyQuerySQL)
|
||||||
import Database.Relational.Schema.PgCatalog.PgAttribute (PgAttribute(PgAttribute), tableOfPgAttribute)
|
import Database.Relational.Schema.PgCatalog.PgAttribute (PgAttribute(PgAttribute), tableOfPgAttribute)
|
||||||
import Database.Relational.Schema.PgCatalog.PgType (PgType(..), tableOfPgType)
|
import Database.Relational.Schema.PgCatalog.PgType (PgType(..), tableOfPgType)
|
||||||
import qualified Database.Relational.Schema.PgCatalog.PgType as Type
|
import qualified Database.Relational.Schema.PgCatalog.PgType as Type
|
||||||
@ -64,11 +65,19 @@ getPrimaryKey' :: IConnection conn
|
|||||||
getPrimaryKey' conn scm' tbl' = do
|
getPrimaryKey' conn scm' tbl' = do
|
||||||
let scm = map toLower scm'
|
let scm = map toLower scm'
|
||||||
tbl = map toLower tbl'
|
tbl = map toLower tbl'
|
||||||
primCols <- runQuery' conn (scm, tbl) primaryKeyQuerySQL
|
mayKeyLen <- runQuery' conn (scm, tbl) primaryKeyLengthQuerySQL
|
||||||
let primaryKeyCols = normalizeColumn `fmap` primCols
|
case mayKeyLen of
|
||||||
putLog $ "getPrimaryKey: primary key = " ++ show primaryKeyCols
|
[] -> do
|
||||||
|
putLog $ "getPrimaryKey: Primary key not found."
|
||||||
return primaryKeyCols
|
return []
|
||||||
|
[keyLen] -> do
|
||||||
|
primCols <- runQuery' conn (scm, tbl) (primaryKeyQuerySQL keyLen)
|
||||||
|
let primaryKeyCols = normalizeColumn `fmap` primCols
|
||||||
|
putLog $ "getPrimaryKey: primary key = " ++ show primaryKeyCols
|
||||||
|
return primaryKeyCols
|
||||||
|
_:_:_ -> do
|
||||||
|
putLog $ "getPrimaryKey: Fail to detect primary key. Something wrong."
|
||||||
|
return []
|
||||||
|
|
||||||
getFields' :: IConnection conn
|
getFields' :: IConnection conn
|
||||||
=> TypeMap
|
=> TypeMap
|
||||||
|
Loading…
Reference in New Issue
Block a user