{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies      #-}
-- |
-- Module: Data.Greskell.GraphSON
-- Description: Encoding and decoding GraphSON
-- Maintainer: Toshio Ito <debug.ito@gmail.com>
--
--
module Data.Greskell.GraphSON
    ( -- * GraphSON
      GraphSON (..)
    , GraphSONTyped (..)
      -- ** constructors
    , nonTypedGraphSON
    , typedGraphSON
    , typedGraphSON'
      -- ** parser support
    , parseTypedGraphSON
      -- * GValue
    , GValue
    , GValueBody (..)
      -- ** constructors
    , nonTypedGValue
    , typedGValue'
      -- * FromGraphSON
    , FromGraphSON (..)
      -- ** parser support
    , Parser
    , parseEither
    , parseUnwrapAll
    , parseUnwrapList
    , (.:)
    , parseJSONViaGValue
      -- * Examples
    , examples
    ) where

import           Control.Applicative                  ((<$>), (<*>), (<|>))
import           Control.Monad                        (when)
import           Data.Aeson                           (FromJSON (parseJSON), FromJSONKey,
                                                       ToJSON (toJSON), Value (..), object, (.=))
import qualified Data.Aeson                           as Aeson
import           Data.Aeson.Key                       (Key)
import qualified Data.Aeson.Key                       as Key
import           Data.Aeson.KeyMap                    (KeyMap)
import qualified Data.Aeson.KeyMap                    as KM
import           Data.Aeson.Types                     (Parser)
import qualified Data.Aeson.Types                     as Aeson (parseEither)
import           Data.Foldable                        (Foldable (foldr))
import           Data.Functor.Identity                (Identity (..))
import           Data.Hashable                        (Hashable (..))
import qualified Data.HashMap.Lazy                    as L (HashMap)
import           Data.HashMap.Strict                  (HashMap)
import           Data.HashSet                         (HashSet)
import           Data.Int                             (Int16, Int32, Int64, Int8)
import qualified Data.IntMap.Lazy                     as L (IntMap)
import qualified Data.IntMap.Lazy                     as LIntMap
import           Data.IntSet                          (IntSet)
import           Data.List.NonEmpty                   (NonEmpty (..))
import qualified Data.Map.Lazy                        as L (Map)
import qualified Data.Map.Lazy                        as LMap
import           Data.Monoid                          (mempty)
import qualified Data.Monoid                          as M
import           Data.Ratio                           (Ratio)
import           Data.Scientific                      (Scientific)
import qualified Data.Semigroup                       as S
import           Data.Sequence                        (Seq)
import           Data.Set                             (Set)
import           Data.Text                            (Text, unpack)
import qualified Data.Text.Lazy                       as TL
import           Data.Traversable                     (Traversable (traverse))
import           Data.UUID                            (UUID)
import qualified Data.UUID                            as UUID
import           Data.Vector                          (Vector)
import           Data.Word                            (Word16, Word32, Word64, Word8)
import           GHC.Exts                             (IsList (Item))
import qualified GHC.Exts                             as List (fromList, toList)
import           GHC.Generics                         (Generic)
import           Numeric.Natural                      (Natural)

import           Data.Greskell.GMap                   (FlattenedMap, GMap, GMapEntry,
                                                       parseToFlattenedMap, parseToGMap,
                                                       parseToGMapEntry, unGMap)


-- re-exports
import           Data.Greskell.GraphSON.Core
import           Data.Greskell.GraphSON.GraphSONTyped (GraphSONTyped (..))
import           Data.Greskell.GraphSON.GValue


-- | Types that can be constructed from 'GValue'. This is analogous to
-- 'FromJSON' class.
--
-- Instances of basic types are implemented based on the following
-- rule.
--
-- - Simple scalar types (e.g. 'Int' and 'Text'): use 'parseUnwrapAll'.
-- - List-like types (e.g. @[]@, 'Vector' and 'Set'): use
--   'parseUnwrapList'.
-- - Map-like types (e.g. 'L.HashMap' and 'L.Map'): parse into 'GMap'
--   first, then unwrap the 'GMap' wrapper. That way, all versions of
--   GraphSON formats are handled properly.
-- - Trivial wrapper types (e.g. 'Identity'): just parse the item inside.
-- - Other types: see the individual instance documentation.
--
-- Note that 'Char' does not have 'FromGraphSON' instance. This is
-- intentional. As stated in the document of
-- 'Data.Greskell.AsIterator.AsIterator', using 'String' in greskell
-- is an error in most cases. To prevent you from using 'String',
-- 'Char' (and thus 'String') don't have 'FromGraphSON' instances.
--
-- @since 0.1.2.0
class FromGraphSON a where
  parseGraphSON :: GValue -> Parser a

-- | Unwrap the given 'GValue' with 'unwrapAll', and just parse the
-- result with 'parseJSON'.
--
-- Useful to implement 'FromGraphSON' instances for scalar types.
--
-- @since 0.1.2.0
parseUnwrapAll :: FromJSON a => GValue -> Parser a
parseUnwrapAll :: forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll GValue
gv = forall a. FromJSON a => Value -> Parser a
parseJSON forall a b. (a -> b) -> a -> b
$ GValue -> Value
unwrapAll GValue
gv

---- Looks like we don't need this.

-- -- | Unwrap the given 'GValue' with 'unwrapOne', parse the result to
-- -- @(t GValue)@, and recursively parse the children with
-- -- 'parseGraphSON'.
-- --
-- -- Useful to implement 'FromGraphSON' instances for 'Traversable'
-- -- types.
-- parseUnwrapTraversable :: (Traversable t, FromJSON (t GValue), FromGraphSON a)
--                        => GValue -> Parser (t a)
-- parseUnwrapTraversable gv = traverse parseGraphSON =<< (parseJSON $ unwrapOne gv)

-- | Extract 'GArray' from the given 'GValue', parse the items in the
-- array, and gather them by 'List.fromList'.
--
-- Useful to implement 'FromGraphSON' instances for 'IsList' types.
--
-- @since 0.1.2.0
parseUnwrapList :: (IsList a, i ~ Item a, FromGraphSON i) => GValue -> Parser a
parseUnwrapList :: forall a i.
(IsList a, i ~ Item a, FromGraphSON i) =>
GValue -> Parser a
parseUnwrapList (GValue (GraphSON Maybe Text
_ (GArray Vector GValue
v))) = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall l. IsList l => [Item l] -> l
List.fromList forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON forall a b. (a -> b) -> a -> b
$ forall l. IsList l => l -> [Item l]
List.toList Vector GValue
v
parseUnwrapList (GValue (GraphSON Maybe Text
_ GValueBody
body)) = forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail ([Char]
"Expects GArray, but got " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show GValueBody
body)

-- | Parse 'GValue' into 'FromGraphSON'.
--
-- @since 0.1.2.0
parseEither :: FromGraphSON a => GValue -> Either String a
parseEither :: forall a. FromGraphSON a => GValue -> Either [Char] a
parseEither = forall a b. (a -> Parser b) -> a -> Either [Char] b
Aeson.parseEither forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON

-- | Like Aeson's 'Aeson..:', but for 'FromGraphSON'.
--
-- @since 1.0.0.0
(.:) :: FromGraphSON a => KeyMap GValue -> Key -> Parser a
KeyMap GValue
go .: :: forall a. FromGraphSON a => KeyMap GValue -> Key -> Parser a
.: Key
label = forall b a. b -> (a -> b) -> Maybe a -> b
maybe Parser a
failure forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON forall a b. (a -> b) -> a -> b
$ forall v. Key -> KeyMap v -> Maybe v
KM.lookup Key
label KeyMap GValue
go
  where
    failure :: Parser a
failure = forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail ([Char]
"Cannot find field " forall a. [a] -> [a] -> [a]
++ Key -> [Char]
Key.toString Key
label)

-- | Implementation of 'parseJSON' based on 'parseGraphSON'. The input
-- 'Value' is first converted to 'GValue', and it's parsed to the
-- output type.
--
-- @since 0.1.2.0
parseJSONViaGValue :: FromGraphSON a => Value -> Parser a
parseJSONViaGValue :: forall a. FromGraphSON a => Value -> Parser a
parseJSONViaGValue Value
v = forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall a. FromJSON a => Value -> Parser a
parseJSON Value
v

---- Trivial instances

instance FromGraphSON GValue where
  parseGraphSON :: GValue -> Parser GValue
parseGraphSON = forall (m :: * -> *) a. Monad m => a -> m a
return
instance FromGraphSON Int where
  parseGraphSON :: GValue -> Parser Int
parseGraphSON = forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll
instance FromGraphSON Text where
  parseGraphSON :: GValue -> Parser Text
parseGraphSON = forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll
instance FromGraphSON TL.Text where
  parseGraphSON :: GValue -> Parser Text
parseGraphSON = forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll
instance FromGraphSON Bool where
  parseGraphSON :: GValue -> Parser Bool
parseGraphSON = forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll
instance FromGraphSON Double where
  parseGraphSON :: GValue -> Parser Double
parseGraphSON = forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll
instance FromGraphSON Float where
  parseGraphSON :: GValue -> Parser Float
parseGraphSON = forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll
instance FromGraphSON Int8 where
  parseGraphSON :: GValue -> Parser Int8
parseGraphSON = forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll
instance FromGraphSON Int16 where
  parseGraphSON :: GValue -> Parser Int16
parseGraphSON = forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll
instance FromGraphSON Int32 where
  parseGraphSON :: GValue -> Parser Int32
parseGraphSON = forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll
instance FromGraphSON Int64 where
  parseGraphSON :: GValue -> Parser Int64
parseGraphSON = forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll
instance FromGraphSON Integer where
  parseGraphSON :: GValue -> Parser Integer
parseGraphSON = forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll
instance FromGraphSON Natural where
  parseGraphSON :: GValue -> Parser Natural
parseGraphSON = forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll
instance (FromJSON a, Integral a) => FromGraphSON (Ratio a) where
  parseGraphSON :: GValue -> Parser (Ratio a)
parseGraphSON = forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll
instance FromGraphSON Word where
  parseGraphSON :: GValue -> Parser Word
parseGraphSON = forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll
instance FromGraphSON Word8 where
  parseGraphSON :: GValue -> Parser Word8
parseGraphSON = forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll
instance FromGraphSON Word16 where
  parseGraphSON :: GValue -> Parser Word16
parseGraphSON = forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll
instance FromGraphSON Word32 where
  parseGraphSON :: GValue -> Parser Word32
parseGraphSON = forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll
instance FromGraphSON Word64 where
  parseGraphSON :: GValue -> Parser Word64
parseGraphSON = forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll
instance FromGraphSON Scientific where
  parseGraphSON :: GValue -> Parser Scientific
parseGraphSON = forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll
instance FromGraphSON IntSet where
  parseGraphSON :: GValue -> Parser IntSet
parseGraphSON = forall a. FromJSON a => GValue -> Parser a
parseUnwrapAll

-- | First convert to 'Text', and convert to 'Key'.
--
-- @since 1.0.0.0
instance FromGraphSON Key where
  parseGraphSON :: GValue -> Parser Key
parseGraphSON = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Text -> Key
Key.fromText forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON

---- List instances

instance FromGraphSON a => FromGraphSON [a] where
  parseGraphSON :: GValue -> Parser [a]
parseGraphSON = forall a i.
(IsList a, i ~ Item a, FromGraphSON i) =>
GValue -> Parser a
parseUnwrapList
instance FromGraphSON a => FromGraphSON (Vector a) where
  parseGraphSON :: GValue -> Parser (Vector a)
parseGraphSON = forall a i.
(IsList a, i ~ Item a, FromGraphSON i) =>
GValue -> Parser a
parseUnwrapList
instance FromGraphSON a => FromGraphSON (Seq a) where
  parseGraphSON :: GValue -> Parser (Seq a)
parseGraphSON = forall a i.
(IsList a, i ~ Item a, FromGraphSON i) =>
GValue -> Parser a
parseUnwrapList
-- | @since 0.1.3.0
instance FromGraphSON a => FromGraphSON (NonEmpty a) where
  parseGraphSON :: GValue -> Parser (NonEmpty a)
parseGraphSON GValue
gv = do
    [a]
list <- forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON GValue
gv
    case [a]
list of
      []         -> forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail ([Char]
"Empty list.")
      (a
a : [a]
rest) -> forall (m :: * -> *) a. Monad m => a -> m a
return (a
a forall a. a -> [a] -> NonEmpty a
:| [a]
rest)

---- Set instances

instance (FromGraphSON a, Ord a) => FromGraphSON (Set a) where
  parseGraphSON :: GValue -> Parser (Set a)
parseGraphSON = forall a i.
(IsList a, i ~ Item a, FromGraphSON i) =>
GValue -> Parser a
parseUnwrapList
instance (FromGraphSON a, Eq a, Hashable a) => FromGraphSON (HashSet a) where
  parseGraphSON :: GValue -> Parser (HashSet a)
parseGraphSON = forall a i.
(IsList a, i ~ Item a, FromGraphSON i) =>
GValue -> Parser a
parseUnwrapList

---- Trivial wrapper type instances

-- | @since 0.1.3.0
instance FromGraphSON a => FromGraphSON (Identity a) where
  parseGraphSON :: GValue -> Parser (Identity a)
parseGraphSON = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. a -> Identity a
Identity forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON
-- | @since 0.1.3.0
instance FromGraphSON a => FromGraphSON (S.Min a) where
  parseGraphSON :: GValue -> Parser (Min a)
parseGraphSON = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. a -> Min a
S.Min forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON
-- | @since 0.1.3.0
instance FromGraphSON a => FromGraphSON (S.Max a) where
  parseGraphSON :: GValue -> Parser (Max a)
parseGraphSON = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. a -> Max a
S.Max forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON
-- | @since 0.1.3.0
instance FromGraphSON a => FromGraphSON (S.First a) where
  parseGraphSON :: GValue -> Parser (First a)
parseGraphSON = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. a -> First a
S.First forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON
-- | @since 0.1.3.0
instance FromGraphSON a => FromGraphSON (S.Last a) where
  parseGraphSON :: GValue -> Parser (Last a)
parseGraphSON = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. a -> Last a
S.Last forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON
-- | @since 0.1.3.0
instance FromGraphSON a => FromGraphSON (S.WrappedMonoid a) where
  parseGraphSON :: GValue -> Parser (WrappedMonoid a)
parseGraphSON = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall m. m -> WrappedMonoid m
S.WrapMonoid forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON
-- | @since 0.1.3.0
instance FromGraphSON a => FromGraphSON (S.Dual a) where
  parseGraphSON :: GValue -> Parser (Dual a)
parseGraphSON = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. a -> Dual a
S.Dual forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON
-- | @since 0.1.3.0
instance FromGraphSON a => FromGraphSON (M.Sum a) where
  parseGraphSON :: GValue -> Parser (Sum a)
parseGraphSON = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. a -> Sum a
M.Sum forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON
-- | @since 0.1.3.0
instance FromGraphSON a => FromGraphSON (M.Product a) where
  parseGraphSON :: GValue -> Parser (Product a)
parseGraphSON = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. a -> Product a
M.Product forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON

-- | @since 0.1.3.0
instance FromGraphSON M.All where
  parseGraphSON :: GValue -> Parser All
parseGraphSON = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Bool -> All
M.All forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON
-- | @since 0.1.3.0
instance FromGraphSON M.Any where
  parseGraphSON :: GValue -> Parser Any
parseGraphSON = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Bool -> Any
M.Any forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON



---- GMap and others

-- | Use 'parseToFlattenedMap'.
instance (FromGraphSON k, FromGraphSON v, IsList (c k v), Item (c k v) ~ (k,v)) => FromGraphSON (FlattenedMap c k v) where
  parseGraphSON :: GValue -> Parser (FlattenedMap c k v)
parseGraphSON GValue
gv = case GValue -> GValueBody
gValueBody GValue
gv of
    GArray Vector GValue
a -> forall (c :: * -> * -> *) k v s.
(IsList (c k v), Item (c k v) ~ (k, v)) =>
(s -> Parser k)
-> (s -> Parser v) -> Vector s -> Parser (FlattenedMap c k v)
parseToFlattenedMap forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON Vector GValue
a
    GValueBody
b        -> forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail ([Char]
"Expects GArray, but got " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show GValueBody
b)

parseGObjectToTraversal :: (Traversable t, FromJSON (t GValue), FromGraphSON v)
                        => KeyMap GValue
                        -> Parser (t v)
parseGObjectToTraversal :: forall (t :: * -> *) v.
(Traversable t, FromJSON (t GValue), FromGraphSON v) =>
KeyMap GValue -> Parser (t v)
parseGObjectToTraversal KeyMap GValue
o = forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (forall a. FromJSON a => Value -> Parser a
parseJSON forall a b. (a -> b) -> a -> b
$ Object -> Value
Object forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. ToJSON a => a -> Value
toJSON KeyMap GValue
o)

-- | Use 'parseToGMap'.
instance (FromGraphSON k, FromGraphSON v, IsList (c k v), Item (c k v) ~ (k,v), Traversable (c k), FromJSON (c k GValue))
         => FromGraphSON (GMap c k v) where
  parseGraphSON :: GValue -> Parser (GMap c k v)
parseGraphSON GValue
gv = case GValue -> GValueBody
gValueBody GValue
gv of
    GObject KeyMap GValue
o -> Either (KeyMap GValue) (Vector GValue) -> Parser (GMap c k v)
parse forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left KeyMap GValue
o
    GArray Vector GValue
a  -> Either (KeyMap GValue) (Vector GValue) -> Parser (GMap c k v)
parse forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right Vector GValue
a
    GValueBody
other     -> forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail ([Char]
"Expects GObject or GArray, but got " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show GValueBody
other)
    where
      parse :: Either (KeyMap GValue) (Vector GValue) -> Parser (GMap c k v)
parse = forall (c :: * -> * -> *) k v s.
(IsList (c k v), Item (c k v) ~ (k, v)) =>
(s -> Parser k)
-> (s -> Parser v)
-> (KeyMap s -> Parser (c k v))
-> Either (KeyMap s) (Vector s)
-> Parser (GMap c k v)
parseToGMap forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON KeyMap GValue -> Parser (c k v)
parseObject
      -- parseObject = parseUnwrapTraversable . GValue . nonTypedGraphSON . GObject  --- Too many wrapping and unwrappings!!!
      parseObject :: KeyMap GValue -> Parser (c k v)
parseObject = forall (t :: * -> *) v.
(Traversable t, FromJSON (t GValue), FromGraphSON v) =>
KeyMap GValue -> Parser (t v)
parseGObjectToTraversal

-- | Use 'parseToGMapEntry'.
instance (FromGraphSON k, FromGraphSON v, FromJSONKey k) => FromGraphSON (GMapEntry k v) where
  parseGraphSON :: GValue -> Parser (GMapEntry k v)
parseGraphSON GValue
val = case GValue -> GValueBody
gValueBody GValue
val of
    GObject KeyMap GValue
o -> Either (KeyMap GValue) (Vector GValue) -> Parser (GMapEntry k v)
parse forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left KeyMap GValue
o
    GArray Vector GValue
a  -> Either (KeyMap GValue) (Vector GValue) -> Parser (GMapEntry k v)
parse forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right Vector GValue
a
    GValueBody
other     -> forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail ([Char]
"Expects GObject or GArray, but got " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show GValueBody
other)
    where
      parse :: Either (KeyMap GValue) (Vector GValue) -> Parser (GMapEntry k v)
parse = forall k s v.
FromJSONKey k =>
(s -> Parser k)
-> (s -> Parser v)
-> Either (KeyMap s) (Vector s)
-> Parser (GMapEntry k v)
parseToGMapEntry forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON


---- Map instances

instance (FromGraphSON v, Eq k, Hashable k, FromJSONKey k, FromGraphSON k) => FromGraphSON (L.HashMap k v) where
  parseGraphSON :: GValue -> Parser (HashMap k v)
parseGraphSON = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall (c :: * -> * -> *) k v. GMap c k v -> c k v
unGMap forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON
instance (FromGraphSON v, Ord k, FromJSONKey k, FromGraphSON k) => FromGraphSON (L.Map k v) where
  parseGraphSON :: GValue -> Parser (Map k v)
parseGraphSON = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall (c :: * -> * -> *) k v. GMap c k v -> c k v
unGMap forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON
-- IntMap cannot be used with GMap directly..
instance FromGraphSON v => FromGraphSON (L.IntMap v) where
  parseGraphSON :: GValue -> Parser (IntMap v)
parseGraphSON = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall v. Map Int v -> IntMap v
mapToIntMap forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (c :: * -> * -> *) k v. GMap c k v -> c k v
unGMap) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON
    where
      mapToIntMap :: L.Map Int v -> L.IntMap v
      mapToIntMap :: forall v. Map Int v -> IntMap v
