Implemented wasp db migrate cli cmd - runs only prisma migrate save for now. (#39)

This commit is contained in:
Matija Sosic 2020-09-15 16:39:56 +02:00 committed by GitHub
parent f06c933182
commit e95fae7f06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 115 additions and 11 deletions

View File

@ -0,0 +1,27 @@
module Command.Db.Migrate
( migrate
) where
import Control.Monad.Except (throwError)
import Control.Monad.IO.Class (liftIO)
import StrongPath ((</>))
import Command (Command, CommandError(..))
import Command.Common (findWaspProjectRootFromCwd, waspSays)
import qualified Common
import qualified Generator.DbGenerator.Operations as DbOps
migrate :: String -> Command ()
migrate migrationName = do
waspRootDir <- findWaspProjectRootFromCwd
let genProjectRootDir = waspRootDir </> Common.dotWaspDirInWaspProjectDir </>
Common.generatedCodeDirInDotWaspDir
waspSays "Saving db migration..."
migrateSaveResult <- liftIO $ DbOps.migrateSave genProjectRootDir migrationName
case migrateSaveResult of
Left migrateSaveError -> throwError $ CommandError $ "Migrate save failed: " ++ migrateSaveError
Right () -> waspSays "Migration has been successfully saved."
waspSays "All done!"

View File

@ -6,6 +6,7 @@ import Command (runCommand)
import Command.CreateNewProject (createNewProject)
import Command.Start (start)
import Command.Clean (clean)
import Command.Db.Migrate (migrate)
main :: IO ()
@ -15,6 +16,7 @@ main = do
["new", projectName] -> runCommand $ createNewProject projectName
["start"] -> runCommand start
["clean"] -> runCommand clean
("db":dbArgs) -> dbCli dbArgs
_ -> printUsage
printUsage :: IO ()
@ -26,11 +28,18 @@ printUsage = putStrLn $ unlines
, " new <project-name>"
, " start"
, " clean"
, " db <commmand> [command-args]"
, ""
, "Examples:"
, " wasp create MyApp"
, " wasp start"
]
-- TODO(matija): maybe extract to a separate module, e.g. DbCli.hs?
dbCli :: [String] -> IO ()
dbCli args = case args of
["migrate", migrationName] -> runCommand $ migrate migrationName
_ -> printDbUsage
printDbUsage :: IO ()
printDbUsage = putStrLn "This is how to use db commands:"

View File

@ -1,5 +1,7 @@
module Generator.DbGenerator
( genDb
, dbRootDirInProjectRootDir
, dbSchemaFileInProjectRootDir
) where
import qualified Path as P
@ -24,6 +26,17 @@ dbRootDirInProjectRootDir = SP.fromPathRelDir [P.reldir|db|]
dbTemplatesDirInTemplatesDir :: Path (Rel TemplatesDir) (Dir DbTemplatesDir)
dbTemplatesDirInTemplatesDir = SP.fromPathRelDir [P.reldir|db|]
dbSchemaFileInDbTemplatesDir :: Path (Rel DbTemplatesDir) File
dbSchemaFileInDbTemplatesDir = SP.fromPathRelFile [P.relfile|schema.prisma|]
dbSchemaFileInDbRootDir :: Path (Rel DbRootDir) File
-- Generated schema file will be in the same relative location as the
-- template file within templates dir.
dbSchemaFileInDbRootDir = SP.castRel dbSchemaFileInDbTemplatesDir
dbSchemaFileInProjectRootDir :: Path (Rel ProjectRootDir) File
dbSchemaFileInProjectRootDir = dbRootDirInProjectRootDir </> dbSchemaFileInDbRootDir
genDb :: Wasp -> CompileOptions -> [FileDraft]
genDb wasp _ =
[ genPrismaSchema $ Wasp.getPSLEntities wasp
@ -32,16 +45,8 @@ genDb wasp _ =
genPrismaSchema :: [EntityPSL] -> FileDraft
genPrismaSchema entities = createTemplateFileDraft dstPath tmplSrcPath (Just templateData)
where
relSrcPath :: Path (Rel DbTemplatesDir) File
relSrcPath = (SP.fromPathRelFile [P.relfile|schema.prisma|])
relDstPath :: Path (Rel DbRootDir) File
-- Generated schema file will be in the same relative location as the
-- template file within templates dir.
relDstPath = SP.castRel relSrcPath
dstPath = dbRootDirInProjectRootDir </> relDstPath
tmplSrcPath = dbTemplatesDirInTemplatesDir </> relSrcPath
dstPath = dbSchemaFileInProjectRootDir
tmplSrcPath = dbTemplatesDirInTemplatesDir </> dbSchemaFileInDbTemplatesDir
templateData = object
[ "entities" .= entities

View File

@ -0,0 +1,29 @@
module Generator.DbGenerator.Jobs
( migrateSave
) where
import Generator.Common (ProjectRootDir)
import qualified Generator.Job as J
import Generator.Job.Process (runNodeCommandAsJob)
import StrongPath (Abs, Dir, Path, (</>))
import qualified StrongPath as SP
import Generator.ServerGenerator.Common (serverRootDirInProjectRootDir)
import Generator.DbGenerator (dbSchemaFileInProjectRootDir)
migrateSave :: Path Abs (Dir ProjectRootDir) -> String -> J.Job
migrateSave projectDir migrationName = do
let serverDir = projectDir </> serverRootDirInProjectRootDir
let schemaFile = projectDir </> dbSchemaFileInProjectRootDir
-- TODO(matija): should we make the type here J.Db? Although actually we are running this
-- from server currently so maybe it is ok? Or maybe that is internal stuff?
--
-- NOTE(matija): We are running this command from server's root dir since that is where
-- Prisma packages (cli and client) are currently installed.
runNodeCommandAsJob serverDir "npx"
[ "prisma", "migrate", "save"
, "--schema", (SP.toFilePath schemaFile)
, "--name", migrationName
, "--create-db" -- Creates db if it doesn't already exist. Otherwise would stop and ask.
, "--experimental"
] J.Server

View File

@ -0,0 +1,34 @@
module Generator.DbGenerator.Operations
( migrateSave
) where
import Control.Concurrent (Chan, newChan, readChan)
import Control.Concurrent.Async (concurrently)
import System.Exit (ExitCode (..))
import StrongPath (Abs, Dir, Path)
import Generator.Common (ProjectRootDir)
import Generator.Job.IO (printJobMessage)
import qualified Generator.Job as J
import Generator.Job (JobMessage)
import qualified Generator.DbGenerator.Jobs as DbJobs
-- | Checks for the changes in db schema file and creates and saves db migration info, but it
-- does not execute it.
migrateSave :: Path Abs (Dir ProjectRootDir) -> String -> IO (Either String ())
migrateSave projectDir migrationName = do
chan <- newChan
(_, dbExitCode) <- concurrently (handleJobMessages chan)
(DbJobs.migrateSave projectDir migrationName chan)
case dbExitCode of
ExitSuccess -> return (Right ())
ExitFailure code -> return $ Left $ "Migrate save failed with exit code: " ++ show code
where
-- TODO(matija): extract & reuse this for other operations.
handleJobMessages :: Chan JobMessage -> IO ()
handleJobMessages chan = do
jobMsg <- readChan chan
case J._data jobMsg of
J.JobOutput {} -> printJobMessage jobMsg >> handleJobMessages chan
J.JobExit {} -> return ()