module IHP.IDE.CodeGen.JobGenerator (buildPlan, buildPlan', JobConfig (..)) where
import IHP.Prelude
import qualified Data.Text as Text
import IHP.IDE.CodeGen.Types
import qualified System.Directory as Directory
data JobConfig = JobConfig
{ JobConfig -> Text
applicationName :: Text
, JobConfig -> Text
tableName :: Text
, JobConfig -> Text
modelName :: Text
, JobConfig -> Bool
isFirstJobInApplication :: Bool
} deriving (JobConfig -> JobConfig -> Bool
(JobConfig -> JobConfig -> Bool)
-> (JobConfig -> JobConfig -> Bool) -> Eq JobConfig
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: JobConfig -> JobConfig -> Bool
== :: JobConfig -> JobConfig -> Bool
$c/= :: JobConfig -> JobConfig -> Bool
/= :: JobConfig -> JobConfig -> Bool
Eq, Int -> JobConfig -> ShowS
[JobConfig] -> ShowS
JobConfig -> String
(Int -> JobConfig -> ShowS)
-> (JobConfig -> String)
-> ([JobConfig] -> ShowS)
-> Show JobConfig
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> JobConfig -> ShowS
showsPrec :: Int -> JobConfig -> ShowS
$cshow :: JobConfig -> String
show :: JobConfig -> String
$cshowList :: [JobConfig] -> ShowS
showList :: [JobConfig] -> ShowS
Show)
buildPlan :: Text -> Text -> IO (Either Text [GeneratorAction])
buildPlan :: Text -> Text -> IO (Either Text [GeneratorAction])
buildPlan Text
jobName Text
applicationName = do
Bool
isFirstJobInApplication <- Bool -> Bool
not (Bool -> Bool) -> IO Bool -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO Bool
Directory.doesFileExist (Text -> String
forall a b. ConvertibleStrings a b => a -> b
cs (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ Text
applicationName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/Worker.hs")
if Text -> Bool
forall mono. MonoFoldable mono => mono -> Bool
null Text
jobName
then Either Text [GeneratorAction] -> IO (Either Text [GeneratorAction])
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either Text [GeneratorAction]
-> IO (Either Text [GeneratorAction]))
-> Either Text [GeneratorAction]
-> IO (Either Text [GeneratorAction])
forall a b. (a -> b) -> a -> b
$ Text -> Either Text [GeneratorAction]
forall a b. a -> Either a b
Left Text
"Job name cannot be empty"
else do
let jobConfig :: JobConfig
jobConfig = JobConfig
{ Text
$sel:applicationName:JobConfig :: Text
applicationName :: Text
applicationName
, $sel:tableName:JobConfig :: Text
tableName = Text
jobName
, $sel:modelName:JobConfig :: Text
modelName = Text -> Text
tableNameToModelName Text
jobName
, Bool
$sel:isFirstJobInApplication:JobConfig :: Bool
isFirstJobInApplication :: Bool
isFirstJobInApplication
}
Either Text [GeneratorAction] -> IO (Either Text [GeneratorAction])
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either Text [GeneratorAction]
-> IO (Either Text [GeneratorAction]))
-> Either Text [GeneratorAction]
-> IO (Either Text [GeneratorAction])
forall a b. (a -> b) -> a -> b
$ [GeneratorAction] -> Either Text [GeneratorAction]
forall a b. b -> Either a b
Right ([GeneratorAction] -> Either Text [GeneratorAction])
-> [GeneratorAction] -> Either Text [GeneratorAction]
forall a b. (a -> b) -> a -> b
$ JobConfig -> [GeneratorAction]
buildPlan' JobConfig
jobConfig
qualifiedJobModuleName :: JobConfig -> Text
qualifiedJobModuleName :: JobConfig -> Text
qualifiedJobModuleName JobConfig
config =
JobConfig
config.applicationName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
".Job." Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> JobConfig -> Text
unqualifiedJobModuleName JobConfig
config
unqualifiedJobModuleName :: JobConfig -> Text
unqualifiedJobModuleName :: JobConfig -> Text
unqualifiedJobModuleName JobConfig
config = HasCallStack => Text -> Text -> Text -> Text
Text -> Text -> Text -> Text
Text.replace Text
"Job" Text
"" (JobConfig
config.modelName)
buildPlan' :: JobConfig -> [GeneratorAction]
buildPlan' :: JobConfig -> [GeneratorAction]
buildPlan' JobConfig
config =
let
name :: Text
name = JobConfig
config.modelName
tableName :: Text
tableName = Text -> Text
modelNameToTableName Text
nameWithSuffix
nameWithSuffix :: Text
nameWithSuffix = if Text
"Job" Text -> Text -> Bool
`isSuffixOf` Text
name
then Text
name
else Text
name Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"Job"
nameWithoutSuffix :: Text
nameWithoutSuffix = if Text
"Job" Text -> Text -> Bool
`isSuffixOf` Text
name
then HasCallStack => Text -> Text -> Text -> Text
Text -> Text -> Text -> Text
Text.replace Text
"Job" Text
"" Text
name
else Text
name
job :: Text
job =
Text
""
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"module " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> JobConfig -> Text
qualifiedJobModuleName JobConfig
config Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" where\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"import " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> JobConfig
config.applicationName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
".Controller.Prelude\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"instance Job " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
nameWithSuffix Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" where\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" perform " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
nameWithSuffix Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" { .. } = do\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" putStrLn \"Hello World!\"\n"
schemaSql :: Text
schemaSql =
Text
""
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"CREATE TABLE " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
tableName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" (\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" status JOB_STATUS DEFAULT 'job_status_not_started' NOT NULL,\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" last_error TEXT DEFAULT NULL,\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" attempts_count INT DEFAULT 0 NOT NULL,\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" locked_at TIMESTAMP WITH TIME ZONE DEFAULT NULL,\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" locked_by UUID DEFAULT NULL,\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" run_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL\n"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
");\n"
emptyWorkerHs :: Text
emptyWorkerHs :: Text
emptyWorkerHs =
let
applicationName :: Text
applicationName = JobConfig
config.applicationName
in String -> Text
forall a b. ConvertibleStrings a b => a -> b
cs [plain|module #{applicationName}.Worker where
import IHP.Prelude
import #{applicationName}.Types
import Generated.Types
import IHP.Job.Runner
import IHP.Job.Types
import #{qualifiedJobModuleName config}
instance Worker #{applicationName}Application where
workers _ =
[ worker @#{nameWithSuffix}
-- Generator Marker
]
|]
in
[ EnsureDirectory { $sel:directory:CreateFile :: Text
directory = JobConfig
config.applicationName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/Job" }
, AppendToFile { $sel:filePath:CreateFile :: Text
filePath = Text
"Application/Schema.sql", $sel:fileContent:CreateFile :: Text
fileContent = Text
schemaSql }
, CreateFile { $sel:filePath:CreateFile :: Text
filePath = JobConfig
config.applicationName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/Job/" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
nameWithoutSuffix Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
".hs", $sel:fileContent:CreateFile :: Text
fileContent = Text
job }
]
[GeneratorAction] -> [GeneratorAction] -> [GeneratorAction]
forall a. Semigroup a => a -> a -> a
<> if JobConfig
config.isFirstJobInApplication
then [ CreateFile { $sel:filePath:CreateFile :: Text
filePath = JobConfig
config.applicationName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/Worker.hs", $sel:fileContent:CreateFile :: Text
fileContent = Text
emptyWorkerHs } ]
else
[ AddImport { $sel:filePath:CreateFile :: Text
filePath = JobConfig
config.applicationName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/Worker.hs", $sel:fileContent:CreateFile :: Text
fileContent = Text
"import " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> JobConfig -> Text
qualifiedJobModuleName JobConfig
config }
, AppendToMarker { $sel:marker:CreateFile :: Text
marker = Text
"-- Generator Marker", $sel:filePath:CreateFile :: Text
filePath = JobConfig
config.applicationName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/Worker.hs", $sel:fileContent:CreateFile :: Text
fileContent = Text
" , worker @" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
nameWithSuffix }
]