Move prisma client to top-level node_modules

This commit is contained in:
Filip Sodić 2023-12-18 17:57:14 +01:00
parent d8f9ee2c24
commit 52c547b3f2
8 changed files with 88 additions and 125 deletions

View File

@ -26,7 +26,7 @@ COPY server/ ./server/
RUN cd server && npm install
{=# usingPrisma =}
COPY db/schema.prisma ./db/
RUN cd server && {= serverPrismaClientOutputDirEnv =} npx prisma generate --schema='{= dbSchemaFileFromServerDir =}'
RUN cd server && npx prisma generate --schema='{= dbSchemaFileFromServerDir =}'
{=/ usingPrisma =}
# Building the server should come after Prisma generation.
RUN cd server && npm run build

View File

@ -10,7 +10,6 @@ datasource db {
generator client {
provider = "prisma-client-js"
output = {=& prismaClientOutputDir =}
{=# prismaPreviewFeatures =}
previewFeatures = {=& . =}
{=/ prismaPreviewFeatures =}

View File

@ -29,7 +29,6 @@ import Wasp.Generator.DbGenerator.Common
dbSchemaFileInDbTemplatesDir,
dbSchemaFileInProjectRootDir,
dbTemplatesDirInTemplatesDir,
prismaClientOutputDirEnvVar,
)
import qualified Wasp.Generator.DbGenerator.Operations as DbOps
import Wasp.Generator.FileDraft (FileDraft, createCopyDirFileDraft, createTemplateFileDraft)
@ -68,7 +67,6 @@ genPrismaSchema spec = do
[ "modelSchemas" .= map entityToPslModelSchema (AS.getDecls @AS.Entity.Entity spec),
"datasourceProvider" .= datasourceProvider,
"datasourceUrl" .= datasourceUrl,
"prismaClientOutputDir" .= makeEnvVarField Wasp.Generator.DbGenerator.Common.prismaClientOutputDirEnvVar,
"prismaPreviewFeatures" .= prismaPreviewFeatures,
"dbExtensions" .= dbExtensions
]
@ -95,7 +93,7 @@ genMigrationsDir spec = return $ createCopyDirFileDraft RemoveExistingDstDir gen
postWriteDbGeneratorActions :: AppSpec -> Path' Abs (Dir ProjectRootDir) -> IO ([GeneratorWarning], [GeneratorError])
postWriteDbGeneratorActions spec dstDir = do
dbGeneratorWarnings <- maybeToList <$> warnIfDbNeedsMigration spec dstDir
dbGeneratorErrors <- maybeToList <$> genPrismaClients spec dstDir
dbGeneratorErrors <- maybeToList <$> generatePrismaClient spec dstDir
return (dbGeneratorWarnings, dbGeneratorErrors)
-- | Checks if user needs to run `wasp db migrate-dev` due to changes in schema.prisma, and if so, returns a warning.
@ -173,12 +171,12 @@ warnProjectDiffersFromDb projectRootDir = do
"Wasp was unable to verify your database is up to date."
<> " Running `wasp db migrate-dev` may fix this and will provide more info."
genPrismaClients :: AppSpec -> Path' Abs (Dir ProjectRootDir) -> IO (Maybe GeneratorError)
genPrismaClients spec projectRootDir =
generatePrismaClient :: AppSpec -> Path' Abs (Dir ProjectRootDir) -> IO (Maybe GeneratorError)
generatePrismaClient spec projectRootDir =
ifM
wasCurrentSchemaAlreadyGenerated
(return Nothing)
generatePrismaClientsIfEntitiesExist
generatePrismaClientIfEntitiesExist
where
wasCurrentSchemaAlreadyGenerated :: IO Bool
wasCurrentSchemaAlreadyGenerated =
@ -186,10 +184,10 @@ genPrismaClients spec projectRootDir =
projectRootDir
Wasp.Generator.DbGenerator.Common.dbSchemaChecksumOnLastGenerateFileProjectRootDir
generatePrismaClientsIfEntitiesExist :: IO (Maybe GeneratorError)
generatePrismaClientsIfEntitiesExist
generatePrismaClientIfEntitiesExist :: IO (Maybe GeneratorError)
generatePrismaClientIfEntitiesExist
| entitiesExist =
either (Just . GenericGeneratorError) (const Nothing) <$> DbOps.generatePrismaClients projectRootDir
either (Just . GenericGeneratorError) (const Nothing) <$> DbOps.generatePrismaClient projectRootDir
| otherwise = return Nothing
entitiesExist = not . null $ getEntities spec

View File

@ -1,8 +1,5 @@
module Wasp.Generator.DbGenerator.Common
( dbMigrationsDirInDbRootDir,
serverPrismaClientOutputDirEnv,
webAppPrismaClientOutputDirEnv,
prismaClientOutputDirInAppComponentDir,
dbSchemaFileFromAppComponentDir,
dbRootDirInProjectRootDir,
dbSchemaChecksumOnLastDbConcurrenceFileProjectRootDir,
@ -19,15 +16,15 @@ module Wasp.Generator.DbGenerator.Common
serverRootDirFromDbRootDir,
webAppRootDirFromDbRootDir,
dbSchemaFileInProjectRootDir,
prismaClientOutputDirEnvVar,
waspProjectDirFromProjectRootDir,
DbSchemaChecksumFile,
)
where
import StrongPath (Dir, File, File', Path', Rel, reldir, relfile, (</>))
import qualified StrongPath as SP
import Wasp.Generator.Common (AppComponentRootDir, DbRootDir, ProjectRootDir, ServerRootDir)
import Wasp.Generator.Templates (TemplatesDir)
import Wasp.Project.Common (WaspProjectDir)
import Wasp.Project.Db.Migrations (DbMigrationsDir)
data DbTemplatesDir
@ -93,21 +90,8 @@ dbSchemaChecksumOnLastGenerateFileInDbRootDir = [relfile|schema.prisma.wasp-gene
dbSchemaChecksumOnLastGenerateFileProjectRootDir :: Path' (Rel ProjectRootDir) (File DbSchemaChecksumOnLastGenerateFile)
dbSchemaChecksumOnLastGenerateFileProjectRootDir = dbRootDirInProjectRootDir </> dbSchemaChecksumOnLastGenerateFileInDbRootDir
prismaClientOutputDirEnvVar :: String
prismaClientOutputDirEnvVar = "PRISMA_CLIENT_OUTPUT_DIR"
prismaClientOutputDirInAppComponentDir :: AppComponentRootDir d => Path' (Rel d) (Dir ServerRootDir)
prismaClientOutputDirInAppComponentDir = [reldir|node_modules/.prisma/client|]
serverPrismaClientOutputDirEnv :: (String, String)
serverPrismaClientOutputDirEnv = appComponentPrismaClientOutputDirEnv serverRootDirFromDbRootDir
webAppPrismaClientOutputDirEnv :: (String, String)
webAppPrismaClientOutputDirEnv = appComponentPrismaClientOutputDirEnv webAppRootDirFromDbRootDir
appComponentPrismaClientOutputDirEnv :: AppComponentRootDir d => Path' (Rel DbRootDir) (Dir d) -> (String, String)
appComponentPrismaClientOutputDirEnv appComponentDirFromDbRootDir =
(prismaClientOutputDirEnvVar, SP.fromRelDir $ appComponentDirFromDbRootDir </> prismaClientOutputDirInAppComponentDir)
waspProjectDirFromProjectRootDir :: Path' (Rel ProjectRootDir) (Dir WaspProjectDir)
waspProjectDirFromProjectRootDir = [reldir|../../|]
data MigrateArgs = MigrateArgs
{ _migrationName :: Maybe String,

View File

@ -13,24 +13,24 @@ module Wasp.Generator.DbGenerator.Jobs
)
where
import StrongPath (Abs, Dir, File, File', Path', (</>))
import StrongPath (Abs, Dir, File', Path', (</>))
import qualified StrongPath as SP
import StrongPath.TH (relfile)
import qualified System.Info
import Wasp.Generator.Common (ProjectRootDir)
import Wasp.Generator.DbGenerator.Common
( MigrateArgs (..),
PrismaDbSchema,
dbSchemaFileInProjectRootDir,
waspProjectDirFromProjectRootDir,
)
import Wasp.Generator.Job (JobType)
import qualified Wasp.Generator.Job as J
import Wasp.Generator.Job.Process (runNodeCommandAsJob, runNodeCommandAsJobWithExtraEnv)
import Wasp.Generator.ServerGenerator.Common (serverRootDirInProjectRootDir)
import Wasp.Generator.ServerGenerator.Db.Seed (dbSeedNameEnvVarName)
import Wasp.Project.Common (WaspProjectDir)
migrateDev :: Path' Abs (Dir ProjectRootDir) -> MigrateArgs -> J.Job
migrateDev projectDir migrateArgs =
migrateDev projectRootDir migrateArgs =
-- NOTE(matija): We are running this command from server's root dir since that is where
-- Prisma packages (cli and client) are currently installed.
-- NOTE(martin): `prisma migrate dev` refuses to execute when interactivity is needed if stdout is being piped,
@ -40,8 +40,8 @@ migrateDev projectDir migrateArgs =
-- we are using `script` to trick Prisma into thinking it is running in TTY (interactively).
runNodeCommandAsJob serverDir "script" scriptArgs J.Db
where
serverDir = projectDir </> serverRootDirInProjectRootDir
schemaFile = projectDir </> dbSchemaFileInProjectRootDir
serverDir = projectRootDir </> serverRootDirInProjectRootDir
schemaFile = projectRootDir </> dbSchemaFileInProjectRootDir
scriptArgs =
if System.Info.os == "darwin"
@ -57,7 +57,7 @@ migrateDev projectDir migrateArgs =
-- * Linux - we are passing the command as one argument, so we MUST quote the paths.
buildPrismaMigrateCmd :: (String -> String) -> [String]
buildPrismaMigrateCmd argQuoter =
[ argQuoter $ absPrismaExecutableFp projectDir,
[ argQuoter $ absPrismaExecutableFp (projectRootDir </> waspProjectDirFromProjectRootDir),
"migrate",
"dev",
"--schema",
@ -85,15 +85,19 @@ asPrismaCliArgs migrateArgs = do
-- Because of the --exit-code flag, it changes the exit code behavior
-- to signal if the diff is empty or not (Empty: 0, Error: 1, Not empty: 2)
migrateDiff :: Path' Abs (Dir ProjectRootDir) -> J.Job
migrateDiff projectDir = runPrismaCommandAsDbJob projectDir $ \schema ->
[ "migrate",
"diff",
"--from-schema-datamodel",
SP.fromAbsFile schema,
"--to-schema-datasource",
SP.fromAbsFile schema,
"--exit-code"
]
migrateDiff projectRootDir =
runPrismaCommandAsJob
projectRootDir
[ "migrate",
"diff",
"--from-schema-datamodel",
SP.fromAbsFile schema,
"--to-schema-datasource",
SP.fromAbsFile schema,
"--exit-code"
]
where
schema = projectRootDir </> dbSchemaFileInProjectRootDir
-- | Checks to see if all migrations are applied to the DB.
-- An exit code of 0 means we successfully verified all migrations are applied.
@ -101,27 +105,34 @@ migrateDiff projectDir = runPrismaCommandAsDbJob projectDir $ \schema ->
-- or (b) there are pending migrations to apply.
-- Therefore, this should be checked **after** a command that ensures connectivity.
migrateStatus :: Path' Abs (Dir ProjectRootDir) -> J.Job
migrateStatus projectDir = runPrismaCommandAsDbJob projectDir $ \schema ->
["migrate", "status", "--schema", SP.fromAbsFile schema]
migrateStatus projectRootDir =
runPrismaCommandAsJob
projectRootDir
["migrate", "status", "--schema", SP.fromAbsFile schema]
where
schema = projectRootDir </> dbSchemaFileInProjectRootDir
-- | Runs `prisma migrate reset`, which drops the tables (so schemas and data is lost) and then
-- reapplies all the migrations.
reset :: Path' Abs (Dir ProjectRootDir) -> J.Job
reset projectDir = runPrismaCommandAsDbJob projectDir $ \schema ->
-- NOTE(martin): We do "--skip-seed" here because I just think seeding happening automatically on
-- reset is too aggressive / confusing.
["migrate", "reset", "--schema", SP.fromAbsFile schema, "--skip-generate", "--skip-seed"]
reset projectRootDir =
runPrismaCommandAsJob
projectRootDir
-- NOTE(martin): We do "--skip-seed" here because I just think seeding happening automatically on
-- reset is too aggressive / confusing.
["migrate", "reset", "--schema", SP.fromAbsFile schema, "--skip-generate", "--skip-seed"]
where
schema = projectRootDir </> dbSchemaFileInProjectRootDir
-- | Runs `prisma db seed`, which executes the seeding script specified in package.json in
-- prisma.seed field.
seed :: Path' Abs (Dir ProjectRootDir) -> String -> J.Job
-- NOTE: Since v 0.3, Prisma doesn't use --schema parameter for `db seed`.
seed projectDir seedName =
seed projectRootDir seedName =
runPrismaCommandAsJobWithExtraEnv
J.Db
[(dbSeedNameEnvVarName, seedName)]
projectDir
(const ["db", "seed"])
projectRootDir
["db", "seed"]
-- | Checks if the DB is running and connectable by running
-- `prisma db execute --stdin --schema <path to db schema>`.
@ -130,56 +141,48 @@ seed projectDir seedName =
-- Since nothing is passed to stdin, `prisma db execute` just runs an empty
-- SQL command, which works perfectly for checking if the database is running.
dbExecuteTest :: Path' Abs (Dir ProjectRootDir) -> J.Job
dbExecuteTest projectDir =
let absSchemaPath = projectDir </> dbSchemaFileInProjectRootDir
in runPrismaCommandAsDbJob
projectDir
(const ["db", "execute", "--stdin", "--schema", SP.fromAbsFile absSchemaPath])
dbExecuteTest projectRootDir =
let absSchemaPath = projectRootDir </> dbSchemaFileInProjectRootDir
in runPrismaCommandAsJob
projectRootDir
["db", "execute", "--stdin", "--schema", SP.fromAbsFile absSchemaPath]
-- | Runs `prisma studio` - Prisma's db inspector.
runStudio :: Path' Abs (Dir ProjectRootDir) -> J.Job
runStudio projectDir = runPrismaCommandAsDbJob projectDir $ \schema ->
["studio", "--schema", SP.fromAbsFile schema]
generatePrismaClient :: Path' Abs (Dir ProjectRootDir) -> (String, String) -> JobType -> J.Job
generatePrismaClient projectDir prismaClientOutputDirEnv jobType =
runPrismaCommandAsJobWithExtraEnv jobType envVars projectDir $ \schema ->
["generate", "--schema", SP.fromAbsFile schema]
runStudio projectRootDir =
runPrismaCommandAsJob projectRootDir ["studio", "--schema", SP.fromAbsFile schema]
where
envVars = [prismaClientOutputDirEnv]
schema = projectRootDir </> dbSchemaFileInProjectRootDir
runPrismaCommandAsDbJob ::
Path' Abs (Dir ProjectRootDir) ->
(Path' Abs (File PrismaDbSchema) -> [String]) ->
J.Job
runPrismaCommandAsDbJob projectDir makeCmdArgs =
runPrismaCommandAsJob J.Db projectDir makeCmdArgs
generatePrismaClient :: Path' Abs (Dir ProjectRootDir) -> J.Job
generatePrismaClient projectRootDir =
runPrismaCommandAsJob projectRootDir args
where
args =
[ "generate",
"--schema",
SP.fromAbsFile $ projectRootDir </> dbSchemaFileInProjectRootDir
]
runPrismaCommandAsJob ::
JobType ->
Path' Abs (Dir ProjectRootDir) ->
(Path' Abs (File PrismaDbSchema) -> [String]) ->
J.Job
runPrismaCommandAsJob jobType projectDir makeCmdArgs =
runPrismaCommandAsJobWithExtraEnv jobType [] projectDir makeCmdArgs
runPrismaCommandAsJob :: Path' Abs (Dir ProjectRootDir) -> [String] -> J.Job
runPrismaCommandAsJob projectRootDir args =
runPrismaCommandAsJobWithExtraEnv [] projectRootDir args
runPrismaCommandAsJobWithExtraEnv ::
JobType ->
[(String, String)] ->
Path' Abs (Dir ProjectRootDir) ->
(Path' Abs (File PrismaDbSchema) -> [String]) ->
[String] ->
J.Job
runPrismaCommandAsJobWithExtraEnv jobType envVars projectDir makeCmdArgs =
runNodeCommandAsJobWithExtraEnv envVars serverDir (absPrismaExecutableFp projectDir) (makeCmdArgs schemaFile) jobType
runPrismaCommandAsJobWithExtraEnv envVars projectRootDir args =
runNodeCommandAsJobWithExtraEnv envVars waspProjectDir (absPrismaExecutableFp waspProjectDir) args J.Db
where
serverDir = projectDir </> serverRootDirInProjectRootDir
schemaFile = projectDir </> dbSchemaFileInProjectRootDir
waspProjectDir = projectRootDir </> waspProjectDirFromProjectRootDir
-- | NOTE: The expectation is that `npm install` was already executed
-- such that we can use the locally installed package.
-- This assumption is ok since it happens during compilation now.
absPrismaExecutableFp :: Path' Abs (Dir ProjectRootDir) -> FilePath
absPrismaExecutableFp projectDir = SP.fromAbsFile prismaExecutableAbs
absPrismaExecutableFp :: Path' Abs (Dir WaspProjectDir) -> FilePath
absPrismaExecutableFp waspProjectDir = SP.fromAbsFile prismaExecutableAbs
where
prismaExecutableAbs :: Path' Abs File'
prismaExecutableAbs = projectDir </> serverRootDirInProjectRootDir </> [relfile|./node_modules/.bin/prisma|]
prismaExecutableAbs = waspProjectDir </> [relfile|./node_modules/.bin/prisma|]

View File

@ -1,6 +1,6 @@
module Wasp.Generator.DbGenerator.Operations
( migrateDevAndCopyToSource,
generatePrismaClients,
generatePrismaClient,
doesSchemaMatchDb,
writeDbSchemaChecksumToFile,
areAllMigrationsAppliedToDb,
@ -12,13 +12,10 @@ module Wasp.Generator.DbGenerator.Operations
)
where
import Control.Applicative (liftA2)
import Control.Concurrent (newChan)
import Control.Concurrent.Async (concurrently)
import Control.Monad (when)
import Control.Monad.Catch (catch)
import Control.Monad.Extra (whenM)
import Data.Either (isRight)
import qualified Data.Text as T
import qualified Path as P
import StrongPath (Abs, Dir, File, Path', Rel, (</>))
@ -36,8 +33,6 @@ import Wasp.Generator.DbGenerator.Common
dbSchemaChecksumOnLastGenerateFileProjectRootDir,
dbSchemaFileInProjectRootDir,
getOnLastDbConcurrenceChecksumFileRefreshAction,
serverPrismaClientOutputDirEnv,
webAppPrismaClientOutputDirEnv,
)
import qualified Wasp.Generator.DbGenerator.Jobs as DbJobs
import Wasp.Generator.FileDraft.WriteableMonad (WriteableMonad (copyDirectoryRecursive, doesDirectoryExist))
@ -184,31 +179,21 @@ isDbConnectionPossible DbConnectionSuccess = True
isDbConnectionPossible DbNotCreated = True
isDbConnectionPossible _ = False
generatePrismaClients :: Path' Abs (Dir ProjectRootDir) -> IO (Either String ())
generatePrismaClients projectRootDir = do
generateResult <- liftA2 (>>) generatePrismaClientForServer generatePrismaClientForWebApp projectRootDir
when (isRight generateResult) updateDbSchemaChecksumOnLastGenerate
return generateResult
where
generatePrismaClientForServer = generatePrismaClient serverPrismaClientOutputDirEnv J.Server
generatePrismaClientForWebApp = generatePrismaClient webAppPrismaClientOutputDirEnv J.WebApp
updateDbSchemaChecksumOnLastGenerate =
writeDbSchemaChecksumToFile projectRootDir dbSchemaChecksumOnLastGenerateFileProjectRootDir
generatePrismaClient ::
(String, String) ->
J.JobType ->
Path' Abs (Dir ProjectRootDir) ->
IO (Either String ())
generatePrismaClient prismaClientOutputDirEnv jobType projectRootDir = do
generatePrismaClient :: Path' Abs (Dir ProjectRootDir) -> IO (Either String ())
generatePrismaClient projectRootDir = do
chan <- newChan
(_, exitCode) <-
concurrently
(readJobMessagesAndPrintThemPrefixed chan)
(DbJobs.generatePrismaClient projectRootDir prismaClientOutputDirEnv jobType chan)
return $ case exitCode of
ExitSuccess -> Right ()
ExitFailure code -> Left $ "Prisma client generation failed with exit code: " ++ show code
(DbJobs.generatePrismaClient projectRootDir chan)
case exitCode of
ExitFailure code -> return $ Left $ "Prisma client generation failed with exit code: " ++ show code
ExitSuccess -> do
updateDbSchemaChecksumOnLastGenerate
return $ Right ()
where
updateDbSchemaChecksumOnLastGenerate =
writeDbSchemaChecksumToFile projectRootDir dbSchemaChecksumOnLastGenerateFileProjectRootDir
-- | Checks `prisma migrate diff` exit code to determine if schema.prisma is
-- different than the DB. Returns Nothing on error as we do not know the current state.

View File

@ -23,7 +23,6 @@ import Wasp.Generator.Common
import Wasp.Generator.DbGenerator.Common
( PrismaDbSchema,
dbSchemaFileFromAppComponentDir,
serverPrismaClientOutputDirEnv,
)
import Wasp.Generator.FileDraft (FileDraft (..), createTemplateFileDraft)
import qualified Wasp.Generator.FileDraft.TemplateFileDraft as TmplFD
@ -31,7 +30,6 @@ import Wasp.Generator.Monad (Generator, GeneratorError, runGenerator)
import Wasp.Generator.Templates (TemplatesDir, compileAndRenderTemplate)
import Wasp.Node.Version (latestMajorNodeVersion)
import qualified Wasp.SemanticVersion as SV
import Wasp.Util (getEnvVarDefinition)
genDockerFiles :: AppSpec -> Generator [FileDraft]
genDockerFiles spec = sequence [genDockerfile spec, genDockerignore spec]
@ -47,7 +45,6 @@ genDockerfile spec = do
( Just $
object
[ "usingPrisma" .= not (null $ AS.getDecls @AS.Entity.Entity spec),
"serverPrismaClientOutputDirEnv" .= getEnvVarDefinition serverPrismaClientOutputDirEnv,
"dbSchemaFileFromServerDir" .= SP.fromRelFile dbSchemaFileFromServerDir,
"nodeMajorVersion" .= show (SV.major latestMajorNodeVersion),
"userDockerfile" .= fromMaybe "" (AS.userDockerfileContents spec)

View File

@ -45,7 +45,6 @@ import Wasp.Env (envVarsToDotEnvContent)
import Wasp.Generator.Common
( ServerRootDir,
makeJsonWithEntityData,
prismaVersion,
)
import Wasp.Generator.FileDraft (FileDraft, createTextFileDraft)
import Wasp.Generator.Monad (Generator)
@ -152,7 +151,6 @@ npmDepsForWasp spec =
("cors", "^2.8.5"),
("express", "~4.18.1"),
("morgan", "~1.10.0"),
("@prisma/client", show prismaVersion),
("jsonwebtoken", "^8.5.1"),
-- NOTE: secure-password has a package.json override for sodium-native.
("secure-password", "^4.0.0"),
@ -172,7 +170,6 @@ npmDepsForWasp spec =
AS.Dependency.fromList
[ ("nodemon", "^2.0.19"),
("standard", "^17.0.0"),
("prisma", show prismaVersion),
-- TODO: Allow users to choose whether they want to use TypeScript
-- in their projects and install these dependencies accordingly.
("typescript", "^5.1.0"),