module Database.PostgreSQL.Query.SqlBuilder.Builder ( SqlBuilder(..) -- * Running , runSqlBuilder -- * Building , emptyB , mkValue , mkMaskedValue , sqlBuilderFromField -- ** Unsafe , sqlBuilderPure , sqlBuilderFromByteString ) where import Blaze.ByteString.Builder (Builder) import Data.ByteString (ByteString) import Data.String import Data.Typeable import Database.PostgreSQL.Query.Import import Database.PostgreSQL.Query.SqlBuilder.Types import Database.PostgreSQL.Simple import Database.PostgreSQL.Simple.Internal import Database.PostgreSQL.Simple.ToField import Database.PostgreSQL.Simple.Types import qualified Blaze.ByteString.Builder as BB import qualified Blaze.ByteString.Builder.Char.Utf8 as BB -- | Builder wich can be effectively concatenated. Requires 'Connection' -- inside for string quoting implemented in __libpq__. Builds two strings: query -- string and log string which may differ. newtype SqlBuilder = SqlBuilder { sqlBuild :: Connection -> LogMasker -> IO SqlBuilderResult } deriving (Typeable, Generic) instance Semigroup SqlBuilder where (SqlBuilder a) <> (SqlBuilder b) = SqlBuilder $ \c masker -> (<>) <$> (a c masker) <*> (b c masker) instance Monoid SqlBuilder where mempty = sqlBuilderPure mempty mappend = (<>) instance IsString SqlBuilder where fromString s = SqlBuilder $ \_ _ -> return $ builderResultPure $ BB.fromString s -- | Returns query string with log bytestring runSqlBuilder :: Connection -> LogMasker -> SqlBuilder -> IO (Query, ByteString) runSqlBuilder con masker (SqlBuilder bld) = toTuple <$> bld con masker where toTuple res = ( Query $ BB.toByteString $ sbQueryString res , BB.toByteString $ sbLogString res ) -- | Typed synonym of 'mempty' emptyB :: SqlBuilder emptyB = mempty -- | Shorthand function to convert single field value to builder mkValue :: (ToField a) => a -> SqlBuilder mkValue = sqlBuilderFromField FieldDefault -- | Shorthand function to convert single masked field value (which should not -- be shown in log) mkMaskedValue :: (ToField a) => a -> SqlBuilder mkMaskedValue = sqlBuilderFromField FieldMasked sqlBuilderFromField :: (ToField a) => FieldOption -> a -> SqlBuilder sqlBuilderFromField fo field = SqlBuilder $ \con masker -> do qbs <- buildAction con "" [] $ toField field let sbQueryString = qbs sbLogString = masker fo qbs return SqlBuilderResult{..} -- | Lift pure bytestring builder to 'SqlBuilder'. This is unsafe to use -- directly in your code. sqlBuilderPure :: Builder -> SqlBuilder sqlBuilderPure b = SqlBuilder $ \_ _ -> pure $ builderResultPure b -- | Unsafe function to make SqlBuilder from arbitrary ByteString. Does not -- perform any checks. Dont use it directly in your code unless you know what -- you are doing. sqlBuilderFromByteString :: ByteString -> SqlBuilder sqlBuilderFromByteString = sqlBuilderPure . BB.fromByteString