packages feed

nonempty-wrapper-aeson (empty) → 0.1.0.0

raw patch · 5 files changed

+217/−0 lines, 5 filesdep +aesondep +basedep +containers

Dependencies added: aeson, base, containers, hspec, hspec-core, hspec-discover, nonempty-wrapper, nonempty-wrapper-aeson

Files

+ LICENSE view
@@ -0,0 +1,15 @@+ISC License++Copyright (c) 2022 Gautier DI FOLCO++Permission to use, copy, modify, and/or distribute this software for any+purpose with or without fee is hereby granted, provided that the above+copyright notice and this permission notice appear in all copies.++THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY+AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR+PERFORMANCE OF THIS SOFTWARE.
+ nonempty-wrapper-aeson.cabal view
@@ -0,0 +1,91 @@+cabal-version:       3.0+name:                nonempty-wrapper-aeson+version:             0.1.0.0+author:              Gautier DI FOLCO+maintainer:          gautier.difolco@gmail.com+category:            Data+build-type:          Simple+license:             ISC+license-file:        LICENSE+synopsis:            aeson instances for 'NonEmpty'+description:         aeson instances for 'NonEmpty'.+Homepage:            http://github.com/blackheaven/nonempty-wrapper/nonempty-wrapper-aeson+tested-with:         GHC==9.2.2, GHC==9.0.2, GHC==8.10.7++library+  default-language:   Haskell2010+  build-depends:+        base == 4.*+      , aeson == 2.*+      , nonempty-wrapper >= 0.1.0.0 && < 1+  hs-source-dirs: src+  exposed-modules:+      Data.Aeson.Types.Instances.NonEmpty+  other-modules:+      Paths_nonempty_wrapper_aeson+  autogen-modules:+      Paths_nonempty_wrapper_aeson+  default-extensions:+      DataKinds+      DefaultSignatures+      DeriveAnyClass+      DeriveGeneric+      DerivingStrategies+      DerivingVia+      DuplicateRecordFields+      FlexibleContexts+      GADTs+      GeneralizedNewtypeDeriving+      KindSignatures+      LambdaCase+      OverloadedLists+      OverloadedStrings+      RankNTypes+      RecordWildCards+      ScopedTypeVariables+      TypeApplications+      TypeFamilies+      TypeOperators+  ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wpartial-fields -Wredundant-constraints++test-suite nonempty-wrapper-aeson-test+  type: exitcode-stdio-1.0+  hs-source-dirs: test+  main-is: Spec.hs+  other-modules:+      Data.Aeson.Types.Instances.NonEmptySpec+      Paths_nonempty_wrapper_aeson+  autogen-modules:+      Paths_nonempty_wrapper_aeson+  default-extensions:+      DataKinds+      DefaultSignatures+      DeriveAnyClass+      DeriveGeneric+      DerivingStrategies+      DerivingVia+      DuplicateRecordFields+      FlexibleContexts+      GADTs+      GeneralizedNewtypeDeriving+      KindSignatures+      LambdaCase+      OverloadedLists+      OverloadedStrings+      RankNTypes+      RecordWildCards+      ScopedTypeVariables+      TypeApplications+      TypeFamilies+      TypeOperators+  ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wpartial-fields -Wredundant-constraints+  build-depends:+      base+    , nonempty-wrapper+    , nonempty-wrapper-aeson+    , aeson+    , containers >= 0.5 && < 1+    , hspec+    , hspec-core+    , hspec-discover+  default-language: Haskell2010
+ src/Data/Aeson/Types/Instances/NonEmpty.hs view
@@ -0,0 +1,75 @@+{-# LANGUAGE UndecidableInstances #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++-- |+-- Module        : Test.QuickCheck.Instances.NonEmpty+-- Copyright     : Gautier DI FOLCO+-- License       : BSD2+--+-- Maintainer    : Gautier DI FOLCO <gautier.difolco@gmail.com>+-- Stability     : Unstable+-- Portability   : GHC+--+-- aeson instances for 'NonEmpty'+module Data.Aeson.Types.Instances.NonEmpty+  ( FromJSON (..),+    ToJSON (..),+    FromJSONKey (..),+    ToJSONKey (..),+  )+where++import Control.Monad ((>=>))+import Data.Aeson+import Data.Aeson.Types+import Data.Coerce+import Data.NonEmpty++instance+  ( FromJSON a,+    Semigroup a,+    NonEmptySingleton a,+    NonEmptyFromContainer a,+    FromJSON (NonEmptySingletonElement a)+  ) =>+  FromJSON (NonEmpty a)+  where+  parseJSON x = do+    raw <- parseJSON x+    case nonEmpty raw of+      Just y -> pure y+      Nothing -> fail "parsing NonEmpty failed, unexpected empty container"++instance+  ( FromJSON a,+    NonEmptySingleton a,+    NonEmptyFromContainer a,+    FromJSON (NonEmptySingletonElement a),+    FromJSONKey (NonEmptySingletonElement a),+    FromJSONKey a,+    Semigroup a+  ) =>+  FromJSONKey (NonEmpty a)+  where+  fromJSONKey =+    case fromJSONKey @a of+      FromJSONKeyCoerce -> FromJSONKeyTextParser (run . coerce)+      FromJSONKeyText f -> FromJSONKeyTextParser (run . f)+      FromJSONKeyTextParser f -> FromJSONKeyTextParser (f >=> run)+      FromJSONKeyValue f -> FromJSONKeyValue (f >=> run)+    where+      run :: a -> Parser (NonEmpty a)+      run x =+        case nonEmpty x of+          Just y -> pure y+          Nothing -> fail "parsing NonEmpty failed, unexpected empty container"++instance (ToJSON a) => ToJSON (NonEmpty a) where+  toJSON = toJSON . getNonEmpty+  toEncoding = toEncoding . getNonEmpty+  toJSONList = toJSONList . map getNonEmpty+  toEncodingList = toEncodingList . map getNonEmpty++instance (ToJSONKey a) => ToJSONKey (NonEmpty a) where+  toJSONKey = contramapToJSONKeyFunction getNonEmpty toJSONKey+  toJSONKeyList = contramapToJSONKeyFunction (map getNonEmpty) toJSONKeyList
+ test/Data/Aeson/Types/Instances/NonEmptySpec.hs view
@@ -0,0 +1,35 @@+module Data.Aeson.Types.Instances.NonEmptySpec+  ( main,+    spec,+  )+where++import Data.Aeson+import Data.Aeson.Types.Instances.NonEmpty ()+import qualified Data.Map.Strict as M+import Data.NonEmpty+import Data.Proxy+import Test.Hspec++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+  describe "decode" $ do+    describe "regular element" $ do+      it "valid case should parse" $+        decode "[42]" `shouldBe` Just (singleton (Proxy @[Int]) 42)+      it "empty case should fail" $+        decode "[]" `shouldBe` Nothing @(NonEmpty String)+    describe "key" $ do+      it "valid case should parse" $+        decode "{\"a\":42}" `shouldBe` Just (M.singleton (singleton (Proxy @String) 'a') (42 :: Int))+      it "empty case should fail" $+        decode "{\"\":42}" `shouldBe` Nothing @(M.Map (NonEmpty String) Int)++  describe "encode" $ do+    it "list of Int" $+      encode (singleton (Proxy @[Int]) 42) `shouldBe` "[42]"+    it "keymap" $+      encode (M.singleton (singleton (Proxy @String) 'a') (42 :: Int)) `shouldBe` "{\"a\":42}"
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}