packages feed

ihp-postgresql-simple-extra-1.3.0: IHP/Postgres/Inet.hs

{-# LANGUAGE TemplateHaskell #-}
{-|
Module: IHP.Postgres.Inet
Description: Adds support for storing IP addresses in INET fields. CIDR Notation is not supported at the moment.
Copyright: (c) digitally induced GmbH, 2020
-}
module IHP.Postgres.Inet where

import BasicPrelude

import Database.PostgreSQL.Simple.ToField
import Database.PostgreSQL.Simple.FromField
import qualified Database.PostgreSQL.Simple.TypeInfo.Static as TI
import Database.PostgreSQL.Simple.TypeInfo.Macro as TI
import Data.Attoparsec.ByteString.Char8 as Attoparsec

-- We use the @ip@ package for representing IP addresses
import qualified Net.IP as IP
import Net.IP (IP)
import qualified Data.Text.Encoding as Text

instance FromField IP where
    fromField f v =
        if typeOid f /= $(inlineTypoid TI.inet)
        then returnError Incompatible f ""
        else case v of
               Nothing -> returnError UnexpectedNull f ""
               Just bs ->
                   case parseOnly parser bs of
                     Left  err -> returnError ConversionFailed f err
                     Right val -> pure val
      where
        parser = do
            ip <- Attoparsec.takeWhile (\char -> char /= ' ')
            case IP.decode (Text.decodeUtf8 ip) of
                Just ip -> pure ip
                Nothing -> fail "Invalid IP"

instance ToField IP where
    toField ip = toField (IP.encode ip)