module IHP.IDE.SchemaDesigner.Controller.Columns where

import IHP.ControllerPrelude
import IHP.IDE.ToolServer.Types

import IHP.IDE.SchemaDesigner.View.Columns.New
import IHP.IDE.SchemaDesigner.View.Columns.Edit
import IHP.IDE.SchemaDesigner.View.Columns.NewForeignKey
import IHP.IDE.SchemaDesigner.View.Columns.EditForeignKey

import IHP.IDE.SchemaDesigner.Types
import IHP.IDE.SchemaDesigner.View.Layout (schemaDesignerLayout, findStatementByName, replace)
import IHP.IDE.SchemaDesigner.Controller.Helper
import IHP.IDE.SchemaDesigner.Controller.Validation


import qualified IHP.IDE.SchemaDesigner.SchemaOperations as SchemaOperations

instance Controller ColumnsController where
    beforeAction :: (?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::ColumnsController) =>
IO ()
beforeAction = (?context::ControllerContext) =>
((?context::ControllerContext) => Layout) -> IO ()
((?context::ControllerContext) => Layout) -> IO ()
setLayout (?context::ControllerContext) => Layout
Layout
Html -> Html
schemaDesignerLayout

    action :: (?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::ColumnsController) =>
ColumnsController -> IO ()
action NewColumnAction { Text
tableName :: Text
$sel:tableName:NewColumnAction :: ColumnsController -> Text
tableName } = do
        [Statement]
statements <- IO [Statement]
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
IO [Statement]
readSchema
        let (Just Statement
table) = Text -> [Statement] -> Maybe Statement
forall {t :: * -> *}.
Foldable t =>
Text -> t Statement -> Maybe Statement
findStatementByName Text
tableName [Statement]
statements
        let tableNames :: [Text]
tableNames = [CreateTable] -> [Text]
forall {a} {b}. HasField "name" a b => [a] -> [b]
nameList ([Statement] -> [CreateTable]
getCreateTable [Statement]
statements)
        let enumNames :: [Text]
enumNames = [Statement] -> [Text]
forall {a} {b}. HasField "name" a b => [a] -> [b]
nameList ([Statement] -> [Statement]
getCreateEnum [Statement]
statements)
        NewColumnView -> IO ()
forall view.
(View view, ?context::ControllerContext) =>
view -> IO ()
render NewColumnView { [Text]
[Statement]
Text
tableName :: Text
statements :: [Statement]
tableNames :: [Text]
enumNames :: [Text]
$sel:statements:NewColumnView :: [Statement]
$sel:tableName:NewColumnView :: Text
$sel:tableNames:NewColumnView :: [Text]
$sel:enumNames:NewColumnView :: [Text]
.. }

    action ColumnsController
CreateColumnAction = do
        let tableName :: Text
tableName = ByteString -> Text
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"tableName"
        let columnName :: Text
columnName = ByteString -> Text
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"name"
        let validationResult :: ValidatorResult
validationResult = Text
columnName Text -> (Text -> ValidatorResult) -> ValidatorResult
forall {t1} {t2}. t1 -> (t1 -> t2) -> t2
|> Text -> ValidatorResult
validateColumn
        case ValidatorResult
validationResult of
            Failure Text
message ->
                (?context::ControllerContext) => Text -> IO ()
Text -> IO ()
setErrorMessage Text
message
            ValidatorResult
Success -> do
                let options :: AddColumnOptions
