module IHP.Job.Queue.StatusInstances
( textToEnumJobStatusMap
, textToEnumJobStatus
) where

import IHP.Prelude
import IHP.Job.Types (JobStatus (..))
import qualified Database.PostgreSQL.Simple.FromField as PG
import qualified Database.PostgreSQL.Simple.ToField as PG
import IHP.ModelSupport (InputValue (..))
import qualified IHP.Controller.Param as Param
import qualified Data.HashMap.Strict as HashMap
import qualified Hasql.Encoders as Encoders
import qualified Hasql.Decoders as Decoders
import Hasql.Implicits.Encoders (DefaultParamEncoder (..))
import qualified Hasql.Mapping.IsScalar as Mapping

-- | Mapping for @JOB_STATUS@:
--
-- > CREATE TYPE JOB_STATUS AS ENUM ('job_status_not_started', 'job_status_running', 'job_status_failed', 'job_status_succeeded', 'job_status_retry');
--
-- These instances are needed by the generated @FromRow@ instances in user apps
-- (see 'compileFromRowInstance' in "IHP.SchemaCompiler").
instance PG.FromField JobStatus where
    fromField :: FieldParser JobStatus
fromField Field
field (Just ByteString
"job_status_not_started") = JobStatus -> Conversion JobStatus
forall a. a -> Conversion a
forall (f :: * -> *) a. Applicative f => a -> f a
pure JobStatus
JobStatusNotStarted
    fromField Field
field (Just ByteString
"job_status_running") = JobStatus -> Conversion JobStatus
forall a. a -> Conversion a
forall (f :: * -> *) a. Applicative f => a -> f a
pure JobStatus
JobStatusRunning
    fromField Field
field (Just ByteString
"job_status_failed") = JobStatus -> Conversion JobStatus
forall a. a -> Conversion a
forall (f :: * -> *) a. Applicative f => a -> f a
pure JobStatus
JobStatusFailed
    fromField Field
field (Just ByteString
"job_status_timed_out") = JobStatus -> Conversion JobStatus
forall a. a -> Conversion a
forall (f :: * -> *) a. Applicative f => a -> f a
pure JobStatus
JobStatusTimedOut
    fromField Field
field (Just ByteString
"job_status_succeeded") = JobStatus -> Conversion JobStatus
forall a. a -> Conversion a
forall (f :: * -> *) a. Applicative f => a -> f a
pure JobStatus
JobStatusSucceeded
    fromField Field
field (Just ByteString
"job_status_retry") = JobStatus -> Conversion JobStatus
forall a. a -> Conversion a
forall (f :: * -> *) a. Applicative f => a -> f a
pure JobStatus
JobStatusRetry
    fromField Field
field (Just ByteString
value) = (String -> Maybe Oid -> String -> String -> String -> ResultError)
-> Field -> String -> Conversion JobStatus
forall a err.
(Typeable a, Exception err) =>
(String -> Maybe Oid -> String -> String -> String -> err)
-> Field -> String -> Conversion a
PG.returnError String -> Maybe Oid -> String -> String -> String -> ResultError
PG.ConversionFailed Field
field (String
"Unexpected value for enum value. Got: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> ByteString -> String
forall a b. ConvertibleStrings a b => a -> b
cs ByteString
value)
    fromField Field
field Maybe ByteString
Nothing = (String -> Maybe Oid -> String -> String -> String -> ResultError)
-> Field -> String -> Conversion JobStatus
forall a err.
(Typeable a, Exception err) =>
(String -> Maybe Oid -> String -> String -> String -> err)
-> Field -> String -> Conversion a
PG.returnError String -> Maybe Oid -> String -> String -> String -> ResultError
PG.UnexpectedNull Field
field String
"Unexpected null for enum value"

-- The default state is @not started@
instance Default JobStatus where
    def :: JobStatus
def = JobStatus
JobStatusNotStarted

-- | See 'FromField' instance above.
instance PG.ToField JobStatus where
    toField :: JobStatus -> Action
toField JobStatus
JobStatusNotStarted = Text -> Action
forall a. ToField a => a -> Action
PG.toField (Text
"job_status_not_started" :: Text)
    toField JobStatus
JobStatusRunning = Text -> Action
forall a. ToField a => a -> Action
PG.toField (Text
"job_status_running" :: Text)
    toField JobStatus
JobStatusFailed = Text -> Action
forall a. ToField a => a -> Action
PG.toField (Text
"job_status_failed" :: Text)
    toField JobStatus
JobStatusTimedOut = Text -> Action
forall a. ToField a => a -> Action
PG.toField (Text
"job_status_timed_out" :: Text)
    toField JobStatus
JobStatusSucceeded = Text -> Action
forall a. ToField a => a -> Action
PG.toField (Text
"job_status_succeeded" :: Text)
    toField JobStatus
JobStatusRetry = Text -> Action
forall a. ToField a => a -> Action
PG.toField (Text
"job_status_retry" :: Text)