mapToIntMap = forall k a b. (k -> a -> b -> b) -> b -> Map k a -> b
LMap.foldrWithKey forall a. Int -> a -> IntMap a -> IntMap a
LIntMap.insert forall a. Monoid a => a
mempty

-- | First convert to 'L.Map' with 'Text' key, and convert to 'KeyMap'.
--
-- @since 1.0.0.0
instance FromGraphSON v => FromGraphSON (KeyMap v) where
  parseGraphSON :: GValue -> Parser (KeyMap v)
parseGraphSON = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall v. Map Key v -> KeyMap v
KM.fromMap forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON

---- Maybe and Either

-- | Parse 'GNull' into 'Nothing'.
instance FromGraphSON a => FromGraphSON (Maybe a) where
  parseGraphSON :: GValue -> Parser (Maybe a)
parseGraphSON (GValue (GraphSON Maybe Text
_ GValueBody
GNull)) = forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
  parseGraphSON GValue
gv                          = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON GValue
gv

-- | Try 'Left', then 'Right'.
instance (FromGraphSON a, FromGraphSON b) => FromGraphSON (Either a b) where
  parseGraphSON :: GValue -> Parser (Either a b)
parseGraphSON GValue
gv = (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON GValue
gv) forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON GValue
gv)

