module Database.PostgreSQL.PQTypes.Model.CompositeType ( CompositeType(..) , CompositeColumn(..) , compositeTypePqFormat , sqlCreateComposite , sqlDropComposite , getDBCompositeTypes ) where import Data.Int import Data.Monoid.Utils import Database.PostgreSQL.PQTypes import qualified Data.ByteString as BS import qualified Data.Text.Encoding as T import Database.PostgreSQL.PQTypes.Model.ColumnType import Database.PostgreSQL.PQTypes.SQL.Builder data CompositeType = CompositeType { ctName :: !(RawSQL ()) , ctColumns :: ![CompositeColumn] } deriving (Eq, Ord, Show) data CompositeColumn = CompositeColumn { ccName :: !(RawSQL ()) , ccType :: ColumnType } deriving (Eq, Ord, Show) -- | Convenience function for converting CompositeType definition to -- corresponding 'pqFormat' definition. compositeTypePqFormat :: CompositeType -> BS.ByteString compositeTypePqFormat ct = "%" `BS.append` T.encodeUtf8 (unRawSQL $ ctName ct) -- | Make SQL query that creates a composite type. sqlCreateComposite :: CompositeType -> RawSQL () sqlCreateComposite CompositeType{..} = smconcat [ "CREATE TYPE" , ctName , "AS (" , mintercalate ", " $ map columnToSQL ctColumns , ")" ] where columnToSQL CompositeColumn{..} = ccName <+> columnTypeToSQL ccType -- | Make SQL query that drops a composite type. sqlDropComposite :: RawSQL () -> RawSQL () sqlDropComposite = ("DROP TYPE" <+>) ---------------------------------------- -- | Get composite types defined in the database. getDBCompositeTypes :: forall m. MonadDB m => m [CompositeType] getDBCompositeTypes = do runQuery_ . sqlSelect "pg_catalog.pg_class c" $ do sqlResult "c.relname::text" sqlResult "c.oid::int4" sqlWhere "pg_catalog.pg_table_is_visible(c.oid)" sqlWhereEq "c.relkind" 'c' sqlOrderBy "c.relname" mapM getComposite =<< fetchMany id where getComposite :: (String, Int32) -> m CompositeType getComposite (name, oid) = do runQuery_ . sqlSelect "pg_catalog.pg_attribute a" $ do sqlResult "a.attname::text" sqlResult "pg_catalog.format_type(a.atttypid, a.atttypmod)" sqlWhereEq "a.attrelid" oid sqlOrderBy "a.attnum" columns <- fetchMany fetch return CompositeType { ctName = unsafeSQL name, ctColumns = columns } where fetch :: (String, ColumnType) -> CompositeColumn fetch (cname, ctype) = CompositeColumn { ccName = unsafeSQL cname, ccType = ctype }