content: module IHP.DataSync.Types where
  
  import IHP.Prelude
  import Data.Aeson
  import IHP.DataSync.DynamicQuery
  import qualified Database.PostgreSQL.Simple as PG
  import Control.Concurrent.MVar as MVar
  
  
  data DataSyncMessage
      = DataSyncQuery { query :: !DynamicSQLQuery, requestId :: !Int, transactionId :: !(Maybe UUID) }
      | CreateDataSubscription { query :: !DynamicSQLQuery, requestId :: !Int }
      | CreateCountSubscription { query :: !DynamicSQLQuery, requestId :: !Int }
      | DeleteDataSubscription { subscriptionId :: !UUID, requestId :: !Int }
      | CreateRecordMessage { table :: !Text, record :: !(HashMap Text Value), requestId :: !Int, transactionId :: !(Maybe UUID) }
      | CreateRecordsMessage { table :: !Text, records :: ![HashMap Text Value], requestId :: !Int, transactionId :: !(Maybe UUID) }
      | UpdateRecordMessage { table :: !Text, id :: !UUID, patch :: !(HashMap Text Value), requestId :: !Int, transactionId :: !(Maybe UUID) }
      | UpdateRecordsMessage { table :: !Text, ids :: ![UUID], patch :: !(HashMap Text Value), requestId :: !Int, transactionId :: !(Maybe UUID) }
      | DeleteRecordMessage { table :: !Text, id :: !UUID, requestId :: !Int, transactionId :: !(Maybe UUID) }
      | DeleteRecordsMessage { table :: !Text, ids :: ![UUID], requestId :: !Int, transactionId :: !(Maybe UUID) }
      | StartTransaction { requestId :: !Int }
      | RollbackTransaction { requestId :: !Int, id :: !UUID }
      | CommitTransaction { requestId :: !Int, id :: !UUID }
      | LoginWithEmailAndPassword { requestId :: !Int, email :: !Text, password :: !Text }
      | LoginWithJWT { requestId :: !Int, jwt :: !Text }
      | CreateUser { requestId :: !Int, email :: !Text, password :: !Text }
      | ConfirmUser { requestId :: !Int, userId :: !UUID, token :: !Text }
      deriving (Eq, Show)
  
  data DataSyncResponse
      = DataSyncResult { result :: ![[Field]], requestId :: !Int }
      | DataSyncError { requestId :: !Int, errorMessage :: !Text }
      | FailedToDecodeMessageError { errorMessage :: !Text }
      | DidCreateDataSubscription { requestId :: !Int, subscriptionId :: !UUID, result :: ![[Field]] }
      | DidCreateCountSubscription { requestId :: !Int, subscriptionId :: !UUID, count :: !Int }
      | DidDeleteDataSubscription { requestId :: !Int, subscriptionId :: !UUID }
      | DidInsert { subscriptionId :: !UUID, record :: ![Field] }
      | DidUpdate { subscriptionId :: !UUID, id :: UUID, changeSet :: !Value }
      | DidDelete { subscriptionId :: !UUID, id :: !UUID }
      | DidChangeCount { subscriptionId :: !UUID, count :: !Int }
      | DidCreateRecord { requestId :: !Int, record :: ![Field] } -- ^ Response to 'CreateRecordMessage'
      | DidCreateRecords { requestId :: !Int, records :: ![[Field]] } -- ^ Response to 'CreateRecordsMessage'
      | DidUpdateRecord { requestId :: !Int, record :: ![Field] } -- ^ Response to 'UpdateRecordMessage'
      | DidUpdateRecords { requestId :: !Int, records :: ![[Field]] } -- ^ Response to 'UpdateRecordsMessage'
      | DidDeleteRecord { requestId :: !Int }
      | DidDeleteRecords { requestId :: !Int }
      | DidStartTransaction { requestId :: !Int, transactionId :: !UUID }
      | DidRollbackTransaction { requestId :: !Int, transactionId :: !UUID }
      | DidCommitTransaction { requestId :: !Int, transactionId :: !UUID }
  
      | LoginSuccessful { requestId :: !Int, userId :: !UUID, jwt :: !Text }
      | UserLocked { requestId :: !Int }
      | UserUnconfirmed { requestId :: !Int }
      | InvalidCredentials { requestId :: !Int }
  
      | DidCreateUser { requestId :: !Int, userId :: !UUID, emailConfirmationRequired :: !Bool, jwt :: !Text }
      | CreateUserFailed { requestId :: !Int, validationFailures :: [(Text, Text)] }
      | DidConfirmUser { requestId :: !Int, jwt :: !Text }
      | DidConfirmUserAlready { requestId :: !Int }
      | ConfirmUserFailed { requestId :: !Int }
  
  data GraphQLResult = GraphQLResult { graphQLResult :: !UndecodedJSON, requestId :: !Int }
  
  data DataSyncTransaction
      = DataSyncTransaction
      { id :: !UUID
      , connection :: !PG.Connection
      , close :: MVar ()
      }
  
  data DataSyncController
      = DataSyncController
      | DataSyncReady
          { subscriptions :: !(HashMap UUID (MVar.MVar ()))
          , transactions :: !(HashMap UUID DataSyncTransaction)
          }
  