options = SchemaOperations.AddColumnOptions
                        { Text
tableName :: Text
$sel:tableName:AddColumnOptions :: Text
tableName
                        , Text
columnName :: Text
$sel:columnName:AddColumnOptions :: Text
columnName
                        , $sel:columnType:AddColumnOptions :: PostgresType
columnType = ByteString -> PostgresType
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"columnType"
                        , $sel:defaultValue:AddColumnOptions :: Maybe Expression
defaultValue = ByteString -> Maybe Expression
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"defaultValue"
                        , $sel:isArray:AddColumnOptions :: Bool
isArray = ByteString -> Bool
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"isArray"
                        , $sel:allowNull:AddColumnOptions :: Bool
allowNull = ByteString -> Bool
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"allowNull"
                        , $sel:isUnique:AddColumnOptions :: Bool
isUnique = ByteString -> Bool
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"isUnique"
                        , $sel:isReference:AddColumnOptions :: Bool
isReference = ByteString -> Bool
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"isReference"
                        , $sel:referenceTable:AddColumnOptions :: Maybe Text
referenceTable = ByteString -> Maybe Text
forall paramType.
(?context::ControllerContext, ParamReader (Maybe paramType)) =>
ByteString -> Maybe paramType
paramOrNothing ByteString
"referenceTable"
                        , $sel:primaryKey:AddColumnOptions :: Bool
primaryKey = ByteString -> Bool
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"primaryKey"
                        , $sel:withIndex:AddColumnOptions :: Bool
withIndex = Bool -> ByteString -> Bool
forall a.
(?context::ControllerContext, ParamReader a) =>
a -> ByteString -> a
paramOrDefault Bool
False ByteString
"withIndex"
                        , $sel:autoPolicy:AddColumnOptions :: Bool
autoPolicy = Bool -> ByteString -> Bool
forall a.
(?context::ControllerContext, ParamReader a) =>
a -> ByteString -> a
paramOrDefault Bool
False ByteString
"autoPolicy"
                        }
                ([Statement] -> [Statement]) -> IO ()
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
([Statement] -> [Statement]) -> IO ()
updateSchema (([Statement] -> [Statement]) -> IO ())
-> ([Statement] -> [Statement]) -> IO ()
forall a b. (a -> b) -> a -> b
$ AddColumnOptions -> [Statement] -> [Statement]
SchemaOperations.addColumn AddColumnOptions
options

        TablesController -> IO ()
forall action.
(?context::ControllerContext, HasPath action) =>
action -> IO ()
redirectTo ShowTableAction { Text
tableName :: Text
$sel:tableName:TablesAction :: Text
.. }

    action EditColumnAction { Int
Text
$sel:tableName:NewColumnAction :: ColumnsController -> Text
tableName :: Text
columnId :: Int
$sel:columnId:NewColumnAction :: ColumnsController -> Int
.. } = do
        let columnId :: Int
columnId = ByteString -> Int
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"columnId"
        let name :: Text
name = Text
tableName
        [Statement]
statements <- IO [Statement]
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
IO [Statement]
readSchema
        let (Just Statement
table) = Text -> [Statement] -> Maybe Statement
forall {t :: * -> *}.
Foldable t =>
Text -> t Statement -> Maybe Statement
findStatementByName Text
name [Statement]
statements
        let table :: Maybe Statement
table = Text -> [Statement] -> Maybe Statement
forall {t :: * -> *}.
Foldable t =>
Text -> t Statement -> Maybe Statement
findStatementByName Text
tableName [Statement]
statements
        let columns :: [Column]
columns = [Column] -> (Statement -> [Column]) -> Maybe Statement -> [Column]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] ((.columns) (CreateTable -> [Column])
-> (Statement -> CreateTable) -> Statement -> [Column]
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Statement -> CreateTable
unsafeGetCreateTable) Maybe Statement
table
        let column :: Column
column = [Column]
columns [Column] -> Int -> Column
forall a. HasCallStack => [a] -> Int -> a
!! Int
columnId
        let enumNames :: [Text]
enumNames = [Statement] -> [Text]
forall {a} {b}. HasField "name" a b => [a] -> [b]
nameList ([Statement] -> [Statement]
getCreateEnum [Statement]
statements)
        EditColumnView -> IO ()
forall view.
(View view, ?context::ControllerContext) =>
view -> IO ()
render EditColumnView { Int
[Text]
[Statement]
Text
Column
tableName :: Text
columnId :: Int
statements :: [Statement]
column :: Column
enumNames :: [Text]
$sel:statements:EditColumnView :: [Statement]
$sel:tableName:EditColumnView :: Text
$sel:columnId:EditColumnView :: Int
$sel:column:EditColumnView :: Column
$sel:enumNames:EditColumnView :: [Text]
.. }

    action ColumnsController
UpdateColumnAction = do
        [Statement]
statements <- IO [Statement]
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
IO [Statement]
readSchema
        let tableName :: Text
tableName = ByteString -> Text
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"tableName"
        let columnName :: Text
columnName = ByteString -> Text
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"name"
        let validationResult :: ValidatorResult
validationResult = Text
columnName Text -> (Text -> ValidatorResult) -> ValidatorResult
forall {t1} {t2}. t1 -> (t1 -> t2) -> t2
|> Text -> ValidatorResult
validateColumn

        case ValidatorResult
validationResult of
            Failure Text
