{-# LANGUAGE GeneralizedNewtypeDeriving #-}

{- |
Copyright : Flipstone Technology Partners 2023
License   : MIT
Stability : Stable

@since 1.0.0.0
-}
module Orville.PostgreSQL.PgCatalog.PgConstraint
  ( PgConstraint (..)
  , ConstraintType (..)
  , ConstraintName
  , constraintNameToString
  , pgConstraintTable
  , constraintRelationOidField
  )
where

import qualified Data.Attoparsec.Text as AttoText
import qualified Data.List as List
import qualified Data.String as String
import qualified Data.Text as T
import qualified Data.Text.Lazy as LT
import qualified Data.Text.Lazy.Builder as LTB
import qualified Database.PostgreSQL.LibPQ as LibPQ

import qualified Orville.PostgreSQL as Orville
import Orville.PostgreSQL.PgCatalog.OidField (oidField, oidTypeField)
import Orville.PostgreSQL.PgCatalog.PgAttribute (AttributeNumber, attributeNumberParser, attributeNumberTextBuilder)

{- |
  The Haskell representation of data read from the @pg_catalog.pg_constraint@
  table. Rows in this table correspond to check, primary key, unique, foreign
  key and exclusion constraints on tables.

@since 1.0.0.0
-}
data PgConstraint = PgConstraint
  { PgConstraint -> Oid
pgConstraintOid :: LibPQ.Oid
  -- ^ The PostgreSQL @oid@ for the constraint.
  , PgConstraint -> ConstraintName
pgConstraintName :: ConstraintName
  -- ^ The constraint name (which may not be unique).
  , PgConstraint -> Oid
pgConstraintNamespaceOid :: LibPQ.Oid
  -- ^ The oid of the namespace that contains the constraint.
  , PgConstraint -> ConstraintType
pgConstraintType :: ConstraintType
  -- ^ The type of constraint.
  , PgConstraint -> Oid
pgConstraintRelationOid :: LibPQ.Oid
  -- ^ The PostgreSQL @oid@ of the table that the constraint is on
  -- (or @0@ if not a table constraint).
  , PgConstraint -> Oid
pgConstraintIndexOid :: LibPQ.Oid
  -- ^ The PostgreSQL @oid@ ef the index supporting this constraint, if it's a
  -- unique, primary key, foreign key or exclusion constraint. Otherwise @0@.
  , PgConstraint -> Maybe [AttributeNumber]
pgConstraintKey :: Maybe [AttributeNumber]
  -- ^ For table constraints, the attribute numbers of the constrained columns.
  -- These correspond to the 'Orville.PostgreSQL.PGCatalog.pgAttributeNumber'
  -- field of 'Orville.PostgreSQL.PGCatalog.PgAttribute'.
  , PgConstraint -> Oid
pgConstraintForeignRelationOid :: LibPQ.Oid
  -- ^ For foreign key constraints, the PostgreSQL @oid@ of the table the
  -- foreign key references.
  , PgConstraint -> Maybe [AttributeNumber]
pgConstraintForeignKey :: Maybe [AttributeNumber]
  -- ^ For foreign key constraints, the attribute numbers of the referenced
  -- columns. These correspond to the
  -- 'Orville.PostgreSQL.PGCatalog.pgAttributeNumber' field of
  -- 'Orville.PostgreSQL.PGCatalog.PgAttribute'.
  , PgConstraint -> Maybe ForeignKeyAction
pgConstraintForeignKeyOnUpdateType :: Maybe Orville.ForeignKeyAction
  -- ^ For foreign key constraints, the on update action type.
  , PgConstraint -> Maybe ForeignKeyAction
pgConstraintForeignKeyOnDeleteType :: Maybe Orville.ForeignKeyAction
  -- ^ For foreign key constraints, the on delete action type.
  }

{- |
  A Haskell type for the name of the constraint represented by a
  'PgConstraint'.

@since 1.0.0.0
-}
newtype ConstraintName
  = ConstraintName T.Text
  deriving (Int -> ConstraintName -> ShowS
[ConstraintName] -> ShowS
ConstraintName -> String
(Int -> ConstraintName -> ShowS)
-> (ConstraintName -> String)
-> ([ConstraintName] -> ShowS)
-> Show ConstraintName
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ConstraintName -> ShowS
showsPrec :: Int -> ConstraintName -> ShowS
$cshow :: ConstraintName -> String
show :: ConstraintName -> String
$cshowList :: [ConstraintName] -> ShowS
showList :: [ConstraintName] -> ShowS
Show, ConstraintName -> ConstraintName -> Bool
(ConstraintName -> ConstraintName -> Bool)
-> (ConstraintName -> ConstraintName -> Bool) -> Eq ConstraintName
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ConstraintName -> ConstraintName -> Bool
== :: ConstraintName -> ConstraintName -> Bool
$c/= :: ConstraintName -> ConstraintName -> Bool
/= :: ConstraintName -> ConstraintName -> Bool
Eq, Eq ConstraintName
Eq ConstraintName
-> (ConstraintName -> ConstraintName -> Ordering)
-> (ConstraintName -> ConstraintName -> Bool)
-> (ConstraintName -> ConstraintName -> Bool)
-> (ConstraintName -> ConstraintName -> Bool)
-> (ConstraintName -> ConstraintName -> Bool)
-> (ConstraintName -> ConstraintName -> ConstraintName)
-> (ConstraintName -> ConstraintName -> ConstraintName)
-> Ord ConstraintName
ConstraintName -> ConstraintName -> Bool
ConstraintName -> ConstraintName -> Ordering
ConstraintName -> ConstraintName -> ConstraintName
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: ConstraintName -> ConstraintName -> Ordering
compare :: ConstraintName -> ConstraintName -> Ordering
$c< :: ConstraintName -> ConstraintName -> Bool
< :: ConstraintName -> ConstraintName -> Bool
$c<= :: ConstraintName -> ConstraintName -> Bool
<= :: ConstraintName -> ConstraintName -> Bool
$c> :: ConstraintName -> ConstraintName -> Bool
> :: ConstraintName -> ConstraintName -> Bool
$c>= :: ConstraintName -> ConstraintName -> Bool
>= :: ConstraintName -> ConstraintName -> Bool
$cmax :: ConstraintName -> ConstraintName -> ConstraintName
max :: ConstraintName -> ConstraintName -> ConstraintName
$cmin :: ConstraintName -> ConstraintName -> ConstraintName
min :: ConstraintName -> ConstraintName -> ConstraintName
Ord, String -> ConstraintName
(String -> ConstraintName) -> IsString ConstraintName
forall a. (String -> a) -> IsString a
$cfromString :: String -> ConstraintName
fromString :: String -> ConstraintName
String.IsString)

{- |
  Converts a 'ConstraintName' to a plain 'String'.

@since 1.0.0.0
-}
constraintNameToString :: ConstraintName -> String
constraintNameToString :: ConstraintName -> String
constraintNameToString (ConstraintName Text
txt) =
  Text -> String
T.unpack Text
txt

{- |
  The type of constraint that a 'PgConstraint' represents, as described at
  https://www.postgresql.org/docs/13/catalog-pg-constraint.html.

@since 1.0.0.0
-}
data ConstraintType
  = CheckConstraint
  | ForeignKeyConstraint
  | PrimaryKeyConstraint
  | UniqueConstraint
  | ConstraintTrigger
  | ExclusionConstraint
  deriving (Int -> ConstraintType -> ShowS
[ConstraintType] -> ShowS
ConstraintType -> String
(Int -> ConstraintType -> ShowS)
-> (ConstraintType -> String)
-> ([ConstraintType] -> ShowS)
-> Show ConstraintType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ConstraintType -> ShowS
showsPrec :: Int -> ConstraintType -> ShowS
$cshow :: ConstraintType -> String
show :: ConstraintType -> String
$cshowList :: [ConstraintType] -> ShowS
showList :: [ConstraintType] -> ShowS
Show, ConstraintType -> ConstraintType -> Bool
(ConstraintType -> ConstraintType -> Bool)
-> (ConstraintType -> ConstraintType -> Bool) -> Eq ConstraintType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ConstraintType -> ConstraintType -> Bool
== :: ConstraintType -> ConstraintType -> Bool
$c/= :: ConstraintType -> ConstraintType -> Bool
/= :: ConstraintType -> ConstraintType -> Bool
Eq)

{- |
  Converts a 'ConstraintType' to the corresponding single character text
  representation used by PostgreSQL.

  See also 'pgTextToConstraintType'

@since 1.0.0.0
-}
constraintTypeToPgText :: ConstraintType -> T.Text
constraintTypeToPgText :: ConstraintType -> Text
constraintTypeToPgText ConstraintType
conType =
  String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$
    case ConstraintType
conType of
      ConstraintType
CheckConstraint -> String
"c"
      ConstraintType
ForeignKeyConstraint -> String
"f"
      ConstraintType
PrimaryKeyConstraint -> String
"p"
      ConstraintType
UniqueConstraint -> String
"u"
      ConstraintType
ConstraintTrigger -> String
"t"
      ConstraintType
ExclusionConstraint -> String
"x"

{- |
  Attempts to parse a PostgreSQL single character textual value as a
  'ConstraintType'

  See also 'constraintTypeToPgText'

@since 1.0.0.0
-}
pgTextToConstraintType :: T.Text -> Either String ConstraintType
pgTextToConstraintType :: Text -> Either String ConstraintType
pgTextToConstraintType Text
text =
  case Text -> String
T.unpack Text
text of
    String
"c" -> ConstraintType -> Either String ConstraintType
forall a b. b -> Either a b
Right ConstraintType
CheckConstraint
    String
"f" -> ConstraintType -> Either String ConstraintType
forall a b. b -> Either a b
Right ConstraintType
ForeignKeyConstraint
    String
"p" -> ConstraintType -> Either String ConstraintType
forall a b. b -> Either a b
Right ConstraintType
PrimaryKeyConstraint
    String
"u" -> ConstraintType -> Either String ConstraintType
forall a b. b -> Either a b
Right ConstraintType
UniqueConstraint
    String
"t" -> ConstraintType -> Either String ConstraintType
forall a b. b -> Either a b
Right ConstraintType
ConstraintTrigger
    String
"x" -> ConstraintType -> Either String ConstraintType
forall a b. b -> Either a b
Right ConstraintType
ExclusionConstraint
    String
typ -> String -> Either String ConstraintType
forall a b. a -> Either a b
Left (String
"Unrecognized PostgreSQL constraint type: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
typ)

{- |
  Converts a 'Maybe Orville.ForeignKeyAction' to the corresponding single character
  text representation used by PostgreSQL.

  See also 'pgTextToForeignKeyAction'

@since 1.0.0.0
-}
foreignKeyActionToPgText :: Maybe Orville.ForeignKeyAction -> T.Text
foreignKeyActionToPgText :: Maybe ForeignKeyAction -> Text
foreignKeyActionToPgText Maybe ForeignKeyAction
mbfkAction =
  String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$
    case Maybe ForeignKeyAction
mbfkAction of
      Just ForeignKeyAction
Orville.NoAction -> String
"a"
      Just ForeignKeyAction
Orville.Restrict -> String
"r"
      Just ForeignKeyAction
Orville.Cascade -> String
"c"
      Just ForeignKeyAction
Orville.SetNull -> String
"n"
      Just ForeignKeyAction
Orville.SetDefault -> String
"d"
      Maybe ForeignKeyAction
Nothing -> String
" "

{- |
  Attempts to parse a PostgreSQL single character textual value as a
  'Maybe Orville.ForeignKeyAction'

  See also 'foreignKeyActionToPgText'

@since 1.0.0.0
-}
pgTextToForeignKeyAction :: T.Text -> Either String (Maybe Orville.ForeignKeyAction)
pgTextToForeignKeyAction :: Text -> Either String (Maybe ForeignKeyAction)
pgTextToForeignKeyAction Text
text =
  case Text -> String
T.unpack Text
text of
    String
"a" -> Maybe ForeignKeyAction -> Either String (Maybe ForeignKeyAction)
forall a b. b -> Either a b
Right (Maybe ForeignKeyAction -> Either String (Maybe ForeignKeyAction))
-> Maybe ForeignKeyAction -> Either String (Maybe ForeignKeyAction)
forall a b. (a -> b) -> a -> b
$ ForeignKeyAction -> Maybe ForeignKeyAction
forall a. a -> Maybe a
Just ForeignKeyAction
Orville.NoAction
    String
"r" -> Maybe ForeignKeyAction -> Either String (Maybe ForeignKeyAction)
forall a b. b -> Either a b
Right (Maybe ForeignKeyAction -> Either String (Maybe ForeignKeyAction))
-> Maybe ForeignKeyAction -> Either String (Maybe ForeignKeyAction)
forall a b. (a -> b) -> a -> b
$ ForeignKeyAction -> Maybe ForeignKeyAction
forall a. a -> Maybe a
Just ForeignKeyAction
Orville.Restrict
    String
"c" -> Maybe ForeignKeyAction -> Either String (Maybe ForeignKeyAction)
forall a b. b -> Either a b
Right (Maybe ForeignKeyAction -> Either String (Maybe ForeignKeyAction))
-> Maybe ForeignKeyAction -> Either String (Maybe ForeignKeyAction)
forall a b. (a -> b) -> a -> b
$ ForeignKeyAction -> Maybe ForeignKeyAction
forall a. a -> Maybe a
Just ForeignKeyAction
Orville.Cascade
    String
"n" -> Maybe ForeignKeyAction -> Either String (Maybe ForeignKeyAction)
forall a b. b -> Either a b
Right (Maybe ForeignKeyAction -> Either String (Maybe ForeignKeyAction))
-> Maybe ForeignKeyAction -> Either String (Maybe ForeignKeyAction)
forall a b. (a -> b) -> a -> b
$ ForeignKeyAction -> Maybe ForeignKeyAction
forall a. a -> Maybe a
Just ForeignKeyAction
Orville.SetNull
    String
"d" -> Maybe ForeignKeyAction -> Either String (Maybe ForeignKeyAction)
forall a b. b -> Either a b
Right (Maybe ForeignKeyAction -> Either String (Maybe ForeignKeyAction))
-> Maybe ForeignKeyAction -> Either String (Maybe ForeignKeyAction)
forall a b. (a -> b) -> a -> b
$ ForeignKeyAction -> Maybe ForeignKeyAction
forall a. a -> Maybe a
Just ForeignKeyAction
Orville.SetDefault
    String
" " -> Maybe ForeignKeyAction -> Either String (Maybe ForeignKeyAction)
forall a b. b -> Either a b
Right Maybe ForeignKeyAction
forall a. Maybe a
Nothing
    String
typ -> String -> Either String (Maybe ForeignKeyAction)
forall a b. a -> Either a b
Left (String
"Unrecognized PostgreSQL foreign key action type: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
typ)

{- |
  An Orville 'Orville.TableDefinition' for querying the
  @pg_catalog.pg_constraint@ table.

@since 1.0.0.0
-}
pgConstraintTable :: Orville.TableDefinition (Orville.HasKey LibPQ.Oid) PgConstraint PgConstraint
pgConstraintTable :: TableDefinition (HasKey Oid) PgConstraint PgConstraint
pgConstraintTable =
  String
-> TableDefinition (HasKey Oid) PgConstraint PgConstraint
-> TableDefinition (HasKey Oid) PgConstraint PgConstraint
forall key writeEntity readEntity.
String
-> TableDefinition key writeEntity readEntity
-> TableDefinition key writeEntity readEntity
Orville.setTableSchema String
"pg_catalog" (TableDefinition (HasKey Oid) PgConstraint PgConstraint
 -> TableDefinition (HasKey Oid) PgConstraint PgConstraint)
-> TableDefinition (HasKey Oid) PgConstraint PgConstraint
-> TableDefinition (HasKey Oid) PgConstraint PgConstraint
forall a b. (a -> b) -> a -> b
$
    String
-> PrimaryKey Oid
-> SqlMarshaller PgConstraint PgConstraint
-> TableDefinition (HasKey Oid) PgConstraint PgConstraint
forall key writeEntity readEntity.
String
-> PrimaryKey key
-> SqlMarshaller writeEntity readEntity
-> TableDefinition (HasKey key) writeEntity readEntity
Orville.mkTableDefinition
      String
"pg_constraint"
      (FieldDefinition NotNull Oid -> PrimaryKey Oid
forall key. FieldDefinition NotNull key -> PrimaryKey key
Orville.primaryKey FieldDefinition NotNull Oid
oidField)
      SqlMarshaller PgConstraint PgConstraint
pgConstraintMarshaller

pgConstraintMarshaller :: Orville.SqlMarshaller PgConstraint PgConstraint
pgConstraintMarshaller :: SqlMarshaller PgConstraint PgConstraint
pgConstraintMarshaller =
  Oid
-> ConstraintName
-> Oid
-> ConstraintType
-> Oid
-> Oid
-> Maybe [AttributeNumber]
-> Oid
-> Maybe [AttributeNumber]
-> Maybe ForeignKeyAction
-> Maybe ForeignKeyAction
-> PgConstraint
PgConstraint
    (Oid
 -> ConstraintName
 -> Oid
 -> ConstraintType
 -> Oid
 -> Oid
 -> Maybe [AttributeNumber]
 -> Oid
 -> Maybe [AttributeNumber]
 -> Maybe ForeignKeyAction
 -> Maybe ForeignKeyAction
 -> PgConstraint)
-> SqlMarshaller PgConstraint Oid
-> SqlMarshaller
     PgConstraint
     (ConstraintName
      -> Oid
      -> ConstraintType
      -> Oid
      -> Oid
      -> Maybe [AttributeNumber]
      -> Oid
      -> Maybe [AttributeNumber]
      -> Maybe ForeignKeyAction
      -> Maybe ForeignKeyAction
      -> PgConstraint)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (PgConstraint -> Oid)
-> FieldDefinition NotNull Oid -> SqlMarshaller PgConstraint Oid
forall writeEntity fieldValue nullability.
(writeEntity -> fieldValue)
-> FieldDefinition nullability fieldValue
-> SqlMarshaller writeEntity fieldValue
Orville.marshallField PgConstraint -> Oid
pgConstraintOid FieldDefinition NotNull Oid
oidField
    SqlMarshaller
  PgConstraint
  (ConstraintName
   -> Oid
   -> ConstraintType
   -> Oid
   -> Oid
   -> Maybe [AttributeNumber]
   -> Oid
   -> Maybe [AttributeNumber]
   -> Maybe ForeignKeyAction
   -> Maybe ForeignKeyAction
   -> PgConstraint)
-> SqlMarshaller PgConstraint ConstraintName
-> SqlMarshaller
     PgConstraint
     (Oid
      -> ConstraintType
      -> Oid
      -> Oid
      -> Maybe [AttributeNumber]
      -> Oid
      -> Maybe [AttributeNumber]
      -> Maybe ForeignKeyAction
      -> Maybe ForeignKeyAction
      -> PgConstraint)
forall a b.
SqlMarshaller PgConstraint (a -> b)
-> SqlMarshaller PgConstraint a -> SqlMarshaller PgConstraint b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (PgConstraint -> ConstraintName)
-> FieldDefinition NotNull ConstraintName
-> SqlMarshaller PgConstraint ConstraintName
forall writeEntity fieldValue nullability.
(writeEntity -> fieldValue)
-> FieldDefinition nullability fieldValue
-> SqlMarshaller writeEntity fieldValue
Orville.marshallField PgConstraint -> ConstraintName
pgConstraintName FieldDefinition NotNull ConstraintName
constraintNameField
    SqlMarshaller
  PgConstraint
  (Oid
   -> ConstraintType
   -> Oid
   -> Oid
   -> Maybe [AttributeNumber]
   -> Oid
   -> Maybe [AttributeNumber]
   -> Maybe ForeignKeyAction
   -> Maybe ForeignKeyAction
   -> PgConstraint)
-> SqlMarshaller PgConstraint Oid
-> SqlMarshaller
     PgConstraint
     (ConstraintType
      -> Oid
      -> Oid
      -> Maybe [AttributeNumber]
      -> Oid
      -> Maybe [AttributeNumber]
      -> Maybe ForeignKeyAction
      -> Maybe ForeignKeyAction
      -> PgConstraint)
forall a b.
SqlMarshaller PgConstraint (a -> b)
-> SqlMarshaller PgConstraint a -> SqlMarshaller PgConstraint b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (PgConstraint -> Oid)
-> FieldDefinition NotNull Oid -> SqlMarshaller PgConstraint Oid
forall writeEntity fieldValue nullability.
(writeEntity -> fieldValue)
-> FieldDefinition nullability fieldValue
-> SqlMarshaller writeEntity fieldValue
Orville.marshallField PgConstraint -> Oid
pgConstraintNamespaceOid FieldDefinition NotNull Oid
constraintNamespaceOidField
    SqlMarshaller
  PgConstraint
  (ConstraintType
   -> Oid
   -> Oid
   -> Maybe [AttributeNumber]
   -> Oid
   -> Maybe [AttributeNumber]
   -> Maybe ForeignKeyAction
   -> Maybe ForeignKeyAction
   -> PgConstraint)
-> SqlMarshaller PgConstraint ConstraintType
-> SqlMarshaller
     PgConstraint
     (Oid
      -> Oid
      -> Maybe [AttributeNumber]
      -> Oid
      -> Maybe [AttributeNumber]
      -> Maybe ForeignKeyAction
      -> Maybe ForeignKeyAction
      -> PgConstraint)
forall a b.
SqlMarshaller PgConstraint (a -> b)
-> SqlMarshaller PgConstraint a -> SqlMarshaller PgConstraint b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (PgConstraint -> ConstraintType)
-> FieldDefinition NotNull ConstraintType
-> SqlMarshaller PgConstraint ConstraintType
forall writeEntity fieldValue nullability.
(writeEntity -> fieldValue)
-> FieldDefinition nullability fieldValue
-> SqlMarshaller writeEntity fieldValue
Orville.marshallField PgConstraint -> ConstraintType
pgConstraintType FieldDefinition NotNull ConstraintType
constraintTypeField
    SqlMarshaller
  PgConstraint
  (Oid
   -> Oid
   -> Maybe [AttributeNumber]
   -> Oid
   -> Maybe [AttributeNumber]
   -> Maybe ForeignKeyAction
   -> Maybe ForeignKeyAction
   -> PgConstraint)
-> SqlMarshaller PgConstraint Oid
-> SqlMarshaller
     PgConstraint
     (Oid
      -> Maybe [AttributeNumber]
      -> Oid
      -> Maybe [AttributeNumber]
      -> Maybe ForeignKeyAction
      -> Maybe ForeignKeyAction
      -> PgConstraint)
forall a b.
SqlMarshaller PgConstraint (a -> b)
-> SqlMarshaller PgConstraint a -> SqlMarshaller PgConstraint b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (PgConstraint -> Oid)
-> FieldDefinition NotNull Oid -> SqlMarshaller PgConstraint Oid
forall writeEntity fieldValue nullability.
(writeEntity -> fieldValue)
-> FieldDefinition nullability fieldValue
-> SqlMarshaller writeEntity fieldValue
Orville.marshallField PgConstraint -> Oid
pgConstraintRelationOid FieldDefinition NotNull Oid
constraintRelationOidField
    SqlMarshaller
  PgConstraint
  (Oid
   -> Maybe [AttributeNumber]
   -> Oid
   -> Maybe [AttributeNumber]
   -> Maybe ForeignKeyAction
   -> Maybe ForeignKeyAction
   -> PgConstraint)
-> SqlMarshaller PgConstraint Oid
-> SqlMarshaller
     PgConstraint
     (Maybe [AttributeNumber]
      -> Oid
      -> Maybe [AttributeNumber]
      -> Maybe ForeignKeyAction
      -> Maybe ForeignKeyAction
      -> PgConstraint)
forall a b.
SqlMarshaller PgConstraint (a -> b)
-> SqlMarshaller PgConstraint a -> SqlMarshaller PgConstraint b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (PgConstraint -> Oid)
-> FieldDefinition NotNull Oid -> SqlMarshaller PgConstraint Oid
forall writeEntity fieldValue nullability.
(writeEntity -> fieldValue)
-> FieldDefinition nullability fieldValue
-> SqlMarshaller writeEntity fieldValue
Orville.marshallField PgConstraint -> Oid
pgConstraintIndexOid FieldDefinition NotNull Oid
constraintIndexOidField
    SqlMarshaller
  PgConstraint
  (Maybe [AttributeNumber]
   -> Oid
   -> Maybe [AttributeNumber]
   -> Maybe ForeignKeyAction
   -> Maybe ForeignKeyAction
   -> PgConstraint)
-> SqlMarshaller PgConstraint (Maybe [AttributeNumber])
-> SqlMarshaller
     PgConstraint
     (Oid
      -> Maybe [AttributeNumber]
      -> Maybe ForeignKeyAction
      -> Maybe ForeignKeyAction
      -> PgConstraint)
forall a b.
SqlMarshaller PgConstraint (a -> b)
-> SqlMarshaller PgConstraint a -> SqlMarshaller PgConstraint b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (PgConstraint -> Maybe [AttributeNumber])
-> FieldDefinition Nullable (Maybe [AttributeNumber])
-> SqlMarshaller PgConstraint (Maybe [AttributeNumber])
forall writeEntity fieldValue nullability.
(writeEntity -> fieldValue)
-> FieldDefinition nullability fieldValue
-> SqlMarshaller writeEntity fieldValue
Orville.marshallField PgConstraint -> Maybe [AttributeNumber]
pgConstraintKey FieldDefinition Nullable (Maybe [AttributeNumber])
constraintKeyField
    SqlMarshaller
  PgConstraint
  (Oid
   -> Maybe [AttributeNumber]
   -> Maybe ForeignKeyAction
   -> Maybe ForeignKeyAction
   -> PgConstraint)
-> SqlMarshaller PgConstraint Oid
-> SqlMarshaller
     PgConstraint
     (Maybe [AttributeNumber]
      -> Maybe ForeignKeyAction
      -> Maybe ForeignKeyAction
      -> PgConstraint)
forall a b.
SqlMarshaller PgConstraint (a -> b)
-> SqlMarshaller PgConstraint a -> SqlMarshaller PgConstraint b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (PgConstraint -> Oid)
-> FieldDefinition NotNull Oid -> SqlMarshaller PgConstraint Oid
forall writeEntity fieldValue nullability.
(writeEntity -> fieldValue)
-> FieldDefinition nullability fieldValue
-> SqlMarshaller writeEntity fieldValue
Orville.marshallField PgConstraint -> Oid
pgConstraintForeignRelationOid FieldDefinition NotNull Oid
constraintForeignRelationOidField
    SqlMarshaller
  PgConstraint
  (Maybe [AttributeNumber]
   -> Maybe ForeignKeyAction
   -> Maybe ForeignKeyAction
   -> PgConstraint)
-> SqlMarshaller PgConstraint (Maybe [AttributeNumber])
-> SqlMarshaller
     PgConstraint
     (Maybe ForeignKeyAction -> Maybe ForeignKeyAction -> PgConstraint)
forall a b.
SqlMarshaller PgConstraint (a -> b)
-> SqlMarshaller PgConstraint a -> SqlMarshaller PgConstraint b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (PgConstraint -> Maybe [AttributeNumber])
-> FieldDefinition Nullable (Maybe [AttributeNumber])
-> SqlMarshaller PgConstraint (Maybe [AttributeNumber])
forall writeEntity fieldValue nullability.
(writeEntity -> fieldValue)
-> FieldDefinition nullability fieldValue
-> SqlMarshaller writeEntity fieldValue
Orville.marshallField PgConstraint -> Maybe [AttributeNumber]
pgConstraintForeignKey FieldDefinition Nullable (Maybe [AttributeNumber])
constraintForeignKeyField
    SqlMarshaller
  PgConstraint
  (Maybe ForeignKeyAction -> Maybe ForeignKeyAction -> PgConstraint)
-> SqlMarshaller PgConstraint (Maybe ForeignKeyAction)
-> SqlMarshaller
     PgConstraint (Maybe ForeignKeyAction -> PgConstraint)
forall a b.
SqlMarshaller PgConstraint (a -> b)
-> SqlMarshaller PgConstraint a -> SqlMarshaller PgConstraint b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (PgConstraint -> Maybe ForeignKeyAction)
-> FieldDefinition NotNull (Maybe ForeignKeyAction)
-> SqlMarshaller PgConstraint (Maybe ForeignKeyAction)
forall writeEntity fieldValue nullability.
(writeEntity -> fieldValue)
-> FieldDefinition nullability fieldValue
-> SqlMarshaller writeEntity fieldValue
Orville.marshallField PgConstraint -> Maybe ForeignKeyAction
pgConstraintForeignKeyOnUpdateType FieldDefinition NotNull (Maybe ForeignKeyAction)
constraintForeignKeyOnUpdateTypeField
    SqlMarshaller PgConstraint (Maybe ForeignKeyAction -> PgConstraint)
-> SqlMarshaller PgConstraint (Maybe ForeignKeyAction)
-> SqlMarshaller PgConstraint PgConstraint
forall a b.
SqlMarshaller PgConstraint (a -> b)
-> SqlMarshaller PgConstraint a -> SqlMarshaller PgConstraint b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (PgConstraint -> Maybe ForeignKeyAction)
-> FieldDefinition NotNull (Maybe ForeignKeyAction)
-> SqlMarshaller PgConstraint (Maybe ForeignKeyAction)
forall writeEntity fieldValue nullability.
(writeEntity -> fieldValue)
-> FieldDefinition nullability fieldValue
-> SqlMarshaller writeEntity fieldValue
Orville.marshallField PgConstraint -> Maybe ForeignKeyAction
pgConstraintForeignKeyOnDeleteType FieldDefinition NotNull (Maybe ForeignKeyAction)
constraintForeignKeyOnDeleteTypeField

{- |
  The @conname@ column of the @pg_constraint@ table.

@since 1.0.0.0
-}
constraintNameField :: Orville.FieldDefinition Orville.NotNull ConstraintName
constraintNameField :: FieldDefinition NotNull ConstraintName
constraintNameField =
  FieldDefinition NotNull Text
-> FieldDefinition NotNull ConstraintName
forall a b nullability.
(Coercible a b, Coercible b a) =>
FieldDefinition nullability a -> FieldDefinition nullability b
Orville.coerceField (FieldDefinition NotNull Text
 -> FieldDefinition NotNull ConstraintName)
-> FieldDefinition NotNull Text
-> FieldDefinition NotNull ConstraintName
forall a b. (a -> b) -> a -> b
$
    String -> FieldDefinition NotNull Text
Orville.unboundedTextField String
"conname"

{- |
  The @connamespace@ column of the @pg_constraint@ table.

@since 1.0.0.0
-}
constraintNamespaceOidField :: Orville.FieldDefinition Orville.NotNull LibPQ.Oid
constraintNamespaceOidField :: FieldDefinition NotNull Oid
constraintNamespaceOidField =
  String -> FieldDefinition NotNull Oid
oidTypeField String
"connamespace"

{- |
  The @contype@ column of the @pg_constraint@ table.

@since 1.0.0.0
-}
constraintTypeField :: Orville.FieldDefinition Orville.NotNull ConstraintType
constraintTypeField :: FieldDefinition NotNull ConstraintType
constraintTypeField =
  (SqlType Text -> SqlType ConstraintType)
-> FieldDefinition NotNull Text
-> FieldDefinition NotNull ConstraintType
forall a b nullability.
(SqlType a -> SqlType b)
-> FieldDefinition nullability a -> FieldDefinition nullability b
Orville.convertField
    ((ConstraintType -> Text)
-> (Text -> Either String ConstraintType)
-> SqlType Text
-> SqlType ConstraintType
forall b a.
(b -> a) -> (a -> Either String b) -> SqlType a -> SqlType b
Orville.tryConvertSqlType ConstraintType -> Text
constraintTypeToPgText Text -> Either String ConstraintType
pgTextToConstraintType)
    (String -> FieldDefinition NotNull Text
Orville.unboundedTextField String
"contype")

{- |
  The @conrelid@ column of the @pg_constraint@ table.

@since 1.0.0.0
-}
constraintRelationOidField :: Orville.FieldDefinition Orville.NotNull LibPQ.Oid
constraintRelationOidField :: FieldDefinition NotNull Oid
constraintRelationOidField =
  String -> FieldDefinition NotNull Oid
oidTypeField String
"conrelid"

{- |
  The @conindid@ column of the @pg_constraint@ table.

@since 1.0.0.0
-}
constraintIndexOidField :: Orville.FieldDefinition Orville.NotNull LibPQ.Oid
constraintIndexOidField :: FieldDefinition NotNull Oid
constraintIndexOidField =
  String -> FieldDefinition NotNull Oid
oidTypeField String
"conindid"

{- |
  The @conkey@ column of the @pg_constraint@ table.

@since 1.0.0.0
-}
constraintKeyField :: Orville.FieldDefinition Orville.Nullable (Maybe [AttributeNumber])
constraintKeyField :: FieldDefinition Nullable (Maybe [AttributeNumber])
constraintKeyField =
  FieldDefinition NotNull [AttributeNumber]
-> FieldDefinition Nullable (Maybe [AttributeNumber])
forall a.
FieldDefinition NotNull a -> FieldDefinition Nullable (Maybe a)
Orville.nullableField (FieldDefinition NotNull [AttributeNumber]
 -> FieldDefinition Nullable (Maybe [AttributeNumber]))
-> FieldDefinition NotNull [AttributeNumber]
-> FieldDefinition Nullable (Maybe [AttributeNumber])
forall a b. (a -> b) -> a -> b
$
    (SqlType Text -> SqlType [AttributeNumber])
-> FieldDefinition NotNull Text
-> FieldDefinition NotNull [AttributeNumber]
forall a b nullability.
(SqlType a -> SqlType b)
-> FieldDefinition nullability a -> FieldDefinition nullability b
Orville.convertField
      (([AttributeNumber] -> Text)
-> (Text -> Either String [AttributeNumber])
-> SqlType Text
-> SqlType [AttributeNumber]
forall b a.
(b -> a) -> (a -> Either String b) -> SqlType a -> SqlType b
Orville.tryConvertSqlType [AttributeNumber] -> Text
attributeNumberListToPgArrayText Text -> Either String [AttributeNumber]
pgArrayTextToAttributeNumberList)
      (String -> FieldDefinition NotNull Text
Orville.unboundedTextField String
"conkey")

{- |
  The @confrelid@ column of the @pg_constraint@ table.

@since 1.0.0.0
-}
constraintForeignRelationOidField :: Orville.FieldDefinition Orville.NotNull LibPQ.Oid
constraintForeignRelationOidField :: FieldDefinition NotNull Oid
constraintForeignRelationOidField =
  String -> FieldDefinition NotNull Oid
oidTypeField String
"confrelid"

{- |
  The @confkey@ column of the @pg_constraint@ table.

@since 1.0.0.0
-}
constraintForeignKeyField :: Orville.FieldDefinition Orville.Nullable (Maybe [AttributeNumber])
constraintForeignKeyField :: FieldDefinition Nullable (Maybe [AttributeNumber])
constraintForeignKeyField =
  FieldDefinition NotNull [AttributeNumber]
-> FieldDefinition Nullable (Maybe [AttributeNumber])
forall a.
FieldDefinition NotNull a -> FieldDefinition Nullable (Maybe a)
Orville.nullableField (FieldDefinition NotNull [AttributeNumber]
 -> FieldDefinition Nullable (Maybe [AttributeNumber]))
-> FieldDefinition NotNull [AttributeNumber]
-> FieldDefinition Nullable (Maybe [AttributeNumber])
forall a b. (a -> b) -> a -> b
$
    (SqlType Text -> SqlType [AttributeNumber])
-> FieldDefinition NotNull Text
-> FieldDefinition NotNull [AttributeNumber]
forall a b nullability.
(SqlType a -> SqlType b)
-> FieldDefinition nullability a -> FieldDefinition nullability b
Orville.convertField
      (([AttributeNumber] -> Text)
-> (Text -> Either String [AttributeNumber])
-> SqlType Text
-> SqlType [AttributeNumber]
forall b a.
(b -> a) -> (a -> Either String b) -> SqlType a -> SqlType b
Orville.tryConvertSqlType [AttributeNumber] -> Text
attributeNumberListToPgArrayText Text -> Either String [AttributeNumber]
pgArrayTextToAttributeNumberList)
      (String -> FieldDefinition NotNull Text
Orville.unboundedTextField String
"confkey")

constraintForeignKeyOnUpdateTypeField :: Orville.FieldDefinition Orville.NotNull (Maybe Orville.ForeignKeyAction)
constraintForeignKeyOnUpdateTypeField :: FieldDefinition NotNull (Maybe ForeignKeyAction)
constraintForeignKeyOnUpdateTypeField =
  (SqlType Text -> SqlType (Maybe ForeignKeyAction))
-> FieldDefinition NotNull Text
-> FieldDefinition NotNull (Maybe ForeignKeyAction)
forall a b nullability.
(SqlType a -> SqlType b)
-> FieldDefinition nullability a -> FieldDefinition nullability b
Orville.convertField
    ((Maybe ForeignKeyAction -> Text)
-> (Text -> Either String (Maybe ForeignKeyAction))
-> SqlType Text
-> SqlType (Maybe ForeignKeyAction)
forall b a.
(b -> a) -> (a -> Either String b) -> SqlType a -> SqlType b
Orville.tryConvertSqlType Maybe ForeignKeyAction -> Text
foreignKeyActionToPgText Text -> Either String (Maybe ForeignKeyAction)
pgTextToForeignKeyAction)
    (String -> FieldDefinition NotNull Text
Orville.unboundedTextField String
"confupdtype")

constraintForeignKeyOnDeleteTypeField :: Orville.FieldDefinition Orville.NotNull (Maybe Orville.ForeignKeyAction)
constraintForeignKeyOnDeleteTypeField :: FieldDefinition NotNull (Maybe ForeignKeyAction)
constraintForeignKeyOnDeleteTypeField =
  (SqlType Text -> SqlType (Maybe ForeignKeyAction))
-> FieldDefinition NotNull Text
-> FieldDefinition NotNull (Maybe ForeignKeyAction)
forall a b nullability.
(SqlType a -> SqlType b)
-> FieldDefinition nullability a -> FieldDefinition nullability b
Orville.convertField
    ((Maybe ForeignKeyAction -> Text)
-> (Text -> Either String (Maybe ForeignKeyAction))
-> SqlType Text
-> SqlType (Maybe ForeignKeyAction)
forall b a.
(b -> a) -> (a -> Either String b) -> SqlType a -> SqlType b
Orville.tryConvertSqlType Maybe ForeignKeyAction -> Text
foreignKeyActionToPgText Text -> Either String (Maybe ForeignKeyAction)
pgTextToForeignKeyAction)
    (String -> FieldDefinition NotNull Text
Orville.unboundedTextField String
"confdeltype")

pgArrayTextToAttributeNumberList :: T.Text -> Either String [AttributeNumber]
pgArrayTextToAttributeNumberList :: Text -> Either String [AttributeNumber]
pgArrayTextToAttributeNumberList Text
text =
  let
    parser :: Parser Text [AttributeNumber]
parser = do
      Char
_ <- Char -> Parser Char
AttoText.char Char
'{'
      [AttributeNumber]
attNums <- Parser Text AttributeNumber
-> Parser Char -> Parser Text [AttributeNumber]
forall (f :: * -> *) a s. Alternative f => f a -> f s -> f [a]
AttoText.sepBy Parser Text AttributeNumber
attributeNumberParser (Char -> Parser Char
AttoText.char Char
',')
      Char
_ <- Char -> Parser Char
AttoText.char Char
'}'
      Parser Text ()
forall t. Chunk t => Parser t ()
AttoText.endOfInput
      [AttributeNumber] -> Parser Text [AttributeNumber]
forall a. a -> Parser Text a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [AttributeNumber]
attNums
  in
    case Parser Text [AttributeNumber]
-> Text -> Either String [AttributeNumber]
forall a. Parser a -> Text -> Either String a
AttoText.parseOnly Parser Text [AttributeNumber]
parser Text
text of
      Left String
err -> String -> Either String [AttributeNumber]
forall a b. a -> Either a b
Left (String
"Unable to decode PostgreSQL Array as AttributeNumber list: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
err)
      Right [AttributeNumber]
nums -> [AttributeNumber] -> Either String [AttributeNumber]
forall a b. b -> Either a b
Right [AttributeNumber]
nums

attributeNumberListToPgArrayText :: [AttributeNumber] -> T.Text
attributeNumberListToPgArrayText :: [AttributeNumber] -> Text
attributeNumberListToPgArrayText [AttributeNumber]
attNums =
  let
    commaDelimitedAttributeNumbers :: Builder
commaDelimitedAttributeNumbers =
      [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ([Builder] -> Builder) -> [Builder] -> Builder
forall a b. (a -> b) -> a -> b
$
        Builder -> [Builder] -> [Builder]
forall a. a -> [a] -> [a]
List.intersperse (Char -> Builder
LTB.singleton Char
',') ((AttributeNumber -> Builder) -> [AttributeNumber] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map AttributeNumber -> Builder
attributeNumberTextBuilder [AttributeNumber]
attNums)
  in
    Text -> Text
LT.toStrict (Text -> Text) -> (Builder -> Text) -> Builder -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> Text
LTB.toLazyText (Builder -> Text) -> Builder -> Text
forall a b. (a -> b) -> a -> b
$
      Char -> Builder
LTB.singleton Char
'{' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
commaDelimitedAttributeNumbers Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
LTB.singleton Char
'}'