instance InputValue JobStatus where
    inputValue :: JobStatus -> Text
inputValue JobStatus
JobStatusNotStarted = Text
"job_status_not_started" :: Text
    inputValue JobStatus
JobStatusRunning = Text
"job_status_running" :: Text
    inputValue JobStatus
JobStatusFailed = Text
"job_status_failed" :: Text
    inputValue JobStatus
JobStatusTimedOut = Text
"job_status_timed_out" :: Text
    inputValue JobStatus
JobStatusSucceeded = Text
"job_status_succeeded" :: Text
    inputValue JobStatus
JobStatusRetry = Text
"job_status_retry" :: Text

instance Param.ParamReader JobStatus where
    readParameter :: ByteString -> Either ByteString JobStatus
readParameter = ByteString -> Either ByteString JobStatus
forall parameter.
(Enum parameter, InputValue parameter) =>
ByteString -> Either ByteString parameter
Param.enumParamReader

-- | Parses a Text value to a JobStatus. Used by hasql decoders.
-- Uses HashMap for O(1) lookup.
textToEnumJobStatusMap :: HashMap.HashMap Text JobStatus
textToEnumJobStatusMap :: HashMap Text JobStatus
textToEnumJobStatusMap = [(Text, JobStatus)] -> HashMap Text JobStatus
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList
    [ (Text
"job_status_not_started", JobStatus
JobStatusNotStarted)
    , (Text
"job_status_running", JobStatus
JobStatusRunning)
    , (Text
"job_status_failed", JobStatus
JobStatusFailed)
    , (Text
"job_status_timed_out", JobStatus
JobStatusTimedOut)
    , (Text
"job_status_succeeded", JobStatus
JobStatusSucceeded)
    , (Text
"job_status_retry", JobStatus
JobStatusRetry)
    ]

textToEnumJobStatus :: Text -> Maybe JobStatus
textToEnumJobStatus :: Text -> Maybe JobStatus
textToEnumJobStatus Text
t = Text -> HashMap Text JobStatus -> Maybe JobStatus
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup Text
t HashMap Text JobStatus
textToEnumJobStatusMap

-- | DefaultParamEncoder for hasql queries using JobStatus in filterWhere
instance DefaultParamEncoder JobStatus where
    defaultParam :: NullableOrNot Value JobStatus
defaultParam = Value JobStatus -> NullableOrNot Value JobStatus
forall (encoder :: * -> *) a. encoder a -> NullableOrNot encoder a
Encoders.nonNullable (Maybe Text -> Text -> (JobStatus -> Text) -> Value JobStatus
forall a. Maybe Text -> Text -> (a -> Text) -> Value a
Encoders.enum (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"public") Text
"job_status" JobStatus -> Text
forall a. InputValue a => a -> Text
inputValue)

-- | DefaultParamEncoder for lists of JobStatus, needed for filterWhereIn/filterWhereNotIn
instance DefaultParamEncoder [JobStatus] where
    defaultParam :: NullableOrNot Value [JobStatus]
defaultParam = Value [JobStatus] -> NullableOrNot Value [JobStatus]
forall (encoder :: * -> *) a. encoder a -> NullableOrNot encoder a
Encoders.nonNullable (Value [JobStatus] -> NullableOrNot Value [JobStatus])
-> Value [JobStatus] -> NullableOrNot Value [JobStatus]
forall a b. (a -> b) -> a -> b
$ NullableOrNot Value JobStatus -> Value [JobStatus]
forall (foldable :: * -> *) element.
Foldable foldable =>
NullableOrNot Value element -> Value (foldable element)
Encoders.foldableArray (NullableOrNot Value JobStatus -> Value [JobStatus])
-> NullableOrNot Value JobStatus -> Value [JobStatus]
forall a b. (a -> b) -> a -> b
$ Value JobStatus -> NullableOrNot Value JobStatus
forall (encoder :: * -> *) a. encoder a -> NullableOrNot encoder a
Encoders.nonNullable (Maybe Text -> Text -> (JobStatus -> Text) -> Value JobStatus
forall a. Maybe Text -> Text -> (a -> Text) -> Value a
Encoders.enum (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"public") Text
"job_status" JobStatus -> Text
forall a. InputValue a => a -> Text
inputValue)

instance Mapping.IsScalar JobStatus where
    encoder :: Value JobStatus
encoder = Maybe Text -> Text -> (JobStatus -> Text) -> Value JobStatus
forall a. Maybe Text -> Text -> (a -> Text) -> Value a
Encoders.enum (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"public") Text
"job_status" JobStatus -> Text
forall a. InputValue a => a -> Text
inputValue
    decoder :: Value JobStatus
decoder = Maybe Text -> Text -> (Text -> Maybe JobStatus) -> Value JobStatus
forall a. Maybe Text -> Text -> (Text -> Maybe a) -> Value a
Decoders.enum (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"public") Text
"job_status" Text -> Maybe JobStatus
textToEnumJobStatus