message ->
                (?context::ControllerContext) => Text -> IO ()
Text -> IO ()
setErrorMessage Text
message
            ValidatorResult
Success -> do
                let options :: UpdateColumnOptions
options = SchemaOperations.UpdateColumnOptions
                        { Text
tableName :: Text
$sel:tableName:UpdateColumnOptions :: Text
tableName
                        , Text
columnName :: Text
$sel:columnName:UpdateColumnOptions :: Text
columnName
                        , $sel:columnId:UpdateColumnOptions :: Int
columnId = ByteString -> Int
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"columnId"
                        , $sel:defaultValue:UpdateColumnOptions :: Maybe Expression
defaultValue = ByteString -> Maybe Expression
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"defaultValue"
                        , $sel:isArray:UpdateColumnOptions :: Bool
isArray = ByteString -> Bool
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"isArray"
                        , $sel:columnType:UpdateColumnOptions :: PostgresType
columnType = ByteString -> PostgresType
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"columnType"
                        , $sel:allowNull:UpdateColumnOptions :: Bool
allowNull = ByteString -> Bool
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"allowNull"
                        , $sel:isUnique:UpdateColumnOptions :: Bool
isUnique = ByteString -> Bool
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"isUnique"
                        , $sel:primaryKey:UpdateColumnOptions :: Bool
primaryKey = ByteString -> Bool
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"primaryKey"
                        }

                ([Statement] -> [Statement]) -> IO ()
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
([Statement] -> [Statement]) -> IO ()
updateSchema (([Statement] -> [Statement]) -> IO ())
-> ([Statement] -> [Statement]) -> IO ()
forall a b. (a -> b) -> a -> b
$ UpdateColumnOptions -> [Statement] -> [Statement]
SchemaOperations.updateColumn UpdateColumnOptions
options
        TablesController -> IO ()
forall action.
(?context::ControllerContext, HasPath action) =>
action -> IO ()
redirectTo ShowTableAction { Text
$sel:tableName:TablesAction :: Text
tableName :: Text
.. }

    action DeleteColumnAction { Int
Text
$sel:tableName:NewColumnAction :: ColumnsController -> Text
$sel:columnId:NewColumnAction :: ColumnsController -> Int
tableName :: Text
columnId :: Int
columnName :: Text
$sel:columnName:NewColumnAction :: ColumnsController -> Text
.. } = do
        [Statement]
statements <- IO [Statement]
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
IO [Statement]
readSchema
        let tableName :: Text
tableName = ByteString -> Text
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"tableName"
        let columnId :: Int
columnId = ByteString -> Int
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"columnId"
        let columnName :: Text
columnName = ByteString -> Text
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"columnName"

        let options :: DeleteColumnOptions
options = SchemaOperations.DeleteColumnOptions
                { Text
tableName :: Text
$sel:tableName:DeleteColumnOptions :: Text
tableName
                , Text
columnName :: Text
$sel:columnName:DeleteColumnOptions :: Text
columnName
                , Int
columnId :: Int
$sel:columnId:DeleteColumnOptions :: Int
columnId
                }

        ([Statement] -> [Statement]) -> IO ()
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
([Statement] -> [Statement]) -> IO ()
updateSchema (([Statement] -> [Statement]) -> IO ())
-> ([Statement] -> [Statement]) -> IO ()
forall a b. (a -> b) -> a -> b
$ DeleteColumnOptions -> [Statement] -> [Statement]
SchemaOperations.deleteColumn DeleteColumnOptions
options

        TablesController -> IO ()
forall action.
(?context::ControllerContext, HasPath action) =>
action -> IO ()
redirectTo ShowTableAction { Text
$sel:tableName:TablesAction :: Text
tableName :: Text
.. }

    action ToggleColumnUniqueAction { Int
Text
$sel:tableName:NewColumnAction :: ColumnsController -> Text
$sel:columnId:NewColumnAction :: ColumnsController -> Int
tableName :: Text
columnId :: Int
.. } = do
        let tableName :: Text
tableName = ByteString -> Text
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"tableName"
        let columnId :: Int
columnId = ByteString -> Int
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"columnId"
        ([Statement] -> [Statement]) -> IO ()
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
([Statement] -> [Statement]) -> IO ()
updateSchema ((Statement -> Statement) -> [Statement] -> [Statement]
forall a b. (a -> b) -> [a] -> [b]
map (Text -> Int -> Statement -> Statement
toggleUniqueInColumn Text
tableName Int
columnId))
        TablesController -> IO ()
