-- This file is part of HamSql -- -- Copyright 2014-2016 by it's authors. -- Some rights reserved. See COPYING, AUTHORS. {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE StandaloneDeriving #-} module Database.YamSql.Internal.SqlId where import Data.Typeable import qualified Data.Text as T import Database.HamSql.Internal.Utils import Database.YamSql.Parser -- | Idable class Show a => ToSqlId a where sqlId :: a -> SqlId sqlIdCode :: a -> Text sqlIdCode = toSqlCode . sqlId class (Typeable a, ToSqlCode a, Eq a, Show a) => SqlIdContent a where sqlIdContentType :: a -> SqlContextObjType class Show a => ToSqlIdPart a where sqlIdPart :: a -> SqlName sqlIdPartType :: a -> SqlContextObjType class ToSqlObjId a where sqlObjId :: a -> SqlName sqlObjIdCode :: a -> Text sqlObjIdCode = toSqlCode . sqlObjId class ToSqlSqoId a where sqlSqoId :: a -> SqlName sqlSqoIdCode :: a -> Text sqlSqoIdCode = toSqlCode . sqlSqoId class ToSqlSqoObjId a where sqlSqoObjId :: a -> SqlName sqlSqoObjIdCode :: a -> Text sqlSqoObjIdCode = toSqlCode . sqlSqoObjId -- | Strings like /TABLE/ type SqlContextObjType = Text class ToSqlIdPartArgs a where sqlIdPartArgs :: a -> [SqlType] -- | SqlId data SqlId where SqlId :: (SqlIdContent a) => { sqlIdContent :: a } -> SqlId deriving instance Show SqlId sqlIdType :: SqlId -> SqlContextObjType sqlIdType (SqlId x) = sqlIdContentType x instance Eq SqlId where SqlId x == SqlId y = Just x == cast y instance Ord SqlId where SqlId x `compare` SqlId y = case sqlIdContentType x `compare` sqlIdContentType y of EQ -> toSqlCode x `compare` toSqlCode y x' -> x' instance ToSqlId SqlId where sqlId = id instance ToSqlCode SqlId where toSqlCode (SqlId x) = toSqlCode x -- | ROLE, DATABASE, SCHEMA data SqlIdContentObj = SqlIdContentObj SqlContextObjType SqlName deriving (Eq, Show) instance SqlIdContent SqlIdContentObj where sqlIdContentType (SqlIdContentObj x _) = x instance ToSqlId SqlIdContentObj where sqlId = SqlId instance ToSqlCode SqlIdContentObj where toSqlCode (SqlIdContentObj _ x) = toSqlCode x instance ToSqlObjId SqlIdContentObj where sqlObjId (SqlIdContentObj _ x) = x -- | TABLE data SqlIdContentSqo = SqlIdContentSqo SqlContextObjType SqlName deriving (Eq, Show) instance SqlIdContent SqlIdContentSqo where sqlIdContentType (SqlIdContentSqo x _) = x instance ToSqlId SqlIdContentSqo where sqlId = SqlId instance ToSqlCode SqlIdContentSqo where toSqlCode (SqlIdContentSqo _ x) = toSqlCode x instance ToSqlSqoId SqlIdContentSqo where sqlSqoId (SqlIdContentSqo _ x) = x -- | TABLE TRIGGER, TABLE CONTRAINT data SqlIdContentSqoObj = SqlIdContentSqoObj SqlContextObjType SqlName SqlName deriving (Eq, Show) instance SqlIdContent SqlIdContentSqoObj where sqlIdContentType (SqlIdContentSqoObj x _ _) = x instance ToSqlId SqlIdContentSqoObj where sqlId = SqlId instance ToSqlCode SqlIdContentSqoObj where toSqlCode (SqlIdContentSqoObj _ x y) = toSqlCode (x <.> y) instance ToSqlSqoId SqlIdContentSqoObj where sqlSqoId (SqlIdContentSqoObj _ x _) = x instance ToSqlSqoObjId SqlIdContentSqoObj where sqlSqoObjId (SqlIdContentSqoObj _ _ x) = x -- | FUNCTION data SqlIdContentSqoArgtypes = SqlIdContentSqoArgtypes SqlContextObjType SqlName [SqlType] deriving (Eq, Show) instance SqlIdContent SqlIdContentSqoArgtypes where sqlIdContentType (SqlIdContentSqoArgtypes x _ _) = x instance ToSqlId SqlIdContentSqoArgtypes where sqlId = SqlId instance ToSqlSqoId SqlIdContentSqoArgtypes where sqlSqoId (SqlIdContentSqoArgtypes _ x _) = x instance ToSqlCode SqlIdContentSqoArgtypes where toSqlCode (SqlIdContentSqoArgtypes _ x ys) = toSqlCode x <> "(" <> T.intercalate ", " (map toSqlCode ys) <> ")" -- ToSqlCode (right now only SqlName) unsafePlainName :: SqlName -> Text unsafePlainName (SqlName n) = n instance Eq SqlName where (==) x y = toSqlCode x == toSqlCode y instance ToSqlCode SqlName where toSqlCode (SqlName n) = if '"' `isIn` n then n else toSqlCode' $ expSqlName $ SqlName n instance SqlIdentifierConcat SqlName where (//) (SqlName s) (SqlName t) = SqlName (s <> t) (<.>) :: SqlName -> SqlName -> SqlName (<.>) (SqlName s) (SqlName t) = SqlName $ s <> "." <> t expSqlName :: SqlName -> [SqlName] expSqlName n = map SqlName (T.splitOn "." (getStr n)) where getStr (SqlName n') = n' instance ToSqlCode SqlType where toSqlCode (SqlType n) -- if quotes are contained -- assume that user cares for correct enquoting = if '"' `isIn` n || -- if at least a pair of brakets is found -- assume that a type like varchar(20) is meant ('(' `isIn` n && ')' `isIn` n) || -- if no dot is present, assume that buildin type -- like integer is meant not ('.' `isIn` n) || -- if % is present, assume that something like -- table%ROWTYPE could be meant '%' `isIn` n then n else toSqlCode' $ expSqlName $ SqlName n instance SqlIdentifierConcat SqlType where (//) (SqlType s) (SqlType t) = SqlType (s <> t) contSqlName :: [SqlName] -> SqlName contSqlName ns = SqlName $ T.intercalate "." $ map getStr ns where getStr (SqlName n') = n' toSqlCode' :: [SqlName] -> Text toSqlCode' xs = T.intercalate "." $ map quotedName xs where quotedName (SqlName s) = "\"" <> s <> "\"" class ToSqlCode a where toSqlCode :: a -> Text class SqlIdentifierConcat a where (//) :: a -> a -> a -- SqlName newtype SqlName = SqlName Text deriving (Generic, Ord, Show, Data) instance FromJSON SqlName where parseJSON = genericParseJSON myOpt instance ToJSON SqlName where toJSON = toYamSqlJson newtype SqlType = SqlType Text deriving (Generic, Show, Eq, Data) instance FromJSON SqlType where parseJSON = genericParseJSON myOpt instance ToJSON SqlType where toJSON = toYamSqlJson