Skip to content

Commit

Permalink
Validation for @default attribute on userEntity (#2311)
Browse files Browse the repository at this point in the history
  • Loading branch information
infomiho authored Oct 1, 2024
1 parent d1f0c79 commit c61f08e
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 43 deletions.
19 changes: 1 addition & 18 deletions waspc/src/Wasp/AppSpec/Entity.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,17 @@ module Wasp.AppSpec.Entity
getPslModelBody,
getIdField,
getIdBlockAttribute,
isFieldUnique,
-- only for testing:
doesFieldHaveAttribute,
)
where

import Data.Aeson (FromJSON (parseJSON))
import Data.Data (Data)
import Data.List (find)
import Wasp.AppSpec.Core.IsDecl (IsDecl)
import Wasp.AppSpec.Entity.Field (Field)
import qualified Wasp.AppSpec.Entity.Field as Field
import qualified Wasp.Psl.Ast.Attribute as Psl.Attribute
import qualified Wasp.Psl.Ast.Model as Psl.Model
import Wasp.Psl.Util (doesPslFieldHaveAttribute, findIdBlockAttribute, findIdField)
import Wasp.Psl.Util (findIdBlockAttribute, findIdField)

data Entity = Entity
{ fields :: ![Field],
Expand Down Expand Up @@ -54,18 +50,5 @@ getPslModelBody = pslModelBody
getIdField :: Entity -> Maybe Psl.Model.Field
getIdField = findIdField . getPslModelBody

isFieldUnique :: String -> Entity -> Maybe Bool
isFieldUnique fieldName = doesFieldHaveAttribute fieldName "unique"

doesFieldHaveAttribute :: String -> String -> Entity -> Maybe Bool
doesFieldHaveAttribute fieldName attrName entity =
doesPslFieldHaveAttribute attrName <$> findPslFieldByName fieldName entity

findPslFieldByName :: String -> Entity -> Maybe Psl.Model.Field
findPslFieldByName fieldName Entity {pslModelBody = Psl.Model.Body elements} =
find isField [field | (Psl.Model.ElementField field) <- elements]
where
isField Psl.Model.Field {_name = name} = name == fieldName

getIdBlockAttribute :: Entity -> Maybe Psl.Attribute.Attribute
getIdBlockAttribute = findIdBlockAttribute . getPslModelBody
15 changes: 10 additions & 5 deletions waspc/src/Wasp/AppSpec/Valid.hs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import Wasp.Generator.Crud (crudDeclarationToOperationsList)
import Wasp.Node.Version (oldestWaspSupportedNodeVersion)
import qualified Wasp.Node.Version as V
import qualified Wasp.Psl.Ast.Model as Psl.Model
import qualified Wasp.Psl.Util as Psl.Util
import Wasp.Psl.Valid (getValidDbSystemFromPrismaSchema)
import qualified Wasp.SemanticVersion as SV
import qualified Wasp.SemanticVersion.VersionBound as SVB
Expand Down Expand Up @@ -128,14 +129,18 @@ validateUserEntity spec =
case App.auth (snd $ getApp spec) of
Nothing -> []
Just auth ->
[ GenericValidationError $ "Entity '" ++ userEntityName ++ "' (referenced by app.auth.userEntity) must have an ID field (specified with the '@id' attribute)"
| isNothing idFieldType
]
case Entity.getIdField userEntity of
Nothing -> [userEntityMissingIdFieldError]
Just idField ->
if Psl.Util.doesPslFieldHaveAttribute "default" idField
then []
else [userEntityIdFieldMissingDefaultAttrError]
where
idFieldType = Entity.getIdField userEntity

(userEntityName, userEntity) = AS.resolveRef spec (Auth.userEntity auth)

userEntityMissingIdFieldError = GenericValidationError $ "Entity '" ++ userEntityName ++ "' (referenced by app.auth.userEntity) must have an ID field (specified with the '@id' attribute)"
userEntityIdFieldMissingDefaultAttrError = GenericValidationError $ "Entity '" ++ userEntityName ++ "' (referenced by app.auth.userEntity) must have an ID field (specified with the '@id' attribute) with a default value"

validateAppAuthIsSetIfAnyPageRequiresAuth :: AppSpec -> [ValidationError]
validateAppAuthIsSetIfAnyPageRequiresAuth spec =
[ GenericValidationError
Expand Down
16 changes: 0 additions & 16 deletions waspc/test/AppSpec/EntityTest.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,6 @@ spec_AppSpecEntityTest = do
getIdField entityWithIdField `shouldBe` Just idField
it "Returns Nothing if primary field doesn't exist" $ do
getIdField entityWithoutIdField `shouldBe` Nothing

describe "isFieldUnique" $ do
it "Returns Nothing if the field doesn't exist on the entity" $ do
Entity.isFieldUnique "nonExistingField" entityWithoutIdField `shouldBe` Nothing
it "Returns Just False if the field exists on the entity but isn't unique" $ do
Entity.isFieldUnique "description" entityWithIdField `shouldBe` Just False
it "Returns Just True if the field exists and is unique" $ do
Entity.isFieldUnique "id" entityWithIdField `shouldBe` Just True

describe "doesFieldHaveAttribute" $ do
it "Returns Nothing if the field doesn't exist on the entity" $ do
Entity.doesFieldHaveAttribute "nonExistingField" "unique" entityWithoutIdField `shouldBe` Nothing
it "Returns Just False if the field exists on the entity but doesn't have the required attribute" $ do
Entity.doesFieldHaveAttribute "description" "id" entityWithIdField `shouldBe` Just False
it "Returns Just True if the field exists on the entity and has the required attribute" $ do
Entity.doesFieldHaveAttribute "id" "id" entityWithIdField `shouldBe` Just True
where
entityWithIdField =
Entity.makeEntity $
Expand Down
37 changes: 33 additions & 4 deletions waspc/test/AppSpec/ValidTest.hs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import qualified Wasp.AppSpec.Query as AS.Query
import qualified Wasp.AppSpec.Route as AS.Route
import qualified Wasp.AppSpec.Valid as ASV
import qualified Wasp.ExternalConfig.PackageJson as EC.PackageJson
import qualified Wasp.Psl.Ast.Argument as Psl.Argument
import qualified Wasp.Psl.Ast.Attribute as Psl.Attribute
import qualified Wasp.Psl.Ast.Model as Psl.Model
import qualified Wasp.SemanticVersion as SV
Expand Down Expand Up @@ -260,22 +261,44 @@ spec_AppSpecValid = do
AS.Decl.makeDecl userEntityName (userEntity :: AS.Entity.Entity)
]
}
let invalidUserEntity =
let invalidUserEntityWithoutIdField =
AS.Entity.makeEntity
( Psl.Model.Body
[]
)
let invalidUserEntityWithoutDefaultAttr =
AS.Entity.makeEntity
( Psl.Model.Body
[ Psl.Model.ElementField $
Psl.Model.Field
{ Psl.Model._name = "id",
Psl.Model._type = Psl.Model.String,
Psl.Model._typeModifiers = [],
Psl.Model._attrs =
[ Psl.Attribute.Attribute
{ Psl.Attribute._attrName = "id",
Psl.Attribute._attrArgs = []
}
]
}
]
)