forall action.
(?context::ControllerContext, HasPath action) =>
action -> IO ()
redirectTo ShowTableAction { Text
$sel:tableName:TablesAction :: Text
tableName :: Text
.. }

    -- FOREIGN KEYS
    action NewForeignKeyAction { Text
$sel:tableName:NewColumnAction :: ColumnsController -> Text
tableName :: Text
tableName, Text
$sel:columnName:NewColumnAction :: ColumnsController -> Text
columnName :: Text
columnName } = do
        let name :: Text
name = Text
tableName
        [Statement]
statements <- IO [Statement]
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
IO [Statement]
readSchema
        let tableNames :: [Text]
tableNames = [CreateTable] -> [Text]
forall {a} {b}. HasField "name" a b => [a] -> [b]
nameList ([Statement] -> [CreateTable]
getCreateTable [Statement]
statements)
        NewForeignKeyView -> IO ()
forall view.
(View view, ?context::ControllerContext) =>
view -> IO ()
render NewForeignKeyView { [Text]
[Statement]
Text
tableName :: Text
columnName :: Text
statements :: [Statement]
tableNames :: [Text]
$sel:statements:NewForeignKeyView :: [Statement]
$sel:tableName:NewForeignKeyView :: Text
$sel:columnName:NewForeignKeyView :: Text
$sel:tableNames:NewForeignKeyView :: [Text]
.. }

    action ColumnsController
CreateForeignKeyAction = do
        let tableName :: Text
tableName = ByteString -> Text
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"tableName"
        let columnName :: Text
columnName = ByteString -> Text
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"columnName"
        let constraintName :: Text
constraintName = ByteString -> Text
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"constraintName"
        let referenceTable :: Text
referenceTable = ByteString -> Text
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"referenceTable"
        let onDelete :: OnDelete
onDelete = OnDelete
NoAction
        ([Statement] -> [Statement]) -> IO ()
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
([Statement] -> [Statement]) -> IO ()
updateSchema (Text
-> Text -> Text -> Text -> OnDelete -> [Statement] -> [Statement]
SchemaOperations.addForeignKeyConstraint Text
tableName Text
columnName Text
constraintName Text
referenceTable OnDelete
onDelete)
        TablesController -> IO ()
forall action.
(?context::ControllerContext, HasPath action) =>
action -> IO ()
redirectTo ShowTableAction { Text
$sel:tableName:TablesAction :: Text
tableName :: Text
.. }

    action EditForeignKeyAction { Text
$sel:tableName:NewColumnAction :: ColumnsController -> Text
tableName :: Text
tableName, Text
$sel:columnName:NewColumnAction :: ColumnsController -> Text
columnName :: Text
columnName, Text
constraintName :: Text
$sel:constraintName:NewColumnAction :: ColumnsController -> Text
constraintName, Text
referenceTable :: Text
$sel:referenceTable:NewColumnAction :: ColumnsController -> Text
referenceTable } = do
        let name :: Text
name = Text
tableName
        [Statement]
statements <- IO [Statement]
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
IO [Statement]
readSchema
        let tableNames :: [Text]
tableNames = [CreateTable] -> [Text]
forall {a} {b}. HasField "name" a b => [a] -> [b]
nameList ([Statement] -> [CreateTable]
getCreateTable [Statement]
statements)
        let (Just Statement
statement) = (Statement -> Bool) -> [Statement] -> Maybe Statement
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find (\Statement
statement -> Statement
statement Statement -> Statement -> Bool
forall a. Eq a => a -> a -> Bool
== AddConstraint { $sel:tableName:StatementCreateTable :: Text
tableName = Text
tableName, $sel:deferrable:StatementCreateTable :: Maybe Bool
deferrable = Maybe Bool
forall a. Maybe a
Nothing, $sel:deferrableType:StatementCreateTable :: Maybe DeferrableType
deferrableType = Maybe DeferrableType
forall a. Maybe a
Nothing, $sel:constraint:StatementCreateTable :: Constraint
constraint = ForeignKeyConstraint { $sel:name:ForeignKeyConstraint :: Maybe Text
name = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
constraintName, $sel:columnName:ForeignKeyConstraint :: Text
columnName = Text
columnName, $sel:referenceTable:ForeignKeyConstraint :: Text
referenceTable = Text
referenceTable, $sel:referenceColumn:ForeignKeyConstraint :: Maybe Text
referenceColumn = Maybe Text
"id", $sel:onDelete:ForeignKeyConstraint :: Maybe OnDelete
onDelete = Statement
statement.constraint.onDelete }}) [Statement]
statements
        Text
