Skip to content
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

disable automatic __typename selection and fix client runtime errors connected to it #773

Merged
merged 16 commits into from
Oct 18, 2022
58 changes: 23 additions & 35 deletions examples/code-gen/src/Client/Requests/GetInterfaceTypes.hs
Original file line number Diff line number Diff line change
Expand Up @@ -30,78 +30,66 @@ instance FromJSON GetInterfaceTypes where
parseJSON = withObject "GetInterfaceTypes" (\v -> GetInterfaceTypes <$> v .: "character" <*> v .: "character2" <*> v .: "character3" <*> v .: "character4")

data GetInterfaceTypesCharacterCharacter
= GetInterfaceTypesCharacterCharacter
{ __typename :: String,
name :: String
}
| GetInterfaceTypesCharacterDeity
{ __typename :: String,
name :: String,
= GetInterfaceTypesCharacterDeity
{ name :: String,
power :: Power
}
| GetInterfaceTypesCharacterHero
{ __typename :: String,
name :: String,
{ name :: String,
hobby :: String
}
| GetInterfaceTypesCharacterCharacter
{ name :: String
}
deriving (Generic, Show, Eq)

instance FromJSON GetInterfaceTypesCharacterCharacter where
parseJSON =
takeValueType
( \case
("Character", v) -> GetInterfaceTypesCharacterCharacter <$> v .: "__typename" <*> v .: "name"
("Deity", v) -> GetInterfaceTypesCharacterDeity <$> v .: "__typename" <*> v .: "name" <*> v .: "power"
("Hero", v) -> GetInterfaceTypesCharacterHero <$> v .: "__typename" <*> v .: "name" <*> v .: "hobby"
(_, v) -> GetInterfaceTypesCharacterCharacter <$> v .: "__typename" <*> v .: "name"
("Deity", v) -> GetInterfaceTypesCharacterDeity <$> v .: "name" <*> v .: "power"
("Hero", v) -> GetInterfaceTypesCharacterHero <$> v .: "name" <*> v .: "hobby"
(_fallback, v) -> GetInterfaceTypesCharacterCharacter <$> v .: "name"
)

data GetInterfaceTypesCharacter2Character = GetInterfaceTypesCharacter2Character
{ __typename :: String,
name1 :: String,
{ name1 :: String,
name :: String
}
deriving (Generic, Show, Eq)

instance FromJSON GetInterfaceTypesCharacter2Character where
parseJSON = withObject "GetInterfaceTypesCharacter2Character" (\v -> GetInterfaceTypesCharacter2Character <$> v .: "__typename" <*> v .: "name1" <*> v .: "name")
parseJSON = withObject "GetInterfaceTypesCharacter2Character" (\v -> GetInterfaceTypesCharacter2Character <$> v .: "name1" <*> v .: "name")

data GetInterfaceTypesCharacter3Character
= GetInterfaceTypesCharacter3Character
{ __typename :: String,
name2 :: String
}
| GetInterfaceTypesCharacter3Hero
{ __typename :: String,
name2 :: String,
= GetInterfaceTypesCharacter3Hero
{ name2 :: String,
hobby :: String
}
| GetInterfaceTypesCharacter3Character
{ name2 :: String
}
deriving (Generic, Show, Eq)

instance FromJSON GetInterfaceTypesCharacter3Character where
parseJSON =
takeValueType
( \case
("Character", v) -> GetInterfaceTypesCharacter3Character <$> v .: "__typename" <*> v .: "name2"
("Hero", v) -> GetInterfaceTypesCharacter3Hero <$> v .: "__typename" <*> v .: "name2" <*> v .: "hobby"
(_, v) -> GetInterfaceTypesCharacter3Character <$> v .: "__typename" <*> v .: "name2"
("Hero", v) -> GetInterfaceTypesCharacter3Hero <$> v .: "name2" <*> v .: "hobby"
(_fallback, v) -> GetInterfaceTypesCharacter3Character <$> v .: "name2"
)

data GetInterfaceTypesCharacter4Character
= GetInterfaceTypesCharacter4Character
{ __typename :: String
}
| GetInterfaceTypesCharacter4Hero
{ __typename :: String,
hobby :: String
= GetInterfaceTypesCharacter4Hero
{ hobby :: String
}
| GetInterfaceTypesCharacter4Character
deriving (Generic, Show, Eq)

instance FromJSON GetInterfaceTypesCharacter4Character where
parseJSON =
takeValueType
( \case
("Character", v) -> GetInterfaceTypesCharacter4Character <$> v .: "__typename"
("Hero", v) -> GetInterfaceTypesCharacter4Hero <$> v .: "__typename" <*> v .: "hobby"
(_, v) -> GetInterfaceTypesCharacter4Character <$> v .: "__typename"
("Hero", v) -> GetInterfaceTypesCharacter4Hero <$> v .: "hobby"
(_fallback, _) -> pure GetInterfaceTypesCharacter4Character
)
36 changes: 24 additions & 12 deletions examples/code-gen/src/Client/Requests/GetUsers.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import Data.Morpheus.Client.CodeGen.Internal
instance RequestType GetUser where
type RequestArgs GetUser = GetUserArgs
__name _ = "GetUser"
__query _ = "# Query Hero with Compile time Validation\nquery GetUser($coordinates: Coordinates!) {\n myUser: user {\n name\n aliasEmail: email\n address(coordinates: $coordinates) {\n city\n }\n aliasAdress: address(coordinates: $coordinates) {\n city\n }\n }\n user {\n email\n name\n }\n\n character {\n ... on Deity {\n power\n }\n }\n}\n"
__query _ = "# Query Hero with Compile time Validation\nquery GetUser($coordinates: Coordinates!) {\n myUser: user {\n name\n aliasEmail: email\n address(coordinates: $coordinates) {\n city\n }\n aliasAdress: address(coordinates: $coordinates) {\n city\n }\n }\n user {\n email\n name\n entity {\n ... on User {\n name\n }\n }\n }\n character {\n ... on Deity {\n power\n }\n }\n}\n"
__type _ = Query

data GetUser = GetUser
Expand Down Expand Up @@ -57,30 +57,42 @@ instance FromJSON GetUserMyUserAliasAdressAddress where

data GetUserUserUser = GetUserUserUser
{ email :: String,
name :: String
name :: String,
entity :: [GetUserUserEntityMyUnion]
}
deriving (Generic, Show, Eq)

instance FromJSON GetUserUserUser where
parseJSON = withObject "GetUserUserUser" (\v -> GetUserUserUser <$> v .: "email" <*> v .: "name")
parseJSON = withObject "GetUserUserUser" (\v -> GetUserUserUser <$> v .: "email" <*> v .: "name" <*> v .: "entity")

data GetUserCharacterCharacter
= GetUserCharacterCharacter
{ __typename :: String
data GetUserUserEntityMyUnion
= GetUserUserEntityUser
{ name :: String
}
| GetUserCharacterDeity
{ __typename :: String,
power :: Power
| GetUserUserEntityMyUnion
deriving (Generic, Show, Eq)

instance FromJSON GetUserUserEntityMyUnion where
parseJSON =
takeValueType
( \case
("User", v) -> GetUserUserEntityUser <$> v .: "name"
(_fallback, _) -> pure GetUserUserEntityMyUnion
)

data GetUserCharacterCharacter
= GetUserCharacterDeity
{ power :: Power
}
| GetUserCharacterCharacter
deriving (Generic, Show, Eq)

instance FromJSON GetUserCharacterCharacter where
parseJSON =
takeValueType
( \case
("Character", v) -> GetUserCharacterCharacter <$> v .: "__typename"
("Deity", v) -> GetUserCharacterDeity <$> v .: "__typename" <*> v .: "power"
(_, v) -> GetUserCharacterCharacter <$> v .: "__typename"
("Deity", v) -> GetUserCharacterDeity <$> v .: "power"
(_fallback, _) -> pure GetUserCharacterCharacter
)

newtype GetUserArgs = GetUserArgs
Expand Down
14 changes: 5 additions & 9 deletions examples/code-gen/src/Client/Requests/NewUsers.hs
Original file line number Diff line number Diff line change
Expand Up @@ -46,22 +46,18 @@ instance FromJSON NewUsersNewUserAddressAddress where
parseJSON = withObject "NewUsersNewUserAddressAddress" (\v -> NewUsersNewUserAddressAddress <$> v .: "city")

data NewUsersNewUserWorshipsCharacter
= NewUsersNewUserWorshipsCharacter
{ __typename :: String
}
| NewUsersNewUserWorshipsHero
{ __typename :: String,
hobby :: String
= NewUsersNewUserWorshipsHero
{ hobby :: String
}
| NewUsersNewUserWorshipsCharacter
deriving (Generic, Show, Eq)

instance FromJSON NewUsersNewUserWorshipsCharacter where
parseJSON =
takeValueType
( \case
("Character", v) -> NewUsersNewUserWorshipsCharacter <$> v .: "__typename"
("Hero", v) -> NewUsersNewUserWorshipsHero <$> v .: "__typename" <*> v .: "hobby"
(_, v) -> NewUsersNewUserWorshipsCharacter <$> v .: "__typename"
("Hero", v) -> NewUsersNewUserWorshipsHero <$> v .: "hobby"
(_fallback, _) -> pure NewUsersNewUserWorshipsCharacter
)

newtype NewUsersArgs = NewUsersArgs
Expand Down
6 changes: 5 additions & 1 deletion examples/code-gen/src/Client/Requests/getUsers.gql
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ query GetUser($coordinates: Coordinates!) {
user {
email
name
entity {
... on User {
name
}
}
}

character {
... on Deity {
power
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,13 @@ import Data.Morpheus.App.Internal.Resolving.Types
mkUnion,
)
import Data.Morpheus.Error (subfieldsNotSelected)
import Data.Morpheus.Internal.Utils (KeyOf (keyOf), selectOr, traverseCollection, (<:>))
import Data.Morpheus.Internal.Utils
( KeyOf (keyOf),
empty,
selectOr,
traverseCollection,
(<:>),
)
import Data.Morpheus.Types.Internal.AST
( GQLError,
Msg (msg),
Expand All @@ -48,7 +54,7 @@ import Data.Morpheus.Types.Internal.AST
unitTypeName,
unpackName,
)
import Relude
import Relude hiding (empty)

resolveSelection ::
( Monad m,
Expand Down Expand Up @@ -78,24 +84,29 @@ resolveSelection _ ResScalar {} _ =
resolveSelection rmap (ResRef ref) sel = ref >>= flip (resolveRef rmap) sel

withObject ::
( Monad m,
MonadError GQLError m,
( MonadError GQLError m,
MonadReader ResolverContext m
) =>
Maybe TypeName ->
(SelectionSet VALID -> m value) ->
(Maybe (SelectionSet VALID) -> m value) ->
SelectionContent VALID ->
m value
withObject __typename f = updateCurrentType __typename . checkContent
where
checkContent (SelectionSet selection) = f selection
checkContent (SelectionSet selection) = f (Just selection)
checkContent (UnionSelection interface unionSel) = do
typename <- asks (typeName . currentType)
selection <- selectOr (pure interface) ((interface <:>) . unionTagSelection) typename unionSel
selection <- selectOr (pure interface) (fx interface) typename unionSel
f selection
checkContent _ = do
sel <- asks currentSelection
throwError $ subfieldsNotSelected (selectionName sel) "" (selectionPosition sel)
where
fx (Just x) y = Just <$> (x <:> unionTagSelection y)
fx Nothing y = pure $ Just $ unionTagSelection y
checkContent _ = noEmptySelection

noEmptySelection :: (MonadError GQLError m, MonadReader ResolverContext m) => m value
noEmptySelection = do
sel <- asks currentSelection
throwError $ subfieldsNotSelected (selectionName sel) "" (selectionPosition sel)

resolveRef ::
( MonadError GQLError m,
Expand Down Expand Up @@ -127,10 +138,9 @@ resolveObject ::
) =>
ResolverMap m ->
ObjectTypeResolver m ->
SelectionSet VALID ->
Maybe (SelectionSet VALID) ->
m ValidValue
resolveObject rmap drv =
fmap Object . traverseCollection resolver
resolveObject rmap drv = fmap Object . maybe (pure empty) (traverseCollection resolver)
where
resolver currentSelection = do
t <- askFieldTypeName (selectionName currentSelection)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ runRootDataResolver
selection =
do
root <- runResolverStateT (toResolverStateT res) ctx
runResolver channels (resolveObject mempty root selection) ctx
runResolver channels (resolveObject mempty root (Just selection)) ctx

runRootResolverValue :: Monad m => RootResolverValue e m -> ResolverContext -> ResponseStream e m (Value VALID)
runRootResolverValue
Expand Down Expand Up @@ -136,7 +136,7 @@ withIntrospection f ctx@ResolverContext {operation} = case splitSystemSelection
mergeRoot y x

introspection :: Monad m => SelectionSet VALID -> ResolverContext -> ResponseStream event m ValidValue
introspection selection ctx@ResolverContext {schema} = runResolver Nothing (resolveObject mempty (schemaAPI schema) selection) ctx
introspection selection ctx@ResolverContext {schema} = runResolver Nothing (resolveObject mempty (schemaAPI schema) (Just selection)) ctx

mergeRoot :: MonadError GQLError m => ValidValue -> ValidValue -> m ValidValue
mergeRoot (Object x) (Object y) = Object <$> merge x y
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
}
}
character {
__typename
... on Character {
name
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
character {
__typename
... on Character {
name
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
character {
__typename
...OnCharacter
...onDeity
...onHero
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
...OnSupernatural
}
character {
__typename
...OnCharacter
}
}
Expand Down
2 changes: 2 additions & 0 deletions morpheus-graphql-app/test/named-resolvers/entities/query.gql
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
query {
entities {
... on Realm {
__typename
name
owner {
name
Expand All @@ -14,6 +15,7 @@ query {
}
}
... on Deity {
__typename
name
power
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
query {
zeus: entity(id: "zeus") {
... on Deity {
__typename
name
power
}
}
olympus: entity(id: "olympus") {
... on Realm {
__typename
name
owner {
name
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
query {
zeus: entity(id: "zeus") {
... on Deity {
__typename
name
power
}
}
olympus: entity(id: "olympus") {
... on Realm {
__typename
name
owner {
name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ data ClientDeclaration
data ClientPreDeclaration
= ToJSONClass DERIVING_MODE CodeGenType
| FromJSONClass DERIVING_MODE CodeGenType
| FromJSONUnionClass CodeGenTypeName [(UnionPat, CodeGenConstructor)]
| FromJSONObjectClass CodeGenTypeName CodeGenConstructor
| RequestTypeClass RequestTypeDefinition
| ClientType CodeGenType

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ invalidConstructorError v = fail $ show v <> " is Not Valid Union Constructor"

takeValueType :: ((String, Object) -> Parser a) -> Value -> Parser a
takeValueType f (Object hMap) = case lookup "__typename" hMap of
Nothing -> fail "key \"__typename\" not found on object"
Nothing -> f ("__TYPENAME_NOT__FOUND__", hMap)
Just (String x) -> f (T.unpack x, hMap)
Just val ->
fail $ "key \"__typename\" should be string but found: " <> show val
Expand Down
Loading