Skip to content

Commit

Permalink
Add getFields and optionalMaybeField
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinSStewart committed Oct 4, 2024
1 parent 9f5982d commit ce6b77c
Showing 1 changed file with 54 additions and 2 deletions.
56 changes: 54 additions & 2 deletions src/Codec.elm
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ module Codec exposing
, encoder, encodeToString, encodeToValue
, string, bool, int, float, char, enum
, maybe, nullable, list, array, dict, set, tuple, triple, result
, ObjectCodec, object, field, optionalField, optionalNullableField, buildObject
, ObjectCodec, object, field, optionalField, optionalNullableField, optionalMaybeField, buildObject
, CustomCodec, custom, variant0, variant1, variant2, variant3, variant4, variant5, variant6, variant7, variant8, buildCustom
, oneOf
, map
, succeed, recursive, fail, andThen, lazy, value, build, constant
, nullableField, maybeField
, getFields
)

{-| A `Codec a` contain a JSON `Decoder a` and the corresponding `a -> Value` encoder.
Expand Down Expand Up @@ -42,7 +43,7 @@ module Codec exposing
# Object Primitives
@docs ObjectCodec, object, field, optionalField, optionalNullableField, buildObject
@docs ObjectCodec, object, field, optionalField, optionalNullableField, optionalMaybeField, buildObject
# Custom Types
Expand All @@ -69,6 +70,11 @@ module Codec exposing
@docs nullableField, maybeField
# Miscellaneous
@docs getFields
-}

import Array exposing (Array)
Expand Down Expand Up @@ -494,6 +500,7 @@ type ObjectCodec a b
= ObjectCodec
{ encoder : a -> List ( String, Value )
, decoder : Decoder b
, fields : List String
}


Expand Down Expand Up @@ -529,9 +536,17 @@ object ctor =
ObjectCodec
{ encoder = \_ -> []
, decoder = JD.succeed ctor
, fields = []
}


{-| Get all of the fields present in an ObjectCodec. This might be useful if you are making a request to a database and you want to both decode the response and be able to include in the request a filter so you only receive the fields you intend to decode.
-}
getFields : ObjectCodec a b -> List String
getFields (ObjectCodec ocodec) =
ocodec.fields


{-| Specify the name, getter and `Codec` for a field.
The name is only used as the field name in the resulting JSON, and has no impact on the Elm side.
Expand All @@ -542,6 +557,7 @@ field name getter codec (ObjectCodec ocodec) =
ObjectCodec
{ encoder = \v -> ( name, encoder codec <| getter v ) :: ocodec.encoder v
, decoder = JD.map2 (\f x -> f x) ocodec.decoder (JD.field name (decoder codec))
, fields = name :: ocodec.fields
}


Expand Down Expand Up @@ -572,6 +588,7 @@ maybeField name getter codec (ObjectCodec ocodec) =
|> JD.field name
|> JD.maybe
|> JD.map2 (\f x -> f x) ocodec.decoder
, fields = name :: ocodec.fields
}


Expand Down Expand Up @@ -608,6 +625,40 @@ optionalField name getter codec (ObjectCodec ocodec) =
JD.succeed Nothing
)
|> JD.map2 (\f x -> f x) ocodec.decoder
, fields = name :: ocodec.fields
}


{-| An object field that might not be present or might contain data that maps to Nothing.
This function flattens both into Nothing rather than making you deal with a `Maybe (Maybe a)` type.
When encoding, if the value is Nothing then the field is not included.
-}
optionalMaybeField : String -> (a -> Maybe f) -> Codec (Maybe f) -> ObjectCodec a (Maybe f -> b) -> ObjectCodec a b
optionalMaybeField name getter codec (ObjectCodec ocodec) =
ObjectCodec
{ encoder =
\v ->
case getter v of
Just present ->
( name, encoder codec (Just present) ) :: ocodec.encoder v

Nothing ->
ocodec.encoder v
, decoder =
-- Decoder inspired by https://github.com/elm-community/json-extra/blob/4.3.0/src/Json/Decode/Extra.elm#L272
JD.keyValuePairs JD.value
|> JD.andThen
(\json ->
if List.any (\( k, _ ) -> k == name) json then
--The field exist, actually run the decoder
JD.field name (decoder codec)

else
-- The field is missing
JD.succeed Nothing
)
|> JD.map2 (\f x -> f x) ocodec.decoder
, fields = name :: ocodec.fields
}


Expand Down Expand Up @@ -644,6 +695,7 @@ optionalNullableField name getter codec (ObjectCodec ocodec) =
JD.succeed Nothing
)
|> JD.map2 (\f x -> f x) ocodec.decoder
, fields = name :: ocodec.fields
}


Expand Down

0 comments on commit ce6b77c

Please sign in to comment.