onDelete <- case Statement
statement.constraint.onDelete of
            Just OnDelete
NoAction -> do Text -> IO Text
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Text
"NoAction"
            Just OnDelete
Restrict -> do Text -> IO Text
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Text
"Restrict"
            Just OnDelete
SetNull -> do Text -> IO Text
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Text
"SetNull"
            Just OnDelete
SetDefault -> do Text -> IO Text
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Text
"SetDefault"
            Just OnDelete
Cascade -> do Text -> IO Text
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Text
"Cascade"
            Maybe OnDelete
Nothing -> do Text -> IO Text
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Text
"NoAction"
        EditForeignKeyView -> IO ()
forall view.
(View view, ?context::ControllerContext) =>
view -> IO ()
render EditForeignKeyView { [Text]
[Statement]
Text
tableName :: Text
columnName :: Text
constraintName :: Text
referenceTable :: Text
statements :: [Statement]
tableNames :: [Text]
onDelete :: Text
$sel:statements:EditForeignKeyView :: [Statement]
$sel:tableName:EditForeignKeyView :: Text
$sel:columnName:EditForeignKeyView :: Text
$sel:tableNames:EditForeignKeyView :: [Text]
$sel:referenceTable:EditForeignKeyView :: Text
$sel:constraintName:EditForeignKeyView :: Text
$sel:onDelete:EditForeignKeyView :: Text
.. }

    action ColumnsController
UpdateForeignKeyAction = do
        [Statement]
statements <- IO [Statement]
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
IO [Statement]
readSchema
        let tableName :: Text
tableName = ByteString -> Text
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"tableName"
        let columnName :: Text
columnName = ByteString -> Text
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"columnName"
        let constraintName :: Text
constraintName = ByteString -> Text
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"constraintName"
        let referenceTable :: Text
referenceTable = ByteString -> Text
forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param ByteString
"referenceTable"
        let constraintId :: Maybe Int
constraintId = [Statement]
statements
                [Statement] -> ([Statement] -> Maybe Int) -> Maybe Int
forall {t1} {t2}. t1 -> (t1 -> t2) -> t2
|> (Statement -> Bool) -> [Statement] -> Maybe Int
forall a. (a -> Bool) -> [a] -> Maybe Int
findIndex \case
                    AddConstraint { $sel:tableName:StatementCreateTable :: Statement -> Text
tableName = Text
fkTable, $sel:constraint:StatementCreateTable :: Statement -> Constraint
constraint = ForeignKeyConstraint { $sel:columnName:ForeignKeyConstraint :: Constraint -> Text
columnName = Text
fkColumnName } } -> Text
tableName Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
fkTable Bool -> Bool -> Bool
&& Text
columnName Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
fkColumnName
                    Statement
otherwise -> Bool
False
        let onDeleteParam :: Text
onDeleteParam = forall valueType.
(?context::ControllerContext, ParamReader valueType) =>
ByteString -> valueType
param @Text ByteString
"onDelete"
        let onDelete :: OnDelete
onDelete = case Text
onDeleteParam of
                Text
"Restrict" -> OnDelete
Restrict
                Text
"SetNull" -> OnDelete
SetNull
                Text
"SetDefault" -> OnDelete
SetDefault
                Text
"Cascade" -> OnDelete
Cascade
                Text
_ -> OnDelete
NoAction
        case Maybe Int
constraintId of
            Just Int
constraintId -> ([Statement] -> [Statement]) -> IO ()
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
([Statement] -> [Statement]) -> IO ()
updateSchema (Text
-> Text
-> Text
-> Text
-> OnDelete
-> Int
-> [Statement]
-> [Statement]
updateForeignKeyConstraint Text
tableName Text
columnName Text
constraintName Text
referenceTable OnDelete
onDelete Int
constraintId)
            Maybe Int
Nothing -> Text -> IO ()
putStrLn (Text
"Error")
        TablesController -> IO ()
