Skip to content

Commit

Permalink
Make sure entity declaration is not used in the Wasp file (#2152)
Browse files Browse the repository at this point in the history
  • Loading branch information
infomiho committed Jul 9, 2024
1 parent 0eef00d commit 8f136fb
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 8 deletions.
20 changes: 20 additions & 0 deletions waspc/src/Wasp/Analyzer.hs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ import Wasp.Analyzer.AnalyzeError
)
import Wasp.Analyzer.Evaluator (Decl, evaluate, takeDecls)
import Wasp.Analyzer.Parser (parseStatements)
import Wasp.Analyzer.Parser.Valid (validateAst)
import Wasp.Analyzer.Prisma (injectEntitiesFromPrismaSchema)
import Wasp.Analyzer.StdTypeDefinitions (stdTypes)
import Wasp.Analyzer.TypeChecker (typeCheck)
Expand All @@ -138,6 +139,25 @@ import qualified Wasp.Psl.Ast.Schema as Psl.Schema
analyze :: Psl.Schema.Schema -> String -> Either [AnalyzeError] [Decl]
analyze prismaSchemaAst =
(left (map ParseError) . parseStatements)
{--
Why introduce AST validation and not just throw a ParseError from the parser?
We want to support the `entity` declaration in the AST but not in the Wasp source
file.
This was the fastest and cleanest (e.g. not having to hack the type checker) way
to allow users to define entities in the Prisma schema file. We are parsing
the `schema.prisma` file and injecting the models into the Wasp AST as entity
statements.
We validate the AST to prevent users from defining entities in the Wasp source
file since we don't want to allow defining entities in two places.
Wasp file -(parse)-> AST -(validate)-> AST -(injectEntities)-> AST (...)
^ disallow entities here
^ inject entities here
--}
>=> (left ((: []) . ValidationError) . validateAst)
>=> injectEntitiesFromPrismaSchema prismaSchemaAst
>=> (left ((: []) . TypeError) . typeCheck stdTypes)
>=> (left ((: []) . EvaluationError) . evaluate stdTypes)
2 changes: 2 additions & 0 deletions waspc/src/Wasp/Analyzer/AnalyzeError.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ data AnalyzeError
= ParseError PE.ParseError
| TypeError TE.TypeError
| EvaluationError EE.EvaluationError
| ValidationError (String, Ctx)
deriving (Show, Eq)

getErrorMessageAndCtx :: AnalyzeError -> (String, Ctx)
getErrorMessageAndCtx = \case
ParseError e -> first (("Parse error:\n" ++) . indent 2) $ PE.getErrorMessageAndCtx e
ValidationError (msg, ctx) -> ("Validation error:\n" ++ indent 2 msg, ctx)
TypeError e -> first (("Type error:\n" ++) . indent 2) $ TE.getErrorMessageAndCtx e
EvaluationError e -> first (("Evaluation error:\n" ++) . indent 2) $ EE.getErrorMessageAndCtx e
26 changes: 26 additions & 0 deletions waspc/src/Wasp/Analyzer/Parser/Valid.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module Wasp.Analyzer.Parser.Valid
( validateAst,
)
where

import Data.List (find)
import qualified Wasp.Analyzer.Parser as P
import Wasp.Analyzer.StdTypeDefinitions.Entity (entityDeclTypeName)

validateAst :: P.AST -> Either (String, P.Ctx) P.AST
validateAst = validateNoEntityDeclInWaspFile

validateNoEntityDeclInWaspFile :: P.AST -> Either (String, P.Ctx) P.AST
validateNoEntityDeclInWaspFile ast@(P.AST stmts) = case findEntityStmt stmts of
Just (P.WithCtx ctx _) -> Left (entitiesNoLongerSupportedError, ctx)
Nothing -> Right ast
where
findEntityStmt :: [P.WithCtx P.Stmt] -> Maybe (P.WithCtx P.Stmt)
findEntityStmt =
find
( \(P.WithCtx _ (P.Decl declTypeName _ _)) -> declTypeName == entityDeclTypeName
)

