mirror of
https://github.com/dillonkearns/elm-pages-v3-beta.git
synced 2024-12-28 06:12:33 +03:00
Update form parser API.
This commit is contained in:
parent
d133441cb7
commit
cfad541029
@ -16,6 +16,14 @@ type Parser error decoded
|
||||
= Parser (Dict String (List error) -> Form.FormState -> ( Maybe decoded, Dict String (List error) ))
|
||||
|
||||
|
||||
optional : String -> Parser error (Maybe String)
|
||||
optional name =
|
||||
(\errors form ->
|
||||
( Just (form |> Dict.get name |> Maybe.map .value), errors )
|
||||
)
|
||||
|> Parser
|
||||
|
||||
|
||||
required : String -> error -> Parser error String
|
||||
required name error =
|
||||
(\errors form ->
|
||||
@ -32,6 +40,27 @@ required name error =
|
||||
|> Parser
|
||||
|
||||
|
||||
int : String -> error -> Parser error Int
|
||||
int name error =
|
||||
(\errors form ->
|
||||
case form |> Dict.get name |> Maybe.map .value of
|
||||
Just "" ->
|
||||
( Nothing, errors |> addError name error )
|
||||
|
||||
Just nonEmptyValue ->
|
||||
case nonEmptyValue |> String.toInt of
|
||||
Just parsedInt ->
|
||||
( Just parsedInt, errors )
|
||||
|
||||
Nothing ->
|
||||
( Nothing, errors |> addError name error )
|
||||
|
||||
Nothing ->
|
||||
( Nothing, errors |> addError name error )
|
||||
)
|
||||
|> Parser
|
||||
|
||||
|
||||
map2 : (value1 -> value2 -> combined) -> Parser error value1 -> Parser error value2 -> Parser error combined
|
||||
map2 combineFn (Parser parser1) (Parser parser2) =
|
||||
(\errors form ->
|
||||
@ -55,11 +84,104 @@ map2 combineFn (Parser parser1) (Parser parser2) =
|
||||
|> Parser
|
||||
|
||||
|
||||
map : (original -> mapped) -> Parser error original -> Parser error mapped
|
||||
map mapFn (Parser parser) =
|
||||
(\errors form ->
|
||||
let
|
||||
( combined1, allErrors1 ) =
|
||||
parser errors form
|
||||
in
|
||||
( Maybe.map mapFn combined1
|
||||
, allErrors1
|
||||
)
|
||||
)
|
||||
|> Parser
|
||||
|
||||
|
||||
validate : String -> (original -> Result error mapped) -> Parser error original -> Parser error mapped
|
||||
validate name mapFn (Parser parser) =
|
||||
(\errors form ->
|
||||
let
|
||||
( combined1, allErrors1 ) =
|
||||
parser errors form
|
||||
in
|
||||
case combined1 |> Maybe.map mapFn of
|
||||
Just (Ok okResult) ->
|
||||
( Just okResult
|
||||
, allErrors1
|
||||
)
|
||||
|
||||
Just (Err error) ->
|
||||
( Nothing
|
||||
, allErrors1 |> addError name error
|
||||
)
|
||||
|
||||
Nothing ->
|
||||
( Nothing
|
||||
, allErrors1
|
||||
)
|
||||
)
|
||||
|> Parser
|
||||
|
||||
|
||||
succeed : value -> Parser error value
|
||||
succeed value =
|
||||
Parser (\errors form -> ( Just value, Dict.empty ))
|
||||
|
||||
|
||||
fail : error -> Parser error value
|
||||
fail error =
|
||||
Parser (\errors form -> ( Nothing, Dict.fromList [ ( "global", [ error ] ) ] ))
|
||||
|
||||
|
||||
andThen : (value1 -> Parser error value2) -> Parser error value1 -> Parser error value2
|
||||
andThen andThenFn (Parser parser1) =
|
||||
(\errors form ->
|
||||
let
|
||||
( combined1, allErrors1 ) =
|
||||
parser1 errors form
|
||||
|
||||
foo : Maybe (Parser error value2)
|
||||
foo =
|
||||
Maybe.map andThenFn combined1
|
||||
in
|
||||
case foo of
|
||||
Just (Parser parser2) ->
|
||||
let
|
||||
( combined2, allErrors2 ) =
|
||||
parser2 errors form
|
||||
in
|
||||
( combined2
|
||||
, Dict.merge (\name errors1 dict -> ( name, errors1 ) :: dict)
|
||||
(\name errors1 errors2 dict -> ( name, errors1 ++ errors2 ) :: dict)
|
||||
(\name errors2 dict -> ( name, errors2 ) :: dict)
|
||||
allErrors1
|
||||
allErrors2
|
||||
[]
|
||||
|> Dict.fromList
|
||||
)
|
||||
|
||||
Nothing ->
|
||||
( Nothing, allErrors1 )
|
||||
)
|
||||
|> Parser
|
||||
|
||||
|
||||
run : Form.FormState -> Parser error decoded -> ( Maybe decoded, Dict String (List error) )
|
||||
run formState (Parser parser) =
|
||||
parser Dict.empty formState
|
||||
|
||||
|
||||
runOnList : List ( String, String ) -> Parser error decoded -> ( Maybe decoded, Dict String (List error) )
|
||||
runOnList rawFormData (Parser parser) =
|
||||
(rawFormData
|
||||
|> List.map
|
||||
(Tuple.mapSecond (\value -> { value = value, status = Form.NotVisited }))
|
||||
|> Dict.fromList
|
||||
)
|
||||
|> parser Dict.empty
|
||||
|
||||
|
||||
addError : String -> error -> Dict String (List error) -> Dict String (List error)
|
||||
addError name error allErrors =
|
||||
allErrors
|
||||
|
@ -14,10 +14,19 @@ formDecoder =
|
||||
(FormParser.required "last" "Last is required")
|
||||
|
||||
|
||||
type Uuid
|
||||
= Uuid String
|
||||
|
||||
|
||||
type Action
|
||||
= Signout
|
||||
| SetQuantity Uuid Int
|
||||
|
||||
|
||||
all : Test
|
||||
all =
|
||||
describe "Path"
|
||||
[ test "join two segments" <|
|
||||
describe "Form Parser"
|
||||
[ test "error for missing required fields" <|
|
||||
\() ->
|
||||
FormParser.run
|
||||
(Dict.fromList
|
||||
@ -41,4 +50,79 @@ all =
|
||||
, ( "last", [ "Last is required" ] )
|
||||
]
|
||||
)
|
||||
, test "parse into custom type" <|
|
||||
\() ->
|
||||
FormParser.run
|
||||
(Dict.fromList
|
||||
[ ( "kind"
|
||||
, { value = "signout"
|
||||
, status = Pages.Form.NotVisited
|
||||
}
|
||||
)
|
||||
]
|
||||
)
|
||||
(FormParser.required "kind" "Kind is required"
|
||||
|> FormParser.andThen
|
||||
(\kind ->
|
||||
if kind == "signout" then
|
||||
FormParser.succeed Signout
|
||||
|
||||
else if kind == "add" then
|
||||
FormParser.map2 SetQuantity
|
||||
(FormParser.required "itemId" "First is required" |> FormParser.map Uuid)
|
||||
(FormParser.int "setQuantity" "Expected setQuantity to be an integer")
|
||||
|
||||
else
|
||||
FormParser.fail "Error"
|
||||
)
|
||||
)
|
||||
|> Expect.equal
|
||||
( Just Signout
|
||||
, Dict.empty
|
||||
)
|
||||
, test "parse into custom type with int" <|
|
||||
\() ->
|
||||
FormParser.run
|
||||
(fields
|
||||
[ ( "kind", "add" )
|
||||
, ( "itemId", "123" )
|
||||
, ( "setQuantity", "1" )
|
||||
]
|
||||
)
|
||||
(FormParser.required "kind" "Kind is required"
|
||||
|> FormParser.andThen
|
||||
(\kind ->
|
||||
if kind == "signout" then
|
||||
FormParser.succeed Signout
|
||||
|
||||
else if kind == "add" then
|
||||
FormParser.map2 SetQuantity
|
||||
(FormParser.required "itemId" "First is required" |> FormParser.map Uuid)
|
||||
-- TODO what's the best way to combine together int and required? Should it be `requiredInt`, or `Form.required |> Form.int`?
|
||||
(FormParser.int "setQuantity" "Expected setQuantity to be an integer")
|
||||
|
||||
else
|
||||
FormParser.fail "Error"
|
||||
)
|
||||
)
|
||||
|> Expect.equal
|
||||
( Just (SetQuantity (Uuid "123") 1)
|
||||
, Dict.empty
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
field : String -> String -> ( String, Pages.Form.FieldState )
|
||||
field name value =
|
||||
( name
|
||||
, { value = value
|
||||
, status = Pages.Form.NotVisited
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
fields : List ( String, String ) -> Dict String Pages.Form.FieldState
|
||||
fields list =
|
||||
list
|
||||
|> List.map (\( name, value ) -> field name value)
|
||||
|> Dict.fromList
|
||||
|
Loading…
Reference in New Issue
Block a user