forall action.
(?context::ControllerContext, HasPath action) =>
action -> IO ()
redirectTo ShowTableAction { Text
$sel:tableName:TablesAction :: Text
tableName :: Text
.. }

    action DeleteForeignKeyAction { Text
$sel:constraintName:NewColumnAction :: ColumnsController -> Text
constraintName :: Text
constraintName, Text
$sel:tableName:NewColumnAction :: ColumnsController -> Text
tableName :: Text
tableName } = do
        [Statement]
statements <- IO [Statement]
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
IO [Statement]
readSchema
        ([Statement] -> [Statement]) -> IO ()
forall controller.
(?context::ControllerContext, ?modelContext::ModelContext,
 ?theAction::controller) =>
([Statement] -> [Statement]) -> IO ()
updateSchema (Text -> [Statement] -> [Statement]
deleteForeignKeyConstraint Text
constraintName)
        TablesController -> IO ()
forall action.
(?context::ControllerContext, HasPath action) =>
action -> IO ()
redirectTo ShowTableAction { Text
$sel:tableName:TablesAction :: Text
tableName :: Text
.. }

toggleUniqueInColumn :: Text -> Int -> Statement -> Statement
toggleUniqueInColumn :: Text -> Int -> Statement -> Statement
toggleUniqueInColumn Text
tableName Int
columnId (StatementCreateTable table :: CreateTable
table@CreateTable { Text
name :: Text
$sel:name:CreateTable :: CreateTable -> Text
name, [Column]
columns :: [Column]
$sel:columns:CreateTable :: CreateTable -> [Column]
columns })
    | Text
name Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
tableName = CreateTable -> Statement
StatementCreateTable (CreateTable -> Statement) -> CreateTable -> Statement
forall a b. (a -> b) -> a -> b
$
        CreateTable
table { $sel:columns:CreateTable :: [Column]
columns = (Int -> Column -> [Column] -> [Column]
forall a. Int -> a -> [a] -> [a]
replace Int
columnId (([Column]
columns [Column] -> Int -> Column
forall a. HasCallStack => [a] -> Int -> a
!! Int
columnId) { $sel:isUnique:Column :: Bool
isUnique = (Bool -> Bool
not ([Column]
columns [Column] -> Int -> Column
forall a. HasCallStack => [a] -> Int -> a
!! Int
columnId).isUnique) }) [Column]
columns) }
toggleUniqueInColumn Text
tableName Int
columnId Statement
statement = Statement
statement

deleteColumnInTable :: Text -> Int -> Statement -> Statement
deleteColumnInTable :: Text -> Int -> Statement -> Statement
deleteColumnInTable Text
tableName Int
columnId (StatementCreateTable table :: CreateTable
table@CreateTable { Text
$sel:name:CreateTable :: CreateTable -> Text
name :: Text
name, [Column]
$sel:columns:CreateTable :: CreateTable -> [Column]
columns :: [Column]
columns })
    | Text
name Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
tableName = CreateTable -> Statement
StatementCreateTable (CreateTable -> Statement) -> CreateTable -> Statement
forall a b. (a -> b) -> a -> b
$
        CreateTable
table { $sel:columns:CreateTable :: [Column]
columns = Column -> [Column] -> [Column]
forall a. Eq a => a -> [a] -> [a]
delete ([Column]
columns [Column] -> Int -> Column
forall a. HasCallStack => [a] -> Int -> a
!! Int
columnId) [Column]
columns}
deleteColumnInTable Text
tableName Int
columnId Statement
statement = Statement
statement


updateForeignKeyConstraint :: Text -> Text -> Text -> Text -> OnDelete -> Int -> [Statement] -> [Statement]
updateForeignKeyConstraint :: Text
-> Text
-> Text
-> Text
-> OnDelete
-> Int
-> [Statement]
-> [Statement]
updateForeignKeyConstraint Text
tableName Text
columnName Text
constraintName Text
referenceTable OnDelete
onDelete Int
constraintId [Statement]
list = Int -> Statement -> [Statement] -> [Statement]
forall a. Int -> a -> [a] -> [a]
replace Int
constraintId AddConstraint { $sel:tableName:StatementCreateTable :: Text
tableName = Text
tableName, $sel:deferrable:StatementCreateTable :: Maybe Bool
deferrable = Maybe Bool
forall a. Maybe a
Nothing, $sel:deferrableType:StatementCreateTable :: Maybe DeferrableType
deferrableType = Maybe DeferrableType
forall a. Maybe a
Nothing, $sel:constraint:StatementCreateTable :: Constraint
constraint = ForeignKeyConstraint { $sel:name:ForeignKeyConstraint :: Maybe Text
name = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
constraintName, $sel:columnName:ForeignKeyConstraint :: Text
columnName = Text
columnName, $sel:referenceTable:ForeignKeyConstraint :: Text
referenceTable = Text
referenceTable, $sel:referenceColumn:ForeignKeyConstraint :: Maybe Text
referenceColumn = Maybe Text
"id", $sel:onDelete:ForeignKeyConstraint :: Maybe OnDelete
onDelete = (OnDelete -> Maybe OnDelete
forall a. a -> Maybe a
Just OnDelete
onDelete) } } [Statement]
list

