Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
38 changes: 19 additions & 19 deletions integration-tests/sqlite/src/Main.gren
Original file line number Diff line number Diff line change
Expand Up @@ -301,15 +301,15 @@ personEncoder p =

personDecoder : Decoder Person
personDecoder =
Decode.string "name" <| \name ->
Decode.string "role" <| \role ->
Decode.field "name" Decode.string <| \name ->
Decode.field "role" Decode.string <| \role ->
Decode.succeed { name = name, role = role }


badPersonDecoder : Decoder Person
badPersonDecoder =
Decode.string "namee" <| \name ->
Decode.string "role_" <| \role ->
Decode.field "namee" Decode.string <| \name ->
Decode.field "role_" Decode.string <| \role ->
Decode.succeed { name = name, role = role }


Expand Down Expand Up @@ -380,8 +380,8 @@ friendshipQ =
"""
, parameters = []
, rowDecoder =
Decode.string "person_a" <| \personA ->
Decode.string "person_b" <| \personB ->
Decode.field "person_a" Decode.string <| \personA ->
Decode.field "person_b" Decode.string <| \personB ->
Decode.succeed { personA = personA, personB = personB }
}

Expand Down Expand Up @@ -424,8 +424,8 @@ badDecoder db =
{ query = "SELECT * FROM people WHERE name = :name"
, parameters = [ Encode.string "name" "Robin" ]
, rowDecoder =
Decode.int "name" <| \name ->
Decode.string "role" <| \role ->
Decode.field "name" Decode.int <| \name ->
Decode.field "role" Decode.string <| \role ->
Decode.succeed { name = name, role = role }
}

Expand Down Expand Up @@ -502,16 +502,16 @@ allFieldTypesEncoder row =

allFieldTypesDecoder : Decoder AllFieldTypes
allFieldTypesDecoder =
Decode.string "string_field" <| \stringField ->
Decode.int "int_field" <| \intField ->
Decode.float "float_field" <| \floatField ->
Decode.bool "bool_true" <| \boolTrue ->
Decode.bool "bool_false" <| \boolFalse ->
Decode.json (Json.Decode.array Json.Decode.string) "json_field" <| \jsonField ->
Decode.time "time_field" <| \timeField ->
Decode.time "time_with_millis_field" <| \timeWithMillisField ->
Decode.maybe Decode.string "maybe_just_string" <| \maybeJustString ->
Decode.maybe Decode.string "maybe_nothing_string" <| \maybeNothingString ->
Decode.field "string_field" Decode.string <| \stringField ->
Decode.field "int_field" Decode.int <| \intField ->
Decode.field "float_field" Decode.float <| \floatField ->
Decode.field "bool_true" Decode.bool <| \boolTrue ->
Decode.field "bool_false" Decode.bool <| \boolFalse ->
Decode.field "json_field" (Decode.json (Json.Decode.array Json.Decode.string)) <| \jsonField ->
Decode.field "time_field" Decode.time <| \timeField ->
Decode.field "time_with_millis_field" Decode.time <| \timeWithMillisField ->
Decode.field "maybe_just_string" (Decode.maybe Decode.string) <| \maybeJustString ->
Decode.field "maybe_nothing_string" (Decode.maybe Decode.string) <| \maybeNothingString ->
Decode.succeed
{ stringField = stringField
, intField = intField
Expand Down Expand Up @@ -612,6 +612,6 @@ allTimesQ =
{ query = "SELECT t FROM times ORDER BY rowid"
, parameters = []
, rowDecoder =
Decode.time "t" <| \t ->
Decode.field "t" Decode.time <| \t ->
Decode.succeed t
}
124 changes: 60 additions & 64 deletions src/Sqlite/Decode.gren
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module Sqlite.Decode exposing
, json
, time
, maybe
, field

-- Composing
, succeed
Expand Down Expand Up @@ -66,51 +67,48 @@ type Decoder a

{-| Decode a string field.
-}
string : String -> (String -> Decoder a) -> Decoder a
string fieldName cont =
fieldHelper fieldName Json.Decode.string cont
string : Decoder String
string =
Json.Decode.string |> Decoder


{-| Decode an integer field.
-}
int : String -> (Int -> Decoder a) -> Decoder a
int fieldName cont =
fieldHelper fieldName Json.Decode.int cont
int : Decoder Int
int =
Json.Decode.int |> Decoder


{-| Decode a float field.
-}
float : String -> (Float -> Decoder a) -> Decoder a
float fieldName cont =
fieldHelper fieldName Json.Decode.float cont
float : Decoder Float
float =
Json.Decode.float |> Decoder


{-| Decode a boolean field.

Booleans in sqlite are stored as integers with 1 and 0 as True and False.
See <https://www.sqlite.org/datatype3.html#boolean_datatype>
-}
bool : String -> (Bool -> Decoder a) -> Decoder a
bool fieldName cont =
let
boolDecoder =
Json.Decode.int
|> Json.Decode.andThen
(\i ->
when i is
0 ->
Json.Decode.succeed False

1 ->
Json.Decode.succeed True

n ->
Json.Decode.fail <|
"Expected 0 or 1 in boolean field, got " ++
String.fromInt n
)
in
fieldHelper fieldName boolDecoder cont
bool : Decoder Bool
bool =
Json.Decode.int
|> Json.Decode.andThen
(\i ->
when i is
0 ->
Json.Decode.succeed False

1 ->
Json.Decode.succeed True

n ->
Json.Decode.fail <|
"Expected 0 or 1 in boolean field, got " ++
String.fromInt n
)
|> Decoder


{-| Decode a JSON field.
Expand All @@ -122,28 +120,25 @@ Use `json()` in your SELECT to ensure you get text regardless of how the JSON wa
{ query = "SELECT json(tags) as tags FROM items WHERE id = 1"
, parameters = []
, rowDecoder =
Sqlite.Decode.json (Json.Decode.array Json.Decode.string) "tags" <| \tags ->
Decode.field "tags" (Decode.json (Json.Decode.array Json.Decode.string)) <| \tags ->
Sqlite.Decode.succeed { tags = tags }
}

See <https://www.sqlite.org/json1.html>
-}
json : Json.Decode.Decoder a -> String -> (a -> Decoder b) -> Decoder b
json jsonDecoder fieldName cont =
let
decoder =
Json.Decode.string
|> Json.Decode.andThen
(\str ->
when Json.Decode.decodeString jsonDecoder str is
Ok val ->
Json.Decode.succeed val

Err err ->
Json.Decode.fail (Json.Decode.errorToString err)
)
in
fieldHelper fieldName decoder cont
json : Json.Decode.Decoder a -> Decoder a
json jsonDecoder =
Json.Decode.string
|> Json.Decode.andThen
(\str ->
when Json.Decode.decodeString jsonDecoder str is
Ok val ->
Json.Decode.succeed val

Err err ->
Json.Decode.fail (Json.Decode.errorToString err)
)
|> Decoder


{-| Decode a Time.Posix value.
Expand All @@ -154,32 +149,28 @@ how both [Sqlite.Encode.time](Sqlite.Encode#time) and
which aligns with SQLite's `unixepoch` function.
See <https://sqlite.org/lang_datefunc.html>
-}
time : String -> (Time.Posix -> Decoder a) -> Decoder a
time fieldName cont =
fieldHelper fieldName
(Json.Decode.map
time : Decoder Time.Posix
time =
Json.Decode.float
|> Json.Decode.map
(\seconds -> Time.millisToPosix (Math.round (seconds * 1000.0)))
Json.Decode.float
)
cont
|> Decoder


{-| Decode a nullable field in the database.

The first parameter is the field decoder function for the type if the value is not null.
For example, to decode a nullable TEXT field:

Sqlite.Decode.maybe Decode.string "nickname" <| \maybeNickname ->
Decode.field (Decode.maybe Decode.string) "nickname" <| \maybeNickname ->
Sqlite.Decode.succeed maybeNickname
-}
maybe : (String -> (a -> Decoder b) -> Decoder b) -> String -> (Maybe a -> Decoder b) -> Decoder b
maybe decoderFn fieldName cont =
maybe : Decoder a -> Decoder (Maybe a)
maybe decoder =
Decoder <|
Json.Decode.oneOf
[ unwrap (decoderFn fieldName (\val -> cont (Just val)))
, Json.Decode.andThen
(\_ -> unwrap (cont Nothing))
(Json.Decode.field fieldName (Json.Decode.null {}))
[ unwrap decoder |> Json.Decode.map Just
, Json.Decode.succeed Nothing
]


Expand Down Expand Up @@ -218,12 +209,17 @@ toJson =
unwrap


fieldHelper : String -> Json.Decode.Decoder a -> (a -> Decoder b) -> Decoder b
fieldHelper fieldName jsonDecoder cont =
fieldHelper : Json.Decode.Decoder a -> (a -> Decoder b) -> Decoder b
fieldHelper jsonDecoder cont =
Decoder <|
Json.Decode.andThen
(\val -> unwrap (cont val))
(Json.Decode.field fieldName jsonDecoder)
jsonDecoder


field : String -> Decoder a -> (a -> Decoder b) -> Decoder b
field fieldName decoder cont =
fieldHelper (Json.Decode.field fieldName (unwrap decoder)) cont


unwrap : Decoder a -> Json.Decode.Decoder a
Expand Down
Loading