it "returns no error if app.auth is not set, regardless of shape of user entity" $ do
ASV.validateAppSpec (makeSpec Nothing invalidUserEntity) `shouldBe` []
ASV.validateAppSpec (makeSpec Nothing invalidUserEntityWithoutIdField) `shouldBe` []
ASV.validateAppSpec (makeSpec Nothing validUserEntity) `shouldBe` []
it "returns no error if app.auth is set and user entity is of valid shape" $ do
ASV.validateAppSpec (makeSpec (Just validAppAuth) validUserEntity) `shouldBe` []
it "returns an error if app.auth is set and user entity is of invalid shape" $ do
ASV.validateAppSpec (makeSpec (Just validAppAuth) invalidUserEntity)
it "returns an error if app.auth is set and user entity wihtout an ID field" $ do
ASV.validateAppSpec (makeSpec (Just validAppAuth) invalidUserEntityWithoutIdField)
`shouldBe` [ Valid.GenericValidationError
"Entity 'User' (referenced by app.auth.userEntity) must have an ID field (specified with the '@id' attribute)"
]
it "returns an error if app.auth is set and user entity with an ID field that is missing the default attr" $ do
ASV.validateAppSpec (makeSpec (Just validAppAuth) invalidUserEntityWithoutDefaultAttr)
`shouldBe` [ Valid.GenericValidationError
"Entity 'User' (referenced by app.auth.userEntity) must have an ID field (specified with the '@id' attribute) with a default value"
]

describe "should validate email sender setup." $ do
let emailAuthConfig =
Expand Down Expand Up @@ -414,6 +437,12 @@ spec_AppSpecValid = do
[ Psl.Attribute.Attribute
{ Psl.Attribute._attrName = "id",
Psl.Attribute._attrArgs = []
},
Psl.Attribute.Attribute
{ Psl.Attribute._attrName = "default",
Psl.Attribute._attrArgs =
[ Psl.Argument.ArgUnnamed (Psl.Argument.FuncExpr "autoincrement" [])
]
}
]
}
Expand Down

0 comments on commit c61f08e

Please sign in to comment.