---- Trivial wrapper for Maybe

-- | @since 0.1.3.0
instance FromGraphSON a => FromGraphSON (M.First a) where
  parseGraphSON :: GValue -> Parser (First a)
parseGraphSON = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. Maybe a -> First a
M.First forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON
-- | @since 0.1.3.0
instance FromGraphSON a => FromGraphSON (M.Last a) where
  parseGraphSON :: GValue -> Parser (Last a)
parseGraphSON = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. Maybe a -> Last a
M.Last forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromGraphSON a => GValue -> Parser a
parseGraphSON


---- Others

-- | Call 'unwrapAll' to remove all GraphSON wrappers.
instance FromGraphSON Value where
  parseGraphSON :: GValue -> Parser Value
parseGraphSON = forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. GValue -> Value
unwrapAll

instance FromGraphSON UUID where
  parseGraphSON :: GValue -> Parser UUID
parseGraphSON GValue
gv = case GValue -> GValueBody
gValueBody GValue
gv of
    GString Text
t -> forall b a. b -> (a -> b) -> Maybe a -> b
maybe Parser UUID
failure forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Text -> Maybe UUID
UUID.fromText Text
t
      where
        failure :: Parser UUID
failure = forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail ([Char]
"Failed to parse into UUID: " forall a. [a] -> [a] -> [a]
++ Text -> [Char]
unpack Text
t)
    GValueBody
