-
Notifications
You must be signed in to change notification settings - Fork 32
Create a Request object and an interpretRequest path #128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
dmaze
wants to merge
4
commits into
haskell-graphql:master
Choose a base branch
from
dmaze:dmaze/request-object
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
c6241d3
Add FromJSON instances for Name, Variable.
dmaze af093b4
Add a generic FromYAML instance for Value.
dmaze 73f83e5
Add a Request object that matches the typical JSON request format.
dmaze 6572204
Improve error handling in FromJSON instances
dmaze File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,8 @@ library: | |
- scientific | ||
- QuickCheck | ||
- text | ||
- vector | ||
- unordered-containers | ||
|
||
tests: | ||
graphql-api-tests: | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,9 +50,14 @@ module GraphQL.Value | |
|
||
import Protolude | ||
|
||
import Control.Monad.Fail | ||
import qualified Data.Aeson as Aeson | ||
import Data.Aeson (ToJSON(..), (.=), pairs) | ||
import Data.Aeson (FromJSON(..), ToJSON(..), (.=), pairs) | ||
import Data.Aeson.Types (typeMismatch) | ||
import qualified Data.HashMap.Lazy as HashMap | ||
import qualified Data.Map as Map | ||
import Data.Scientific (toRealFloat) | ||
import qualified Data.Vector as Vector | ||
import Test.QuickCheck (Arbitrary(..), Gen, oneof, listOf, sized) | ||
|
||
import GraphQL.Internal.Arbitrary (arbitraryText) | ||
|
@@ -86,6 +91,11 @@ instance Traversable Value' where | |
traverse f (ValueList' xs) = ValueList' <$> traverse f xs | ||
traverse f (ValueObject' xs) = ValueObject' <$> traverse f xs | ||
|
||
instance FromJSON scalar => FromJSON (Value' scalar) where | ||
parseJSON (Aeson.Object x) = ValueObject' <$> parseJSON (Aeson.Object x) | ||
parseJSON (Aeson.Array x) = ValueList' <$> parseJSON (Aeson.Array x) | ||
parseJSON x = ValueScalar' <$> parseJSON x | ||
|
||
instance ToJSON scalar => ToJSON (Value' scalar) where | ||
toJSON (ValueScalar' x) = toJSON x | ||
toJSON (ValueList' x) = toJSON x | ||
|
@@ -151,6 +161,11 @@ toObject _ = empty | |
-- * Scalars | ||
|
||
-- | A non-variable value which contains no other values. | ||
-- | ||
-- Note that the 'FromJSON' instance always decodes JSON strings to | ||
-- GraphQL strings (never enums) and JSON numbers to GraphQL floats | ||
-- (never ints); doing a better job of resolving this requires query | ||
-- context. | ||
data ConstScalar | ||
= ConstInt Int32 | ||
| ConstFloat Double | ||
|
@@ -160,6 +175,13 @@ data ConstScalar | |
| ConstNull | ||
deriving (Eq, Ord, Show) | ||
|
||
instance FromJSON ConstScalar where | ||
parseJSON (Aeson.String x) = parseJSON (Aeson.String x) >>= return . ConstString | ||
parseJSON (Aeson.Number x) = return $ ConstFloat $ toRealFloat x | ||
parseJSON (Aeson.Bool x) = return $ ConstBoolean x | ||
parseJSON Aeson.Null = return ConstNull | ||
parseJSON other = typeMismatch "Scalar" other | ||
|
||
instance ToJSON ConstScalar where | ||
toJSON (ConstInt x) = toJSON x | ||
toJSON (ConstFloat x) = toJSON x | ||
|
@@ -213,14 +235,12 @@ astToScalar _ = empty | |
|
||
-- * Strings | ||
|
||
newtype String = String Text deriving (Eq, Ord, Show) | ||
newtype String = String Text deriving (Eq, Ord, Show, Aeson.FromJSON, | ||
Aeson.ToJSON) | ||
|
||
instance Arbitrary String where | ||
arbitrary = String <$> arbitraryText | ||
|
||
instance ToJSON String where | ||
toJSON (String x) = toJSON x | ||
|
||
-- * Lists | ||
|
||
newtype List' scalar = List' [Value' scalar] deriving (Eq, Ord, Show, Functor) | ||
|
@@ -245,6 +265,9 @@ instance Arbitrary scalar => Arbitrary (List' scalar) where | |
-- invalid lists. | ||
arbitrary = List' <$> listOf arbitrary | ||
|
||
instance FromJSON scalar => FromJSON (List' scalar) where | ||
parseJSON = Aeson.withArray "List" $ \v -> | ||
mapM parseJSON v >>= return . List' . Vector.toList | ||
|
||
instance ToJSON scalar => ToJSON (List' scalar) where | ||
toJSON (List' x) = toJSON x | ||
|
@@ -302,6 +325,16 @@ objectFromList xs = Object' <$> OrderedMap.orderedMap xs | |
unionObjects :: [Object' scalar] -> Maybe (Object' scalar) | ||
unionObjects objects = Object' <$> OrderedMap.unions [obj | Object' obj <- objects] | ||
|
||
instance FromJSON scalar => FromJSON (Object' scalar) where | ||
parseJSON = Aeson.withObject "Object" $ \v -> do | ||
-- Order of keys is lost before we get here | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you remind me why this is relevant? |
||
let kvps = HashMap.toList v | ||
names <- mapM parseJSON (Aeson.String <$> fst <$> kvps) | ||
values <- mapM parseJSON (snd <$> kvps) | ||
case objectFromList $ zip names values of | ||
Nothing -> fail "duplicate keys in object" | ||
Just obj -> return obj | ||
|
||
instance ToJSON scalar => ToJSON (Object' scalar) where | ||
-- Direct encoding to preserve order of keys / values | ||
toJSON (Object' xs) = toJSON (Map.fromList [(unName k, v) | (k, v) <- OrderedMap.toList xs]) | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a little uncomfortable about this. The "Zen of Python" advises "in the face of ambiguity, refuse the temptation to guess", and I think that's good advice.
Some options I could think of:
FromJSON
instance for this, and instead have a series of functions that take the query (or whatever the minimal necessary context is) and aValue
to be parsed, so that we can unambiguously parse these thingsFromJSON
instances for these new typesAmbiguousConstScalar
type. Then, have a function that transformsAmbiguousConstScalar -> ConstScalar
by also taking a query context. This type would need fewer branches thanConstScalar
.ConstScalar
a phantom type, where the phantom parameter is whether it's ambiguous or not. Then, have a function that transformsConstScalar Ambiguous -> ConstScalar Unambiguous
by also taking a query context