deleteForeignKeyConstraint :: Text -> [Statement] -> [Statement]
deleteForeignKeyConstraint :: Text -> [Statement] -> [Statement]
deleteForeignKeyConstraint Text
constraintName = (Statement -> Bool) -> [Statement] -> [Statement]
forall a. (a -> Bool) -> [a] -> [a]
filter \case
    AddConstraint { Constraint
$sel:constraint:StatementCreateTable :: Statement -> Constraint
constraint :: Constraint
constraint } | Constraint
constraint.name Maybe Text -> Maybe Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text -> Maybe Text
forall a. a -> Maybe a
Just Text
constraintName -> Bool
False
    Statement
otherwise -> Bool
True


deleteTableIndex :: Text -> [Statement] -> [Statement]
deleteTableIndex :: Text -> [Statement] -> [Statement]
deleteTableIndex Text
indexName [Statement]
list =
    [Statement]
list
    [Statement] -> ([Statement] -> [Statement]) -> [Statement]
forall {t1} {t2}. t1 -> (t1 -> t2) -> t2
|> (Statement -> Bool) -> [Statement] -> [Statement]
forall a. (a -> Bool) -> [a] -> [a]
filter \case
        CreateIndex { $sel:indexName:StatementCreateTable :: Statement -> Text
indexName = Text
indexName' } -> Text
indexName' Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
/= Text
indexName
        Statement
otherwise -> Bool
True

getCreateTable :: [Statement] -> [CreateTable]
getCreateTable :: [Statement] -> [CreateTable]
getCreateTable [Statement]
statements = (Statement -> [CreateTable] -> [CreateTable])
-> [CreateTable] -> [Statement] -> [CreateTable]
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Statement -> [CreateTable] -> [CreateTable]
step [] [Statement]
statements
  where
    step :: Statement -> [CreateTable] -> [CreateTable]
step (StatementCreateTable CreateTable
createTable) [CreateTable]
createTables = CreateTable
createTable CreateTable -> [CreateTable] -> [CreateTable]
forall a. a -> [a] -> [a]
: [CreateTable]
createTables
    step Statement
_ [CreateTable]
createTables = [CreateTable]
createTables

getCreateEnum :: [Statement] -> [Statement]
getCreateEnum [Statement]
statements = (Statement -> Bool) -> [Statement] -> [Statement]
forall a. (a -> Bool) -> [a] -> [a]
filter Statement -> Bool
isCreateEnumType [Statement]
statements
isCreateEnumType :: Statement -> Bool
isCreateEnumType CreateEnumType {} = Bool
True
isCreateEnumType Statement
_ = Bool
False

nameList :: [a] -> [b]
nameList [a]
statements = (a -> b) -> [a] -> [b]
forall a b. (a -> b) -> [a] -> [b]
map (.name) [a]
statements


validateColumn :: Validator Text
validateColumn :: Text -> ValidatorResult
validateColumn = Text -> [Text] -> Maybe Text -> Text -> ValidatorResult
validateNameInSchema Text
"column name" [] Maybe Text
forall a. Maybe a
Nothing

referencingColumnForeignKeyConstraints :: Text -> Text -> t Statement -> Maybe Statement
referencingColumnForeignKeyConstraints Text
tableName Text
columnName =
    (Statement -> Bool) -> t Statement -> Maybe Statement
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find \case
        AddConstraint { $sel:tableName:StatementCreateTable :: Statement -> Text
tableName = Text
constraintTable, $sel:constraint:StatementCreateTable :: Statement -> Constraint
constraint = ForeignKeyConstraint { $sel:columnName:ForeignKeyConstraint :: Constraint -> Text
columnName = Text
fkColumnName  }  } -> Text
constraintTable Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
tableName Bool -> Bool -> Bool
&& Text
fkColumnName Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
columnName
        Statement
otherwise -> Bool
False