b -> forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail ([Char]
"Expected GString, but got " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show GValueBody
b)

-- | For any input 'GValue', 'parseGraphSON' returns @()@. For
-- example, you can use it to ignore data you get from the Gremlin
-- server.
instance FromGraphSON () where
  parseGraphSON :: GValue -> Parser ()
parseGraphSON GValue
_ = forall (m :: * -> *) a. Monad m => a -> m a
return ()


-- | Examples of using this module. See the source. The 'fst' of the output is the testee, while the
-- 'snd' is the expectation.
examples :: [(String, String)]
examples :: [([Char], [Char])]
examples =
  [ (forall a. Show a => a -> [Char]
show (forall a. FromJSON a => ByteString -> Maybe a
Aeson.decode ByteString
"1000" :: Maybe (GraphSON Int32)), [Char]
"Just (GraphSON {gsonType = Nothing, gsonValue = 1000})")
  , (forall a. Show a => a -> [Char]
show (forall a. FromJSON a => ByteString -> Maybe a
Aeson.decode ByteString
"{\"@type\": \"g:Int32\", \"@value\": 1000}" :: Maybe (GraphSON Int32)), [Char]
"Just (GraphSON {gsonType = Just \"g:Int32\", gsonValue = 1000})")
  , (forall a. Show a => a -> [Char]
show (forall v. v -> GraphSON v
nonTypedGraphSON (Int
10 :: Int)), [Char]
"GraphSON {gsonType = Nothing, gsonValue = 10}")
  , (forall a. Show a => a -> [Char]
show (forall v. GraphSONTyped v => v -> GraphSON v
typedGraphSON (Int32
10 :: Int32)), [Char]
"GraphSON {gsonType = Just \"g:Int32\", gsonValue = 10}")
  , (forall a. Show a => a -> [Char]
show (forall v. Text -> v -> GraphSON v
typedGraphSON' Text
"g:Int32" (Int
10 :: Int)), [Char]
"GraphSON {gsonType = Just \"g:Int32\", gsonValue = 10}")
  ]