ihp-ide-1.4.0: IHP/IDE/SchemaDesigner/Controller/Validation.hs
module IHP.IDE.SchemaDesigner.Controller.Validation where
import IHP.ControllerPrelude
import Text.Countable (singularize)
isUniqueInList :: (Foldable t, Eq a) => t a -> Maybe a -> Validator a
isUniqueInList list oldValue newValue
| newValue `elem` list && Just newValue /= oldValue = Failure "Value is in forbidden list and not equal to old value"
| otherwise = Success
isNotIllegalKeyword :: Validator Text
isNotIllegalKeyword name
| isIllegalKeyword name = Failure $ tshow name <> " is a reserved keyword and can not be used as a name"
| otherwise = Success
validateNameInSchema :: Text -> [Text] -> Maybe Text -> Validator Text
validateNameInSchema nameType namesInUse oldName =
validateAll [ nonEmpty |> withCustomErrorMessage (ucfirst nameType <> " cannot be empty")
, isNotIllegalKeyword
, isUniqueInList namesInUse oldName
|> withCustomErrorMessage (ucfirst nameType <> " is already used")
]
isIllegalKeyword :: Text -> Bool
isIllegalKeyword input =
case input of
"_" -> True
_ -> isSQLKeyword input || (isHaskellKeyword (singularize input))
isSQLKeyword :: Text -> Bool
isSQLKeyword input = case (toUpper input) of
"BIGINT" -> True
"BIT" -> True
"BOOLEAN" -> True
"CHAR" -> True
"CHARACTER" -> True
"COALESCE" -> True
"CONVERT" -> True
"DEC" -> True
"DECIMAL" -> True
"EXISTS" -> True
"EXTRACT" -> True
"FLOAT" -> True
"GREATEST" -> True
"INOUT" -> True
"INT" -> True
"INTEGER" -> True
"INTERVAL" -> True
"LEAST" -> True
"NATIONAL" -> True
"NCHAR" -> True
"NONE" -> True
"NULLIF" -> True
"NUMERIC" -> True
"OUT" -> True
"OVERLAY" -> True
"POSITION" -> True
"PRECISION" -> True
"REAL" -> True
"ROW" -> True
"SETOF" -> True
"SMALLINT" -> True
"SUBSTRING" -> True
"TIME" -> True
"TIMESTAMP" -> True
"TREAT" -> True
"TRIM" -> True
"VARCHAR" -> True
"ALL" -> True
"ANALYSE" -> True
"ANALYZE" -> True
"AND" -> True
"ANY" -> True
"ARRAY" -> True
"AS" -> True
"ASC" -> True
"ASYMMETRIC" -> True
"BOTH" -> True
"CASE" -> True
"CAST" -> True
"CHECK" -> True
"COLLATE" -> True
"COLUMN" -> True
"CONSTRAINT" -> True
"CREATE" -> True
"CURRENT_DATE" -> True
"CURRENT_ROLE" -> True
"CURRENT_TIME" -> True
"CURRENT_TIMESTAMP" -> True
"CURRENT_USER" -> True
"DEFAULT" -> True
"DEFERRABLE" -> True
"DESC" -> True
"DISTINCT" -> True
"DO" -> True
"ELSE" -> True
"END" -> True
"EXCEPT" -> True
"FALSE" -> True
"FOR" -> True
"FOREIGN" -> True
"FROM" -> True
"GRANT" -> True
"GROUP" -> True
"HAVING" -> True
"IN" -> True
"INITIALLY" -> True
"INTERSECT" -> True
"INTO" -> True
"LEADING" -> True
"LIMIT" -> True
"LOCALTIME" -> True
"LOCALTIMESTAMP" -> True
"NEW" -> True
"NOT" -> True
"NULL" -> True
"OFF" -> True
"OFFSET" -> True
"OLD" -> True
"ON" -> True
"ONLY" -> True
"OR" -> True
"ORDER" -> True
"PLACING" -> True
"PRIMARY" -> True
"REFERENCES" -> True
"SELECT" -> True
"SESSION_USER" -> True
"SOME" -> True
"SYMMETRIC" -> True
"TABLE" -> True
"THEN" -> True
"TO" -> True
"TRAILING" -> True
"TRUE" -> True
"UNION" -> True
"UNIQUE" -> True
"USER" -> True
"USING" -> True
"WHEN" -> True
"WHERE" -> True
"AUTHORIZATION" -> True
"BETWEEN" -> True
"BINARY" -> True
"CROSS" -> True
"FREEZE" -> True
"FULL" -> True
"ILIKE" -> True
"INNER" -> True
"IS" -> True
"ISNULL" -> True
"JOIN" -> True
"LEFT" -> True
"LIKE" -> True
"NATURAL" -> True
"NOTNULL" -> True
"OUTER" -> True
"OVERLAPS" -> True
"RIGHT" -> True
"SIMILAR" -> True
"VERBOSE" -> True
"BYTEA" -> True
_ -> False
-- "toLower" feels more natural for Haskell keywords
isHaskellKeyword :: Text -> Bool
isHaskellKeyword input =
case (toLower input) of
"as" -> True
"case" -> True
"class" -> True
"data" -> True
"default" -> True
"deriving" -> True
"do" -> True
"else" -> True
"hiding" -> True
"if" -> True
"import" -> True
"in" -> True
"infix" -> True
"infixl" -> True
"infixr" -> True
"instance" -> True
"let" -> True
"module" -> True
"newtype" -> True
"of" -> True
"qualified" -> True
"then" -> True
"type" -> True
"where" -> True
"forall" -> True
"mdo" -> True
"family" -> True
"role" -> True
"pattern" -> True
"static" -> True
"group" -> True
"by" -> True
"using" -> True
"foreign" -> True
"export" -> True
"label" -> True
"dynamic" -> True
"safe" -> True
"interruptible" -> True
"unsafe" -> True
"stdcall" -> True
"ccall" -> True
"capi" -> True
"prim" -> True
"javascript" -> True
"rec" -> True
"proc" -> True
_ -> False