content: {-# 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)
  