entitiesNoLongerSupportedError :: String
entitiesNoLongerSupportedError =
"Entities can no longer be defined in the .wasp file. You should migrate your entities to the schema.prisma file. Read more: https://wasp-lang.dev/docs/migrate-from-0-13-to-0-14#migrate-to-the-new-schemaprisma-file"
10 changes: 8 additions & 2 deletions waspc/src/Wasp/Analyzer/StdTypeDefinitions/Entity.hs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
{-# LANGUAGE TypeApplications #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

module Wasp.Analyzer.StdTypeDefinitions.Entity () where
module Wasp.Analyzer.StdTypeDefinitions.Entity
( entityDeclTypeName,
)
where

import Control.Arrow (left)
import Wasp.Analyzer.Evaluator.EvaluationError (mkEvaluationError)
Expand All @@ -16,7 +19,7 @@ import qualified Wasp.Psl.Parser.Model
instance IsDeclType Entity where
declType =
DeclType
{ dtName = "entity",
{ dtName = entityDeclTypeName,
dtBodyType = Type.QuoterType "psl",
dtEvaluate = \typeDefinitions bindings declName expr ->
Decl.makeDecl @Entity declName <$> declEvaluate typeDefinitions bindings expr
Expand All @@ -27,3 +30,6 @@ instance IsDeclType Entity where
left (ER.mkEvaluationError ctx . ER.ParseError . ER.EvaluationParseErrorParsec) $
makeEntity <$> Wasp.Psl.Parser.Model.parseBody pslString
_ -> Left $ mkEvaluationError ctx $ ER.ExpectedType (Type.QuoterType "psl") (TC.AST.exprType expr)

entityDeclTypeName :: String
entityDeclTypeName = "entity"
12 changes: 6 additions & 6 deletions waspc/src/Wasp/Analyzer/TypeChecker/TypeError.hs
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ data TypeError'
-- We use "unify" in the TypeChecker when trying to infer the common type for
-- typed expressions that we know should be of the same type (e.g. for
-- elements in the list).
= UnificationError TypeCoercionError
= UnificationError TypeCoercionError
-- | Type coercion error that occurs when trying to use the typed expression
-- of type T1 where T2 is expected. If T2 is a super type of T1 and T1 can be
-- safely coerced to T2, no problem, but if not, we get this error.
| CoercionError TypeCoercionError
| NoDeclarationType TypeName
| UndefinedIdentifier Identifier
| QuoterUnknownTag QuoterTag
| DictDuplicateField DictFieldName
| CoercionError TypeCoercionError
| NoDeclarationType TypeName
| UndefinedIdentifier Identifier
| QuoterUnknownTag QuoterTag
| DictDuplicateField DictFieldName
deriving (Eq, Show)
{- ORMOLU_ENABLE -}

Expand Down
71 changes: 71 additions & 0 deletions waspc/test/Analyzer/ValidTest.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
module Analyzer.ValidTest where

import Data.Either (fromRight, isRight)
import Test.Tasty.Hspec
import Wasp.Analyzer.Parser hiding (withCtx)
import qualified Wasp.Analyzer.Parser as P
import Wasp.Analyzer.Parser.Valid (validateAst)
import qualified Wasp.Version as WV

spec_ValidateAst :: Spec
spec_ValidateAst = do
it "Returns an error when entities are used" $ do
validateAndParseSource (waspSourceLines ++ entityDeclarationLines)
`shouldBe` Left
( "Entities can no longer be defined in the .wasp file. You should migrate your entities to the schema.prisma file. Read more: https://wasp-lang.dev/docs/migrate-from-0-13-to-0-14#migrate-to-the-new-schemaprisma-file",
P.Ctx
( P.SourceRegion
(P.SourcePosition 34 1)
(P.SourcePosition 37 5)
)
)

it "Returns AST when everything is correct" $ do
isRight (validateAndParseSource waspSourceLines) `shouldBe` True
where
validateAndParseSource = validateAst . parseSource

parseSource = fromRight (error "Parsing went wrong") . parseStatements . unlines

waspSourceLines =
[ "app Todo {",
" wasp: {",
" version: \"^" ++ show WV.waspVersion ++ "\",",
" },",
" title: \"Todo App\",",
" head: [\"foo\", \"bar\"],",
" auth: {",
" userEntity: User,",
" methods: {",
" usernameAndPassword: {",
" userSignupFields: import { getUserFields } from \"@src/auth/signup.js\",",
" }",
" },",
" onAuthFailedRedirectTo: \"/\",",
" },",
"}",
"",
"page HomePage {",
" component: import Home from \"@src/pages/Main\"",
"}",
"",
"route HomeRoute { path: \"/\", to: HomePage }",
"",
"query getUsers {",
" fn: import { getAllUsers } from \"@src/foo.js\",",
" entities: [User]",
"}",
"",
"action updateUser {",
" fn: import { updateUser } from \"@src/foo.js\",",
" entities: [User],",
" auth: true",
"}"
]

entityDeclarationLines =
[ "entity User {=psl",
" id Int @id @default(autoincrement())",
" email String @unique",
"psl=}"
]
2 changes: 2 additions & 0 deletions waspc/waspc.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ library
Wasp.Analyzer.Parser.SourceSpan
Wasp.Analyzer.Parser.Token
Wasp.Analyzer.Parser.TokenSet
Wasp.Analyzer.Parser.Valid
Wasp.Analyzer.StdTypeDefinitions
Wasp.Analyzer.StdTypeDefinitions.App.Dependency
Wasp.Analyzer.StdTypeDefinitions.Entity
Expand Down Expand Up @@ -612,6 +613,7 @@ test-suite waspc-test
Analyzer.TestUtil
Analyzer.TypeChecker.InternalTest
Analyzer.TypeCheckerTest
Analyzer.ValidTest
AnalyzerTest
AppSpec.ValidTest
AppSpec.EntityTest
Expand Down
1 change: 1 addition & 0 deletions waspc/waspls/src/Wasp/LSP/Diagnostic.hs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ waspErrorAsPrettyEditorMessage = Text.pack . fst . W.getErrorMessageAndCtx

waspErrorSource :: W.AnalyzeError -> Text
waspErrorSource (W.ParseError _) = "parse"
waspErrorSource (W.ValidationError _) = "validate"
waspErrorSource (W.TypeError _) = "typecheck"
waspErrorSource (W.EvaluationError _) = "evaluate"

Expand Down

0 comments on commit 8f136fb

Please sign in to comment.