Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make sure entity declaration is not used in the Wasp file #2152

Merged
merged 7 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 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,7 @@ import qualified Wasp.Psl.Ast.Schema as Psl.Schema
analyze :: Psl.Schema.Schema -> String -> Either [AnalyzeError] [Decl]
analyze prismaSchemaAst =
(left (map ParseError) . parseStatements)
>=> (left ((: []) . ValidationError) . validateAst)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imagine opening up this PR after reviewing and writing TypeScript all day. And the first thing you see is this line here.

Oh well, time to gaslight myself into thinking Haskell is readable again 😄

>=> 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
27 changes: 27 additions & 0 deletions waspc/src/Wasp/Analyzer/Parser/Valid.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module Wasp.Analyzer.Parser.Valid
( validateAst,
)
where

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

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 findEntityDecl stmts of
sodic marked this conversation as resolved.
Show resolved Hide resolved
Just (P.WithCtx ctx _) -> Left (entitiesNoLongerSupportedError, ctx)
Nothing -> Right ast
where
findEntityDecl :: [P.WithCtx P.Stmt] -> Maybe (P.WithCtx P.Stmt)
findEntityDecl = find isEntityDecl
Copy link
Contributor

@sodic sodic Jul 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can pattern-match the maybe here and return a boolean, no need to propagate it.

You can then call the function includesEntities :: [P.WithCtx P.Stmt] -> Bool

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue here is that I need the ctx that contains the SourceRange to produce the error, so I do need the result, not just the Bool answer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've adjusted the code a bit 🤷


isEntityDecl :: P.WithCtx P.Stmt -> Bool
isEntityDecl = \case
P.WithCtx _ (P.Decl "entity" _ _) -> True
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How come we need to hardcode "entity" here? I haven't looked at this code for a long time so it might be necessary, but it seems weird.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well spotted! We should make sure that the entity declaration type name ("entity") is the same in the:

  • definition of the entity declaration type
  • here.

I'll make it happen 👍

_ -> False

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"
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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Formatting

-- | 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
Loading