json-spec 0.4.1.0 → 0.5.0.0
raw patch · 4 files changed
+94/−12 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Data.JsonSpec: [unField] :: Field (key :: Symbol) t -> t
+ Data.JsonSpec: unField :: forall (key :: Symbol) t. Field key t -> t
Files
- json-spec.cabal +1/−1
- src/Data/JsonSpec.hs +6/−5
- src/Data/JsonSpec/Spec.hs +19/−1
- test/jsonspec.hs +68/−5
json-spec.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: json-spec-version: 0.4.1.0+version: 0.5.0.0 synopsis: Type-level JSON specification maintainer: rick@owensmurray.com description: See the README at: https://github.com/owensmurray/json-spec#json-spec
src/Data/JsonSpec.hs view
@@ -74,6 +74,7 @@ SpecJSON(..), Tag(..), Field(..),+ unField, JSONStructure, Rec(..), eitherDecode,@@ -90,11 +91,11 @@ fromJSONStructure), StructureFromJSON(reprParseJSON), eitherDecode) import Data.JsonSpec.Encode (HasJsonEncodingSpec(EncodingSpec, toJSONStructure), StructureToJSON(reprToJSON), encode)-import Data.JsonSpec.Spec (Field(Field, unField), FieldSpec(Optional,- Required), Rec(Rec, unRec), Specification(JsonArray, JsonBool,- JsonDateTime, JsonEither, JsonInt, JsonLet, JsonNullable, JsonNum,- JsonObject, JsonRaw, JsonRef, JsonString, JsonTag), Tag(Tag), (:::),- (::?), JSONStructure)+import Data.JsonSpec.Spec (Field(Field), FieldSpec(Optional, Required),+ Rec(Rec, unRec), Specification(JsonArray, JsonBool, JsonDateTime,+ JsonEither, JsonInt, JsonLet, JsonNullable, JsonNum, JsonObject,+ JsonRaw, JsonRef, JsonString, JsonTag), Tag(Tag), (:::), (::?),+ JSONStructure, unField) import Prelude ((.), (<$>), (=<<))
src/Data/JsonSpec/Spec.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE PolyKinds #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-}@@ -13,6 +14,7 @@ sym, Tag(..), Field(..),+ unField, Rec(..), JStruct, FieldSpec(..),@@ -28,7 +30,9 @@ import Data.String (IsString(fromString)) import Data.Text (Text) import Data.Time (UTCTime)+import GHC.Records (HasField(getField)) import GHC.TypeLits (KnownSymbol, Symbol, symbolVal)+import Prelude (($), Bool, Either, Eq, Int, Maybe, Show) {-|@@ -201,6 +205,12 @@ > (Field @key3 valueType, > ()))) + Note! "Object structures" of this type have the appropriate 'HasField'+ instances, which allows you to use -XOverloadedRecordDot to extract+ values as an alternative to pattern matching the whole tuple structure+ when building your 'HasJsonDecodingSpec' instances. See @TestHasField@+ in the tests for an example+ Arrays, booleans, numbers, and strings are just Lists, 'Bool's, 'Scientific's, and 'Text's respectively. @@ -323,8 +333,16 @@ {-| Structural representation of an object field. -}-newtype Field (key :: Symbol) t = Field {unField :: t}+newtype Field (key :: Symbol) t = Field t deriving stock (Show, Eq)+instance {-# overlappable #-} (HasField k more v) => HasField k (Field notIt x, more) v where+ getField (_, more) = getField @k @_ @v more+instance HasField k (Field k v, more) v where+ getField (Field v, _) = v+++unField :: Field key t -> t+unField (Field t) = t {- |
test/jsonspec.hs view
@@ -2,6 +2,7 @@ {-# LANGUAGE DerivingVia #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-}@@ -11,6 +12,7 @@ {-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -Wwarn #-} {- Because of GHC-69797 -}+{- But re-enable the errors we most care about -} {-# OPTIONS_GHC -Werror=missing-import-lists #-} module Main (main) where@@ -18,21 +20,22 @@ import Control.Monad (join) import Data.Aeson (FromJSON, ToJSON) import Data.ByteString.Lazy (ByteString)-import Data.JsonSpec (Field(Field, unField), FieldSpec(Optional,+import Data.JsonSpec (Field(Field), FieldSpec(Optional, Required), HasJsonDecodingSpec(DecodingSpec, fromJSONStructure), HasJsonEncodingSpec(EncodingSpec, toJSONStructure), Rec(Rec, unRec), SpecJSON(SpecJSON), Specification(JsonArray, JsonBool, JsonDateTime, JsonEither, JsonInt, JsonLet, JsonNullable, JsonNum, JsonObject, JsonRaw, JsonRef, JsonString, JsonTag), Tag(Tag), (:::), (::?),- eitherDecode, encode)+ eitherDecode, encode, unField) import Data.Proxy (Proxy(Proxy)) import Data.Scientific (Scientific) import Data.Text (Text) import Data.Time (UTCTime(UTCTime)) import OM.Show (ShowJ(ShowJ))-import Prelude (Applicative(pure), Bool(False, True), Either(Left,- Right), Enum(toEnum), Functor(fmap), Maybe(Just, Nothing), Monad((>>=)),- Traversable(traverse), ($), (.), Eq, IO, Int, Show, String, realToFrac)+import Prelude (Applicative(pure), Bool(False, True), Either(Left, Right),+ Enum(toEnum), Functor(fmap), Maybe(Just, Nothing), Monad((>>=)),+ Num(negate), Traversable(traverse), ($), (.), Eq, IO, Int, Show,+ String, realToFrac) import Test.Hspec (describe, hspec, it, shouldBe) import qualified Data.Aeson as A @@ -399,7 +402,36 @@ in actual `shouldBe` expected + it "HasField" $+ let+ expected :: Maybe TestHasField+ expected =+ Just+ TestHasField+ { thfFoo = "foo"+ , thfBar = 10+ , thfBaz =+ TestSubObj+ { foo2 = "bar"+ , bar2 = negate 10+ }+ } + actual :: Maybe TestHasField+ actual =+ A.decode+ "{\+ \ \"foo\": \"foo\",\+ \ \"bar\": 10,\+ \ \"baz\": {\+ \ \"a_string\": \"bar\",\+ \ \"an_int\": -10\+ \ }\+ \}"+ in+ actual `shouldBe` expected++ sampleTestObject :: TestObj sampleTestObject = TestObj@@ -709,5 +741,36 @@ ())))) = pure TestOptionality { toFoo , toBar , toBaz , toQux }+++data TestHasField = TestHasField+ { thfFoo :: Text+ , thfBar :: Int+ , thfBaz :: TestSubObj+ }+ deriving stock (Show, Eq)+ deriving (FromJSON) via (SpecJSON TestHasField)+instance HasJsonDecodingSpec TestHasField where+ type DecodingSpec TestHasField =+ JsonObject+ '[ "foo" ::: JsonString+ , "bar" ::: JsonInt+ , "baz" ::: JsonObject+ '[ "a_string" ::: JsonString+ , "an_int" ::: JsonInt+ ]+ ]+ fromJSONStructure val =+ pure+ TestHasField+ { thfFoo = val.foo+ , thfBar = val.bar+ , thfBaz =+ TestSubObj+ { foo2 = val.baz.a_string+ , bar2 = val.baz.an_int+ }++ }