content: {-|
  Module: IHP.IDE.SchemaDesigner.Types
  Description: Types for representing an AST of SQL DDL
  Copyright: (c) digitally induced GmbH, 2020
  -}
  module IHP.IDE.SchemaDesigner.Types where
  
  import IHP.Prelude
  
  data Statement
      =
      -- | CREATE TABLE name ( columns );
        StatementCreateTable { unsafeGetCreateTable :: CreateTable }
      -- | CREATE TYPE name AS ENUM ( values );
      | CreateEnumType { name :: Text, values :: [Text] }
      -- | DROP TYPE name;
      | DropEnumType { name :: Text }
      -- | CREATE EXTENSION IF NOT EXISTS "name";
      | CreateExtension { name :: Text, ifNotExists :: Bool }
      -- | ALTER TABLE tableName ADD CONSTRAINT constraint;
      | AddConstraint { tableName :: Text, constraint :: Constraint, deferrable :: Maybe Bool, deferrableType :: Maybe DeferrableType }
      -- | ALTER TABLE tableName DROP CONSTRAINT constraintName;
      | DropConstraint { tableName, constraintName :: Text }
      -- | ALTER TABLE tableName ADD COLUMN column;
      | AddColumn { tableName :: Text, column :: Column }
      -- | ALTER TABLE tableName DROP COLUMN columnName;
      | DropColumn { tableName :: Text, columnName :: Text }
      -- | DROP TABLE tableName;
      | DropTable { tableName :: Text }
      | UnknownStatement { raw :: Text }
      | Comment { content :: Text }
      -- | CREATE INDEX indexName ON tableName (columnName); CREATE INDEX indexName ON tableName (LOWER(columnName));
      -- | CREATE UNIQUE INDEX name ON table (column [, ...]);
      | CreateIndex { indexName :: Text, unique :: Bool, tableName :: Text, columns :: [IndexColumn], whereClause :: Maybe Expression, indexType :: Maybe IndexType }
      -- | DROP INDEX indexName;
      | DropIndex { indexName :: Text }
      -- | CREATE OR REPLACE FUNCTION functionName(param1 TEXT, param2 INT) RETURNS TRIGGER AS $$functionBody$$ language plpgsql;
      | CreateFunction { functionName :: Text, functionArguments :: [(Text, PostgresType)], functionBody :: Text, orReplace :: Bool, returns :: PostgresType, language :: Text }
      -- | ALTER TABLE tableName ENABLE ROW LEVEL SECURITY;
      | EnableRowLevelSecurity { tableName :: Text }
      -- CREATE POLICY name ON tableName USING using WITH CHECK check;
      | CreatePolicy { name :: Text, tableName :: Text, action :: Maybe PolicyAction, using :: Maybe Expression, check :: Maybe Expression }
      -- SET name = value;
      | Set { name :: Text, value :: Expression }
      -- SELECT query;
      | SelectStatement { query :: Text }
      -- CREATE SEQUENCE name;
      | CreateSequence { name :: Text }
      -- ALTER TABLE tableName RENAME COLUMN from TO to;
      | RenameColumn { tableName :: Text, from :: Text, to :: Text }
      -- ALTER TYPE enumName ADD VALUE newValue;
      | AddValueToEnumType { enumName :: Text, newValue :: Text, ifNotExists :: Bool }
      -- ALTER TABLE tableName ALTER COLUMN columnName DROP NOT NULL;
      | DropNotNull { tableName :: Text, columnName :: Text }
      -- ALTER TABLE tableName ALTER COLUMN columnName SET NOT NULL;
      | SetNotNull { tableName :: Text, columnName :: Text }
      -- | ALTER TABLE from RENAME TO to;
      | RenameTable { from :: Text, to :: Text }
      -- | DROP POLICY policyName ON tableName;
      | DropPolicy { tableName :: Text, policyName :: Text }
      -- ALTER TABLE tableName ALTER COLUMN columnName SET DEFAULT 'value';
      | SetDefaultValue { tableName :: Text, columnName :: Text, value :: Expression }
      -- ALTER TABLE tableName ALTER COLUMN columnName DROP DEFAULT;
      | DropDefaultValue { tableName :: Text, columnName :: Text }
      -- | CREATE TRIGGER ..;
      | CreateTrigger { name :: !Text, eventWhen :: !TriggerEventWhen, event :: !TriggerEvent, tableName :: !Text, for :: !TriggerFor, whenCondition :: Maybe Expression, functionName :: !Text, arguments :: ![Expression] }
      -- | CREATE EVENT TRIGGER ..;
      | CreateEventTrigger { name :: !Text, eventOn :: !Text, whenCondition :: Maybe Expression, functionName :: !Text, arguments :: ![Expression] }
      -- | DROP TRIGGER .. ON ..;
      | DropTrigger { name :: !Text, tableName :: !Text }
      -- | DROP EVENT TRIGGER ..;
      | DropEventTrigger { name :: !Text }
      -- | BEGIN;
      | Begin
      -- | COMMIT;
      | Commit
      | DropFunction { functionName :: !Text }
      deriving (Eq, Show)
  
  data DeferrableType
      = InitiallyImmediate
      | InitiallyDeferred
      deriving (Eq, Show)
  
  data CreateTable
    = CreateTable
        { name :: Text
        , columns :: [Column]
        , primaryKeyConstraint :: PrimaryKeyConstraint
        , constraints :: [Constraint]
        , unlogged :: !Bool
        }
    deriving (Eq, Show)
  
  data Column = Column
      { name :: Text
      , columnType :: PostgresType
      , defaultValue :: Maybe Expression
      , notNull :: Bool
      , isUnique :: Bool
      , generator :: Maybe ColumnGenerator
      }
      deriving (Eq, Show)
  
  data OnDelete
      = NoAction
      | Restrict
      | SetNull
      | SetDefault
      | Cascade
      deriving (Show, Eq)
  
  data ColumnGenerator
      = ColumnGenerator
      { generate :: !Expression
      , stored :: !Bool
      } deriving (Show, Eq)
  
  newtype PrimaryKeyConstraint
    = PrimaryKeyConstraint { primaryKeyColumnNames :: [Text] }
    deriving (Eq, Show)
  
  data Constraint
      -- | FOREIGN KEY (columnName) REFERENCES referenceTable (referenceColumn) ON DELETE onDelete;
      = ForeignKeyConstraint
          { name :: !(Maybe Text)
          , columnName :: !Text
          , referenceTable :: !Text
          , referenceColumn :: !(Maybe Text)
          , onDelete :: !(Maybe OnDelete)
          }
      | UniqueConstraint
          { name :: !(Maybe Text)
          , columnNames :: ![Text]
          }
      | CheckConstraint
          { name :: !(Maybe Text)
          , checkExpression :: !Expression
          }
      | ExcludeConstraint
          { name :: !(Maybe Text)
          , excludeElements :: ![ExcludeConstraintElement]
          , predicate :: !(Maybe Expression)
          , indexType :: !(Maybe IndexType)
          }
      | AlterTableAddPrimaryKey
          { name :: !(Maybe Text)
          , primaryKeyConstraint :: !PrimaryKeyConstraint
          }
      deriving (Eq, Show)
  
  data ExcludeConstraintElement = ExcludeConstraintElement { element :: !Text, operator :: !Text }
      deriving (Eq, Show)
  
  data Expression =
      -- | Sql string like @'hello'@
      TextExpression Text
      -- | Simple variable like @users@
      | VarExpression Text
      -- | Simple call, like @COALESCE(name, 'unknown name')@
      | CallExpression Text [Expression]
      -- | Not equal operator, a <> b
      | NotEqExpression Expression Expression
      -- | Equal operator, a = b
      | EqExpression Expression Expression
      -- | a AND b
      | AndExpression Expression Expression
      -- | a IS b
      | IsExpression Expression Expression
      -- | a IN b
      | InExpression Expression Expression
      -- | ('a', 'b')
      | InArrayExpression [Expression]
      -- | NOT a
      | NotExpression Expression
      -- | EXISTS a
      | ExistsExpression Expression
      -- | a OR b
      | OrExpression Expression Expression
      -- | a < b
      | LessThanExpression Expression Expression
      -- | a <= b
      | LessThanOrEqualToExpression Expression Expression
      -- | a > b
      | GreaterThanExpression Expression Expression
      -- | a >= b
      | GreaterThanOrEqualToExpression Expression Expression
      -- | Double literal value, e.g. 0.1337
      | DoubleExpression Double
      -- | Integer literal value, e.g. 1337
      | IntExpression Int
      -- | value::type
      | TypeCastExpression Expression PostgresType
      | SelectExpression Select
      | DotExpression Expression Text
      | ConcatenationExpression Expression Expression -- ^ a || b
      deriving (Eq, Show)
  
  data Select = Select
      { columns :: [Expression]
      , from :: Expression
      , alias :: Maybe Text
      , whereClause :: Expression
      } deriving (Eq, Show)
  
  data PostgresType
      = PUUID
      | PText
      | PInt
      | PSmallInt
      | PBigInt
      | PBoolean
      | PTimestampWithTimezone
      | PTimestamp
      | PReal
      | PDouble
      | PPoint
      | PPolygon
      | PDate
      | PBinary
      | PTime
      | PInterval { fields :: Maybe Text }
      | PNumeric { precision :: Maybe Int, scale :: Maybe Int }
      | PVaryingN (Maybe Int)
      | PCharacterN Int
      | PSingleChar
      | PSerial
      | PBigserial
      | PJSONB
      | PInet
      | PTSVector
      | PArray PostgresType
      | PTrigger
      | PEventTrigger
      | PCustomType Text
      deriving (Eq, Show)
  
  data TriggerEventWhen
      = Before
      | After
      | InsteadOf
      deriving (Eq, Show)
  
  data TriggerEvent
      = TriggerOnInsert
      | TriggerOnUpdate
      | TriggerOnDelete
      | TriggerOnTruncate
      deriving (Eq, Show)
  
  data TriggerFor
      = ForEachRow
      | ForEachStatement
      deriving (Eq, Show)
  
  data PolicyAction
      = PolicyForAll
      | PolicyForSelect
      | PolicyForInsert
      | PolicyForUpdate
      | PolicyForDelete
      deriving (Eq, Show)
  
  data IndexType = Btree | Gin | Gist
      deriving (Eq, Show)
  
  data IndexColumn
      = IndexColumn { column :: Expression, columnOrder :: [IndexColumnOrder] }
      deriving (Eq, Show)
  
  data IndexColumnOrder
      = Asc | Desc | NullsFirst | NullsLast
      deriving (Eq, Show)
  