packages feed

persistent-iproute-0.2.5: Database/Persist/Instances/IP.hs

{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings  #-}
module Database.Persist.Instances.IP where

#if __GLASGOW_HASKELL__ <= 708
import Control.Applicative (pure, (<$>))
#endif
import Data.Aeson.IP ()
import Data.ByteString.Char8 (ByteString, pack,unpack)
import Data.IP (IPRange, IP)
import qualified Data.Text as T
import Database.Persist
import Database.Persist.Sql
import Text.Read (readMaybe)
import Web.HttpApiData (ToHttpApiData(..),FromHttpApiData(..))
import Web.PathPieces (PathPiece(..))

note :: Maybe b -> T.Text -> Either T.Text b
{-# INLINE note #-}
note x y = maybe (Left y) Right x

ctor :: ByteString -> PersistValue
{-# INLINE ctor #-}

ctorName :: T.Text
{-# INLINE ctorName #-}

unCtor :: PersistValue -> Maybe ByteString
{-# INLINE unCtor #-}

#if MIN_VERSION_persistent(2,11,0)
ctor = PersistLiteralEscaped
ctorName = "PersistLiteralEscaped"
unCtor x = case x of {PersistLiteralEscaped y -> Just y; _ -> Nothing}
#else
ctor = PersistDbSpecific
ctorName = "PersistDbSpecific"
unCtor x = case x of {PersistDbSpecific y -> Just y; _ -> Nothing}
#endif

instance PersistField IP where
    toPersistValue = ctor . pack . show

    fromPersistValue pval = do
        ipBS <- unCtor pval `note` mconcat ["IP must be converted from ", ctorName]
        let ipStr = unpack ipBS
        readMaybe ipStr `note` mconcat ["Unable to parse IP: ", T.pack ipStr]

instance PersistFieldSql IP where
#ifdef USE_IP4R
    sqlType _ = SqlOther "IPADDRESS"
#else
    sqlType _ = SqlOther "INET"
#endif

instance PersistField IPRange where
    toPersistValue = ctor . pack . show

    fromPersistValue pval = do
        iprBS <- unCtor pval `note` mconcat ["IPRange must be converted from ", ctorName]
        let iprStr = unpack iprBS
        readMaybe iprStr `note` mconcat ["Unable to parse IPRange: ", T.pack iprStr]

instance PersistFieldSql IPRange where
#ifdef USE_IP4R
    sqlType _ = SqlOther "IPRANGE"
#else
    sqlType _ = SqlOther "CIDR"
#endif


-- The following instances don't really make sense, but persistent
-- requires them so I defined them anyway.
instance PathPiece IPRange where
    fromPathPiece = readMaybe . T.unpack . T.replace "%2F" "/"
    toPathPiece = T.replace "/" "%2F" . T.pack . show

instance PathPiece IP where
    fromPathPiece = readMaybe . T.unpack
    toPathPiece = T.pack . show

instance ToHttpApiData IP where
    toUrlPiece = T.pack . show

instance ToHttpApiData IPRange where
    toUrlPiece = T.replace "/" "%2F" . T.pack . show

instance FromHttpApiData IP where
    parseUrlPiece txt
        | Just ip <- readMaybe $ T.unpack txt = Right ip
        | otherwise = Left $ mconcat ["Unable to parse IP: ", txt]

instance FromHttpApiData IPRange where
    parseUrlPiece txt
        | Just ipr <- readMaybe . T.unpack $ T.replace "%2F" "/" txt = Right ipr
        | otherwise = Left $ mconcat ["Unable to parse IPRange: ", txt]