packages feed

morpheus-graphql 0.6.2 → 0.7.0

raw patch · 122 files changed

+6828/−4913 lines, 122 filesdep +th-lift-instancesPVP ok

version bump matches the API change (PVP)

Dependencies added: th-lift-instances

API changes (from Hackage documentation)

- Data.Morpheus.Document: toMorpheusHaskellAPi :: String -> ByteString -> Either ByteString ByteString
- Data.Morpheus.Types: [FailedResolver] :: {unFailedResolver :: String} -> Resolver o m event value
- Data.Morpheus.Types: liftEitherM :: (PureOperation o, Monad m) => m (Either String a) -> Resolver o m e a
- Data.Morpheus.Types: liftM :: (PureOperation o, Monad m) => m a -> Resolver o m e a
+ Data.Morpheus.Document: parseDSL :: ByteString -> Either String DataTypeLib
+ Data.Morpheus.Types: lift :: (MonadTrans t, Monad m) => m a -> t m a
+ Data.Morpheus.Types: liftEither :: (LiftEither o res, Monad m) => m (Either (ResError res) a) -> res o event m a
+ Data.Morpheus.Types: type ResolveM e m a = MutRes e m (a (MutRes e m))
+ Data.Morpheus.Types: type ResolveQ e m a = Res e m (a (Res e m))
+ Data.Morpheus.Types: type ResolveS e m a = SubRes e m (a (Res e m))
+ Data.Morpheus.Types.Internal.AST: ArgsType :: Key -> ResolverKind -> ArgsType
+ Data.Morpheus.Types.Internal.AST: Argument :: Value -> ValueOrigin -> Position -> Argument
+ Data.Morpheus.Types.Internal.AST: Boolean :: Bool -> ScalarValue
+ Data.Morpheus.Types.Internal.AST: ClientQuery :: String -> [ClientType] -> Maybe TypeD -> ClientQuery
+ Data.Morpheus.Types.Internal.AST: ClientType :: TypeD -> DataTypeKind -> ClientType
+ Data.Morpheus.Types.Internal.AST: ConsD :: String -> [DataField] -> ConsD
+ Data.Morpheus.Types.Internal.AST: DataEnum :: DataEnum -> DataType
+ Data.Morpheus.Types.Internal.AST: DataEnumValue :: Name -> Maybe Meta -> DataEnumValue
+ Data.Morpheus.Types.Internal.AST: DataField :: Key -> [(Key, DataArgument)] -> Maybe ArgsType -> TypeAlias -> Maybe Meta -> DataField
+ Data.Morpheus.Types.Internal.AST: DataInputObject :: DataObject -> DataType
+ Data.Morpheus.Types.Internal.AST: DataInputUnion :: DataUnion -> DataType
+ Data.Morpheus.Types.Internal.AST: DataObject :: DataObject -> DataType
+ Data.Morpheus.Types.Internal.AST: DataScalar :: DataScalar -> DataType
+ Data.Morpheus.Types.Internal.AST: DataTyCon :: Key -> DataFingerprint -> Maybe Meta -> a -> DataTyCon a
+ Data.Morpheus.Types.Internal.AST: DataTypeLib :: HashMap Key DataType -> (Key, DataObject) -> Maybe (Key, DataObject) -> Maybe (Key, DataObject) -> DataTypeLib
+ Data.Morpheus.Types.Internal.AST: DataUnion :: DataUnion -> DataType
+ Data.Morpheus.Types.Internal.AST: DataValidator :: (Value -> Either Key Value) -> DataValidator
+ Data.Morpheus.Types.Internal.AST: Directive :: Name -> [(Name, Value)] -> Directive
+ Data.Morpheus.Types.Internal.AST: Enum :: Text -> Value
+ Data.Morpheus.Types.Internal.AST: ExternalResolver :: ResolverKind
+ Data.Morpheus.Types.Internal.AST: FinalDataType :: DataType -> RawDataType
+ Data.Morpheus.Types.Internal.AST: Float :: Float -> ScalarValue
+ Data.Morpheus.Types.Internal.AST: Fragment :: Key -> Position -> RawSelectionSet -> Fragment
+ Data.Morpheus.Types.Internal.AST: GQLQuery :: FragmentLib -> RawOperation -> [(Key, Value)] -> GQLQuery
+ Data.Morpheus.Types.Internal.AST: GQLTypeD :: TypeD -> DataTypeKind -> [TypeD] -> (Name, DataType) -> GQLTypeD
+ Data.Morpheus.Types.Internal.AST: INLINE :: ValueOrigin
+ Data.Morpheus.Types.Internal.AST: Implements :: [Key] -> DataObject -> RawDataType
+ Data.Morpheus.Types.Internal.AST: InlineFragment :: Fragment -> RawSelection
+ Data.Morpheus.Types.Internal.AST: Int :: Int -> ScalarValue
+ Data.Morpheus.Types.Internal.AST: Interface :: DataObject -> RawDataType
+ Data.Morpheus.Types.Internal.AST: KindEnum :: DataTypeKind
+ Data.Morpheus.Types.Internal.AST: KindInputObject :: DataTypeKind
+ Data.Morpheus.Types.Internal.AST: KindInputUnion :: DataTypeKind
+ Data.Morpheus.Types.Internal.AST: KindList :: DataTypeKind
+ Data.Morpheus.Types.Internal.AST: KindNonNull :: DataTypeKind
+ Data.Morpheus.Types.Internal.AST: KindObject :: Maybe OperationType -> DataTypeKind
+ Data.Morpheus.Types.Internal.AST: KindScalar :: DataTypeKind
+ Data.Morpheus.Types.Internal.AST: KindUnion :: DataTypeKind
+ Data.Morpheus.Types.Internal.AST: List :: [Value] -> Value
+ Data.Morpheus.Types.Internal.AST: ListType :: DataTypeWrapper
+ Data.Morpheus.Types.Internal.AST: Meta :: Maybe Description -> [Directive] -> Meta
+ Data.Morpheus.Types.Internal.AST: Mutation :: OperationType
+ Data.Morpheus.Types.Internal.AST: NonNullType :: DataTypeWrapper
+ Data.Morpheus.Types.Internal.AST: Null :: Value
+ Data.Morpheus.Types.Internal.AST: Object :: Object -> Value
+ Data.Morpheus.Types.Internal.AST: Operation :: Maybe Key -> OperationType -> args -> sel -> Position -> Operation args sel
+ Data.Morpheus.Types.Internal.AST: PlainResolver :: ResolverKind
+ Data.Morpheus.Types.Internal.AST: Position :: Int -> Int -> Position
+ Data.Morpheus.Types.Internal.AST: Query :: OperationType
+ Data.Morpheus.Types.Internal.AST: RawArgument :: Argument -> RawArgument
+ Data.Morpheus.Types.Internal.AST: RawSelectionField :: RawSelection' () -> RawSelection
+ Data.Morpheus.Types.Internal.AST: RawSelectionSet :: RawSelection' RawSelectionSet -> RawSelection
+ Data.Morpheus.Types.Internal.AST: Ref :: Key -> Position -> Ref
+ Data.Morpheus.Types.Internal.AST: Scalar :: ScalarValue -> Value
+ Data.Morpheus.Types.Internal.AST: Selection :: args -> Position -> Maybe Key -> rec -> Selection args rec
+ Data.Morpheus.Types.Internal.AST: SelectionField :: SelectionRec
+ Data.Morpheus.Types.Internal.AST: SelectionSet :: SelectionSet -> SelectionRec
+ Data.Morpheus.Types.Internal.AST: Spread :: Ref -> RawSelection
+ Data.Morpheus.Types.Internal.AST: String :: Text -> ScalarValue
+ Data.Morpheus.Types.Internal.AST: Subscription :: OperationType
+ Data.Morpheus.Types.Internal.AST: SystemFingerprint :: Key -> DataFingerprint
+ Data.Morpheus.Types.Internal.AST: TypeAlias :: Key -> Maybe Key -> [TypeWrapper] -> TypeAlias
+ Data.Morpheus.Types.Internal.AST: TypeD :: String -> [String] -> [ConsD] -> Maybe Meta -> TypeD
+ Data.Morpheus.Types.Internal.AST: TypeList :: TypeWrapper
+ Data.Morpheus.Types.Internal.AST: TypeMaybe :: TypeWrapper
+ Data.Morpheus.Types.Internal.AST: TypeVarResolver :: ResolverKind
+ Data.Morpheus.Types.Internal.AST: TypeableFingerprint :: [String] -> DataFingerprint
+ Data.Morpheus.Types.Internal.AST: UnionSelection :: UnionSelection -> SelectionRec
+ Data.Morpheus.Types.Internal.AST: VARIABLE :: ValueOrigin
+ Data.Morpheus.Types.Internal.AST: Variable :: Key -> Bool -> [TypeWrapper] -> Position -> a -> Variable a
+ Data.Morpheus.Types.Internal.AST: VariableRef :: Ref -> RawArgument
+ Data.Morpheus.Types.Internal.AST: [aliasArgs] :: TypeAlias -> Maybe Key
+ Data.Morpheus.Types.Internal.AST: [aliasTyCon] :: TypeAlias -> Key
+ Data.Morpheus.Types.Internal.AST: [aliasWrappers] :: TypeAlias -> [TypeWrapper]
+ Data.Morpheus.Types.Internal.AST: [argsTypeName] :: ArgsType -> Key
+ Data.Morpheus.Types.Internal.AST: [argumentOrigin] :: Argument -> ValueOrigin
+ Data.Morpheus.Types.Internal.AST: [argumentPosition] :: Argument -> Position
+ Data.Morpheus.Types.Internal.AST: [argumentValue] :: Argument -> Value
+ Data.Morpheus.Types.Internal.AST: [cFields] :: ConsD -> [DataField]
+ Data.Morpheus.Types.Internal.AST: [cName] :: ConsD -> String
+ Data.Morpheus.Types.Internal.AST: [clientKind] :: ClientType -> DataTypeKind
+ Data.Morpheus.Types.Internal.AST: [clientType] :: ClientType -> TypeD
+ Data.Morpheus.Types.Internal.AST: [column] :: Position -> Int
+ Data.Morpheus.Types.Internal.AST: [directiveArgs] :: Directive -> [(Name, Value)]
+ Data.Morpheus.Types.Internal.AST: [directiveName] :: Directive -> Name
+ Data.Morpheus.Types.Internal.AST: [enumMeta] :: DataEnumValue -> Maybe Meta
+ Data.Morpheus.Types.Internal.AST: [enumName] :: DataEnumValue -> Name
+ Data.Morpheus.Types.Internal.AST: [fieldArgsType] :: DataField -> Maybe ArgsType
+ Data.Morpheus.Types.Internal.AST: [fieldArgs] :: DataField -> [(Key, DataArgument)]
+ Data.Morpheus.Types.Internal.AST: [fieldMeta] :: DataField -> Maybe Meta
+ Data.Morpheus.Types.Internal.AST: [fieldName] :: DataField -> Key
+ Data.Morpheus.Types.Internal.AST: [fieldType] :: DataField -> TypeAlias
+ Data.Morpheus.Types.Internal.AST: [fragmentPosition] :: Fragment -> Position
+ Data.Morpheus.Types.Internal.AST: [fragmentSelection] :: Fragment -> RawSelectionSet
+ Data.Morpheus.Types.Internal.AST: [fragmentType] :: Fragment -> Key
+ Data.Morpheus.Types.Internal.AST: [fragments] :: GQLQuery -> FragmentLib
+ Data.Morpheus.Types.Internal.AST: [implementsInterfaces] :: RawDataType -> [Key]
+ Data.Morpheus.Types.Internal.AST: [inputVariables] :: GQLQuery -> [(Key, Value)]
+ Data.Morpheus.Types.Internal.AST: [isVariableRequired] :: Variable a -> Bool
+ Data.Morpheus.Types.Internal.AST: [line] :: Position -> Int
+ Data.Morpheus.Types.Internal.AST: [metaDescription] :: Meta -> Maybe Description
+ Data.Morpheus.Types.Internal.AST: [metaDirectives] :: Meta -> [Directive]
+ Data.Morpheus.Types.Internal.AST: [mutation] :: DataTypeLib -> Maybe (Key, DataObject)
+ Data.Morpheus.Types.Internal.AST: [operationArgs] :: Operation args sel -> args
+ Data.Morpheus.Types.Internal.AST: [operationName] :: Operation args sel -> Maybe Key
+ Data.Morpheus.Types.Internal.AST: [operationPosition] :: Operation args sel -> Position
+ Data.Morpheus.Types.Internal.AST: [operationSelection] :: Operation args sel -> sel
+ Data.Morpheus.Types.Internal.AST: [operationType] :: Operation args sel -> OperationType
+ Data.Morpheus.Types.Internal.AST: [operation] :: GQLQuery -> RawOperation
+ Data.Morpheus.Types.Internal.AST: [queryArgsType] :: ClientQuery -> Maybe TypeD
+ Data.Morpheus.Types.Internal.AST: [queryText] :: ClientQuery -> String
+ Data.Morpheus.Types.Internal.AST: [queryTypes] :: ClientQuery -> [ClientType]
+ Data.Morpheus.Types.Internal.AST: [query] :: DataTypeLib -> (Key, DataObject)
+ Data.Morpheus.Types.Internal.AST: [refName] :: Ref -> Key
+ Data.Morpheus.Types.Internal.AST: [refPosition] :: Ref -> Position
+ Data.Morpheus.Types.Internal.AST: [resKind] :: ArgsType -> ResolverKind
+ Data.Morpheus.Types.Internal.AST: [selectionAlias] :: Selection args rec -> Maybe Key
+ Data.Morpheus.Types.Internal.AST: [selectionArguments] :: Selection args rec -> args
+ Data.Morpheus.Types.Internal.AST: [selectionPosition] :: Selection args rec -> Position
+ Data.Morpheus.Types.Internal.AST: [selectionRec] :: Selection args rec -> rec
+ Data.Morpheus.Types.Internal.AST: [subscription] :: DataTypeLib -> Maybe (Key, DataObject)
+ Data.Morpheus.Types.Internal.AST: [tCons] :: TypeD -> [ConsD]
+ Data.Morpheus.Types.Internal.AST: [tMeta] :: TypeD -> Maybe Meta
+ Data.Morpheus.Types.Internal.AST: [tName] :: TypeD -> String
+ Data.Morpheus.Types.Internal.AST: [tNamespace] :: TypeD -> [String]
+ Data.Morpheus.Types.Internal.AST: [typeArgD] :: GQLTypeD -> [TypeD]
+ Data.Morpheus.Types.Internal.AST: [typeD] :: GQLTypeD -> TypeD
+ Data.Morpheus.Types.Internal.AST: [typeData] :: DataTyCon a -> a
+ Data.Morpheus.Types.Internal.AST: [typeFingerprint] :: DataTyCon a -> DataFingerprint
+ Data.Morpheus.Types.Internal.AST: [typeKindD] :: GQLTypeD -> DataTypeKind
+ Data.Morpheus.Types.Internal.AST: [typeMeta] :: DataTyCon a -> Maybe Meta
+ Data.Morpheus.Types.Internal.AST: [typeName] :: DataTyCon a -> Key
+ Data.Morpheus.Types.Internal.AST: [typeOriginal] :: GQLTypeD -> (Name, DataType)
+ Data.Morpheus.Types.Internal.AST: [types] :: DataTypeLib -> HashMap Key DataType
+ Data.Morpheus.Types.Internal.AST: [unImplements] :: RawDataType -> DataObject
+ Data.Morpheus.Types.Internal.AST: [validateValue] :: DataValidator -> Value -> Either Key Value
+ Data.Morpheus.Types.Internal.AST: [variablePosition] :: Variable a -> Position
+ Data.Morpheus.Types.Internal.AST: [variableTypeWrappers] :: Variable a -> [TypeWrapper]
+ Data.Morpheus.Types.Internal.AST: [variableType] :: Variable a -> Key
+ Data.Morpheus.Types.Internal.AST: [variableValue] :: Variable a -> a
+ Data.Morpheus.Types.Internal.AST: allDataTypes :: DataTypeLib -> [(Key, DataType)]
+ Data.Morpheus.Types.Internal.AST: anonymousRef :: Key -> Ref
+ Data.Morpheus.Types.Internal.AST: class GQLValue a
+ Data.Morpheus.Types.Internal.AST: coerceDataObject :: Failure error m => error -> DataType -> m DataObject
+ Data.Morpheus.Types.Internal.AST: convertToHaskellName :: Text -> Text
+ Data.Morpheus.Types.Internal.AST: convertToJSONName :: Text -> Text
+ Data.Morpheus.Types.Internal.AST: createAlias :: Key -> TypeAlias
+ Data.Morpheus.Types.Internal.AST: createArgument :: Key -> ([TypeWrapper], Key) -> (Key, DataField)
+ Data.Morpheus.Types.Internal.AST: createDataTypeLib :: [(Key, DataType)] -> Validation DataTypeLib
+ Data.Morpheus.Types.Internal.AST: createEnumType :: Key -> [Key] -> (Key, DataType)
+ Data.Morpheus.Types.Internal.AST: createEnumValue :: Key -> DataEnumValue
+ Data.Morpheus.Types.Internal.AST: createField :: DataArguments -> Key -> ([TypeWrapper], Key) -> DataField
+ Data.Morpheus.Types.Internal.AST: createInputUnionFields :: Key -> [Key] -> [(Key, DataField)]
+ Data.Morpheus.Types.Internal.AST: createScalarType :: Key -> (Key, DataType)
+ Data.Morpheus.Types.Internal.AST: createType :: Key -> a -> DataTyCon a
+ Data.Morpheus.Types.Internal.AST: createUnionType :: Key -> [Key] -> (Key, DataType)
+ Data.Morpheus.Types.Internal.AST: data ArgsType
+ Data.Morpheus.Types.Internal.AST: data Argument
+ Data.Morpheus.Types.Internal.AST: data ClientQuery
+ Data.Morpheus.Types.Internal.AST: data ClientType
+ Data.Morpheus.Types.Internal.AST: data ConsD
+ Data.Morpheus.Types.Internal.AST: data DataEnumValue
+ Data.Morpheus.Types.Internal.AST: data DataField
+ Data.Morpheus.Types.Internal.AST: data DataFingerprint
+ Data.Morpheus.Types.Internal.AST: data DataTyCon a
+ Data.Morpheus.Types.Internal.AST: data DataType
+ Data.Morpheus.Types.Internal.AST: data DataTypeKind
+ Data.Morpheus.Types.Internal.AST: data DataTypeLib
+ Data.Morpheus.Types.Internal.AST: data DataTypeWrapper
+ Data.Morpheus.Types.Internal.AST: data Directive
+ Data.Morpheus.Types.Internal.AST: data Fragment
+ Data.Morpheus.Types.Internal.AST: data GQLQuery
+ Data.Morpheus.Types.Internal.AST: data GQLTypeD
+ Data.Morpheus.Types.Internal.AST: data Meta
+ Data.Morpheus.Types.Internal.AST: data Operation args sel
+ Data.Morpheus.Types.Internal.AST: data OperationType
+ Data.Morpheus.Types.Internal.AST: data Position
+ Data.Morpheus.Types.Internal.AST: data RawArgument
+ Data.Morpheus.Types.Internal.AST: data RawDataType
+ Data.Morpheus.Types.Internal.AST: data RawSelection
+ Data.Morpheus.Types.Internal.AST: data Ref
+ Data.Morpheus.Types.Internal.AST: data ResolverKind
+ Data.Morpheus.Types.Internal.AST: data ScalarValue
+ Data.Morpheus.Types.Internal.AST: data Selection args rec
+ Data.Morpheus.Types.Internal.AST: data SelectionRec
+ Data.Morpheus.Types.Internal.AST: data TypeAlias
+ Data.Morpheus.Types.Internal.AST: data TypeD
+ Data.Morpheus.Types.Internal.AST: data TypeWrapper
+ Data.Morpheus.Types.Internal.AST: data Value
+ Data.Morpheus.Types.Internal.AST: data ValueOrigin
+ Data.Morpheus.Types.Internal.AST: data Variable a
+ Data.Morpheus.Types.Internal.AST: decodeScientific :: Scientific -> ScalarValue
+ Data.Morpheus.Types.Internal.AST: defineType :: (Key, DataType) -> DataTypeLib -> DataTypeLib
+ Data.Morpheus.Types.Internal.AST: fieldVisibility :: (Key, DataField) -> Bool
+ Data.Morpheus.Types.Internal.AST: fromDataType :: (DataTyCon () -> v) -> DataType -> v
+ Data.Morpheus.Types.Internal.AST: getDataType :: Failure error m => Key -> DataTypeLib -> error -> m DataType
+ Data.Morpheus.Types.Internal.AST: getOperationDataType :: Operation a b -> DataTypeLib -> Validation DataObject
+ Data.Morpheus.Types.Internal.AST: getOperationName :: Maybe Key -> Key
+ Data.Morpheus.Types.Internal.AST: gqlBoolean :: GQLValue a => Bool -> a
+ Data.Morpheus.Types.Internal.AST: gqlList :: GQLValue a => [a] -> a
+ Data.Morpheus.Types.Internal.AST: gqlNull :: GQLValue a => a
+ Data.Morpheus.Types.Internal.AST: gqlObject :: GQLValue a => [(Text, a)] -> a
+ Data.Morpheus.Types.Internal.AST: gqlScalar :: GQLValue a => ScalarValue -> a
+ Data.Morpheus.Types.Internal.AST: gqlString :: GQLValue a => Text -> a
+ Data.Morpheus.Types.Internal.AST: initTypeLib :: (Key, DataObject) -> DataTypeLib
+ Data.Morpheus.Types.Internal.AST: insertType :: (Key, DataType) -> TypeUpdater
+ Data.Morpheus.Types.Internal.AST: instance GHC.Show.Show Data.Morpheus.Types.Internal.AST.GQLQuery
+ Data.Morpheus.Types.Internal.AST: instance Language.Haskell.TH.Syntax.Lift Data.Morpheus.Types.Internal.AST.GQLQuery
+ Data.Morpheus.Types.Internal.AST: isDefaultTypeName :: Key -> Bool
+ Data.Morpheus.Types.Internal.AST: isEntNode :: DataType -> Bool
+ Data.Morpheus.Types.Internal.AST: isFieldNullable :: DataField -> Bool
+ Data.Morpheus.Types.Internal.AST: isInput :: DataTypeKind -> Bool
+ Data.Morpheus.Types.Internal.AST: isNullable :: [TypeWrapper] -> Bool
+ Data.Morpheus.Types.Internal.AST: isObject :: DataTypeKind -> Bool
+ Data.Morpheus.Types.Internal.AST: isOutputObject :: DataTypeKind -> Bool
+ Data.Morpheus.Types.Internal.AST: isPrimitiveTypeName :: Key -> Bool
+ Data.Morpheus.Types.Internal.AST: isSchemaTypeName :: Key -> Bool
+ Data.Morpheus.Types.Internal.AST: isSubscription :: DataTypeKind -> Bool
+ Data.Morpheus.Types.Internal.AST: isTypeDefined :: Key -> DataTypeLib -> Maybe DataFingerprint
+ Data.Morpheus.Types.Internal.AST: isWeaker :: [TypeWrapper] -> [TypeWrapper] -> Bool
+ Data.Morpheus.Types.Internal.AST: kindOf :: DataType -> DataTypeKind
+ Data.Morpheus.Types.Internal.AST: lookupDataObject :: (Monad m, Failure e m) => e -> Key -> DataTypeLib -> m DataObject
+ Data.Morpheus.Types.Internal.AST: lookupDataType :: Key -> DataTypeLib -> Maybe DataType
+ Data.Morpheus.Types.Internal.AST: lookupDataUnion :: (Monad m, Failure e m) => e -> Key -> DataTypeLib -> m DataUnion
+ Data.Morpheus.Types.Internal.AST: lookupDeprecated :: Meta -> Maybe Directive
+ Data.Morpheus.Types.Internal.AST: lookupDeprecatedReason :: Directive -> Maybe Key
+ Data.Morpheus.Types.Internal.AST: lookupField :: Failure error m => Key -> [(Key, field)] -> error -> m field
+ Data.Morpheus.Types.Internal.AST: lookupFieldAsSelectionSet :: (Monad m, Failure GQLErrors m) => Position -> Key -> DataTypeLib -> DataField -> m DataObject
+ Data.Morpheus.Types.Internal.AST: lookupInputType :: Failure e m => Key -> DataTypeLib -> e -> m DataType
+ Data.Morpheus.Types.Internal.AST: lookupSelectionField :: Failure GQLErrors Validation => Position -> Key -> DataObject -> Validation DataField
+ Data.Morpheus.Types.Internal.AST: lookupType :: Failure e m => e -> [(Key, a)] -> Key -> m a
+ Data.Morpheus.Types.Internal.AST: lookupUnionTypes :: (Monad m, Failure GQLErrors m) => Position -> Key -> DataTypeLib -> DataField -> m [DataObject]
+ Data.Morpheus.Types.Internal.AST: newtype DataValidator
+ Data.Morpheus.Types.Internal.AST: replaceValue :: Value -> Value
+ Data.Morpheus.Types.Internal.AST: sysTypes :: [Key]
+ Data.Morpheus.Types.Internal.AST: toGQLWrapper :: [TypeWrapper] -> [DataTypeWrapper]
+ Data.Morpheus.Types.Internal.AST: toHSWrappers :: [DataTypeWrapper] -> [TypeWrapper]
+ Data.Morpheus.Types.Internal.AST: toListField :: DataField -> DataField
+ Data.Morpheus.Types.Internal.AST: toNullableField :: DataField -> DataField
+ Data.Morpheus.Types.Internal.AST: type Arguments = Collection Argument
+ Data.Morpheus.Types.Internal.AST: type Collection a = [(Key, a)]
+ Data.Morpheus.Types.Internal.AST: type DataArgument = DataField
+ Data.Morpheus.Types.Internal.AST: type DataArguments = [(Key, DataArgument)]
+ Data.Morpheus.Types.Internal.AST: type DataEnum = DataTyCon [DataEnumValue]
+ Data.Morpheus.Types.Internal.AST: type DataObject = DataTyCon [(Key, DataField)]
+ Data.Morpheus.Types.Internal.AST: type DataScalar = DataTyCon DataValidator
+ Data.Morpheus.Types.Internal.AST: type DataUnion = DataTyCon [Key]
+ Data.Morpheus.Types.Internal.AST: type DefaultValue = Maybe Value
+ Data.Morpheus.Types.Internal.AST: type Description = Key
+ Data.Morpheus.Types.Internal.AST: type FragmentLib = [(Key, Fragment)]
+ Data.Morpheus.Types.Internal.AST: type Key = Text
+ Data.Morpheus.Types.Internal.AST: type MUTATION = 'Mutation
+ Data.Morpheus.Types.Internal.AST: type Message = Text
+ Data.Morpheus.Types.Internal.AST: type Name = Key
+ Data.Morpheus.Types.Internal.AST: type Object = [(Text, Value)]
+ Data.Morpheus.Types.Internal.AST: type QUERY = 'Query
+ Data.Morpheus.Types.Internal.AST: type RawArguments = Collection RawArgument
+ Data.Morpheus.Types.Internal.AST: type RawOperation = Operation VariableDefinitions RawSelectionSet
+ Data.Morpheus.Types.Internal.AST: type RawSelection' a = Selection RawArguments a
+ Data.Morpheus.Types.Internal.AST: type RawSelectionSet = Collection RawSelection
+ Data.Morpheus.Types.Internal.AST: type SUBSCRIPTION = 'Subscription
+ Data.Morpheus.Types.Internal.AST: type SelectionSet = Collection ValidSelection
+ Data.Morpheus.Types.Internal.AST: type TypeUpdater = LibUpdater DataTypeLib
+ Data.Morpheus.Types.Internal.AST: type ValidOperation = Operation Arguments SelectionSet
+ Data.Morpheus.Types.Internal.AST: type ValidSelection = Selection Arguments SelectionRec
+ Data.Morpheus.Types.Internal.AST: type ValidVariables = Collection (Variable Value)
+ Data.Morpheus.Types.Internal.AST: type VariableDefinitions = Collection (Variable DefaultValue)
+ Data.Morpheus.Types.Internal.AST: type Variables = Map Key Value
- Data.Morpheus.Client: defineByDocument :: IO ByteString -> (GQLQueryRoot, String) -> Q [Dec]
+ Data.Morpheus.Client: defineByDocument :: IO ByteString -> (GQLQuery, String) -> Q [Dec]
- Data.Morpheus.Client: defineByDocumentFile :: String -> (GQLQueryRoot, String) -> Q [Dec]
+ Data.Morpheus.Client: defineByDocumentFile :: String -> (GQLQuery, String) -> Q [Dec]
- Data.Morpheus.Client: defineByIntrospection :: IO ByteString -> (GQLQueryRoot, String) -> Q [Dec]
+ Data.Morpheus.Client: defineByIntrospection :: IO ByteString -> (GQLQuery, String) -> Q [Dec]
- Data.Morpheus.Client: defineByIntrospectionFile :: String -> (GQLQueryRoot, String) -> Q [Dec]
+ Data.Morpheus.Client: defineByIntrospectionFile :: String -> (GQLQuery, String) -> Q [Dec]
- Data.Morpheus.Client: defineQuery :: IO (Validation DataTypeLib) -> (GQLQueryRoot, String) -> Q [Dec]
+ Data.Morpheus.Client: defineQuery :: IO (Validation DataTypeLib) -> (GQLQuery, String) -> Q [Dec]
- Data.Morpheus.Kind: data ResContext (kind :: GQL_KIND) (operation :: OperationType) (m :: * -> *) event value
+ Data.Morpheus.Kind: data ResContext (kind :: GQL_KIND) (operation :: OperationType) event (m :: * -> *) value
- Data.Morpheus.Types: Errors :: [JSONError] -> GQLResponse
+ Data.Morpheus.Types: Errors :: [GQLError] -> GQLResponse
- Data.Morpheus.Types: GQLRootResolver :: query (Resolver QUERY m event) -> mut (Resolver MUTATION m event) -> sub (Resolver SUBSCRIPTION m event) -> GQLRootResolver event
+ Data.Morpheus.Types: GQLRootResolver :: query (Resolver QUERY event m) -> mut (Resolver MUTATION event m) -> sub (Resolver SUBSCRIPTION event m) -> GQLRootResolver event
- Data.Morpheus.Types: [MutResolver] :: {mutEvents :: [event], mutResolver :: ExceptT String m value} -> Resolver MUTATION m event value
+ Data.Morpheus.Types: [MutResolver] :: {unMutResolver :: ResultT event String 'True m ([event], value)} -> Resolver MUTATION event m value
- Data.Morpheus.Types: [QueryResolver] :: {unQueryResolver :: ExceptT String m value} -> Resolver QUERY m event value
+ Data.Morpheus.Types: [QueryResolver] :: {unQueryResolver :: ResultT () String 'True m value} -> Resolver QUERY event m value
- Data.Morpheus.Types: [SubResolver] :: {subChannels :: [StreamChannel event], subResolver :: event -> Resolver QUERY m event value} -> Resolver SUBSCRIPTION m event value
+ Data.Morpheus.Types: [SubResolver] :: {subChannels :: [StreamChannel event], subResolver :: event -> Resolver QUERY event m value} -> Resolver SUBSCRIPTION event m value
- Data.Morpheus.Types: [mutationResolver] :: GQLRootResolver event -> mut (Resolver MUTATION m event)
+ Data.Morpheus.Types: [mutationResolver] :: GQLRootResolver event -> mut (Resolver MUTATION event m)
- Data.Morpheus.Types: [queryResolver] :: GQLRootResolver event -> query (Resolver QUERY m event)
+ Data.Morpheus.Types: [queryResolver] :: GQLRootResolver event -> query (Resolver QUERY event m)
- Data.Morpheus.Types: [subscriptionResolver] :: GQLRootResolver event -> sub (Resolver SUBSCRIPTION m event)
+ Data.Morpheus.Types: [subscriptionResolver] :: GQLRootResolver event -> sub (Resolver SUBSCRIPTION event m)
- Data.Morpheus.Types: constMutRes :: Monad m => [e] -> a -> args -> MutRes m e a
+ Data.Morpheus.Types: constMutRes :: Monad m => [e] -> a -> args -> MutRes e m a
- Data.Morpheus.Types: constRes :: (PureOperation o, Monad m) => b -> a -> Resolver o m e b
+ Data.Morpheus.Types: constRes :: (LiftEither o Resolver, Monad m) => b -> a -> Resolver o e m b
- Data.Morpheus.Types: data Resolver (o :: OperationType) (m :: * -> *) event value
+ Data.Morpheus.Types: data Resolver (o :: OperationType) event (m :: * -> *) value
- Data.Morpheus.Types: type IOMutRes = MutRes IO
+ Data.Morpheus.Types: type IOMutRes e = MutRes e IO
- Data.Morpheus.Types: type IORes = Res IO
+ Data.Morpheus.Types: type IORes e = Res e IO
- Data.Morpheus.Types: type IOSubRes = SubRes IO
+ Data.Morpheus.Types: type IOSubRes e = SubRes e IO

Files

README.md view
@@ -29,7 +29,7 @@ resolver: lts-14.8  extra-deps:-  - morpheus-graphql-0.6.2+  - morpheus-graphql-0.7.0 ```  As Morpheus is quite new, make sure stack can find morpheus-graphql by running `stack upgrade` and `stack update`@@ -45,9 +45,15 @@   deity(name: String!): Deity! } +"""+Description for Deity+""" type Deity {+  """+  Description for name+  """   name: String!-  power: String+  power: String String! @deprecated(reason: "some reason for") } ``` @@ -95,6 +101,8 @@  Template Haskell Generates types: `Query` , `Deity`, `DeityArgs`, that can be used by `rootResolver` +`descriptions` and `deprecations` will be displayed in intropsection.+ `importGQLDocumentWithNamespace` will generate Types with namespaced fields. if you don't need napespacing use `importGQLDocument`  ### with Native Haskell Types@@ -138,7 +146,7 @@  ```haskell resolveDeity :: DeityArgs -> IORes e Deity-resolveDeity DeityArgs { name, mythology } = liftEitherM $ dbDeity name mythology+resolveDeity DeityArgs { name, mythology } = liftEither $ dbDeity name mythology  askDB :: Text -> Maybe Text -> IO (Either String Deity) askDB = ...@@ -281,25 +289,23 @@ ### Mutations  In addition to queries, Morpheus also supports mutations. The behave just like regular queries and are defined similarly:-Just exchange deriving `GQLQuery` for `GQLMutation` and declare them separately at the `GQLRootResolver` definition  ```haskell newtype Mutation m = Mutation-  { createDeity :: Form -> m Deity+  { createDeity :: MutArgs -> m Deity   } deriving (Generic, GQLType) -createDeityMutation :: Form -> m (Deity m)-createDeityMutation = ...--rootResolver :: GQLRootResolver IO Query Mutation Undefined+rootResolver :: GQLRootResolver IO  () Query Mutation Undefined rootResolver =   GQLRootResolver     { queryResolver = Query {...}-    , mutationResolver = Mutation {-       createDeity = createDeityMutation-    }+    , mutationResolver = Mutation { createDeity }     , subscriptionResolver = Undefined     }+    where+      -- Mutation Without Event Triggering+      createDeity :: MutArgs -> ResolveM () IO Deity+      createDeity_args = lift setDBAddress  gqlApi :: ByteString -> IO ByteString gqlApi = interpreter rootResolver@@ -321,6 +327,8 @@   = ContentA Int   | ContentB Text +type MyEvent = Event Channel Content+ newtype Query m = Query   { deity :: () -> m Deity   } deriving (Generic)@@ -329,29 +337,33 @@   { createDeity :: () -> m Deity   } deriving (Generic) -newtype Subscription m = Subscription+newtype Subscription (m ::  * -> * ) = Subscription   { newDeity :: () -> m  Deity   } deriving (Generic)  type APIEvent = Event Channel Content  rootResolver :: GQLRootResolver IO APIEvent Query Mutation Subscription-rootResolver =-  GQLRootResolver-    { queryResolver = Query {deity = const fetchDeity}-    , mutationResolver = Mutation {createDeity}-    , subscriptionResolver = Subscription {newDeity}-    }-  where-    createDeity _args = MutResolver events updateDeity-        where-        events = [Event {channels = [ChannelA], content = ContentA 1}]-        updateDeity = updateDBDeity-    newDeity _args = SubResolver [ChannelA] subResolver-      where-        subResolver (Event [ChannelA] (ContentA _value)) = fetchDeity  -- resolve New State-        subResolver (Event [ChannelA] (ContentB _value)) = fetchDeity   -- resolve New State-        subResolver _                                    = fetchDeity -- Resolve Old State+rootResolver = GQLRootResolver+  { queryResolver        = Query { deity }+  , mutationResolver     = Mutation { createDeity }+  , subscriptionResolver = Subscription { newDeity }+  }+ where+  deity _args = fetchDeity+  -- Mutation Without Event Triggering+  createDeity :: () -> ResolveM EVENT IO Address+  createDeity _args = MutResolver \$ do+      value <- lift dbCreateDeity+      pure (+        [Event { channels = [ChannelA], content = ContentA 1 }],+        value+      )+  newDeity _args = SubResolver [ChannelA] subResolver+   where+    subResolver (Event [ChannelA] (ContentA _value)) = fetchDeity  -- resolve New State+    subResolver (Event [ChannelA] (ContentB _value)) = fetchDeity   -- resolve New State+    subResolver _ = fetchDeity -- Resolve Old State ```  ## Morpheus `GraphQL Client` with Template haskell QuasiQuotes
changelog.md view
@@ -1,3 +1,136 @@+## [0.7.0] - 24.11.2019++## Removed++- `toMorpheusHaskellAPi` from `Data.Morpheus.Document` functionality will be migrated in `morpheus-graphql-cli`++## Changed++- `liftM` to `MonadTrans` instance method `lift`++- `liftEitherM` to `liftEither`++- `Resolver operation m event value` -> `Resolver operation event m value` , monad trans needs that last 2 type arguments are monad and value that why it was necessary++- exposed `Data.Morpheus.Types.Internal.AST`++- Mutation Resolver was changed from++```+resolver :: () -> ResolveM EVENT IO Address+resolver = MutResolver  {+  mutEvents = [someEventForSubscription],+  mutResolver = lift setDBAddress+}+```++```haskell+-- Mutation Wit Event Triggering : sends events to subscription+resolver :: () -> ResolveM EVENT IO Address+resolver = MutResolver \$ do+  value <- lift setDBAddress+  pure ([someEventForSubscription], value)+-- or+-- Mutation Without Event Triggering+resolver :: () -> ResolveM EVENT IO Address+resolver _args = lift setDBAddress+```++### Added++- added `parseDSL` to `Data.Morpheus.Document`++- GraphQL SDL support fully supports descriptions: onTypes, fields , args ...+  with (enums, inputObjects , union, object)+  for example :++  ```gql+  """+  Description for Type Address+  """+  type Address {+    """+    Description for Field city+    """+    city: String!+    street(+      """+      Description argument id+      """+      id: ID!+    ): Int!+  }+  ```++  ###### GraphQL SDL++  ```gql+  type User {+    name: String! @deprecated(reason: "some reason")+  }+  ```++  will displayed in introspection++  ###### introspection.json++  ```json+  {+    "data": {+      "__type": {+        "fields": [+          {+            "name": "city",+            "isDeprecated": true,+            "deprecationReason": "test deprecation field with reason"+          }+        ]+      }+    }+  }+  ```++- basic support of directive `@deprecated` on `enumValue` and object `field`, only on introspection++- GraphQL Client deprecation warnings++  on type++  ```gql+  type Human {+    humanName: String!+    lifetime: Lifetime! @deprecated(reason: "some reason")+    profession: Profession+  }+  ```++  compiler output:++  ```+  warning:+    Morpheus Client Warning:+    {+      "message":"the field \"Human.lifetime\" is deprecated. some reason",+      "locations":[{"line":24,"column":15}]+    }+  ```++- new helper resolver types aliases:++  - ResolveQ : for Query+  - ResolveM : for Mutation+  - ResolveS : for Subscription++  `ResolveM EVENT IO Address` is same as `MutRes EVENT IO (Address (MutRes EVENT IO))`++  is helpfull wenn you want to resolve GraphQL object++### Fixed++- added missing Monad instance for Mutation resolver+- `defineByIntrospectionFile` does not breaks if schema contains interfaces+- Morpheus Client supports `Subscription` and `Mutation`operations+ ## [0.6.2] - 2.11.2019  ## Added
morpheus-graphql.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 6d77e1db039ce6a4a5ef7761d0b18beb9ea7067fbb99372bd3a97510e4da4a43+-- hash: a97de9ffea5713a01a84ffef6bd7ee41104d3d898f2d6a90ae0ef0be27ba7568  name:           morpheus-graphql-version:        0.6.2+version:        0.7.0 synopsis:       Morpheus GraphQL description:    Build GraphQL APIs with your favourite functional language! category:       web, graphql@@ -23,7 +23,6 @@     changelog.md     README.md data-files:-    test/Feature/Holistic/API.gql     test/Feature/Holistic/arguments/nameConflict/query.gql     test/Feature/Holistic/arguments/undefinedArgument/query.gql     test/Feature/Holistic/arguments/unknownArguments/query.gql@@ -39,6 +38,12 @@     test/Feature/Holistic/introspection/defaultTypes/ID/query.gql     test/Feature/Holistic/introspection/defaultTypes/Int/query.gql     test/Feature/Holistic/introspection/defaultTypes/String/query.gql+    test/Feature/Holistic/introspection/deprecated/enumValue/query.gql+    test/Feature/Holistic/introspection/deprecated/field/query.gql+    test/Feature/Holistic/introspection/description/enum/query.gql+    test/Feature/Holistic/introspection/description/inputObject/query.gql+    test/Feature/Holistic/introspection/description/object/query.gql+    test/Feature/Holistic/introspection/description/union/query.gql     test/Feature/Holistic/introspection/kinds/ENUM/query.gql     test/Feature/Holistic/introspection/kinds/INPUT_OBJECT/query.gql     test/Feature/Holistic/introspection/kinds/OBJECT/query.gql@@ -68,6 +73,7 @@     test/Feature/Holistic/parsing/missingCloseBrace/query.gql     test/Feature/Holistic/parsing/notNullSpacing/query.gql     test/Feature/Holistic/parsing/singleLineComments/query.gql+    test/Feature/Holistic/schema.gql     test/Feature/Holistic/selection/AliasNameConflict/query.gql     test/Feature/Holistic/selection/AliasResolve/query.gql     test/Feature/Holistic/selection/AliasUnknownField/query.gql@@ -133,6 +139,12 @@     test/Feature/Holistic/introspection/defaultTypes/ID/response.json     test/Feature/Holistic/introspection/defaultTypes/Int/response.json     test/Feature/Holistic/introspection/defaultTypes/String/response.json+    test/Feature/Holistic/introspection/deprecated/enumValue/response.json+    test/Feature/Holistic/introspection/deprecated/field/response.json+    test/Feature/Holistic/introspection/description/enum/response.json+    test/Feature/Holistic/introspection/description/inputObject/response.json+    test/Feature/Holistic/introspection/description/object/response.json+    test/Feature/Holistic/introspection/description/union/response.json     test/Feature/Holistic/introspection/kinds/ENUM/response.json     test/Feature/Holistic/introspection/kinds/INPUT_OBJECT/response.json     test/Feature/Holistic/introspection/kinds/OBJECT/response.json@@ -242,6 +254,7 @@       Data.Morpheus.Server       Data.Morpheus.Document       Data.Morpheus.Client+      Data.Morpheus.Types.Internal.AST   other-modules:       Data.Morpheus.Error.Arguments       Data.Morpheus.Error.Client.Client@@ -269,7 +282,6 @@       Data.Morpheus.Execution.Document.Introspect       Data.Morpheus.Execution.Internal.Declare       Data.Morpheus.Execution.Internal.Decode-      Data.Morpheus.Execution.Internal.GraphScanner       Data.Morpheus.Execution.Internal.Utils       Data.Morpheus.Execution.Server.Decode       Data.Morpheus.Execution.Server.Encode@@ -281,7 +293,6 @@       Data.Morpheus.Execution.Subscription.ClientRegister       Data.Morpheus.Parsing.Document.Parser       Data.Morpheus.Parsing.Document.TypeSystem-      Data.Morpheus.Parsing.Internal.Create       Data.Morpheus.Parsing.Internal.Internal       Data.Morpheus.Parsing.Internal.Pattern       Data.Morpheus.Parsing.Internal.Terms@@ -292,30 +303,23 @@       Data.Morpheus.Parsing.Request.Operation       Data.Morpheus.Parsing.Request.Parser       Data.Morpheus.Parsing.Request.Selection-      Data.Morpheus.Rendering.Haskell.Render-      Data.Morpheus.Rendering.Haskell.Terms-      Data.Morpheus.Rendering.Haskell.Types-      Data.Morpheus.Rendering.Haskell.Values       Data.Morpheus.Rendering.RenderGQL       Data.Morpheus.Rendering.RenderIntrospection       Data.Morpheus.Schema.Schema       Data.Morpheus.Schema.SchemaAPI       Data.Morpheus.Schema.TypeKind-      Data.Morpheus.Types.Custom       Data.Morpheus.Types.GQLScalar       Data.Morpheus.Types.GQLType       Data.Morpheus.Types.ID+      Data.Morpheus.Types.Internal.AST.Base+      Data.Morpheus.Types.Internal.AST.Data       Data.Morpheus.Types.Internal.AST.Operation-      Data.Morpheus.Types.Internal.AST.RawSelection       Data.Morpheus.Types.Internal.AST.Selection-      Data.Morpheus.Types.Internal.Base-      Data.Morpheus.Types.Internal.Data-      Data.Morpheus.Types.Internal.DataD-      Data.Morpheus.Types.Internal.Resolver-      Data.Morpheus.Types.Internal.Stream+      Data.Morpheus.Types.Internal.AST.Value+      Data.Morpheus.Types.Internal.Resolving+      Data.Morpheus.Types.Internal.Resolving.Core+      Data.Morpheus.Types.Internal.Resolving.Resolver       Data.Morpheus.Types.Internal.TH-      Data.Morpheus.Types.Internal.Validation-      Data.Morpheus.Types.Internal.Value       Data.Morpheus.Types.Internal.WebSocket       Data.Morpheus.Types.IO       Data.Morpheus.Types.Types@@ -325,7 +329,6 @@       Data.Morpheus.Validation.Query.Arguments       Data.Morpheus.Validation.Query.Fragment       Data.Morpheus.Validation.Query.Selection-      Data.Morpheus.Validation.Query.Utils.Selection       Data.Morpheus.Validation.Query.Validation       Data.Morpheus.Validation.Query.Variable       Paths_morpheus_graphql@@ -342,6 +345,7 @@     , scientific >=0.3.6.2 && <0.4     , template-haskell >=2.0 && <=2.16     , text >=1.2.3.0 && <1.3+    , th-lift-instances >=0.1.1 && <=0.2.0     , transformers >=0.3.0.0 && <0.6     , unordered-containers >=0.2.8.0 && <0.3     , uuid >=1.0 && <=1.4@@ -381,6 +385,7 @@     , tasty-hunit     , template-haskell >=2.0 && <=2.16     , text >=1.2.3.0 && <1.3+    , th-lift-instances >=0.1.1 && <=0.2.0     , transformers >=0.3.0.0 && <0.6     , unordered-containers >=0.2.8.0 && <0.3     , uuid >=1.0 && <=1.4
src/Data/Morpheus.hs view
@@ -1,6 +1,8 @@ -- | Build GraphQL APIs with your favourite functional language! module Data.Morpheus   ( Interpreter(..)-  ) where+  )+where -import           Data.Morpheus.Execution.Server.Interpreter (Interpreter (..))+import           Data.Morpheus.Execution.Server.Interpreter+                                                ( Interpreter(..) )
src/Data/Morpheus/Client.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE NamedFieldPuns    #-} {-# LANGUAGE OverloadedStrings #-}  module Data.Morpheus.Client@@ -10,38 +9,46 @@   , defineByDocumentFile   , defineByIntrospection   , defineByIntrospectionFile-  ) where+  )+where -import           Data.ByteString.Lazy                    (ByteString)-import qualified Data.ByteString.Lazy                    as L (readFile)+import           Data.ByteString.Lazy           ( ByteString )+import qualified Data.ByteString.Lazy          as L+                                                ( readFile ) import           Language.Haskell.TH import           Language.Haskell.TH.Quote -import           Data.Morpheus.Document                  (parseFullGQLDocument)+import           Data.Morpheus.Document         ( parseFullGQLDocument ) -- MORPHEUS-import           Data.Morpheus.Execution.Client.Build    (defineQuery)-import           Data.Morpheus.Execution.Client.Compile  (compileSyntax)-import           Data.Morpheus.Execution.Client.Fetch    (Fetch (..))-import           Data.Morpheus.Parsing.JSONSchema.Parse  (decodeIntrospection)-import           Data.Morpheus.Types.Internal.Data       (DataTypeLib)-import           Data.Morpheus.Types.Internal.Validation (Validation)-import           Data.Morpheus.Types.Types               (GQLQueryRoot)+import           Data.Morpheus.Execution.Client.Build+                                                ( defineQuery )+import           Data.Morpheus.Execution.Client.Compile+                                                ( compileSyntax )+import           Data.Morpheus.Execution.Client.Fetch+                                                ( Fetch(..) )+import           Data.Morpheus.Parsing.JSONSchema.Parse+                                                ( decodeIntrospection )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Validation )+import           Data.Morpheus.Types.Internal.AST+                                                ( GQLQuery+                                                , DataTypeLib+                                                )  gql :: QuasiQuoter-gql =-  QuasiQuoter-    { quoteExp = compileSyntax-    , quotePat = notHandled "Patterns"-    , quoteType = notHandled "Types"-    , quoteDec = notHandled "Declarations"-    }-  where-    notHandled things = error $ things ++ " are not supported by the GraphQL QuasiQuoter"+gql = QuasiQuoter { quoteExp  = compileSyntax+                  , quotePat  = notHandled "Patterns"+                  , quoteType = notHandled "Types"+                  , quoteDec  = notHandled "Declarations"+                  }+ where+  notHandled things =+    error $ things ++ " are not supported by the GraphQL QuasiQuoter" -defineByDocumentFile :: String -> (GQLQueryRoot, String) -> Q [Dec]+defineByDocumentFile :: String -> (GQLQuery, String) -> Q [Dec] defineByDocumentFile = defineByDocument . L.readFile -defineByIntrospectionFile :: String -> (GQLQueryRoot, String) -> Q [Dec]+defineByIntrospectionFile :: String -> (GQLQuery, String) -> Q [Dec] defineByIntrospectionFile = defineByIntrospection . L.readFile  --@@ -49,11 +56,11 @@ -- TODO: Define By API -- Validates By Server API ---defineByDocument :: IO ByteString -> (GQLQueryRoot, String) -> Q [Dec]+defineByDocument :: IO ByteString -> (GQLQuery, String) -> Q [Dec] defineByDocument doc = defineQuery (schemaByDocument doc)  schemaByDocument :: IO ByteString -> IO (Validation DataTypeLib) schemaByDocument documentGQL = parseFullGQLDocument <$> documentGQL -defineByIntrospection :: IO ByteString -> (GQLQueryRoot, String) -> Q [Dec]+defineByIntrospection :: IO ByteString -> (GQLQuery, String) -> Q [Dec] defineByIntrospection json = defineQuery (decodeIntrospection <$> json)
src/Data/Morpheus/Document.hs view
@@ -1,39 +1,64 @@+{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE NamedFieldPuns   #-}  module Data.Morpheus.Document   ( toGraphQLDocument-  , toMorpheusHaskellAPi   , gqlDocument   , parseFullGQLDocument   , importGQLDocument   , importGQLDocumentWithNamespace-  ) where+  , parseDSL+  )+where -import           Control.Monad                                ((>=>))-import           Data.ByteString.Lazy.Char8                   (ByteString, pack)-import           Data.Text                                    (Text)-import qualified Data.Text.Lazy                               as LT (toStrict)-import           Data.Text.Lazy.Encoding                      (decodeUtf8)+import           Control.Monad                  ( (>=>) )+import           Data.ByteString.Lazy.Char8     ( ByteString+                                                , pack+                                                )+import           Data.Text                      ( Text )+import qualified Data.Text.Lazy                as LT+                                                ( toStrict )+import           Data.Text.Lazy.Encoding        ( decodeUtf8 ) import           Language.Haskell.TH  -- -- MORPHEUS-import           Data.Morpheus.Execution.Document.Compile     (compileDocument, gqlDocument)-import           Data.Morpheus.Execution.Server.Resolve       (RootResCon, fullSchema)-import           Data.Morpheus.Rendering.Haskell.Render       (renderHaskellDocument)-import           Data.Morpheus.Rendering.RenderGQL            (renderGraphQLDocument)-import           Data.Morpheus.Types                          (GQLRootResolver)+import           Data.Morpheus.Execution.Document.Compile+                                                ( compileDocument+                                                , gqlDocument+                                                )+import           Data.Morpheus.Execution.Server.Resolve+                                                ( RootResCon+                                                , fullSchema+                                                )+import           Data.Morpheus.Parsing.Document.Parser+                                                ( parseTypes ) -import           Data.Morpheus.Parsing.Document.Parser        (parseTypes)-import           Data.Morpheus.Parsing.Internal.Create        (createDataTypeLib)-import           Data.Morpheus.Schema.SchemaAPI               (defaultTypes)-import           Data.Morpheus.Types.Internal.Data            (DataTypeLib)-import           Data.Morpheus.Types.Internal.Validation      (Validation)-import           Data.Morpheus.Validation.Document.Validation (validatePartialDocument)+import           Data.Morpheus.Rendering.RenderGQL+                                                ( renderGraphQLDocument )+import           Data.Morpheus.Schema.SchemaAPI ( defaultTypes )+import           Data.Morpheus.Types            ( GQLRootResolver )+import           Data.Morpheus.Types.Internal.AST+                                                ( DataTypeLib+                                                , createDataTypeLib+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Validation+                                                , Result(..)+                                                )+import           Data.Morpheus.Validation.Document.Validation+                                                ( validatePartialDocument ) +                                              +parseDSL :: ByteString -> Either String DataTypeLib+parseDSL doc = case parseGraphQLDocument doc of+  Failure errors     -> Left (show errors)+  Success { result } -> Right result++ parseDocument :: Text -> Validation DataTypeLib-parseDocument doc = parseTypes doc >>= validatePartialDocument >>= createDataTypeLib+parseDocument doc =+  parseTypes doc >>= validatePartialDocument >>= createDataTypeLib  parseGraphQLDocument :: ByteString -> Validation DataTypeLib parseGraphQLDocument x = parseDocument (LT.toStrict $ decodeUtf8 x)@@ -42,20 +67,19 @@ parseFullGQLDocument = parseGraphQLDocument >=> defaultTypes  -- | Generates schema.gql file from 'GQLRootResolver'-toGraphQLDocument :: RootResCon m event query mut sub => proxy (GQLRootResolver m event query mut sub) -> ByteString-toGraphQLDocument x =-  case fullSchema x of-    Left errors -> pack (show errors)-    Right lib   -> renderGraphQLDocument lib+toGraphQLDocument+  :: RootResCon m event query mut sub+  => proxy (GQLRootResolver m event query mut sub)+  -> ByteString+toGraphQLDocument x = case fullSchema x of+  Failure errors           -> pack (show errors)+  Success { result = lib } -> renderGraphQLDocument lib -toMorpheusHaskellAPi :: String -> ByteString -> Either ByteString ByteString-toMorpheusHaskellAPi moduleName doc =-  case parseGraphQLDocument doc of-    Left errors -> Left $ pack (show errors)-    Right lib   -> Right $ renderHaskellDocument moduleName lib + importGQLDocument :: String -> Q [Dec] importGQLDocument src = runIO (readFile src) >>= compileDocument False  importGQLDocumentWithNamespace :: String -> Q [Dec]-importGQLDocumentWithNamespace src = runIO (readFile src) >>= compileDocument True+importGQLDocumentWithNamespace src =+  runIO (readFile src) >>= compileDocument True
src/Data/Morpheus/Error/Arguments.hs view
@@ -5,13 +5,21 @@   , unknownArguments   , argumentGotInvalidValue   , argumentNameCollision-  ) where+  )+where -import           Data.Morpheus.Error.Utils               (errorMessage)-import           Data.Morpheus.Types.Internal.Base       (EnhancedKey (..), Position)-import           Data.Morpheus.Types.Internal.Validation (GQLError (..), GQLErrors)-import           Data.Text                               (Text)-import qualified Data.Text                               as T (concat)+import           Data.Morpheus.Error.Utils      ( errorMessage )+import           Data.Morpheus.Types.Internal.AST.Base+                                                ( Ref(..)+                                                , Position+                                                )+import           Data.Morpheus.Types.Internal.Resolving.Core+                                                ( GQLError(..)+                                                , GQLErrors+                                                )+import           Data.Text                      ( Text )+import qualified Data.Text                     as T+                                                ( concat )  {-   ARGUMENTS:@@ -28,29 +36,27 @@   - date(name: "name") -> "Unknown argument \"name\" on field \"date\" of type \"Experience\"." -} argumentGotInvalidValue :: Text -> Text -> Position -> GQLErrors-argumentGotInvalidValue key' inputMessage' position' =-  errorMessage position' text-  where-    text = T.concat ["Argument ", key', " got invalid value ;", inputMessage']+argumentGotInvalidValue key' inputMessage' position' = errorMessage position'+                                                                    text+ where+  text = T.concat ["Argument ", key', " got invalid value ;", inputMessage'] -unknownArguments :: Text -> [EnhancedKey] -> GQLErrors+unknownArguments :: Text -> [Ref] -> GQLErrors unknownArguments fieldName = map keyToError-  where-    keyToError (EnhancedKey argName pos) =-      GQLError {desc = toMessage argName, positions = [pos]}-    toMessage argName =-      T.concat-        ["Unknown Argument \"", argName, "\" on Field \"", fieldName, "\"."]+ where+  keyToError (Ref argName pos) =+    GQLError { message = toMessage argName, locations = [pos] }+  toMessage argName = T.concat+    ["Unknown Argument \"", argName, "\" on Field \"", fieldName, "\"."] -argumentNameCollision :: [EnhancedKey] -> GQLErrors+argumentNameCollision :: [Ref] -> GQLErrors argumentNameCollision = map keyToError-  where-    keyToError (EnhancedKey argName pos) =-      GQLError {desc = toMessage argName, positions = [pos]}-    toMessage argName =-      T.concat ["There can Be only One Argument Named \"", argName, "\""]+ where+  keyToError (Ref argName pos) =+    GQLError { message = toMessage argName, locations = [pos] }+  toMessage argName =+    T.concat ["There can Be only One Argument Named \"", argName, "\""] -undefinedArgument :: EnhancedKey -> GQLErrors-undefinedArgument (EnhancedKey key' position') = errorMessage position' text-  where-    text = T.concat ["Required Argument: \"", key', "\" was not Defined"]+undefinedArgument :: Ref -> GQLErrors+undefinedArgument (Ref key' position') = errorMessage position' text+  where text = T.concat ["Required Argument: \"", key', "\" was not Defined"]
src/Data/Morpheus/Error/Client/Client.hs view
@@ -1,11 +1,55 @@+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+ module Data.Morpheus.Error.Client.Client   ( renderGQLErrors-  ) where+  , deprecatedEnum+  , deprecatedField+  , gqlWarnings+  )+where -import           Data.Aeson                              (encode)-import           Data.ByteString.Lazy.Char8              (unpack)-import           Data.Morpheus.Error.Utils               (renderErrors)-import           Data.Morpheus.Types.Internal.Validation (GQLErrors)+import           Data.Aeson                     ( encode )+import           Data.ByteString.Lazy.Char8     ( unpack )+import           Data.Morpheus.Error.Utils      ( errorMessage )+import           Data.Morpheus.Types.Internal.Resolving.Core+                                                ( GQLErrors )+import           Data.Morpheus.Types.Internal.AST.Base+                                                ( Ref(..)+                                                , Description+                                                , Name+                                                )+import           Language.Haskell.TH            ( Q+                                                , reportWarning+                                                )+import           Data.Semigroup                 ( (<>) )  renderGQLErrors :: GQLErrors -> String-renderGQLErrors = unpack . encode . renderErrors+renderGQLErrors = unpack . encode++deprecatedEnum :: Name -> Ref -> Maybe Description -> GQLErrors+deprecatedEnum typeName Ref { refPosition, refName } reason =+  errorMessage refPosition+    $  "the enum value "+    <> typeName+    <> "."+    <> refName+    <> "\" is deprecated."+    <> maybe "" (" " <>) reason++deprecatedField :: Name -> Ref -> Maybe Description -> GQLErrors+deprecatedField typeName Ref { refPosition, refName } reason =+  errorMessage refPosition+    $  "the field \""+    <> typeName+    <> "."+    <> refName+    <> "\" is deprecated."+    <> maybe "" (" " <>) reason++gqlWarnings :: GQLErrors -> Q ()+gqlWarnings []       = pure ()+gqlWarnings warnings = mapM_ handleWarning warnings+ where+  handleWarning warning =+    reportWarning ("Morpheus GraphQL Warning: " <> (unpack . encode) warning)
src/Data/Morpheus/Error/Document/Interface.hs view
@@ -5,17 +5,21 @@   ( unknownInterface   , partialImplements   , ImplementsError(..)-  ) where+  )+where -import           Data.Morpheus.Error.Utils               (globalErrorMessage)-import           Data.Morpheus.Types.Internal.Base       (Key)-import           Data.Morpheus.Types.Internal.Validation (GQLError (..), GQLErrors)-import           Data.Semigroup                          ((<>))+import           Data.Morpheus.Error.Utils      ( globalErrorMessage )+import           Data.Morpheus.Types.Internal.AST.Base+                                                ( Key )+import           Data.Morpheus.Types.Internal.Resolving.Core+                                                ( GQLError(..)+                                                , GQLErrors+                                                )+import           Data.Semigroup                 ( (<>) )  unknownInterface :: Key -> GQLErrors unknownInterface name = globalErrorMessage message-  where-    message = "Unknown Interface \"" <> name <> "\"."+  where message = "Unknown Interface \"" <> name <> "\"."  data ImplementsError   = UnexpectedType { expectedType :: Key@@ -24,12 +28,24 @@  partialImplements :: Key -> [(Key, Key, ImplementsError)] -> GQLErrors partialImplements name = map impError-  where-    impError (interfaceName, key, errorType) = GQLError {desc = message, positions = []}-      where-        message =-          "type \"" <> name <> "\" implements Interface \"" <> interfaceName <> "\" Partially," <>-          detailedMessage errorType-        detailedMessage UnexpectedType {expectedType, foundType} =-          " on key \"" <> key <> "\" expected type \"" <> expectedType <> "\" found \"" <> foundType <> "\"."-        detailedMessage UndefinedField = " key \"" <> key <> "\" not found ."+ where+  impError (interfaceName, key, errorType) = GQLError { message   = message+                                                      , locations = []+                                                      }+   where+    message =+      "type \""+        <> name+        <> "\" implements Interface \""+        <> interfaceName+        <> "\" Partially,"+        <> detailedMessage errorType+    detailedMessage UnexpectedType { expectedType, foundType } =+      " on key \""+        <> key+        <> "\" expected type \""+        <> expectedType+        <> "\" found \""+        <> foundType+        <> "\"."+    detailedMessage UndefinedField = " key \"" <> key <> "\" not found ."
src/Data/Morpheus/Error/Fragment.hs view
@@ -7,16 +7,23 @@   , unknownFragment   , cannotBeSpreadOnType   , fragmentNameCollision-  ) where+  )+where -import           Data.Semigroup                          ((<>))-import           Data.Text                               (Text)-import qualified Data.Text                               as T+import           Data.Semigroup                 ( (<>) )+import           Data.Text                      ( Text )+import qualified Data.Text                     as T  -- MORPHEUS-import           Data.Morpheus.Error.Utils               (errorMessage)-import           Data.Morpheus.Types.Internal.Base       (EnhancedKey (..), Position)-import           Data.Morpheus.Types.Internal.Validation (GQLError (..), GQLErrors)+import           Data.Morpheus.Error.Utils      ( errorMessage )+import           Data.Morpheus.Types.Internal.AST.Base+                                                ( Ref(..)+                                                , Position+                                                )+import           Data.Morpheus.Types.Internal.Resolving.Core+                                                ( GQLError(..)+                                                , GQLErrors+                                                )  {-   FRAGMENT:@@ -29,57 +36,53 @@     fragment H on D {...}  ->  "Unknown type \"D\"."     {...H} -> "Unknown fragment \"H\"." -}-fragmentNameCollision :: [EnhancedKey] -> GQLErrors+fragmentNameCollision :: [Ref] -> GQLErrors fragmentNameCollision = map toError-  where-    toError EnhancedKey {uid, location} =-      GQLError-        { desc = "There can be only one fragment named \"" <> uid <> "\"."-        , positions = [location]-        }+ where+  toError Ref { refName, refPosition } = GQLError+    { message      = "There can be only one fragment named \"" <> refName <> "\"."+    , locations = [refPosition]+    } -unusedFragment :: [EnhancedKey] -> GQLErrors+unusedFragment :: [Ref] -> GQLErrors unusedFragment = map toError-  where-    toError EnhancedKey {uid, location} =-      GQLError-        { desc = "Fragment \"" <> uid <> "\" is never used."-        , positions = [location]-        }+ where+  toError Ref { refName, refPosition } = GQLError+    { message      = "Fragment \"" <> refName <> "\" is never used."+    , locations = [refPosition]+    } -cannotSpreadWithinItself :: [EnhancedKey] -> GQLErrors+cannotSpreadWithinItself :: [Ref] -> GQLErrors cannotSpreadWithinItself fragments =-  [GQLError {desc = text, positions = map location fragments}]-  where-    text =-      T.concat-        [ "Cannot spread fragment \""-        , uid $ head fragments-        , "\" within itself via "-        , T.intercalate "," (map uid fragments)-        , "."-        ]+  [GQLError { message = text, locations = map refPosition fragments }]+ where+  text = T.concat+    [ "Cannot spread fragment \""+    , refName $ head fragments+    , "\" within itself via "+    , T.intercalate "," (map refName fragments)+    , "."+    ]  -- {...H} -> "Unknown fragment \"H\"." unknownFragment :: Text -> Position -> GQLErrors unknownFragment key' position' = errorMessage position' text-  where-    text = T.concat ["Unknown Fragment \"", key', "\"."]+  where text = T.concat ["Unknown Fragment \"", key', "\"."]  -- Fragment type mismatch -> "Fragment \"H\" cannot be spread here as objects of type \"Hobby\" can never be of type \"Experience\"." cannotBeSpreadOnType :: Maybe Text -> Text -> Position -> Text -> GQLErrors-cannotBeSpreadOnType key' type' position' selectionType' =-  errorMessage position' text-  where-    text =-      T.concat-        [ "Fragment"-        , getName key'-        , " cannot be spread here as objects of type \""-        , selectionType'-        , "\" can never be of type \""-        , type'-        , "\"."-        ]-    getName (Just x') = T.concat [" \"", x', "\""]-    getName Nothing   = ""+cannotBeSpreadOnType key' type' position' selectionType' = errorMessage+  position'+  text+ where+  text = T.concat+    [ "Fragment"+    , getName key'+    , " cannot be spread here as objects of type \""+    , selectionType'+    , "\" can never be of type \""+    , type'+    , "\"."+    ]+  getName (Just x') = T.concat [" \"", x', "\""]+  getName Nothing   = ""
src/Data/Morpheus/Error/Input.hs view
@@ -1,18 +1,25 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}  module Data.Morpheus.Error.Input   ( inputErrorMessage   , InputError(..)   , Prop(..)   , InputValidation-  ) where--import           Data.Aeson                         (encode)-import           Data.ByteString.Lazy.Char8         (unpack)-import           Data.Morpheus.Types.Internal.Value (Value)-import           Data.Text                          (Text)-import qualified Data.Text                          as T (concat, intercalate, pack)+  )+where +import           Data.Aeson                     ( encode )+import           Data.ByteString.Lazy.Char8     ( unpack )+import           Data.Morpheus.Types.Internal.AST.Value+                                                ( Value )+import           Data.Text                      ( Text )+import qualified Data.Text                     as T+                                                ( concat+                                                , intercalate+                                                , pack+                                                ) type InputValidation a = Either InputError a  data InputError@@ -30,33 +37,31 @@ inputErrorMessage (UnexpectedType path type' value errorMessage) =   expectedTypeAFoundB path type' value errorMessage inputErrorMessage (UndefinedField path' field') = undefinedField path' field'-inputErrorMessage (UnknownField path' field') = unknownField path' field'+inputErrorMessage (UnknownField   path' field') = unknownField path' field'  pathToText :: [Prop] -> Text pathToText []    = "" pathToText path' = T.concat ["on ", T.intercalate "." $ fmap propKey path']  expectedTypeAFoundB :: [Prop] -> Text -> Value -> Maybe Text -> Text-expectedTypeAFoundB path' expected found Nothing =-  T.concat-    [ pathToText path'-    , " Expected type \""-    , expected-    , "\" found "-    , T.pack (unpack $ encode found)-    , "."-    ]-expectedTypeAFoundB path' expected found (Just errorMessage) =-  T.concat-    [ pathToText path'-    , " Expected type \""-    , expected-    , "\" found "-    , T.pack (unpack $ encode found)-    , "; "-    , errorMessage-    , "."-    ]+expectedTypeAFoundB path' expected found Nothing = T.concat+  [ pathToText path'+  , " Expected type \""+  , expected+  , "\" found "+  , T.pack (unpack $ encode found)+  , "."+  ]+expectedTypeAFoundB path' expected found (Just errorMessage) = T.concat+  [ pathToText path'+  , " Expected type \""+  , expected+  , "\" found "+  , T.pack (unpack $ encode found)+  , "; "+  , errorMessage+  , "."+  ]  undefinedField :: [Prop] -> Text -> Text undefinedField path' field' =
src/Data/Morpheus/Error/Internal.hs view
@@ -5,33 +5,42 @@   , internalArgumentError   , internalUnknownTypeMessage   , internalError-  ) where+  )+where -import           Data.Text                               (Text)-import qualified Data.Text                               as T (concat, pack)+import           Data.Text                      ( Text )+import qualified Data.Text                     as T+                                                ( concat+                                                , pack+                                                )+import           Data.Semigroup                 ( (<>) )  -- MORPHEUS-import           Data.Morpheus.Error.Utils               (globalErrorMessage)-import           Data.Morpheus.Types.Internal.Validation (GQLErrors)-import           Data.Morpheus.Types.Internal.Value      (Value (..))+import           Data.Morpheus.Error.Utils      ( globalErrorMessage )+import           Data.Morpheus.Types.Internal.Resolving.Core+                                                ( Validation+                                                , GQLErrors+                                                , Failure(..)+                                                )+import           Data.Morpheus.Types.Internal.AST.Value+                                                ( Value(..) )   -- GQL:: if no mutation defined -> "Schema is not configured for mutations." -- all kind internal error in development-internalError :: Text -> Either GQLErrors b-internalError x = Left $ globalErrorMessage $ T.concat ["INTERNAL ERROR: ", x]+internalError :: Text -> Validation b+internalError x = failure $ globalErrorMessage $ "INTERNAL ERROR: " <> x  -- if type did not not found, but was defined by Schema internalUnknownTypeMessage :: Text -> GQLErrors-internalUnknownTypeMessage x =-  globalErrorMessage $-  T.concat ["type did not not found, but was defined by Schema", x]+internalUnknownTypeMessage x = globalErrorMessage+  $ T.concat ["type did not not found, but was defined by Schema", x]  -- if arguments is already validated but has not found required argument-internalArgumentError :: Text -> Either GQLErrors b-internalArgumentError x = internalError $ T.concat ["Argument ", x]+internalArgumentError :: Text -> Validation b+internalArgumentError x = internalError $ "Argument " <> x  -- if value is already validated but value has different type-internalTypeMismatch :: Text -> Value -> Either GQLErrors b+internalTypeMismatch :: Text -> Value -> Validation b internalTypeMismatch text jsType =-  internalError $ T.concat ["Type mismatch ", text, T.pack $ show jsType]+  internalError $ "Type mismatch " <> text <> T.pack (show jsType)
src/Data/Morpheus/Error/Mutation.hs view
@@ -2,11 +2,14 @@  module Data.Morpheus.Error.Mutation   ( mutationIsNotDefined-  ) where+  )+where -import           Data.Morpheus.Error.Utils               (errorMessage)-import           Data.Morpheus.Types.Internal.Base       (Position)-import           Data.Morpheus.Types.Internal.Validation (GQLErrors)+import           Data.Morpheus.Error.Utils      ( errorMessage )+import           Data.Morpheus.Types.Internal.AST.Base+                                                ( Position )+import           Data.Morpheus.Types.Internal.Resolving.Core+                                                ( GQLErrors )  mutationIsNotDefined :: Position -> GQLErrors mutationIsNotDefined position' =
src/Data/Morpheus/Error/Schema.hs view
@@ -3,12 +3,14 @@ module Data.Morpheus.Error.Schema   ( nameCollisionError   , schemaValidationError-  ) where+  )+where -import           Data.Morpheus.Error.Utils               (globalErrorMessage)-import           Data.Morpheus.Types.Internal.Validation (GQLErrors)-import           Data.Semigroup                          ((<>))-import           Data.Text                               (Text)+import           Data.Morpheus.Error.Utils      ( globalErrorMessage )+import           Data.Morpheus.Types.Internal.Resolving.Core+                                                ( GQLErrors )+import           Data.Semigroup                 ( (<>) )+import           Data.Text                      ( Text )  schemaValidationError :: Text -> GQLErrors schemaValidationError error' =@@ -16,6 +18,7 @@  nameCollisionError :: Text -> GQLErrors nameCollisionError name =-  schemaValidationError $-  "Name collision: \"" <> name <>-  "\" is used for different dataTypes in two separate modules"+  schemaValidationError+    $  "Name collision: \""+    <> name+    <> "\" is used for different dataTypes in two separate modules"
src/Data/Morpheus/Error/Selection.hs view
@@ -5,43 +5,66 @@   , subfieldsNotSelected   , duplicateQuerySelections   , hasNoSubfields-  , fieldNotResolved-  , resolverError-  ) where+  , resolvingFailedError+  )+where -import           Data.Morpheus.Error.Utils               (errorMessage)-import           Data.Morpheus.Types.Internal.Base       (EnhancedKey (..), Position)-import           Data.Morpheus.Types.Internal.Validation (GQLError (..), GQLErrors)-import           Data.Text                               (Text, pack)-import qualified Data.Text                               as T (concat)+import           Data.Semigroup                 ( (<>) )+import           Data.Morpheus.Error.Utils      ( errorMessage )+import           Data.Morpheus.Types.Internal.AST.Base+                                                ( Ref(..)+                                                , Position+                                                )+import           Data.Morpheus.Types.Internal.Resolving.Core+                                                ( GQLError(..)+                                                , GQLErrors+                                                )+import           Data.Text                      ( Text )+import qualified Data.Text                     as T+                                                ( concat ) -resolverError :: Position -> Text -> String -> GQLErrors-resolverError pos name message = fieldNotResolved pos name (pack message) -fieldNotResolved :: Position -> Text -> Text -> GQLErrors-fieldNotResolved position' key' message' = errorMessage position' text-  where-    text = T.concat ["Failure on Resolving Field \"", key', "\": ", message']+resolvingFailedError :: Position -> Text -> Text -> GQLError+resolvingFailedError position name reason = GQLError+  { message   = "Failure on Resolving Field \"" <> name <> "\": " <> reason+  , locations = [position]+  } + -- GQL: "Field \"default\" must not have a selection since type \"String!\" has no subfields." hasNoSubfields :: Text -> Text -> Position -> GQLErrors hasNoSubfields key typeName position = errorMessage position text-  where-    text = T.concat ["Field \"", key, "\" must not have a selection since type \"", typeName, "\" has no subfields."]+ where+  text = T.concat+    [ "Field \""+    , key+    , "\" must not have a selection since type \""+    , typeName+    , "\" has no subfields."+    ]  cannotQueryField :: Text -> Text -> Position -> GQLErrors cannotQueryField key typeName position = errorMessage position text-  where-    text = T.concat ["Cannot query field \"", key, "\" on type \"", typeName, "\"."]+ where+  text =+    T.concat ["Cannot query field \"", key, "\" on type \"", typeName, "\"."] -duplicateQuerySelections :: Text -> [EnhancedKey] -> GQLErrors+duplicateQuerySelections :: Text -> [Ref] -> GQLErrors duplicateQuerySelections parentType = map keyToError-  where-    keyToError (EnhancedKey key' pos) = GQLError {desc = toMessage key', positions = [pos]}-    toMessage key' = T.concat ["duplicate selection of key \"", key', "\" on type \"", parentType, "\"."]+ where+  keyToError (Ref key' pos) =+    GQLError { message = toMessage key', locations = [pos] }+  toMessage key' = T.concat+    ["duplicate selection of key \"", key', "\" on type \"", parentType, "\"."]  -- GQL:: Field \"hobby\" of type \"Hobby!\" must have a selection of subfields. Did you mean \"hobby { ... }\"? subfieldsNotSelected :: Text -> Text -> Position -> GQLErrors subfieldsNotSelected key typeName position = errorMessage position text-  where-    text = T.concat ["Field \"", key, "\" of type \"", typeName, "\" must have a selection of subfields"]+ where+  text = T.concat+    [ "Field \""+    , key+    , "\" of type \""+    , typeName+    , "\" must have a selection of subfields"+    ]
src/Data/Morpheus/Error/Subscription.hs view
@@ -2,11 +2,14 @@  module Data.Morpheus.Error.Subscription   ( subscriptionIsNotDefined-  ) where+  )+where -import           Data.Morpheus.Error.Utils               (errorMessage)-import           Data.Morpheus.Types.Internal.Base       (Position)-import           Data.Morpheus.Types.Internal.Validation (GQLErrors)+import           Data.Morpheus.Error.Utils      ( errorMessage )+import           Data.Morpheus.Types.Internal.AST.Base+                                                ( Position )+import           Data.Morpheus.Types.Internal.Resolving.Core+                                                ( GQLErrors )  subscriptionIsNotDefined :: Position -> GQLErrors subscriptionIsNotDefined position' =
src/Data/Morpheus/Error/Utils.hs view
@@ -3,31 +3,39 @@ module Data.Morpheus.Error.Utils   ( errorMessage   , globalErrorMessage-  , renderErrors   , badRequestError   , toLocation-  ) where+  )+where -import           Data.ByteString.Lazy.Char8              (ByteString, pack)-import           Data.Morpheus.Types.Internal.Base       (Position)-import           Data.Morpheus.Types.Internal.Validation (GQLError (..), GQLErrors, JSONError (..), Location (..))-import           Data.Text                               (Text)-import           Text.Megaparsec                         (SourcePos (SourcePos), sourceColumn, sourceLine, unPos)+import           Data.ByteString.Lazy.Char8     ( ByteString+                                                , pack+                                                )+import           Data.Morpheus.Types.Internal.AST.Base+                                                ( Position )+import           Data.Morpheus.Types.Internal.Resolving.Core+                                                ( GQLError(..)+                                                , GQLErrors+                                                , GQLError(..)+                                                , Position(..)+                                                )+import           Data.Text                      ( Text )+import           Text.Megaparsec                ( SourcePos(SourcePos)+                                                , sourceColumn+                                                , sourceLine+                                                , unPos+                                                )  errorMessage :: Position -> Text -> GQLErrors-errorMessage position text = [GQLError {desc = text, positions = [position]}]+errorMessage position message = [GQLError { message, locations = [position] }]  globalErrorMessage :: Text -> GQLErrors-globalErrorMessage text = [GQLError {desc = text, positions = []}]--renderErrors :: [GQLError] -> [JSONError]-renderErrors = map renderError--renderError :: GQLError -> JSONError-renderError GQLError {desc, positions} = JSONError {message = desc, locations = positions}+globalErrorMessage message = [GQLError { message, locations = [] }] -toLocation :: SourcePos -> Location-toLocation SourcePos {sourceLine, sourceColumn} = Location {line = unPos sourceLine, column = unPos sourceColumn}+toLocation :: SourcePos -> Position+toLocation SourcePos { sourceLine, sourceColumn } =+  Position { line = unPos sourceLine, column = unPos sourceColumn }  badRequestError :: String -> ByteString-badRequestError aesonError' = pack $ "Bad Request. Could not decode Request body: " ++ aesonError'+badRequestError aesonError' =+  pack $ "Bad Request. Could not decode Request body: " ++ aesonError'
src/Data/Morpheus/Error/Variable.hs view
@@ -7,75 +7,78 @@   , uninitializedVariable   , unusedVariables   , incompatibleVariableType-  ) where+  )+where -import           Data.Morpheus.Error.Utils               (errorMessage)-import           Data.Morpheus.Types.Internal.Base       (EnhancedKey (..), Position)-import           Data.Morpheus.Types.Internal.Validation (GQLError (..), GQLErrors)-import           Data.Semigroup                          ((<>))-import           Data.Text                               (Text)-import qualified Data.Text                               as T (concat)+import           Data.Morpheus.Error.Utils      ( errorMessage )+import           Data.Morpheus.Types.Internal.AST.Base+                                                ( Ref(..)+                                                , Position+                                                )+import           Data.Morpheus.Types.Internal.Resolving.Core+                                                ( GQLError(..)+                                                , GQLErrors+                                                )+import           Data.Semigroup                 ( (<>) )+import           Data.Text                      ( Text )+import qualified Data.Text                     as T+                                                ( concat )  -- query M ( $v : String ) { a(p:$v) } -> "Variable \"$v\" of type \"String\" used in position expecting type \"LANGUAGE\"." incompatibleVariableType :: Text -> Text -> Text -> Position -> GQLErrors incompatibleVariableType variableName variableType argType argPosition =   errorMessage argPosition text-  where-    text =-      "Variable \"$" <> variableName <> "\" of type \"" <> variableType <>-      "\" used in position expecting type \"" <>-      argType <>-      "\"."+ where+  text =+    "Variable \"$"+      <> variableName+      <> "\" of type \""+      <> variableType+      <> "\" used in position expecting type \""+      <> argType+      <> "\"."  -- query M ( $v : String ) { a } -> "Variable \"$bla\" is never used in operation \"MyMutation\".",-unusedVariables :: Text -> [EnhancedKey] -> GQLErrors+unusedVariables :: Text -> [Ref] -> GQLErrors unusedVariables operator' = map keyToError-  where-    keyToError (EnhancedKey key' position') =-      GQLError {desc = text key', positions = [position']}-    text key' =-      T.concat-        [ "Variable \"$"-        , key'-        , "\" is never used in operation \""-        , operator'-        , "\"."-        ]+ where+  keyToError (Ref key' position') =+    GQLError { message = text key', locations = [position'] }+  text key' = T.concat+    ["Variable \"$", key', "\" is never used in operation \"", operator', "\"."]  -- type mismatch -- { "v": 1  }        "Variable \"$v\" got invalid value 1; Expected type LANGUAGE." variableGotInvalidValue :: Text -> Text -> Position -> GQLErrors-variableGotInvalidValue name' inputMessage' position' =-  errorMessage position' text-  where-    text =-      T.concat ["Variable \"$", name', "\" got invalid value; ", inputMessage']+variableGotInvalidValue name' inputMessage' position' = errorMessage+  position'+  text+ where+  text =+    T.concat ["Variable \"$", name', "\" got invalid value; ", inputMessage']  unknownType :: Text -> Position -> GQLErrors unknownType type' position' = errorMessage position' text-  where-    text = T.concat ["Unknown type \"", type', "\"."]+  where text = T.concat ["Unknown type \"", type', "\"."]  undefinedVariable :: Text -> Position -> Text -> GQLErrors undefinedVariable operation' position' key' = errorMessage position' text-  where-    text =-      T.concat-        [ "Variable \""-        , key'-        , "\" is not defined by operation \""-        , operation'-        , "\"."-        ]+ where+  text = T.concat+    [ "Variable \""+    , key'+    , "\" is not defined by operation \""+    , operation'+    , "\"."+    ]  uninitializedVariable :: Position -> Text -> Text -> GQLErrors uninitializedVariable position' type' key' = errorMessage position' text-  where-    text =-      T.concat-        [ "Variable \"$"-        , key'-        , "\" of required type \""-        , type'-        , "!\" was not provided."-        ]+ where+  text = T.concat+    [ "Variable \"$"+    , key'+    , "\" of required type \""+    , type'+    , "!\" was not provided."+    ]
src/Data/Morpheus/Execution/Client/Aeson.hs view
@@ -12,129 +12,147 @@   ( deriveFromJSON   , deriveToJSON   , takeValueType-  ) where+  )+where  import           Data.Aeson import           Data.Aeson.Types-import qualified Data.HashMap.Lazy                      as H (lookup)-import           Data.Semigroup                         ((<>))-import           Data.Text                              (unpack)+import qualified Data.HashMap.Lazy             as H+                                                ( lookup )+import           Data.Semigroup                 ( (<>) )+import           Data.Text                      ( unpack ) import           Language.Haskell.TH -import           Data.Morpheus.Execution.Internal.Utils (nameSpaceTypeString)+import           Data.Morpheus.Execution.Internal.Utils+                                                ( nameSpaceTypeString )  -- -- MORPHEUS-import           Data.Morpheus.Types.Internal.Data      (DataField (..), isFieldNullable)-import           Data.Morpheus.Types.Internal.DataD     (ConsD (..), TypeD (..))-import           Data.Morpheus.Types.Internal.TH        (destructRecord, instanceFunD, instanceHeadT)+import           Data.Morpheus.Types.Internal.AST+                                                ( DataField(..)+                                                , isFieldNullable+                                                , ConsD(..)+                                                , TypeD(..)+                                                )+import           Data.Morpheus.Types.Internal.TH+                                                ( destructRecord+                                                , instanceFunD+                                                , instanceHeadT+                                                )  -- FromJSON deriveFromJSON :: TypeD -> Q Dec-deriveFromJSON TypeD {tCons = []} = fail "Type Should Have at least one Constructor"-deriveFromJSON TypeD {tName, tNamespace, tCons = [cons]} = defineFromJSON name (aesonObject tNamespace) cons-  where-    name = nameSpaceTypeString tNamespace tName-deriveFromJSON typeD@TypeD {tName, tCons, tNamespace}+deriveFromJSON TypeD { tCons = [] } =+  fail "Type Should Have at least one Constructor"+deriveFromJSON TypeD { tName, tNamespace, tCons = [cons] } = defineFromJSON+  name+  (aesonObject tNamespace)+  cons+  where name = nameSpaceTypeString tNamespace tName+deriveFromJSON typeD@TypeD { tName, tCons, tNamespace }   | isEnum tCons = defineFromJSON name aesonEnum tCons-  | otherwise = defineFromJSON name (aesonUnionObject tNamespace) typeD-  where-    name = nameSpaceTypeString tNamespace tName+  | otherwise    = defineFromJSON name (aesonUnionObject tNamespace) typeD+  where name = nameSpaceTypeString tNamespace tName  aesonObject :: [String] -> ConsD -> ExpQ-aesonObject tNamespace con@ConsD {cName} =-  appE [|withObject name|] (lamE [varP (mkName "o")] ((aesonObjectBody tNamespace) con))-  where-    name = nameSpaceTypeString tNamespace cName+aesonObject tNamespace con@ConsD { cName } = appE+  [|withObject name|]+  (lamE [varP (mkName "o")] (aesonObjectBody tNamespace con))+  where name = nameSpaceTypeString tNamespace cName  aesonObjectBody :: [String] -> ConsD -> ExpQ-aesonObjectBody namespace ConsD {cName, cFields} = handleFields cFields-  where-    consName = mkName $ nameSpaceTypeString namespace cName-    -------------------------------------------    handleFields [] = fail $ "No Empty Object"-    handleFields fields = startExp fields-    -----------------------------------------------------------------------------------      -- Optional Field-      where-        defField field@DataField {fieldName}-          | isFieldNullable field = [|o .:? fName|]-          | otherwise = [|o .: fName|]-          where-            fName = unpack fieldName-            --------------------------------------------------------------------        startExp fNames = uInfixE (conE consName) (varE '(<$>)) (applyFields fNames)-          where-            applyFields []     = fail "No Empty fields"-            applyFields [x]    = defField x-            applyFields (x:xs) = uInfixE (defField x) (varE '(<*>)) (applyFields xs)+aesonObjectBody namespace ConsD { cName, cFields } = handleFields cFields+ where+  consName = mkName $ nameSpaceTypeString namespace cName+  ------------------------------------------+  handleFields []     = fail "No Empty Object"+  handleFields fields = startExp fields+  ----------------------------------------------------------------------------------+   where+    defField field@DataField { fieldName }+      | isFieldNullable field = [|o .:? fName|]+      | otherwise             = [|o .: fName|]+      where fName = unpack fieldName+        -------------------------------------------------------------------+    startExp fNames = uInfixE (conE consName)+                              (varE '(<$>))+                              (applyFields fNames)+     where+      applyFields []  = fail "No Empty fields"+      applyFields [x] = defField x+      applyFields (x : xs) =+        uInfixE (defField x) (varE '(<*>)) (applyFields xs)  aesonUnionObject :: [String] -> TypeD -> ExpQ-aesonUnionObject namespace TypeD {tCons} =-  appE (varE $ 'takeValueType) (lamCaseE ((map buildMatch tCons) <> [elseCaseEXP]))-  where-    buildMatch cons@ConsD {cName} = match pattern body []-      where-        pattern = tupP [litP (stringL cName), varP $ mkName "o"]-        body = normalB $ aesonObjectBody namespace cons+aesonUnionObject namespace TypeD { tCons } = appE+  (varE 'takeValueType)+  (lamCaseE (map buildMatch tCons <> [elseCaseEXP]))+ where+  buildMatch cons@ConsD { cName } = match objectPattern body []+   where+    objectPattern = tupP [litP (stringL cName), varP $ mkName "o"]+    body          = normalB $ aesonObjectBody namespace cons  takeValueType :: ((String, Object) -> Parser a) -> Value -> Parser a-takeValueType f (Object hMap) =-  case H.lookup "__typename" hMap of-    Nothing         -> fail "key \"__typename\" not found on object"-    Just (String x) -> pure (unpack x, hMap) >>= f-    Just val        -> fail $ "key \"__typename\" should be string but found: " <> show val-takeValueType _ _ = fail $ "expected Object"+takeValueType f (Object hMap) = case H.lookup "__typename" hMap of+  Nothing         -> fail "key \"__typename\" not found on object"+  Just (String x) -> pure (unpack x, hMap) >>= f+  Just val ->+    fail $ "key \"__typename\" should be string but found: " <> show val+takeValueType _ _ = fail "expected Object"  defineFromJSON :: String -> (t -> ExpQ) -> t -> DecQ defineFromJSON tName parseJ cFields = instanceD (cxt []) iHead [method]-  where-    iHead = instanceHeadT ''FromJSON tName []-    ------------------------------------------    method = instanceFunD 'parseJSON [] (parseJ cFields)+ where+  iHead  = instanceHeadT ''FromJSON tName []+  -----------------------------------------+  method = instanceFunD 'parseJSON [] (parseJ cFields)  isEnum :: [ConsD] -> Bool isEnum = not . isEmpty . filter (isEmpty . cFields)-  where-    isEmpty = (0 ==) . length+  where isEmpty = (0 ==) . length  aesonEnum :: [ConsD] -> ExpQ aesonEnum cons = lamCaseE handlers-  where-    handlers = (map buildMatch cons) <> [elseCaseEXP]-      where-        buildMatch ConsD {cName} = match pattern body []-          where-            pattern = litP $ stringL cName-            body = normalB $ appE (varE 'pure) (conE $ mkName cName)+ where+  handlers = map buildMatch cons <> [elseCaseEXP]+   where+    buildMatch ConsD { cName } = match enumPat body []+     where+      enumPat = litP $ stringL cName+      body    = normalB $ appE (varE 'pure) (conE $ mkName cName)  elseCaseEXP :: MatchQ elseCaseEXP = match (varP varName) body []-  where-    varName = mkName "invalidValue"-    body =-      normalB $-      appE-        (varE $ mkName "fail")-        (uInfixE (appE (varE 'show) (varE varName)) (varE '(<>)) (stringE $ " is Not Valid Union Constructor"))+ where+  varName = mkName "invalidValue"+  body    = normalB $ appE+    (varE $ mkName "fail")+    (uInfixE (appE (varE 'show) (varE varName))+             (varE '(<>))+             (stringE " is Not Valid Union Constructor")+    )  -- ToJSON deriveToJSON :: TypeD -> Q [Dec]-deriveToJSON TypeD {tCons = []} = fail "Type Should Have at least one Constructor"-deriveToJSON TypeD {tName, tCons = [ConsD {cFields}]} = pure <$> instanceD (cxt []) appHead methods-  where-    appHead = instanceHeadT ''ToJSON tName []-    -------------------------------------------------------------------    -- defines: toJSON (User field1 field2 ...)= object ["name" .= name, "age" .= age, ...]-    methods = [funD 'toJSON [clause argsE (normalB body) []]]-      where-        argsE = [destructRecord tName varNames]-        body = appE (varE 'object) (listE $ map decodeVar varNames)-        decodeVar name = [|name .= $(varName)|]-          where-            varName = varE $ mkName name-        varNames = map (unpack . fieldName) cFields-deriveToJSON TypeD {tName, tCons}-  | isEnum tCons = pure <$> instanceD (cxt []) (instanceHeadT ''ToJSON tName []) []+deriveToJSON TypeD { tCons = [] } =+  fail "Type Should Have at least one Constructor"+deriveToJSON TypeD { tName, tCons = [ConsD { cFields }] } =+  pure <$> instanceD (cxt []) appHead methods+ where+  appHead = instanceHeadT ''ToJSON tName []+  ------------------------------------------------------------------+  -- defines: toJSON (User field1 field2 ...)= object ["name" .= name, "age" .= age, ...]+  methods = [funD 'toJSON [clause argsE (normalB body) []]]+   where+    argsE = [destructRecord tName varNames]+    body  = appE (varE 'object) (listE $ map decodeVar varNames)+    decodeVar name = [|name .= $(varName)|] where varName = varE $ mkName name+    varNames = map (unpack . fieldName) cFields+deriveToJSON TypeD { tName, tCons }+  | isEnum tCons+  = pure <$> instanceD (cxt []) (instanceHeadT ''ToJSON tName []) []+  |     -- enum: uses default aeson instance derivation methods-  | otherwise = fail "Input Unions are not yet supported"+    otherwise+  = fail "Input Unions are not yet supported"
src/Data/Morpheus/Execution/Client/Build.hs view
@@ -6,42 +6,70 @@  module Data.Morpheus.Execution.Client.Build   ( defineQuery-  ) where+  )+where -import           Data.Semigroup                           ((<>))+import           Data.Semigroup                 ( (<>) ) import           Language.Haskell.TH  -- -- MORPHEUS-import           Data.Morpheus.Error.Client.Client        (renderGQLErrors)-import           Data.Morpheus.Execution.Client.Aeson     (deriveFromJSON, deriveToJSON)-import           Data.Morpheus.Execution.Client.Compile   (validateWith)-import           Data.Morpheus.Execution.Client.Fetch     (deriveFetch)-import           Data.Morpheus.Execution.Internal.Declare (declareType)-import           Data.Morpheus.Types.Internal.Data        (DataTypeKind (..), DataTypeLib, isOutputObject)-import           Data.Morpheus.Types.Internal.DataD       (GQLTypeD (..), QueryD (..), TypeD (..))-import           Data.Morpheus.Types.Internal.Validation  (Validation)-import           Data.Morpheus.Types.Types                (GQLQueryRoot (..))+import           Data.Morpheus.Error.Client.Client+                                                ( renderGQLErrors+                                                , gqlWarnings+                                                )+import           Data.Morpheus.Execution.Client.Aeson+                                                ( deriveFromJSON+                                                , deriveToJSON+                                                )+import           Data.Morpheus.Execution.Client.Compile+                                                ( validateWith )+import           Data.Morpheus.Execution.Client.Fetch+                                                ( deriveFetch )+import           Data.Morpheus.Execution.Internal.Declare+                                                ( declareType ) -defineQuery :: IO (Validation DataTypeLib) -> (GQLQueryRoot, String) -> Q [Dec]+import           Data.Morpheus.Types.Internal.AST+                                                ( GQLQuery(..)+                                                , DataTypeKind(..)+                                                , DataTypeLib+                                                , isOutputObject+                                                , ClientType(..)+                                                , ClientQuery(..)+                                                , TypeD(..)+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Validation+                                                , Result(..)+                                                )++++defineQuery :: IO (Validation DataTypeLib) -> (GQLQuery, String) -> Q [Dec] defineQuery ioSchema queryRoot = do   schema <- runIO ioSchema   case schema >>= (`validateWith` queryRoot) of-    Left errors  -> fail (renderGQLErrors errors)-    Right queryD -> defineQueryD queryD+    Failure errors               -> fail (renderGQLErrors errors)+    Success { result, warnings } -> gqlWarnings warnings >> defineQueryD result -defineQueryD :: QueryD -> Q [Dec]-defineQueryD QueryD {queryTypes = rootType:subTypes, queryText, queryArgsType} = do-  rootDecs <- defineOperationType (queryArgumentType queryArgsType) queryText rootType-  subTypeDecs <- concat <$> traverse declareT subTypes-  return $ rootDecs ++ subTypeDecs-  where-    declareT GQLTypeD {typeD, typeKindD}-      | isOutputObject typeKindD || typeKindD == KindUnion = withToJSON declareOutputType typeD-      | typeKindD == KindEnum = withToJSON declareInputType typeD-      | otherwise = declareInputType typeD-defineQueryD QueryD {queryTypes = []} = return [] +defineQueryD :: ClientQuery -> Q [Dec]+defineQueryD ClientQuery { queryTypes = rootType : subTypes, queryText, queryArgsType }+  = do+    rootDecs <- defineOperationType (queryArgumentType queryArgsType)+                                    queryText+                                    rootType+    subTypeDecs <- concat <$> traverse declareT subTypes+    return $ rootDecs ++ subTypeDecs+ where+  declareT ClientType { clientType, clientKind }+    | isOutputObject clientKind || clientKind == KindUnion = withToJSON+      declareOutputType+      clientType+    | clientKind == KindEnum = withToJSON declareInputType clientType+    | otherwise = declareInputType clientType+defineQueryD ClientQuery { queryTypes = [] } = return []+ declareOutputType :: TypeD -> Q [Dec] declareOutputType typeD = pure [declareType False Nothing [''Show] typeD] @@ -53,16 +81,18 @@ withToJSON :: (TypeD -> Q [Dec]) -> TypeD -> Q [Dec] withToJSON f datatype = do   toJson <- deriveFromJSON datatype-  dec <- f datatype+  dec    <- f datatype   pure (toJson : dec)  queryArgumentType :: Maybe TypeD -> (Type, Q [Dec])-queryArgumentType Nothing                       = (ConT $ mkName "()", pure [])-queryArgumentType (Just rootType@TypeD {tName}) = (ConT $ mkName tName, declareInputType rootType)+queryArgumentType Nothing = (ConT $ mkName "()", pure [])+queryArgumentType (Just rootType@TypeD { tName }) =+  (ConT $ mkName tName, declareInputType rootType) -defineOperationType :: (Type, Q [Dec]) -> String -> GQLTypeD -> Q [Dec]-defineOperationType (argType, argumentTypes) query GQLTypeD {typeD} = do-  rootType <- withToJSON declareOutputType typeD-  typeClassFetch <- deriveFetch argType (tName typeD) query-  argsT <- argumentTypes-  pure $ rootType <> typeClassFetch <> argsT+defineOperationType :: (Type, Q [Dec]) -> String -> ClientType -> Q [Dec]+defineOperationType (argType, argumentTypes) query ClientType { clientType } =+  do+    rootType       <- withToJSON declareOutputType clientType+    typeClassFetch <- deriveFetch argType (tName clientType) query+    argsT          <- argumentTypes+    pure $ rootType <> typeClassFetch <> argsT
src/Data/Morpheus/Execution/Client/Compile.hs view
@@ -5,37 +5,60 @@ module Data.Morpheus.Execution.Client.Compile   ( compileSyntax   , validateWith-  ) where+  )+where -import qualified Data.Text                                  as T (pack)+import qualified Data.Text                     as T+                                                ( pack ) import           Language.Haskell.TH -import           Data.Morpheus.Error.Client.Client          (renderGQLErrors)--import           Data.Morpheus.Execution.Client.Selection   (operationTypes)-import           Data.Morpheus.Parsing.Request.Parser       (parseGQL)-import qualified Data.Morpheus.Types.Internal.AST.Operation as O (Operation (..))-import           Data.Morpheus.Types.Internal.Data          (DataTypeLib)-import           Data.Morpheus.Types.IO                     (GQLRequest (..))- -- --  Morpheus-import           Data.Morpheus.Types.Internal.DataD         (QueryD (..))-import           Data.Morpheus.Types.Internal.Validation    (Validation)-import           Data.Morpheus.Types.Types                  (GQLQueryRoot (..))-import           Data.Morpheus.Validation.Internal.Utils    (VALIDATION_MODE (..))-import           Data.Morpheus.Validation.Query.Validation  (validateRequest) ++import           Data.Morpheus.Error.Client.Client+                                                ( renderGQLErrors+                                                , gqlWarnings+                                                )++import           Data.Morpheus.Execution.Client.Selection+                                                ( operationTypes )+import           Data.Morpheus.Parsing.Request.Parser+                                                ( parseGQL )+import qualified Data.Morpheus.Types.Internal.AST+                                               as O+                                                ( Operation(..) )+import           Data.Morpheus.Types.IO         ( GQLRequest(..) )++import           Data.Morpheus.Types.Internal.AST+                                                ( GQLQuery(..)+                                                , DataTypeLib+                                                , ClientQuery(..)+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Validation+                                                , Result(..)+                                                )+import           Data.Morpheus.Validation.Internal.Utils+                                                ( VALIDATION_MODE(..) )+import           Data.Morpheus.Validation.Query.Validation+                                                ( validateRequest )+ compileSyntax :: String -> Q Exp-compileSyntax queryText =-  case parseGQL request of-    Left errors -> fail (renderGQLErrors errors)-    Right root  -> [|(root, queryText)|]-  where-    request = GQLRequest {query = T.pack queryText, operationName = Nothing, variables = Nothing}+compileSyntax queryText = case parseGQL request of+  Failure errors -> fail (renderGQLErrors errors)+  Success { result, warnings } ->+    gqlWarnings warnings >> [|(result, queryText)|]+ where+  request = GQLRequest { query         = T.pack queryText+                       , operationName = Nothing+                       , variables     = Nothing+                       } -validateWith :: DataTypeLib -> (GQLQueryRoot, String) -> Validation QueryD-validateWith schema (rawRequest@GQLQueryRoot {operation}, queryText) = do+validateWith :: DataTypeLib -> (GQLQuery, String) -> Validation ClientQuery+validateWith schema (rawRequest@GQLQuery { operation }, queryText) = do   validOperation <- validateRequest schema WITHOUT_VARIABLES rawRequest-  (queryArgsType, queryTypes) <- operationTypes schema (O.operationArgs operation) validOperation-  return QueryD {queryText, queryTypes, queryArgsType}+  (queryArgsType, queryTypes) <- operationTypes schema+                                                (O.operationArgs operation)+                                                validOperation+  return ClientQuery { queryText, queryTypes, queryArgsType }
src/Data/Morpheus/Execution/Client/Fetch.hs view
@@ -8,27 +8,36 @@ module Data.Morpheus.Execution.Client.Fetch   ( Fetch(..)   , deriveFetch-  ) where+  )+where -import           Control.Monad                   ((>=>))-import           Data.Aeson                      (FromJSON, ToJSON (..), eitherDecode, encode)-import           Data.ByteString.Lazy            (ByteString)-import           Data.Text                       (pack)+import           Control.Monad                  ( (>=>) )+import           Data.Aeson                     ( FromJSON+                                                , ToJSON(..)+                                                , eitherDecode+                                                , encode+                                                )+import           Data.ByteString.Lazy           ( ByteString )+import           Data.Text                      ( pack ) import           Language.Haskell.TH  -import qualified Data.Aeson                      as A-import qualified Data.Aeson.Types                as A+import qualified Data.Aeson                    as A+import qualified Data.Aeson.Types              as A  -- -- MORPHEUS-import           Data.Morpheus.Types.Internal.TH (instanceHeadT, typeInstanceDec)-import           Data.Morpheus.Types.IO          (GQLRequest (..), JSONResponse (..))+import           Data.Morpheus.Types.Internal.TH+                                                ( instanceHeadT+                                                , typeInstanceDec+                                                )+import           Data.Morpheus.Types.IO         ( GQLRequest(..)+                                                , JSONResponse(..)+                                                )  fixVars :: A.Value -> Maybe A.Value-fixVars x-  | x == A.emptyArray = Nothing-  | otherwise         = Just x+fixVars x | x == A.emptyArray = Nothing+          | otherwise         = Just x  class Fetch a where   type Args a :: *@@ -48,10 +57,11 @@   fetch :: (Monad m, FromJSON a) => (ByteString -> m ByteString) -> Args a -> m (Either String a)  deriveFetch :: Type -> String -> String -> Q [Dec]-deriveFetch resultType typeName query = pure <$> instanceD (cxt []) iHead methods-  where-    iHead = instanceHeadT ''Fetch typeName []-    methods =-      [ funD 'fetch [clause [] (normalB [|__fetch query typeName|]) []]-      , pure $ typeInstanceDec  ''Args  (ConT $ mkName typeName) resultType-      ]+deriveFetch resultType typeName queryString =+  pure <$> instanceD (cxt []) iHead methods+ where+  iHead = instanceHeadT ''Fetch typeName []+  methods =+    [ funD 'fetch [clause [] (normalB [|__fetch queryString typeName|]) []]+    , pure $ typeInstanceDec ''Args (ConT $ mkName typeName) resultType+    ]
src/Data/Morpheus/Execution/Client/Selection.hs view
@@ -6,201 +6,302 @@  module Data.Morpheus.Execution.Client.Selection   ( operationTypes-  ) where+  )+where -import           Data.Maybe                                    (fromMaybe)-import           Data.Semigroup                                ((<>))-import           Data.Text                                     (Text, pack, unpack)+import           Data.Maybe                     ( fromMaybe )+import           Data.Semigroup                 ( (<>) )+import           Data.Text                      ( Text+                                                , pack+                                                , unpack+                                                ) -- -- MORPHEUS-import           Data.Morpheus.Error.Utils                     (globalErrorMessage)-import           Data.Morpheus.Execution.Internal.GraphScanner (LibUpdater, resolveUpdates)-import           Data.Morpheus.Execution.Internal.Utils        (nameSpaceType)-import           Data.Morpheus.Types.Internal.AST.Operation    (DefaultValue, Operation (..), ValidOperation,-                                                                Variable (..), VariableDefinitions, getOperationName)-import           Data.Morpheus.Types.Internal.AST.Selection    (Selection (..), SelectionRec (..), SelectionSet,-                                                                ValidSelection)-import           Data.Morpheus.Types.Internal.Data             (DataField (..), DataType (..), DataTyCon (..),-                                                                DataTypeKind (..), DataTypeLib (..), Key,-                                                                TypeAlias (..), allDataTypes)-import           Data.Morpheus.Types.Internal.DataD            (ConsD (..), GQLTypeD (..), TypeD (..))-import           Data.Morpheus.Types.Internal.Validation       (GQLErrors, Validation)-import           Data.Morpheus.Validation.Internal.Utils       (lookupType)-import           Data.Set                                      (fromList, toList)+import           Data.Morpheus.Error.Client.Client+                                                ( deprecatedField )+import           Data.Morpheus.Error.Utils      ( globalErrorMessage )+import           Data.Morpheus.Execution.Internal.Utils+                                                ( nameSpaceType )+import           Data.Morpheus.Types.Internal.AST+                                                ( DefaultValue+                                                , Operation(..)+                                                , ValidOperation+                                                , Variable(..)+                                                , VariableDefinitions+                                                , getOperationName+                                                , getOperationDataType+                                                , Selection(..)+                                                , SelectionRec(..)+                                                , SelectionSet+                                                , ValidSelection+                                                , Ref(..) +                                                , DataField(..)+                                                , DataTyCon(..)+                                                , DataType(..)+                                                , DataTypeKind(..)+                                                , DataTypeLib(..)+                                                , Key+                                                , TypeAlias(..)+                                                , DataEnumValue(..)+                                                , allDataTypes+                                                , lookupType+                                                , ConsD(..)+                                                , ClientType(..)+                                                , TypeD(..)+                                                , lookupDeprecated+                                                , lookupDeprecatedReason+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( GQLErrors+                                                , Validation+                                                , Failure(..)+                                                , Result(..)+                                                , Position+                                                , LibUpdater+                                                , resolveUpdates+                                                )+import           Data.Set                       ( fromList+                                                , toList+                                                )  removeDuplicates :: [Text] -> [Text] removeDuplicates = toList . fromList  compileError :: Text -> GQLErrors-compileError x = globalErrorMessage $ "Unhandled Compile Time Error: \"" <> x <> "\" ;"+compileError x =+  globalErrorMessage $ "Unhandled Compile Time Error: \"" <> x <> "\" ;" -operationTypes :: DataTypeLib -> VariableDefinitions -> ValidOperation -> Validation (Maybe TypeD, [GQLTypeD])+operationTypes+  :: DataTypeLib+  -> VariableDefinitions+  -> ValidOperation+  -> Validation (Maybe TypeD, [ClientType]) operationTypes lib variables = genOperation-  where-    genOperation Operation {operationName, operationSelection} = do-      (queryTypes, enums) <- genRecordType [] (getOperationName operationName) queryDataType operationSelection-      inputTypeRequests <- resolveUpdates [] $ map (scanInputTypes lib . variableType . snd) variables-      inputTypesAndEnums <- buildListedTypes (inputTypeRequests <> enums)-      pure (rootArguments (getOperationName operationName <> "Args"), queryTypes <> inputTypesAndEnums)-      where-        queryDataType = DataObject $ snd $ query lib-    --------------------------------------------------------------------------    buildListedTypes = fmap concat . traverse (buildInputType lib) . removeDuplicates-    --------------------------------------------------------------------------    -- generates argument types for Operation Head-    rootArguments :: Text -> Maybe TypeD-    rootArguments argsName-      | null variables = Nothing-      | otherwise = Just rootArgumentsType+ where+  genOperation operation@Operation { operationName, operationSelection } = do+    datatype            <- DataObject <$> getOperationDataType operation lib+    (queryTypes, enums) <- genRecordType []+                                         (getOperationName operationName)+                                         datatype+                                         operationSelection+    inputTypeRequests <- resolveUpdates []+      $ map (scanInputTypes lib . variableType . snd) variables+    inputTypesAndEnums <- buildListedTypes (inputTypeRequests <> enums)+    pure+      ( rootArguments (getOperationName operationName <> "Args")+      , queryTypes <> inputTypesAndEnums+      )+  -------------------------------------------------------------------------+  buildListedTypes =+    fmap concat . traverse (buildInputType lib) . removeDuplicates+  -------------------------------------------------------------------------+  -- generates argument types for Operation Head+  rootArguments :: Text -> Maybe TypeD+  rootArguments argsName | null variables = Nothing+                         | otherwise      = Just rootArgumentsType++   where+    rootArgumentsType :: TypeD+    rootArgumentsType = TypeD+      { tName      = unpack argsName+      , tNamespace = []+      , tCons      = [ ConsD { cName   = unpack argsName+                             , cFields = map fieldD variables+                             }+                     ]+      , tMeta      = Nothing+      }+     where+      fieldD :: (Text, Variable DefaultValue) -> DataField+      fieldD (key, Variable { variableType, variableTypeWrappers }) = DataField+        { fieldName     = key+        , fieldArgs     = []+        , fieldArgsType = Nothing+        , fieldType     = TypeAlias { aliasWrappers = variableTypeWrappers+                                    , aliasTyCon    = variableType+                                    , aliasArgs     = Nothing+                                    }+        , fieldMeta     = Nothing+        }+  ---------------------------------------------------------+  -- generates selection Object Types+  genRecordType+    :: [Key]+    -> Key+    -> DataType+    -> SelectionSet+    -> Validation ([ClientType], [Text])+  genRecordType path name dataType recordSelSet = do+    (con, subTypes, requests) <- genConsD (unpack name) dataType recordSelSet+    pure+      ( ClientType+          { clientType = TypeD { tName+                               , tNamespace = map unpack path+                               , tCons      = [con]+                               , tMeta      = Nothing+                               }+          , clientKind = KindObject Nothing+          }+        : subTypes+      , requests+      )+   where+    tName = unpack name+    genConsD+      :: String+      -> DataType+      -> SelectionSet+      -> Validation (ConsD, [ClientType], [Text])+    genConsD cName datatype selSet = do+      (cFields, subTypes, requests) <- unzip3 <$> traverse genField selSet+      pure (ConsD { cName, cFields }, concat subTypes, concat requests)+     where+      genField+        :: (Text, ValidSelection)+        -> Validation (DataField, [ClientType], [Text])+      genField (fName, sel@Selection { selectionAlias, selectionPosition }) =+        do+          (fieldDataType, fieldType) <- lookupFieldType lib+                                                        fieldPath+                                                        datatype+                                                        selectionPosition+                                                        fName+          (subTypes, requests) <- subTypesBySelection fieldDataType sel+          pure+            ( DataField { fieldName+                        , fieldArgs     = []+                        , fieldArgsType = Nothing+                        , fieldType+                        , fieldMeta     = Nothing+                        }+            , subTypes+            , requests+            )+       where+        fieldPath = path <> [fieldName]+        -------------------------------+        fieldName = fromMaybe fName selectionAlias         -------------------------------------------      where-        rootArgumentsType :: TypeD-        rootArgumentsType =-          TypeD-            { tName = unpack argsName-            , tNamespace = []-            , tCons = [ConsD {cName = unpack argsName, cFields = map fieldD variables}]-            }-          where-            fieldD :: (Text, Variable DefaultValue) -> DataField-            fieldD (key, Variable {variableType, variableTypeWrappers}) =-              DataField-                { fieldName = key-                , fieldArgs = []-                , fieldArgsType = Nothing-                , fieldType =-                    TypeAlias {aliasWrappers = variableTypeWrappers, aliasTyCon = variableType, aliasArgs = Nothing}-                , fieldHidden = False-                }-    ----------------------------------------------------------    -- generates selection Object Types-    genRecordType :: [Key] -> Key -> DataType -> SelectionSet -> Validation ([GQLTypeD], [Text])-    genRecordType path name dataType recordSelSet = do-      (con, subTypes, requests) <- genConsD (unpack name) dataType recordSelSet-      pure-        ( GQLTypeD-            { typeD = TypeD {tName, tNamespace = map unpack path, tCons = [con]}-            , typeKindD = KindObject Nothing-            , typeArgD = []-            } :-          subTypes-        , requests)-      where-        tName = unpack name-        genConsD :: String -> DataType -> SelectionSet -> Validation (ConsD, [GQLTypeD], [Text])-        genConsD cName datatype selSet = do-          cFields <- traverse genField selSet-          (subTypes, requests) <- newFieldTypes datatype selSet-          pure (ConsD {cName, cFields}, concat subTypes, concat requests)-          ----------------------------------------------------------------------------------------------          where-            genField :: (Text, ValidSelection) -> Validation DataField-            genField (fieldName, sel@Selection { selectionAlias }) = genFieldD sel-              where-                fieldPath = path <> [fromMaybe fieldName selectionAlias]-                --------------------------------                genFieldD Selection {selectionAlias = Just aliasFieldName} = do-                  fieldType <- snd <$> lookupFieldType lib fieldPath datatype fieldName-                  pure $ DataField {fieldName = aliasFieldName, fieldArgs = [], fieldArgsType = Nothing, fieldType, fieldHidden = False}-                genFieldD _ = do-                  fieldType <- snd <$> lookupFieldType lib fieldPath datatype fieldName-                  pure $ DataField {fieldName, fieldArgs = [], fieldArgsType = Nothing, fieldType, fieldHidden = False}-            -------------------------------------------------------------------------------------------------------------            newFieldTypes :: DataType -> SelectionSet -> Validation ([[GQLTypeD]], [[Text]])-            newFieldTypes parentType seSet = unzip <$> mapM valSelection seSet-              where-                valSelection (key, selection@Selection { selectionAlias }) = do-                  fieldDatatype <- fst <$> lookupFieldType lib fieldPath parentType key-                  validateSelection fieldDatatype selection-                  ---------------------------------------------------------------------                  where-                    fieldPath = path <> [fromMaybe key selectionAlias]-                    ---------------------------------------------------------------------                    validateSelection :: DataType -> ValidSelection -> Validation ([GQLTypeD], [Text])-                    validateSelection dType Selection {selectionRec = SelectionField} = leafType dType-                    --withLeaf buildLeaf dType-                    validateSelection dType Selection {selectionRec = SelectionSet selectionSet} =-                      genRecordType fieldPath (typeFrom [] dType) dType selectionSet-                    ---- UNION-                    validateSelection dType Selection {selectionRec = UnionSelection unionSelections} = do-                      (tCons, subTypes, requests) <- unzip3 <$> mapM getUnionType unionSelections-                      pure-                        ( GQLTypeD-                            { typeD =-                                TypeD {tNamespace = map unpack fieldPath, tName = unpack $ typeFrom [] dType, tCons}-                            , typeKindD = KindUnion-                            , typeArgD = []-                            } :-                          concat subTypes-                        , concat requests)-                      where-                        getUnionType (selectedTyName, selectionVariant) = do-                          conDatatype <- getType lib selectedTyName-                          genConsD (unpack selectedTyName) conDatatype selectionVariant+        subTypesBySelection+          :: DataType -> ValidSelection -> Validation ([ClientType], [Text])+        subTypesBySelection dType Selection { selectionRec = SelectionField } =+          leafType dType+          --withLeaf buildLeaf dType+        subTypesBySelection dType Selection { selectionRec = SelectionSet selectionSet }+          = genRecordType fieldPath (typeFrom [] dType) dType selectionSet+          ---- UNION+        subTypesBySelection dType Selection { selectionRec = UnionSelection unionSelections }+          = do+            (tCons, subTypes, requests) <-+              unzip3 <$> mapM getUnionType unionSelections+            pure+              ( ClientType+                  { clientType = TypeD { tNamespace = map unpack fieldPath+                                       , tName      = unpack $ typeFrom [] dType+                                       , tCons+                                       , tMeta      = Nothing+                                       }+                  , clientKind = KindUnion+                  }+                : concat subTypes+              , concat requests+              )+         where+          getUnionType (selectedTyName, selectionVariant) = do+            conDatatype <- getType lib selectedTyName+            genConsD (unpack selectedTyName) conDatatype selectionVariant  scanInputTypes :: DataTypeLib -> Key -> LibUpdater [Key]-scanInputTypes lib name collected-  | name `elem` collected = pure collected-  | otherwise = getType lib name >>= scanType-  where-    scanType (DataInputObject DataTyCon {typeData}) = resolveUpdates (name : collected) (map toInputTypeD typeData)-      where-        toInputTypeD :: (Text, DataField) -> LibUpdater [Key]-        toInputTypeD (_, DataField {fieldType = TypeAlias {aliasTyCon}}) = scanInputTypes lib aliasTyCon-    scanType (DataEnum DataTyCon {typeName}) = pure (collected <> [typeName])-    scanType _ = pure collected+scanInputTypes lib name collected | name `elem` collected = pure collected+                                  | otherwise = getType lib name >>= scanType+ where+  scanType (DataInputObject DataTyCon { typeData }) = resolveUpdates+    (name : collected)+    (map toInputTypeD typeData)+   where+    toInputTypeD :: (Text, DataField) -> LibUpdater [Key]+    toInputTypeD (_, DataField { fieldType = TypeAlias { aliasTyCon } }) =+      scanInputTypes lib aliasTyCon+  scanType (DataEnum DataTyCon { typeName }) = pure (collected <> [typeName])+  scanType _ = pure collected -buildInputType :: DataTypeLib -> Text -> Validation [GQLTypeD]+buildInputType :: DataTypeLib -> Text -> Validation [ClientType] buildInputType lib name = getType lib name >>= subTypes-  where-    subTypes (DataInputObject DataTyCon {typeName, typeData}) = do-      fields <- traverse toFieldD typeData-      pure-        [ GQLTypeD-            { typeD =-                TypeD-                  { tName = unpack typeName-                  , tNamespace = []-                  , tCons = [ConsD {cName = unpack typeName, cFields = fields}]-                  }-            , typeArgD = []-            , typeKindD = KindInputObject-            }-        ]-          -----------------------------------------------------------------      where-        toFieldD :: (Text, DataField) -> Validation DataField-        toFieldD (_, field@DataField {fieldType}) = do-          aliasTyCon <- typeFrom [] <$> getType lib (aliasTyCon fieldType)-          pure $ field {fieldType = fieldType {aliasTyCon}}-    subTypes (DataEnum DataTyCon {typeName, typeData}) =-      pure-        [ GQLTypeD-            { typeD = TypeD {tName = unpack typeName, tNamespace = [], tCons = map enumOption typeData}-            , typeArgD = []-            , typeKindD = KindEnum-            }-        ]-      where-        enumOption eName = ConsD {cName = unpack eName, cFields = []}-    subTypes _ = pure []+ where+  subTypes (DataInputObject DataTyCon { typeName, typeData }) = do+    fields <- traverse toFieldD typeData+    pure+      [ ClientType+          { clientType =+            TypeD+              { tName      = unpack typeName+              , tNamespace = []+              , tCons = [ConsD { cName = unpack typeName, cFields = fields }]+              , tMeta      = Nothing+              }+          , clientKind = KindInputObject+          }+      ] -lookupFieldType :: DataTypeLib -> [Key] -> DataType -> Text -> Validation (DataType, TypeAlias)-lookupFieldType lib path (DataObject DataTyCon {typeData}) key =-  case lookup key typeData of-    Just DataField {fieldType = alias@TypeAlias {aliasTyCon}} -> trans <$> getType lib aliasTyCon-      where trans x = (x, alias {aliasTyCon = typeFrom path x, aliasArgs = Nothing})-    Nothing -> Left (compileError $ "cant find field \""<> key<>"\"")-lookupFieldType _ _ dt _ = Left (compileError $ "Type should be output Object \"" <> pack (show dt))+   where+    toFieldD :: (Text, DataField) -> Validation DataField+    toFieldD (_, field@DataField { fieldType }) = do+      aliasTyCon <- typeFrom [] <$> getType lib (aliasTyCon fieldType)+      pure $ field { fieldType = fieldType { aliasTyCon } }+  subTypes (DataEnum DataTyCon { typeName, typeData }) = pure+    [ ClientType+        { clientType = TypeD { tName      = unpack typeName+                             , tNamespace = []+                             , tCons      = map enumOption typeData+                             , tMeta      = Nothing+                             }+        , clientKind = KindEnum+        }+    ]+   where+    enumOption DataEnumValue { enumName } =+      ConsD { cName = unpack enumName, cFields = [] }+  subTypes _ = pure []  -leafType :: DataType -> Validation ([GQLTypeD], [Text])-leafType (DataEnum DataTyCon {typeName}) = pure ([],[typeName])-leafType DataScalar {}                   = pure ([],[])-leafType _                               = Left $ compileError "Invalid schema Expected scalar"+lookupFieldType+  :: DataTypeLib+  -> [Key]+  -> DataType+  -> Position+  -> Text+  -> Validation (DataType, TypeAlias)+lookupFieldType lib path (DataObject DataTyCon { typeData, typeName }) refPosition key+  = case lookup key typeData of+    Just DataField { fieldType = alias@TypeAlias { aliasTyCon }, fieldMeta } ->+      checkDeprecated >> (trans <$> getType lib aliasTyCon)+     where+      trans x =+        (x, alias { aliasTyCon = typeFrom path x, aliasArgs = Nothing })+      ------------------------------------------------------------------+      checkDeprecated :: Validation ()+      checkDeprecated = case fieldMeta >>= lookupDeprecated of+        Just deprecation -> Success { result = (), warnings, events = [] }+         where+          warnings = deprecatedField typeName+                                     Ref { refName = key, refPosition }+                                     (lookupDeprecatedReason deprecation)+        Nothing -> pure ()+    ------------------+    Nothing -> failure+      (compileError $ "cant find field \"" <> pack (show typeData) <> "\"")+lookupFieldType _ _ dt _ _ =+  failure (compileError $ "Type should be output Object \"" <> pack (show dt)) ++leafType :: DataType -> Validation ([ClientType], [Text])+leafType (DataEnum DataTyCon { typeName }) = pure ([], [typeName])+leafType DataScalar{} = pure ([], [])+leafType _ = failure $ compileError "Invalid schema Expected scalar"+ getType :: DataTypeLib -> Text -> Validation DataType-getType lib typename = lookupType (compileError typename) (allDataTypes lib) typename+getType lib typename =+  lookupType (compileError typename) (allDataTypes lib) typename  typeFromScalar :: Text -> Text typeFromScalar "Boolean" = "Bool"@@ -211,9 +312,9 @@ typeFromScalar _         = "ScalarValue"  typeFrom :: [Key] -> DataType -> Text-typeFrom _ (DataScalar DataTyCon {typeName}) = typeFromScalar typeName-typeFrom _ (DataEnum x)                      = typeName x-typeFrom _ (DataInputObject x)               = typeName x-typeFrom path (DataObject x)                 = pack $ nameSpaceType path $ typeName x-typeFrom path (DataUnion x)                  = pack $ nameSpaceType path $ typeName x-typeFrom _ (DataInputUnion x)                = typeName x+typeFrom _ (DataScalar DataTyCon { typeName }) = typeFromScalar typeName+typeFrom _ (DataEnum x) = typeName x+typeFrom _ (DataInputObject x) = typeName x+typeFrom path (DataObject x) = pack $ nameSpaceType path $ typeName x+typeFrom path (DataUnion x) = pack $ nameSpaceType path $ typeName x+typeFrom _ (DataInputUnion x) = typeName x
src/Data/Morpheus/Execution/Document/Compile.hs view
@@ -1,47 +1,61 @@-{-# LANGUAGE NamedFieldPuns #-}+{-#LANGUAGE NamedFieldPuns #-}  module Data.Morpheus.Execution.Document.Compile   ( compileDocument   , gqlDocument   , gqlDocumentNamespace-  ) where+  )+where -import qualified Data.Text                                    as T (pack)+import qualified Data.Text                     as T+                                                ( pack ) import           Language.Haskell.TH import           Language.Haskell.TH.Quote  -- --  Morpheus-import           Data.Morpheus.Error.Client.Client            (renderGQLErrors)-import           Data.Morpheus.Execution.Document.Convert     (renderTHTypes)-import           Data.Morpheus.Execution.Document.Declare     (declareTypes)-import           Data.Morpheus.Parsing.Document.Parser        (parseTypes)+import           Data.Morpheus.Error.Client.Client+                                                ( renderGQLErrors+                                                , gqlWarnings+                                                )+import           Data.Morpheus.Execution.Document.Convert+                                                ( renderTHTypes )+import           Data.Morpheus.Execution.Document.Declare+                                                ( declareTypes )+import           Data.Morpheus.Parsing.Document.Parser+                                                ( parseTypes ) import           Data.Morpheus.Validation.Document.Validation+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Result(..) ) + gqlDocumentNamespace :: QuasiQuoter-gqlDocumentNamespace =-  QuasiQuoter-    { quoteExp = notHandled "Expressions"-    , quotePat = notHandled "Patterns"-    , quoteType = notHandled "Types"-    , quoteDec = compileDocument True-    }-  where-    notHandled things = error $ things ++ " are not supported by the GraphQL QuasiQuoter"+gqlDocumentNamespace = QuasiQuoter { quoteExp  = notHandled "Expressions"+                                   , quotePat  = notHandled "Patterns"+                                   , quoteType = notHandled "Types"+                                   , quoteDec  = compileDocument True+                                   }+ where+  notHandled things =+    error $ things ++ " are not supported by the GraphQL QuasiQuoter"  gqlDocument :: QuasiQuoter-gqlDocument =-  QuasiQuoter-    { quoteExp = notHandled "Expressions"-    , quotePat = notHandled "Patterns"-    , quoteType = notHandled "Types"-    , quoteDec = compileDocument False-    }-  where-    notHandled things = error $ things ++ " are not supported by the GraphQL QuasiQuoter"+gqlDocument = QuasiQuoter { quoteExp  = notHandled "Expressions"+                          , quotePat  = notHandled "Patterns"+                          , quoteType = notHandled "Types"+                          , quoteDec  = compileDocument False+                          }+ where+  notHandled things =+    error $ things ++ " are not supported by the GraphQL QuasiQuoter"  compileDocument :: Bool -> String -> Q [Dec] compileDocument namespace documentTXT =-  case parseTypes (T.pack documentTXT) >>= validatePartialDocument >>= renderTHTypes namespace of-    Left errors  -> fail (renderGQLErrors errors)-    Right schema -> declareTypes namespace schema+  case+      parseTypes (T.pack documentTXT)+      >>= validatePartialDocument+      >>= renderTHTypes namespace+    of+      Failure errors -> fail (renderGQLErrors errors)+      Success { result = schema, warnings } ->+        gqlWarnings warnings >> declareTypes namespace schema
src/Data/Morpheus/Execution/Document/Convert.hs view
@@ -6,140 +6,180 @@  module Data.Morpheus.Execution.Document.Convert   ( renderTHTypes-  ) where+  )+where -import           Data.Semigroup                          ((<>))-import           Data.Text                               (Text, pack, unpack)+import           Data.Semigroup                 ( (<>) )+import           Data.Text                      ( Text+                                                , pack+                                                , unpack+                                                )  -- -- MORPHEUS-import           Data.Morpheus.Error.Internal            (internalError)-import           Data.Morpheus.Execution.Internal.Utils  (capital)-import           Data.Morpheus.Types.Internal.Data       (ArgsType (..), DataField (..), DataType (..),-                                                          DataTyCon (..), DataTypeKind (..), OperationType (..),-                                                          ResolverKind (..), TypeAlias (..), sysTypes)-import           Data.Morpheus.Types.Internal.DataD      (ConsD (..), GQLTypeD (..), TypeD (..))-import           Data.Morpheus.Types.Internal.Validation (Validation)+import           Data.Morpheus.Error.Internal   ( internalError )+import           Data.Morpheus.Execution.Internal.Utils+                                                ( capital )+import           Data.Morpheus.Types.Internal.AST+                                                ( ArgsType(..)+                                                , DataField(..)+                                                , DataTyCon(..)+                                                , DataType(..)+                                                , DataTypeKind(..)+                                                , OperationType(..)+                                                , ResolverKind(..)+                                                , TypeAlias(..)+                                                , DataEnumValue(..)+                                                , sysTypes+                                                , ConsD(..)+                                                , GQLTypeD(..)+                                                , TypeD(..)+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Validation )  renderTHTypes :: Bool -> [(Text, DataType)] -> Validation [GQLTypeD] renderTHTypes namespace lib = traverse renderTHType lib-  where-    renderTHType :: (Text, DataType) -> Validation GQLTypeD-    renderTHType (tyConName, x) = genType x-      where-        genArgsTypeName fieldName-          | namespace = sysName tyConName <> argTName-          | otherwise = argTName-          where-            argTName = capital fieldName <> "Args"-        genArgumentType :: (Text, DataField) -> Validation [TypeD]-        genArgumentType (_, DataField {fieldArgs = []}) = pure []-        genArgumentType (fieldName, DataField {fieldArgs}) =-          pure-            [ TypeD-                { tName-                , tNamespace = []-                , tCons = [ConsD {cName = sysName $ pack tName, cFields = map genField fieldArgs}]-                }-            ]-          where-            tName = genArgsTypeName $ sysName fieldName-        --------------------------------------------        genFieldTypeName = genTypeName-        -------------------------------        --genTypeName :: Text -> Text-        genTypeName "String" = "Text"-        genTypeName "Boolean" = "Bool"-        genTypeName name-          | name `elem` sysTypes = "S" <> name-        genTypeName name = name-        -----------------------------------------        sysName = unpack . genTypeName-        ----------------------------------------------------------------------------------------------        genField :: (Text, DataField) -> DataField-        genField (_, field@DataField {fieldType = alias@TypeAlias {aliasTyCon}}) =-          field {fieldType = alias {aliasTyCon = genFieldTypeName aliasTyCon}}-        ----------------------------------------------------------------------------------------------        genResField :: (Text, DataField) -> DataField-        genResField (_, field@DataField {fieldName, fieldArgs, fieldType = alias@TypeAlias {aliasTyCon}}) =-          field {fieldType = alias {aliasTyCon = ftName, aliasArgs}, fieldArgsType}-          where-            ftName = genFieldTypeName aliasTyCon-            ----------------------------------------            aliasArgs =-              case lookup aliasTyCon lib of-                Just DataObject {} -> Just "m"-                Just DataUnion {}  -> Just "m"-                _                  -> Nothing-            ------------------------------------            fieldArgsType = Just $ ArgsType {argsTypeName, resKind = getFieldType ftName}-              where-                argsTypeName-                  | null fieldArgs = "()"-                  | otherwise = pack $ genArgsTypeName $ unpack fieldName-                ---------------------------------------                getFieldType key =-                  case lookup key lib of-                    Nothing            -> ExternalResolver-                    Just DataObject {} -> TypeVarResolver-                    Just DataUnion {}  -> TypeVarResolver-                    Just _             -> PlainResolver-        ---------------------------------------------        genType (DataEnum DataTyCon {typeName, typeData}) =-          pure-            GQLTypeD-              { typeD = TypeD {tName = sysName typeName, tNamespace = [], tCons = map enumOption typeData}-              , typeKindD = KindEnum-              , typeArgD = []-              }-          where-            enumOption name = ConsD {cName = sysName name, cFields = []}-        genType (DataScalar _) = internalError "Scalar Types should defined By Native Haskell Types"-        genType (DataInputUnion _) = internalError "Input Unions not Supported"-        genType (DataInputObject DataTyCon {typeName, typeData}) =-          pure-            GQLTypeD-              { typeD =-                  TypeD-                    { tName = sysName typeName-                    , tNamespace = []-                    , tCons = [ConsD {cName = sysName typeName, cFields = map genField typeData}]-                    }-              , typeKindD = KindInputObject-              , typeArgD = []+ where+  renderTHType :: (Text, DataType) -> Validation GQLTypeD+  renderTHType (tyConName, x) = genType x+   where+    genArgsTypeName fieldName | namespace = sysName tyConName <> argTName+                              | otherwise = argTName+      where argTName = capital fieldName <> "Args"+    genArgumentType :: (Text, DataField) -> Validation [TypeD]+    genArgumentType (_        , DataField { fieldArgs = [] }) = pure []+    genArgumentType (fieldName, DataField { fieldArgs }     ) = pure+      [ TypeD+          { tName+          , tNamespace = []+          , tCons      = [ ConsD { cName   = sysName $ pack tName+                                 , cFields = map genField fieldArgs+                                 }+                         ]+          , tMeta      = Nothing+          }+      ]+      where tName = genArgsTypeName $ sysName fieldName+    -------------------------------------------+    genFieldTypeName = genTypeName+    ------------------------------+    --genTypeName :: Text -> Text+    genTypeName "String"                    = "Text"+    genTypeName "Boolean"                   = "Bool"+    genTypeName name | name `elem` sysTypes = "S" <> name+    genTypeName name                        = name+    ----------------------------------------+    sysName = unpack . genTypeName+    ---------------------------------------------------------------------------------------------+    genField :: (Text, DataField) -> DataField+    genField (_, field@DataField { fieldType = alias@TypeAlias { aliasTyCon } })+      = field { fieldType = alias { aliasTyCon = genFieldTypeName aliasTyCon }               }-        genType (DataObject DataTyCon {typeName, typeData}) = do-          typeArgD <- concat <$> traverse genArgumentType typeData-          pure-            GQLTypeD-              { typeD =-                  TypeD-                    { tName = sysName typeName-                    , tNamespace = []-                    , tCons = [ConsD {cName = sysName typeName, cFields = map genResField typeData}]-                    }-              , typeKindD =-                  if typeName == "Subscription"-                    then KindObject (Just Subscription)-                    else KindObject Nothing-              , typeArgD+    ---------------------------------------------------------------------------------------------+    genResField :: (Text, DataField) -> DataField+    genResField (_, field@DataField { fieldName, fieldArgs, fieldType = alias@TypeAlias { aliasTyCon } })+      = field { fieldType     = alias { aliasTyCon = ftName, aliasArgs }+              , fieldArgsType               }-        genType (DataUnion DataTyCon {typeName, typeData}) = do-          let tCons = map unionCon typeData-          pure-            GQLTypeD-              {typeD = TypeD {tName = unpack typeName, tNamespace = [], tCons}, typeKindD = KindUnion, typeArgD = []}-          where-            unionCon field@DataField {fieldType} =-              ConsD-                { cName-                , cFields =-                    [ field-                        { fieldName = pack $ "un" <> cName-                        , fieldType = TypeAlias {aliasTyCon = pack utName, aliasArgs = Just "m", aliasWrappers = []}+     where+      ftName    = genFieldTypeName aliasTyCon+      ---------------------------------------+      aliasArgs = case lookup aliasTyCon lib of+        Just DataObject{} -> Just "m"+        Just DataUnion{}  -> Just "m"+        _                 -> Nothing+      -----------------------------------+      fieldArgsType = Just+        $ ArgsType { argsTypeName, resKind = getFieldType ftName }+       where+        argsTypeName | null fieldArgs = "()"+                     | otherwise = pack $ genArgsTypeName $ unpack fieldName+        --------------------------------------+        getFieldType key = case lookup key lib of+          Nothing           -> ExternalResolver+          Just DataObject{} -> TypeVarResolver+          Just DataUnion{}  -> TypeVarResolver+          Just _            -> PlainResolver+    --------------------------------------------+    genType dt@(DataEnum DataTyCon { typeName, typeData, typeMeta }) = pure+      GQLTypeD+        { typeD        = TypeD { tName      = sysName typeName+                               , tNamespace = []+                               , tCons      = map enumOption typeData+                               , tMeta      = typeMeta+                               }+        , typeKindD    = KindEnum+        , typeArgD     = []+        , typeOriginal = (typeName, dt)+        }+     where+      enumOption DataEnumValue { enumName } =+        ConsD { cName = sysName enumName, cFields = [] }+    genType (DataScalar _) =+      internalError "Scalar Types should defined By Native Haskell Types"+    genType (DataInputUnion _) = internalError "Input Unions not Supported"+    genType dt@(DataInputObject DataTyCon { typeName, typeData, typeMeta }) =+      pure GQLTypeD+        { typeD        =+          TypeD+            { tName      = sysName typeName+            , tNamespace = []+            , tCons      = [ ConsD { cName   = sysName typeName+                                   , cFields = map genField typeData+                                   }+                           ]+            , tMeta      = typeMeta+            }+        , typeKindD    = KindInputObject+        , typeArgD     = []+        , typeOriginal = (typeName, dt)+        }+    genType dt@(DataObject DataTyCon { typeName, typeData, typeMeta }) = do+      typeArgD <- concat <$> traverse genArgumentType typeData+      pure GQLTypeD+        { typeD        = TypeD+                           { tName      = sysName typeName+                           , tNamespace = []+                           , tCons = [ ConsD { cName = sysName typeName+                                             , cFields = map genResField typeData+                                             }+                                     ]+                           , tMeta      = typeMeta+                           }+        , typeKindD    = if typeName == "Subscription"+                           then KindObject (Just Subscription)+                           else KindObject Nothing+        , typeArgD+        , typeOriginal = (typeName, dt)+        }+    genType dt@(DataUnion DataTyCon { typeName, typeData, typeMeta }) = do+      let tCons = map unionCon typeData+      pure GQLTypeD+        { typeD        = TypeD { tName      = unpack typeName+                               , tNamespace = []+                               , tCons+                               , tMeta      = typeMeta+                               }+        , typeKindD    = KindUnion+        , typeArgD     = []+        , typeOriginal = (typeName, dt)+        }+     where+      unionCon memberName = ConsD+        { cName+        , cFields = [ DataField+                        { fieldName     = pack $ "un" <> cName+                        , fieldType     = TypeAlias { aliasTyCon = pack utName+                                                    , aliasArgs = Just "m"+                                                    , aliasWrappers = []+                                                    }+                        , fieldMeta     = Nothing+                        , fieldArgs     = []+                        , fieldArgsType = Nothing                         }                     ]-                }-              where-                cName = sysName typeName <> utName-                utName = sysName $ aliasTyCon fieldType+        }+       where+        cName  = sysName typeName <> utName+        utName = sysName memberName
src/Data/Morpheus/Execution/Document/Declare.hs view
@@ -4,51 +4,67 @@  module Data.Morpheus.Execution.Document.Declare   ( declareTypes-  ) where+  )+where -import           Data.Semigroup                              ((<>))+import           Data.Semigroup                 ( (<>) ) import           Language.Haskell.TH  -- -- MORPHEUS-import           Data.Morpheus.Execution.Document.Decode     (deriveDecode)-import           Data.Morpheus.Execution.Document.Encode     (deriveEncode)-import           Data.Morpheus.Execution.Document.GQLType    (deriveGQLType)-import           Data.Morpheus.Execution.Document.Introspect (deriveObjectRep)-import           Data.Morpheus.Execution.Internal.Declare    (declareType)-import           Data.Morpheus.Types.Internal.Data           (isInput, isObject)-import           Data.Morpheus.Types.Internal.DataD          (GQLTypeD (..))+import           Data.Morpheus.Execution.Document.Decode+                                                ( deriveDecode )+import           Data.Morpheus.Execution.Document.Encode+                                                ( deriveEncode )+import           Data.Morpheus.Execution.Document.GQLType+                                                ( deriveGQLType )+import           Data.Morpheus.Execution.Document.Introspect+                                                ( deriveObjectRep+                                                , instanceIntrospect+                                                )+import           Data.Morpheus.Execution.Internal.Declare+                                                ( declareType )+import           Data.Morpheus.Types.Internal.AST+                                                ( isInput+                                                , isObject+                                                , GQLTypeD(..)+                                                )  declareTypes :: Bool -> [GQLTypeD] -> Q [Dec] declareTypes namespace = fmap concat . traverse (declareGQLType namespace)  declareGQLType :: Bool -> GQLTypeD -> Q [Dec]-declareGQLType namespace gqlType@GQLTypeD {typeD, typeKindD, typeArgD} = do-  mainType <- declareMainType-  argTypes <- declareArgTypes-  gqlInstances <- deriveGQLInstances-  typeClasses <- deriveGQLType gqlType-  pure $ mainType <> typeClasses <> argTypes <> gqlInstances-  where-    deriveGQLInstances = concat <$> sequence gqlInstances-      where-        gqlInstances-          | isObject typeKindD && isInput typeKindD = [deriveObjectRep (typeD, Just typeKindD), deriveDecode typeD]-          | isObject typeKindD = [deriveObjectRep (typeD, Just typeKindD), deriveEncode gqlType]-          | otherwise = []-    ---------------------------------------------------    declareArgTypes = do-      introspectArgs <- concat <$> traverse deriveArgsRep typeArgD-      decodeArgs <- concat <$> traverse deriveDecode typeArgD-      return $ argsTypeDecs <> decodeArgs <> introspectArgs-      where-        deriveArgsRep args = deriveObjectRep (args, Nothing)-        -----------------------------------------------------        argsTypeDecs = map (declareType namespace Nothing []) typeArgD-        ---------------------------------------------------    declareMainType = declareT-      where-        declareT = pure [declareType namespace (Just typeKindD) derivingClasses typeD]-        derivingClasses-          | isInput typeKindD = [''Show]-          | otherwise = []+declareGQLType namespace gqlType@GQLTypeD { typeD, typeKindD, typeArgD, typeOriginal }+  = do+    mainType       <- declareMainType+    argTypes       <- declareArgTypes+    gqlInstances   <- deriveGQLInstances+    typeClasses    <- deriveGQLType gqlType+    introspectEnum <- instanceIntrospect typeOriginal+    pure $ mainType <> typeClasses <> argTypes <> gqlInstances <> introspectEnum+ where+  deriveGQLInstances = concat <$> sequence gqlInstances+   where+    gqlInstances+      | isObject typeKindD && isInput typeKindD+      = [deriveObjectRep (typeD, Just typeKindD), deriveDecode typeD]+      | isObject typeKindD+      = [deriveObjectRep (typeD, Just typeKindD), deriveEncode gqlType]+      | otherwise+      = []+  --------------------------------------------------+  declareArgTypes = do+    introspectArgs <- concat <$> traverse deriveArgsRep typeArgD+    decodeArgs     <- concat <$> traverse deriveDecode typeArgD+    return $ argsTypeDecs <> decodeArgs <> introspectArgs+   where+    deriveArgsRep args = deriveObjectRep (args, Nothing)+    ----------------------------------------------------+    argsTypeDecs = map (declareType namespace Nothing []) typeArgD+      --------------------------------------------------+  declareMainType = declareT+   where+    declareT =+      pure [declareType namespace (Just typeKindD) derivingClasses typeD]+    derivingClasses | isInput typeKindD = [''Show]+                    | otherwise         = []
src/Data/Morpheus/Execution/Document/Decode.hs view
@@ -7,29 +7,42 @@  module Data.Morpheus.Execution.Document.Decode   ( deriveDecode-  ) where+  )+where -import           Data.Text                               (Text)+import           Data.Text                      ( Text ) import           Language.Haskell.TH  -- -- MORPHEUS-import           Data.Morpheus.Execution.Internal.Decode (decodeFieldWith, decodeObjectExpQ)-import           Data.Morpheus.Execution.Server.Decode   (Decode (..), DecodeObject (..))-import           Data.Morpheus.Types.Internal.DataD      (TypeD (..))-import           Data.Morpheus.Types.Internal.TH         (instanceHeadT)-import           Data.Morpheus.Types.Internal.Validation (Validation)-import           Data.Morpheus.Types.Internal.Value      (Object)+import           Data.Morpheus.Execution.Internal.Decode+                                                ( decodeFieldWith+                                                , decodeObjectExpQ+                                                )+import           Data.Morpheus.Execution.Server.Decode+                                                ( Decode(..)+                                                , DecodeObject(..)+                                                )+import           Data.Morpheus.Types.Internal.AST+                                                ( TypeD(..)+                                                , Object+                                                )+import           Data.Morpheus.Types.Internal.TH+                                                ( instanceHeadT )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Validation ) + (.:) :: Decode a => Object -> Text -> Validation a object .: selectorName = decodeFieldWith decode selectorName object  deriveDecode :: TypeD -> Q [Dec]-deriveDecode TypeD {tName, tCons = [cons]} = pure <$> instanceD (cxt []) appHead methods-  where-    appHead = instanceHeadT ''DecodeObject tName []-    methods = [funD 'decodeObject [clause argsE (normalB body) []]]-      where-        argsE = map (varP . mkName) ["o"]-        body = decodeObjectExpQ [|(.:)|] cons+deriveDecode TypeD { tName, tCons = [cons] } =+  pure <$> instanceD (cxt []) appHead methods+ where+  appHead = instanceHeadT ''DecodeObject tName []+  methods = [funD 'decodeObject [clause argsE (normalB body) []]]+   where+    argsE = map (varP . mkName) ["o"]+    body  = decodeObjectExpQ [|(.:)|] cons deriveDecode _ = pure []
src/Data/Morpheus/Execution/Document/Encode.hs view
@@ -5,65 +5,98 @@  module Data.Morpheus.Execution.Document.Encode   ( deriveEncode-  ) where+  )+where -import           Data.Text                             (unpack)-import           Data.Typeable                         (Typeable)+import           Data.Text                      ( unpack )+import           Data.Typeable                  ( Typeable ) import           Language.Haskell.TH-import           Data.Semigroup                        ((<>))+import           Data.Semigroup                 ( (<>) )  -- -- MORPHEUS-import           Data.Morpheus.Execution.Server.Encode (Encode (..), ObjectResolvers (..))-import           Data.Morpheus.Types.GQLType           (TRUE)-import           Data.Morpheus.Types.Internal.Data     (DataField (..), QUERY, SUBSCRIPTION, isSubscription)-import           Data.Morpheus.Types.Internal.DataD    (ConsD (..), GQLTypeD (..), TypeD (..))-import           Data.Morpheus.Types.Internal.Resolver (Resolver, MapGraphQLT (..), Resolving,PureOperation)-import           Data.Morpheus.Types.Internal.TH       (applyT, destructRecord, instanceHeadMultiT, typeT)+import           Data.Morpheus.Execution.Server.Encode+                                                ( Encode(..)+                                                , ObjectResolvers(..)+                                                )+import           Data.Morpheus.Types.GQLType    ( TRUE )+import           Data.Morpheus.Types.Internal.AST+                                                ( DataField(..)+                                                , QUERY+                                                , SUBSCRIPTION+                                                , isSubscription+                                                , ConsD(..)+                                                , GQLTypeD(..)+                                                , TypeD(..)+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Resolver+                                                , MapStrategy(..)+                                                , LiftEither+                                                , ResolvingStrategy+                                                )+import           Data.Morpheus.Types.Internal.TH+                                                ( applyT+                                                , destructRecord+                                                , instanceHeadMultiT+                                                , typeT+                                                ) --- @Subscription:------     instance (Monad m, Typeable m) => ObjectResolvers 'True (<Subscription> (SubResolver m e c)) (SubResolveT m e c Value) where---          objectResolvers _ (<Subscription> x y) = [("newAddress", encode x), ("newUser", encode y)]------ @Object:------   instance (Monad m, Typeable m) => ObjectResolvers 'True (<Object> (Resolver m)) (ResolveT m Value) where---          objectResolvers _ (<Object> x y) = [("field1", encode x), ("field2", encode y)]------- +encodeVars :: [String]+encodeVars = ["e", "m"] +encodeVarsT :: [TypeQ]+encodeVarsT = map (varT . mkName) encodeVars+ deriveEncode :: GQLTypeD -> Q [Dec]-deriveEncode GQLTypeD {typeKindD, typeD = TypeD {tName, tCons = [ConsD {cFields}]}} =-  pure <$> instanceD (cxt constrains) appHead methods-  where -    subARgs = conT ''SUBSCRIPTION : map (varT . mkName) ["m","e"]-    instanceArgs-          | isSubscription typeKindD = subARgs-          | otherwise =  map (varT . mkName) ["o","m","e"]-    mainType = applyT (mkName tName) [mainTypeArg]-      where-        mainTypeArg-          | isSubscription typeKindD = applyT ''Resolver subARgs-          | otherwise = typeT ''Resolver ["fieldOKind","m","e"] -    -----------------------------------------------------------------------------------------+deriveEncode GQLTypeD { typeKindD, typeD = TypeD { tName, tCons = [ConsD { cFields }] } }+  = pure <$> instanceD (cxt constrains) appHead methods+ where+  subARgs = conT ''SUBSCRIPTION : encodeVarsT+  instanceArgs | isSubscription typeKindD = subARgs+               | otherwise = map (varT . mkName) ("o" : encodeVars)+  mainType = applyT (mkName tName) [mainTypeArg]+   where+    mainTypeArg | isSubscription typeKindD = applyT ''Resolver subARgs+                | otherwise                = typeT ''Resolver (fo_ : encodeVars)+  -----------------------------------------------------------------------------------------+  fo_ = "fieldOperationKind"+  po_ = "o"+  ---------------------+  typeables+    | isSubscription typeKindD+    = [applyT ''MapStrategy $ map conT [''QUERY, ''SUBSCRIPTION]]+    | otherwise+    = [ iLiftEither ''ResolvingStrategy+      , iLiftEither ''Resolver+      , typeT ''MapStrategy [fo_, po_]+      , iTypeable fo_+      , iTypeable po_+      ]+  -------------------------+  iLiftEither name = applyT ''LiftEither [varT $ mkName fo_, conT name]+  -------------------------+  iTypeable name = typeT ''Typeable [name]+  -------------------------------------------+  -- defines Constraint: (Typeable m, Monad m)+  constrains =     typeables-         | isSubscription typeKindD =  [applyT ''MapGraphQLT $ map conT [''QUERY, ''SUBSCRIPTION],applyT ''Resolving [conT ''QUERY, varT $ mkName "m", varT $ mkName "e"]]-         | otherwise = [typeT ''PureOperation ["fieldOKind"],typeT ''MapGraphQLT ["fieldOKind","o"] , typeT ''Resolving ["fieldOKind","m","e"] , typeT ''Typeable ["fieldOKind"] , typeT ''Typeable ["o"]]-    -- defines Constraint: (Typeable m, Monad m)-    constrains = typeables <>[typeT ''Monad ["m"], applyT ''Encode (mainType:instanceArgs) , typeT ''Typeable ["m"],typeT ''Typeable ["e"]]-    --------------------------------------------------------------------    -- defines: instance <constraint> =>  ObjectResolvers ('TRUE) (<Type> (ResolveT m)) (ResolveT m value) where-    appHead = instanceHeadMultiT ''ObjectResolvers (conT ''TRUE) (mainType: instanceArgs)-    -------------------------------------------------------------------    -- defines: objectResolvers <Type field1 field2 ...> = [("field1",encode field1),("field2",encode field2), ...]-    methods = [funD 'objectResolvers [clause argsE (normalB body) []]]-      where-        argsE = [varP (mkName "_"), destructRecord tName varNames]-        body = listE $ map decodeVar varNames-        decodeVar name = [|(name, encode $(varName))|]-          where-            varName = varE $ mkName name-        varNames = map (unpack . fieldName) cFields+      <> [ typeT ''Monad ["m"]+         , applyT ''Encode (mainType : instanceArgs)+         , iTypeable "e"+         , iTypeable "m"+         ]+  -------------------------------------------------------------------+  -- defines: instance <constraint> =>  ObjectResolvers ('TRUE) (<Type> (ResolveT m)) (ResolveT m value) where+  appHead =+    instanceHeadMultiT ''ObjectResolvers (conT ''TRUE) (mainType : instanceArgs)+  ------------------------------------------------------------------+  -- defines: objectResolvers <Type field1 field2 ...> = [("field1",encode field1),("field2",encode field2), ...]+  methods = [funD 'objectResolvers [clause argsE (normalB body) []]]+   where+    argsE = [varP (mkName "_"), destructRecord tName varNames]+    body  = listE $ map decodeVar varNames+    decodeVar name = [|(name, encode $(varName))|]+      where varName = varE $ mkName name+    varNames = map (unpack . fieldName) cFields deriveEncode _ = pure []
src/Data/Morpheus/Execution/Document/GQLType.hs view
@@ -6,67 +6,87 @@  module Data.Morpheus.Execution.Document.GQLType   ( deriveGQLType-  ) where+  )+where -import           Data.Text                                (pack)+import           Data.Text                      ( pack+                                                , unpack+                                                ) import           Language.Haskell.TH-+import           Data.Semigroup                 ( (<>) ) -- -- MORPHEUS-import           Data.Morpheus.Execution.Internal.Declare (tyConArgs)-import           Data.Morpheus.Kind                       (ENUM, INPUT_OBJECT, INPUT_UNION, OBJECT, SCALAR, UNION,-                                                           WRAPPER)-import           Data.Morpheus.Types.GQLType              (GQLType (..), TRUE)-import           Data.Morpheus.Types.Internal.Data        (DataTypeKind (..), isObject, isSchemaTypeName)-import           Data.Morpheus.Types.Internal.DataD       (GQLTypeD (..), TypeD (..))-import           Data.Morpheus.Types.Internal.TH          (instanceHeadT, typeT, typeInstanceDec)-import           Data.Typeable                            (Typeable)+import           Data.Morpheus.Execution.Internal.Declare+                                                ( tyConArgs )+import           Data.Morpheus.Kind             ( ENUM+                                                , INPUT_OBJECT+                                                , INPUT_UNION+                                                , OBJECT+                                                , SCALAR+                                                , UNION+                                                , WRAPPER+                                                )+import           Data.Morpheus.Types.GQLType    ( GQLType(..)+                                                , TRUE+                                                )+import           Data.Morpheus.Types.Internal.AST+                                                ( DataTypeKind(..)+                                                , Meta(..)+                                                , isObject+                                                , isSchemaTypeName+                                                , GQLTypeD(..)+                                                , TypeD(..)+                                                )+import           Data.Morpheus.Types.Internal.TH+                                                ( instanceHeadT+                                                , typeT+                                                , typeInstanceDec+                                                , instanceProxyFunD+                                                )+import           Data.Typeable                  ( Typeable )  genTypeName :: String -> String-genTypeName ('S':name)-  | isSchemaTypeName (pack name) = name+genTypeName ('S' : name) | isSchemaTypeName (pack name) = name genTypeName name = name -- deriveGQLType :: GQLTypeD -> Q [Dec]-deriveGQLType GQLTypeD {typeD = TypeD {tName}, typeKindD} =-  pure <$> instanceD (cxt constrains) iHead (def__typeName : typeFamilies)-  where-    def__typeName = funD '__typeName [clause argsE (normalB body) []]-      where-        body = [|pack name|]-          where-            name = genTypeName tName-    -- defines method: __typeName _ = tName-    argsE = map (varP . mkName) ["_"]-    typeArgs = tyConArgs typeKindD-    -----------------------------------------------    iHead = instanceHeadT ''GQLType tName typeArgs-    headSig = typeT (mkName tName) typeArgs-    ------------------------------------------------    constrains = map conTypeable typeArgs-      where-        conTypeable name = typeT ''Typeable [name]-    ------------------------------------------------    typeFamilies-      | isObject typeKindD = [deriveCUSTOM, deriveKind]-      | otherwise = [deriveKind]-    ----------------------------------------------      where-        deriveCUSTOM = do-          typeN <- headSig-          pure $ typeInstanceDec ''CUSTOM typeN (ConT ''TRUE)-        ----------------------------------------------------------------        deriveKind = do-          typeN <- headSig-          pure $ typeInstanceDec ''KIND typeN (ConT $ toKIND typeKindD)-        ----------------------------------        toKIND KindScalar      = ''SCALAR-        toKIND KindEnum        = ''ENUM-        toKIND (KindObject _)  = ''OBJECT-        toKIND KindUnion       = ''UNION-        toKIND KindInputObject = ''INPUT_OBJECT-        toKIND KindList        = ''WRAPPER-        toKIND KindNonNull     = ''WRAPPER-        toKIND KindInputUnion  = ''INPUT_UNION+deriveGQLType GQLTypeD { typeD = TypeD { tName, tMeta }, typeKindD } =+  pure <$> instanceD (cxt constrains) iHead (functions <> typeFamilies)+ where+  functions = map+    instanceProxyFunD+    [ ('__typeName , [|pack (genTypeName tName)|])+    , ('description, descriptionValue)+    ]+   where+    descriptionValue = case tMeta >>= metaDescription of+      Nothing -> [| Nothing  |]+      Just x  -> [| Just (pack desc)|] where desc = unpack x+  -------------------------------------------------+  typeArgs   = tyConArgs typeKindD+  ----------------------------------------------+  iHead      = instanceHeadT ''GQLType tName typeArgs+  headSig    = typeT (mkName tName) typeArgs+  -----------------------------------------------+  constrains = map conTypeable typeArgs+    where conTypeable name = typeT ''Typeable [name]+  -----------------------------------------------+  typeFamilies | isObject typeKindD = [deriveCUSTOM, deriveKind]+               | otherwise          = [deriveKind]+   where+    deriveCUSTOM = do+      typeN <- headSig+      pure $ typeInstanceDec ''CUSTOM typeN (ConT ''TRUE)+    ---------------------------------------------------------------+    deriveKind = do+      typeN <- headSig+      pure $ typeInstanceDec ''KIND typeN (ConT $ toKIND typeKindD)+    ---------------------------------+    toKIND KindScalar      = ''SCALAR+    toKIND KindEnum        = ''ENUM+    toKIND (KindObject _)  = ''OBJECT+    toKIND KindUnion       = ''UNION+    toKIND KindInputObject = ''INPUT_OBJECT+    toKIND KindList        = ''WRAPPER+    toKIND KindNonNull     = ''WRAPPER+    toKIND KindInputUnion  = ''INPUT_UNION
src/Data/Morpheus/Execution/Document/Introspect.hs view
@@ -4,32 +4,43 @@ {-# LANGUAGE TemplateHaskell   #-}  module Data.Morpheus.Execution.Document.Introspect-  ( deriveObjectRep+  ( deriveObjectRep , instanceIntrospect   ) where +import Data.Maybe(maybeToList) import           Data.Proxy                                (Proxy (..)) import           Data.Text                                 (unpack) import           Data.Typeable                             (Typeable)-import           Language.Haskell.TH+import           Language.Haskell.TH    -- MORPHEUS import           Data.Morpheus.Execution.Internal.Declare  (tyConArgs) import           Data.Morpheus.Execution.Server.Introspect (Introspect (..), ObjectFields (..)) import           Data.Morpheus.Types.GQLType               (GQLType (__typeName), TRUE)-import           Data.Morpheus.Types.Internal.Data         (ArgsType (..), DataField (..), DataTypeKind, TypeAlias (..))-import           Data.Morpheus.Types.Internal.DataD        (ConsD (..), TypeD (..))-import           Data.Morpheus.Types.Internal.TH           (instanceFunD, instanceHeadMultiT, typeT)+import           Data.Morpheus.Types.Internal.AST          (ConsD (..), TypeD (..), ArgsType (..),Key, DataType(..), DataField (..),insertType,DataTypeKind(..), TypeAlias (..))+import           Data.Morpheus.Types.Internal.TH           (instanceFunD, instanceProxyFunD,instanceHeadT, instanceHeadMultiT, typeT) ++instanceIntrospect :: (Key,DataType) -> Q [Dec]+-- FIXME: dirty fix for introspection+instanceIntrospect ("__DirectiveLocation",_) = pure []+instanceIntrospect ("__TypeKind",_) = pure []+instanceIntrospect (name, DataEnum enumType) =+  pure <$> instanceD (cxt []) iHead [defineIntrospect]+  where+    -----------------------------------------------+    iHead = instanceHeadT ''Introspect  (unpack name) []+    defineIntrospect = instanceProxyFunD ('introspect,body)+      where+        body =[| insertType (name, DataEnum enumType) |]+instanceIntrospect _ = pure []+ -- [((Text, DataField), TypeUpdater)] deriveObjectRep :: (TypeD, Maybe DataTypeKind) -> Q [Dec] deriveObjectRep (TypeD {tName, tCons = [ConsD {cFields}]}, tKind) =-  pure <$> instanceWithOverlapD overlapping (cxt constrains) iHead methods+  pure <$> instanceD (cxt constrains) iHead methods   where-    overlapping = Just Overlapping-    typeArgs =-      case tKind of-        Just typeKind -> tyConArgs typeKind-        Nothing       -> []+    typeArgs = concatMap tyConArgs (maybeToList tKind)     constrains = map conTypeable typeArgs       where         conTypeable name = typeT ''Typeable [name]@@ -61,14 +72,14 @@ buildFields :: [DataField] -> ExpQ buildFields = listE . map buildField   where-    buildField DataField {fieldName, fieldArgs, fieldType = alias@TypeAlias {aliasArgs, aliasWrappers}} =+    buildField DataField {fieldName, fieldArgs, fieldType = alias@TypeAlias {aliasArgs, aliasWrappers}, fieldMeta} =       [|( fName         , DataField             { fieldName = fName             , fieldArgs = fArgs             , fieldArgsType = Nothing             , fieldType = TypeAlias {aliasTyCon = __typeName $(proxyT alias), aliasArgs = aArgs, aliasWrappers}-            , fieldHidden = False+            , fieldMeta             })|]       where         fName = unpack fieldName
src/Data/Morpheus/Execution/Internal/Declare.hs view
@@ -10,74 +10,92 @@ module Data.Morpheus.Execution.Internal.Declare   ( declareType   , tyConArgs-  ) where+  )+where -import           Data.Maybe                             (maybe)-import           Data.Text                              (pack, unpack)-import           GHC.Generics                           (Generic)+import           Data.Maybe                     ( maybe )+import           Data.Text                      ( pack+                                                , unpack+                                                )+import           GHC.Generics                   ( Generic ) import           Language.Haskell.TH  -- MORPHEUS-import           Data.Morpheus.Execution.Internal.Utils (nameSpaceType, nameSpaceWith)-import           Data.Morpheus.Types.Internal.Data      (ArgsType (..), DataField (..), DataTypeKind (..),-                                                         DataTypeKind (..), TypeAlias (..), WrapperD (..),-                                                         isOutputObject, isSubscription)-import           Data.Morpheus.Types.Internal.DataD     (ConsD (..), TypeD (..))-import           Data.Morpheus.Types.Internal.Resolver  (UnSubResolver)+import           Data.Morpheus.Execution.Internal.Utils+                                                ( nameSpaceType+                                                , nameSpaceWith+                                                )+import           Data.Morpheus.Types.Internal.AST+                                                ( ArgsType(..)+                                                , DataField(..)+                                                , DataTypeKind(..)+                                                , DataTypeKind(..)+                                                , TypeAlias(..)+                                                , TypeWrapper(..)+                                                , isOutputObject+                                                , isSubscription+                                                , ConsD(..)+                                                , TypeD(..)+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( UnSubResolver )  type Arrow = (->)  declareTypeAlias :: Bool -> TypeAlias -> Type-declareTypeAlias isSub TypeAlias {aliasTyCon, aliasWrappers, aliasArgs} = wrappedT aliasWrappers-  where-    wrappedT :: [WrapperD] -> Type-    wrappedT (ListD:xs)  = AppT (ConT ''[]) $ wrappedT xs-    wrappedT (MaybeD:xs) = AppT (ConT ''Maybe) $ wrappedT xs-    wrappedT []          = decType aliasArgs-    -------------------------------------------------------    typeName = ConT (mkName $ unpack aliasTyCon)-    ---------------------------------------------    decType _-      | isSub = AppT typeName (AppT (ConT ''UnSubResolver) (VarT $ mkName "m"))-    decType (Just par) = AppT typeName (VarT $ mkName $ unpack par)-    decType _ = typeName+declareTypeAlias isSub TypeAlias { aliasTyCon, aliasWrappers, aliasArgs } =+  wrappedT aliasWrappers+ where+  wrappedT :: [TypeWrapper] -> Type+  wrappedT (TypeList  : xs) = AppT (ConT ''[]) $ wrappedT xs+  wrappedT (TypeMaybe : xs) = AppT (ConT ''Maybe) $ wrappedT xs+  wrappedT []               = decType aliasArgs+  ------------------------------------------------------+  typeName = ConT (mkName $ unpack aliasTyCon)+  --------------------------------------------+  decType _ | isSub =+    AppT typeName (AppT (ConT ''UnSubResolver) (VarT $ mkName "m"))+  decType (Just par) = AppT typeName (VarT $ mkName $ unpack par)+  decType _          = typeName  tyConArgs :: DataTypeKind -> [String]-tyConArgs kindD-  | isOutputObject kindD || kindD == KindUnion = ["m"]-  | otherwise = []+tyConArgs kindD | isOutputObject kindD || kindD == KindUnion = ["m"]+                | otherwise = []  -- declareType declareType :: Bool -> Maybe DataTypeKind -> [Name] -> TypeD -> Dec-declareType namespace kindD derivingList TypeD {tName, tCons, tNamespace} =-  DataD [] (genName tName) tVars Nothing (map cons tCons) $ map derive (''Generic : derivingList)-  where-    genName = mkName . nameSpaceType (map pack tNamespace) . pack-    tVars = maybe [] (declareTyVar . tyConArgs) kindD-      where-        declareTyVar = map (PlainTV . mkName)-    defBang = Bang NoSourceUnpackedness NoSourceStrictness-    derive className = DerivClause Nothing [ConT className]-    cons ConsD {cName, cFields} = RecC (genName cName) (map declareField cFields)-      where-        declareField DataField {fieldName, fieldArgsType, fieldType} = (fName, defBang, fiType)-          where-            fName-              | namespace = mkName (nameSpaceWith tName (unpack fieldName))-              | otherwise = mkName (unpack fieldName)-            fiType = genFieldT fieldArgsType-              where-                monadVar = VarT $ mkName "m"-                ----------------------------                genFieldT Nothing = fType False-                genFieldT (Just ArgsType {argsTypeName}) = AppT (AppT arrowType argType) (fType True)-                  where-                    argType = ConT $ mkName (unpack argsTypeName)-                    arrowType = ConT ''Arrow-                -------------------------------------------------                fType isResolver-                  | maybe False isSubscription kindD = AppT monadVar result-                  | isResolver = AppT monadVar result-                  | otherwise = result-                -------------------------------------------------                result = declareTypeAlias (maybe False isSubscription kindD) fieldType+declareType namespace kindD derivingList TypeD { tName, tCons, tNamespace } =+  DataD [] (genName tName) tVars Nothing (map cons tCons)+    $ map derive (''Generic : derivingList)+ where+  genName = mkName . nameSpaceType (map pack tNamespace) . pack+  tVars   = maybe [] (declareTyVar . tyConArgs) kindD+    where declareTyVar = map (PlainTV . mkName)+  defBang = Bang NoSourceUnpackedness NoSourceStrictness+  derive className = DerivClause Nothing [ConT className]+  cons ConsD { cName, cFields } = RecC (genName cName)+                                       (map declareField cFields)+   where+    declareField DataField { fieldName, fieldArgsType, fieldType } =+      (fName, defBang, fiType)+     where+      fName | namespace = mkName (nameSpaceWith tName (unpack fieldName))+            | otherwise = mkName (unpack fieldName)+      fiType = genFieldT fieldArgsType+       where+        monadVar = VarT $ mkName "m"+        ---------------------------+        genFieldT Nothing                          = fType False+        genFieldT (Just ArgsType { argsTypeName }) = AppT+          (AppT arrowType argType)+          (fType True)+         where+          argType   = ConT $ mkName (unpack argsTypeName)+          arrowType = ConT ''Arrow+        ------------------------------------------------+        fType isResolver+          | maybe False isSubscription kindD = AppT monadVar result+          | isResolver                       = AppT monadVar result+          | otherwise                        = result+        ------------------------------------------------+        result = declareTypeAlias (maybe False isSubscription kindD) fieldType
src/Data/Morpheus/Execution/Internal/Decode.hs view
@@ -10,62 +10,74 @@   , withUnion   , decodeFieldWith   , decodeObjectExpQ-  ) where+  )+where -import           Data.Semigroup                          ((<>))-import           Data.Text                               (unpack)-import           Language.Haskell.TH                     (ExpQ, conE, mkName, uInfixE, varE)+import           Data.Semigroup                 ( (<>) )+import           Data.Text                      ( unpack )+import           Language.Haskell.TH            ( ExpQ+                                                , conE+                                                , mkName+                                                , uInfixE+                                                , varE+                                                )  -- MORPHEUS-import           Data.Morpheus.Error.Internal            (internalArgumentError, internalTypeMismatch)-import           Data.Morpheus.Types.Internal.Data       (DataField (..), Key)-import           Data.Morpheus.Types.Internal.DataD      (ConsD (..))-import           Data.Morpheus.Types.Internal.Validation (Validation)-import           Data.Morpheus.Types.Internal.Value      (Object, Value (..))+import           Data.Morpheus.Error.Internal   ( internalArgumentError+                                                , internalTypeMismatch+                                                )+import           Data.Morpheus.Types.Internal.AST+                                                ( DataField(..)+                                                , Key+                                                , ConsD(..) +                                                , Object+                                                , Value(..))+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Validation ) + decodeObjectExpQ :: ExpQ -> ConsD -> ExpQ-decodeObjectExpQ fieldDecoder ConsD {cName, cFields} = handleFields cFields-  where-    consName = conE (mkName cName)-    -----------------------------------------------------------------------------------    handleFields fNames = uInfixE consName (varE '(<$>)) (applyFields fNames)-      where-        applyFields []     = fail "No Empty fields"-        applyFields [x]    = defField x-        applyFields (x:xs) = uInfixE (defField x) (varE '(<*>)) (applyFields xs)-        -------------------------------------------------------------------------        defField DataField {fieldName} = uInfixE (varE (mkName "o")) fieldDecoder [|fName|]-          where-            fName = unpack fieldName+decodeObjectExpQ fieldDecoder ConsD { cName, cFields } = handleFields cFields+ where+  consName = conE (mkName cName)+  ----------------------------------------------------------------------------------+  handleFields fNames = uInfixE consName (varE '(<$>)) (applyFields fNames)+   where+    applyFields []       = fail "No Empty fields"+    applyFields [x     ] = defField x+    applyFields (x : xs) = uInfixE (defField x) (varE '(<*>)) (applyFields xs)+    ------------------------------------------------------------------------+    defField DataField { fieldName } = uInfixE (varE (mkName "o"))+                                               fieldDecoder+                                               [|fName|]+      where fName = unpack fieldName  withObject :: (Object -> Validation a) -> Value -> Validation a withObject f (Object object) = f object withObject _ isType          = internalTypeMismatch "Object" isType  withMaybe :: Monad m => (Value -> m a) -> Value -> m (Maybe a)-withMaybe _ Null   = pure Nothing-withMaybe decode x = Just <$> decode x+withMaybe _      Null = pure Nothing+withMaybe decode x    = Just <$> decode x  withList :: (Value -> Validation a) -> Value -> Validation [a] withList decode (List li) = mapM decode li-withList _ isType         = internalTypeMismatch "List" isType+withList _      isType    = internalTypeMismatch "List" isType  withEnum :: (Key -> Validation a) -> Value -> Validation a withEnum decode (Enum value) = decode value-withEnum _ isType            = internalTypeMismatch "Enum" isType+withEnum _      isType       = internalTypeMismatch "Enum" isType  withUnion :: (Key -> Object -> Object -> Validation a) -> Object -> Validation a-withUnion decoder unions =-  case lookup "tag" unions of-    Just (Enum key) ->-      case lookup key unions of-        Nothing    -> internalArgumentError ("type \"" <> key <> "\" was not provided on object")-        Just value -> withObject (decoder key unions) value-    Just _ -> internalArgumentError "tag must be Enum"-    Nothing -> internalArgumentError "tag not found on Input Union"+withUnion decoder unions = case lookup "tag" unions of+  Just (Enum key) -> case lookup key unions of+    Nothing -> internalArgumentError+      ("type \"" <> key <> "\" was not provided on object")+    Just value -> withObject (decoder key unions) value+  Just _  -> internalArgumentError "tag must be Enum"+  Nothing -> internalArgumentError "tag not found on Input Union"  decodeFieldWith :: (Value -> Validation a) -> Key -> Object -> Validation a-decodeFieldWith decoder name object =-  case lookup name object of-    Nothing    -> internalArgumentError ("Missing Field: \"" <> name <> "\"")-    Just value -> decoder value+decodeFieldWith decoder name object = case lookup name object of+  Nothing    -> internalArgumentError ("Missing Field: \"" <> name <> "\"")+  Just value -> decoder value
− src/Data/Morpheus/Execution/Internal/GraphScanner.hs
@@ -1,14 +0,0 @@-module Data.Morpheus.Execution.Internal.GraphScanner-  ( LibUpdater-  , resolveUpdates-  ) where--import           Control.Monad                           (foldM)-import           Data.Function                           ((&))-import           Data.Morpheus.Types.Internal.Validation (Validation)--type LibUpdater lib = lib -> Validation lib---- Helper Functions-resolveUpdates :: lib -> [LibUpdater lib] -> Validation lib-resolveUpdates = foldM (&)
src/Data/Morpheus/Execution/Internal/Utils.hs view
@@ -4,11 +4,16 @@   , nameSpaceWith   , nameSpaceType   , nameSpaceTypeString-  ) where+  )+where -import           Data.Char      (toLower, toUpper)-import           Data.Semigroup ((<>))-import           Data.Text      (Text, unpack)+import           Data.Char                      ( toLower+                                                , toUpper+                                                )+import           Data.Semigroup                 ( (<>) )+import           Data.Text                      ( Text+                                                , unpack+                                                )   nameSpaceTypeString :: [String] -> String -> String@@ -21,9 +26,9 @@ nameSpaceWith nSpace name = nonCapital nSpace <> capital name  nonCapital :: String -> String-nonCapital []     = []-nonCapital (x:xs) = toLower x : xs+nonCapital []       = []+nonCapital (x : xs) = toLower x : xs  capital :: String -> String-capital []     = []-capital (x:xs) = toUpper x : xs+capital []       = []+capital (x : xs) = toUpper x : xs
src/Data/Morpheus/Execution/Server/Decode.hs view
@@ -14,26 +14,49 @@   ( decodeArguments   , Decode(..)   , DecodeObject(..)-  ) where+  )+where -import           Data.Proxy                                      (Proxy (..))-import           Data.Semigroup                                  ((<>))-import           Data.Text                                       (pack)+import           Data.Proxy                     ( Proxy(..) )+import           Data.Semigroup                 ( (<>) )+import           Data.Text                      ( pack ) import           GHC.Generics  -- MORPHEUS-import           Data.Morpheus.Error.Internal                    (internalArgumentError, internalTypeMismatch)-import           Data.Morpheus.Execution.Internal.Decode         (decodeFieldWith, withEnum, withList, withMaybe,-                                                                  withObject, withUnion)-import           Data.Morpheus.Execution.Server.Generics.EnumRep (EnumRep (..))-import           Data.Morpheus.Kind                              (ENUM, GQL_KIND, INPUT_OBJECT, INPUT_UNION, SCALAR)-import           Data.Morpheus.Types.GQLScalar                   (GQLScalar (..), toScalar)-import           Data.Morpheus.Types.GQLType                     (GQLType (KIND, __typeName))-import           Data.Morpheus.Types.Internal.AST.Selection      (Argument (..), Arguments)-import           Data.Morpheus.Types.Internal.Base               (Key)-import           Data.Morpheus.Types.Internal.Validation         (Validation)-import           Data.Morpheus.Types.Internal.Value              (Object, Value (..))+import           Data.Morpheus.Error.Internal   ( internalArgumentError+                                                , internalTypeMismatch+                                                )+import           Data.Morpheus.Execution.Internal.Decode+                                                ( decodeFieldWith+                                                , withEnum+                                                , withList+                                                , withMaybe+                                                , withObject+                                                , withUnion+                                                )+import           Data.Morpheus.Execution.Server.Generics.EnumRep+                                                ( EnumRep(..) )+import           Data.Morpheus.Kind             ( ENUM+                                                , GQL_KIND+                                                , INPUT_OBJECT+                                                , INPUT_UNION+                                                , SCALAR+                                                )+import           Data.Morpheus.Types.GQLScalar  ( GQLScalar(..)+                                                , toScalar+                                                )+import           Data.Morpheus.Types.GQLType    ( GQLType(KIND, __typeName) )+import           Data.Morpheus.Types.Internal.AST+                                                ( Key+                                                , Argument(..)+                                                , Arguments+                                                , Object+                                                , Value(..)+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Validation ) + -- | Decode GraphQL query arguments and input values class Decode a where   decode :: Value -> Validation a@@ -53,10 +76,9 @@  -- SCALAR instance (GQLScalar a) => DecodeKind SCALAR a where-  decodeKind _ value =-    case toScalar value >>= parseValue of-      Right scalar      -> return scalar-      Left errorMessage -> internalTypeMismatch errorMessage value+  decodeKind _ value = case toScalar value >>= parseValue of+    Right scalar       -> return scalar+    Left  errorMessage -> internalTypeMismatch errorMessage value  -- ENUM instance (Generic a, EnumRep (Rep a)) => DecodeKind ENUM a where@@ -73,8 +95,7 @@ -- GENERIC decodeArguments :: DecodeObject p => Arguments -> Validation p decodeArguments = decodeObject . fmap toObject-  where-    toObject (x, y) = (x, argumentValue y)+  where toObject (x, y) = (x, argumentValue y)  class DecodeObject a where   decodeObject :: Object -> Validation a@@ -98,11 +119,11 @@ -- Recursive Decoding: (Selector (Rec1 )) instance (Selector s, GQLType a, Decode a) => GDecode (M1 S s (K1 i a)) where   unionTags _ = [__typeName (Proxy @a)]-  decodeUnion = fmap (M1 . K1) . decode . Object+  decodeUnion    = fmap (M1 . K1) . decode . Object   __decodeObject = fmap (M1 . K1) . decodeRec-    where-      fieldName = pack $ selName (undefined :: M1 S s f a)-      decodeRec = withObject (decodeFieldWith decode fieldName)+   where+    fieldName = pack $ selName (undefined :: M1 S s f a)+    decodeRec = withObject (decodeFieldWith decode fieldName)  instance (Datatype c, GDecode f) => GDecode (M1 D c f) where   decodeUnion = fmap M1 . decodeUnion@@ -119,14 +140,15 @@  instance (GDecode a, GDecode b) => GDecode (a :+: b) where   decodeUnion = withUnion handleUnion-    where-      handleUnion name unions object-        | [name] == l1Tags = L1 <$> decodeUnion object-        | [name] == r1Tags = R1 <$> decodeUnion object-        | name `elem` l1Tags = L1 <$> decodeUnion unions-        | name `elem` r1Tags = R1 <$> decodeUnion unions-        | otherwise = internalArgumentError ("type \"" <> name <> "\" could not find in union")-        where-          l1Tags = unionTags $ Proxy @a-          r1Tags = unionTags $ Proxy @b+   where+    handleUnion name unions object+      | [name] == l1Tags = L1 <$> decodeUnion object+      | [name] == r1Tags = R1 <$> decodeUnion object+      | name `elem` l1Tags = L1 <$> decodeUnion unions+      | name `elem` r1Tags = R1 <$> decodeUnion unions+      | otherwise = internalArgumentError+        ("type \"" <> name <> "\" could not find in union")+     where+      l1Tags = unionTags $ Proxy @a+      r1Tags = unionTags $ Proxy @b   unionTags _ = unionTags (Proxy @a) ++ unionTags (Proxy @b)
src/Data/Morpheus/Execution/Server/Encode.hs view
@@ -19,109 +19,153 @@   , encodeSubscription   , encodeMutation   , ObjectResolvers(..)-  ) where+  )+where -import           Data.Map                                        (Map)-import qualified Data.Map                                        as M (toList)-import           Data.Maybe                                      (fromMaybe)-import           Data.Proxy                                      (Proxy (..))-import           Data.Semigroup                                  ((<>))-import           Data.Set                                        (Set)-import qualified Data.Set                                        as S (toList)-import           Data.Text                                       (pack)+import           Data.Map                       ( Map )+import qualified Data.Map                      as M+                                                ( toList )+import           Data.Maybe                     ( fromMaybe )+import           Data.Proxy                     ( Proxy(..) )+import           Data.Semigroup                 ( (<>) )+import           Data.Set                       ( Set )+import qualified Data.Set                      as S+                                                ( toList )+import           Data.Text                      ( pack ) import           GHC.Generics  -- MORPHEUS-import           Data.Morpheus.Error.Internal                    (internalUnknownTypeMessage)-import           Data.Morpheus.Execution.Server.Decode           (DecodeObject, decodeArguments)-import           Data.Morpheus.Execution.Server.Generics.EnumRep (EnumRep (..))-import           Data.Morpheus.Kind                              (ENUM, GQL_KIND, OBJECT, ResContext (..), SCALAR,-                                                                  UNION, VContext (..))-import           Data.Morpheus.Types.Custom                      (MapKind, Pair (..), mapKindFromList)-import           Data.Morpheus.Types.GQLScalar                   (GQLScalar (..))-import           Data.Morpheus.Types.GQLType                     (GQLType (CUSTOM, KIND, __typeName))-import           Data.Morpheus.Types.Internal.AST.Operation      (Operation (..), ValidOperation)-import           Data.Morpheus.Types.Internal.AST.Selection      (Selection (..), SelectionRec (..), ValidSelection)-import           Data.Morpheus.Types.Internal.Base               (Key)-import           Data.Morpheus.Types.Internal.Data               (MUTATION, OperationType, QUERY, SUBSCRIPTION)-import           Data.Morpheus.Types.Internal.Resolver           (MapGraphQLT (..), PureOperation (..), Resolver (..),-                                                                  Resolving (..), ResolvingStrategy (..), resolveObject,-                                                                  withObject)-import           Data.Morpheus.Types.Internal.Validation         (Validation)-import           Data.Morpheus.Types.Internal.Value              (GQLValue (..), Value (..))+import           Data.Morpheus.Error.Internal   ( internalUnknownTypeMessage )+import           Data.Morpheus.Execution.Server.Decode+                                                ( DecodeObject+                                                , decodeArguments+                                                )+import           Data.Morpheus.Execution.Server.Generics.EnumRep+                                                ( EnumRep(..) )+import           Data.Morpheus.Kind             ( ENUM+                                                , GQL_KIND+                                                , OBJECT+                                                , ResContext(..)+                                                , SCALAR+                                                , UNION+                                                , VContext(..)+                                                )+import           Data.Morpheus.Types.Types     ( MapKind+                                                , Pair(..)+                                                , mapKindFromList+                                                )+import           Data.Morpheus.Types.GQLScalar  ( GQLScalar(..) )+import           Data.Morpheus.Types.GQLType    ( GQLType+                                                  ( CUSTOM+                                                  , KIND+                                                  , __typeName+                                                  )+                                                )+import           Data.Morpheus.Types.Internal.AST+                                                ( Operation(..)+                                                , ValidOperation+                                                , Key,+                                                  MUTATION+                                                , OperationType+                                                , QUERY+                                                , SUBSCRIPTION+                                                , Selection(..)+                                                , SelectionRec(..)+                                                , ValidSelection+                                                , GQLValue(..)+                                                , Value(..)+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( MapStrategy(..)+                                                , LiftEither(..)+                                                , Resolver(..)+                                                , resolving+                                                , toResolver+                                                , ResolvingStrategy(..)+                                                , resolveObject+                                                , withObject+                                                , Validation+                                                , failure+                                                ) -class Encode resolver o m e where-  encode :: PureOperation o => resolver -> (Key, ValidSelection) -> ResolvingStrategy o m e Value+class Encode resolver o e (m :: * -> *) where+  encode :: resolver -> (Key, ValidSelection) -> ResolvingStrategy o e m Value -instance {-# OVERLAPPABLE #-} (EncodeKind (KIND a) a o m e , PureOperation o) => Encode a o m e where+instance {-# OVERLAPPABLE #-} (EncodeKind (KIND a) a o e m , LiftEither o ResolvingStrategy) => Encode a o e m where   encode resolver = encodeKind (VContext resolver :: VContext (KIND a) a)  -- MAYBE-instance (Monad m , Encode a o m e) => Encode (Maybe a) o m e where+instance (Monad m , LiftEither o ResolvingStrategy,Encode a o e m) => Encode (Maybe a) o e m where   encode = maybe (const $ pure gqlNull) encode  --  Tuple  (a,b)-instance Encode (Pair k v) o m e => Encode (k, v) o m e where+instance Encode (Pair k v) o e m => Encode (k, v) o e m where   encode (key, value) = encode (Pair key value)  --  Set-instance Encode [a] o m e => Encode (Set a) o m e where+instance Encode [a] o e m => Encode (Set a) o e m where   encode = encode . S.toList  --  Map-instance (Eq k, Monad m, Encode (MapKind k v (Resolver o m e)) o m e) => Encode (Map k v)  o m e  where-  encode value = encode ((mapKindFromList $ M.toList value) :: MapKind k v (Resolver o m e))+instance (Eq k, Monad m,LiftEither o Resolver, Encode (MapKind k v (Resolver o e m)) o e m) => Encode (Map k v)  o e m where+  encode value =+    encode ((mapKindFromList $ M.toList value) :: MapKind k v (Resolver o e m))  -- LIST []-instance (Monad m, Encode a o m e) => Encode [a] o m e where+instance (Monad m, Encode a o e m, LiftEither o ResolvingStrategy) => Encode [a] o e m where   encode list query = gqlList <$> traverse (`encode` query) list - --  GQL a -> Resolver b, MUTATION, SUBSCRIPTION, QUERY-instance (DecodeObject a, Resolving fO m e ,Monad m,PureOperation fO, MapGraphQLT fO o, Encode b fO m e ) => Encode (a -> Resolver fO m e b) o m e where-  encode resolver selection@(_, Selection { selectionArguments }) = mapGraphQLT $ resolving encode (getArgs args resolver)  selection-     where-      args :: Validation a-      args =  decodeArguments selectionArguments+instance (DecodeObject a, Monad m,LiftEither fo Resolver, MapStrategy fo o, Encode b fo e m) => Encode (a -> Resolver fo e m b) o e m where+  encode resolver selection@(_, Selection { selectionArguments }) =+    mapStrategy $ resolving encode (toResolver args resolver) selection+   where+    args :: Validation a+    args = decodeArguments selectionArguments  -- ENCODE GQL KIND-class EncodeKind (kind :: GQL_KIND) a o m e  where-  encodeKind :: PureOperation o =>  VContext kind a -> (Key, ValidSelection) -> ResolvingStrategy o m e Value+class EncodeKind (kind :: GQL_KIND) a o e (m :: * -> *) where+  encodeKind :: LiftEither o ResolvingStrategy =>  VContext kind a -> (Key, ValidSelection) -> ResolvingStrategy o e m Value  -- SCALAR-instance (GQLScalar a, Monad m) => EncodeKind SCALAR a o m e where+instance (GQLScalar a, Monad m) => EncodeKind SCALAR a o e m where   encodeKind = pure . pure . gqlScalar . serialize . unVContext  -- ENUM-instance (Generic a, EnumRep (Rep a), Monad m) => EncodeKind ENUM a o m e where+instance (Generic a, EnumRep (Rep a), Monad m) => EncodeKind ENUM a o e m where   encodeKind = pure . pure . gqlString . encodeRep . from . unVContext  --  OBJECT-instance (Monad m, EncodeCon o m e a, Monad m, GResolver OBJECT (Rep a) o m e) => EncodeKind OBJECT a o m e where-  encodeKind (VContext value)  = withObject encodeK-    where-      encodeK selection = resolveObject selection (__typenameResolver : objectResolvers (Proxy :: Proxy (CUSTOM a)) value)-      __typenameResolver = ("__typename", const $ pure $ gqlString $ __typeName (Proxy @a))+instance (Monad m, EncodeCon o e m a, Monad m, GResolver OBJECT (Rep a) o e m) => EncodeKind OBJECT a o e m where+  encodeKind (VContext value) = withObject encodeK+   where+    encodeK selection = resolveObject+      selection+      (__typenameResolver : objectResolvers (Proxy :: Proxy (CUSTOM a)) value)+    __typenameResolver =+      ("__typename", const $ pure $ gqlString $ __typeName (Proxy @a))  -- exploreKindChannels -- UNION-instance (Monad m, GQL_RES a, GResolver UNION (Rep a) o m e) => EncodeKind UNION a o m e where-  encodeKind (VContext value) (key, sel@Selection {selectionRec = UnionSelection selections}) =-    resolver (key, sel {selectionRec = SelectionSet lookupSelection})-      -- SPEC: if there is no any fragment that supports current object Type GQL returns {}-    where-      lookupSelection = fromMaybe [] $ lookup typeName selections-      (typeName, resolver) = unionResolver value-  encodeKind _ _ = Fail $ internalUnknownTypeMessage "union Resolver only should recieve UnionSelection"+instance (Monad m, GQL_RES a, GResolver UNION (Rep a) o e m) => EncodeKind UNION a o e m where+  encodeKind (VContext value) (key, sel@Selection { selectionRec = UnionSelection selections })+    = resolver (key, sel { selectionRec = SelectionSet lookupSelection })+   where+    lookupSelection      = fromMaybe [] $ lookup typeName selections+    (typeName, resolver) = unionResolver value+  encodeKind _ _ = failure $ internalUnknownTypeMessage+    "union Resolver only should recieve UnionSelection"  -- Types & Constrains ------------------------------------------------------- type GQL_RES a = (Generic a, GQLType a) -type EncodeOperator o m e a  = a -> ValidOperation -> ResolvingStrategy o m e Value+type EncodeOperator o e m a+  = a -> ValidOperation -> ResolvingStrategy o e m Value -type EncodeCon o m e a = (GQL_RES a,  ObjectResolvers (CUSTOM a) a o m e)+type EncodeCon o e m a = (GQL_RES a, ObjectResolvers (CUSTOM a) a o e m) -type FieldRes  o m e   = (Key, (Key, ValidSelection) -> ResolvingStrategy o m e Value)+type FieldRes o e m+  = (Key, (Key, ValidSelection) -> ResolvingStrategy o e m Value)  type family GRes (kind :: GQL_KIND) value :: * @@ -130,64 +174,82 @@ type instance GRes UNION v = (Key, (Key, ValidSelection) -> v)  --- GENERICS -------------------------------------------------class ObjectResolvers (custom :: Bool) a (o :: OperationType) (m :: * -> *) e where-  objectResolvers :: PureOperation o =>  Proxy custom -> a -> [(Key, (Key, ValidSelection) -> ResolvingStrategy o m e Value)]+class ObjectResolvers (custom :: Bool) a (o :: OperationType) e (m :: * -> *) where+  objectResolvers :: Proxy custom -> a -> [(Key, (Key, ValidSelection) -> ResolvingStrategy o e m Value)] -instance (Generic a, GResolver OBJECT (Rep a) o m e ) => ObjectResolvers 'False a o m e where-  objectResolvers _ = getResolvers (ResContext :: ResContext OBJECT o m e value) . from+instance (Generic a, GResolver OBJECT (Rep a) o e m ) => ObjectResolvers 'False a o e m where+  objectResolvers _ =+    getResolvers (ResContext :: ResContext OBJECT o e m value) . from -unionResolver :: (Generic a, PureOperation o, GResolver UNION (Rep a) o m e) => a -> (Key, (Key, ValidSelection) -> ResolvingStrategy o m e Value)-unionResolver = getResolvers (ResContext :: ResContext UNION o m e value) . from+unionResolver+  :: (Generic a, GResolver UNION (Rep a) o e m)+  => a+  -> (Key, (Key, ValidSelection) -> ResolvingStrategy o e m Value)+unionResolver =+  getResolvers (ResContext :: ResContext UNION o e m value) . from  -- | Derives resolvers for OBJECT and UNION-class GResolver (kind :: GQL_KIND) f o m e where-  getResolvers :: PureOperation o => ResContext kind o m e value -> f a -> GRes kind (ResolvingStrategy o m e Value)+class GResolver (kind :: GQL_KIND) f o e (m :: * -> *) where+  getResolvers :: ResContext kind o e m value -> f a -> GRes kind (ResolvingStrategy o e m Value) -instance GResolver kind f o m e => GResolver kind (M1 D c f) o m e where+instance GResolver kind f o e m => GResolver kind (M1 D c f) o e m where   getResolvers context (M1 src) = getResolvers context src -instance GResolver kind f o m e => GResolver kind (M1 C c f) o m e where+instance GResolver kind f o e m => GResolver kind (M1 C c f) o e m where   getResolvers context (M1 src) = getResolvers context src  -- OBJECT-instance GResolver OBJECT U1 o m e where+instance GResolver OBJECT U1 o e m where   getResolvers _ _ = [] -instance (Selector s, GQLType a, Encode a o m e) => GResolver OBJECT (M1 S s (K1 s2 a)) o m e where+instance (Selector s, GQLType a, Encode a o e m) => GResolver OBJECT (M1 S s (K1 s2 a)) o e m where   getResolvers _ m@(M1 (K1 src)) = [(pack (selName m), encode src)] -instance (GResolver OBJECT f o m e, GResolver OBJECT g o m e) => GResolver OBJECT (f :*: g) o m e where-  getResolvers context (a :*: b)  = getResolvers context a  ++ getResolvers context b+instance (GResolver OBJECT f o e m, GResolver OBJECT g o e m) => GResolver OBJECT (f :*: g) o e m where+  getResolvers context (a :*: b) =+    getResolvers context a ++ getResolvers context b  -- UNION-instance (Selector s, GQLType a, Encode a o m e ) => GResolver UNION (M1 S s (K1 s2 a)) o m e where+instance (Selector s, GQLType a, Encode a o e m ) => GResolver UNION (M1 S s (K1 s2 a)) o e m where   getResolvers _ (M1 (K1 src)) = (__typeName (Proxy @a), encode src) -instance (GResolver UNION a o m e, GResolver UNION b o m e) => GResolver UNION (a :+: b) o m e where+instance (GResolver UNION a o e m, GResolver UNION b o e m) => GResolver UNION (a :+: b) o e m where   getResolvers context (L1 x) = getResolvers context x   getResolvers context (R1 x) = getResolvers context x  ----- HELPERS -----------------------------encodeQuery ::-     forall m event query (schema :: (* -> *) -> *). (Monad m, EncodeCon QUERY m event (schema (Resolver QUERY m event)), EncodeCon QUERY m event query, Resolving QUERY m event)-  => schema (Resolver QUERY m event)-  -> EncodeOperator QUERY m event query-encodeQuery schema = encodeOperationWith (objectResolvers (Proxy :: Proxy (CUSTOM (schema (Resolver QUERY m event)))) schema)+encodeQuery+  :: forall m event query (schema :: (* -> *) -> *)+   . ( Monad m+     , EncodeCon QUERY event m (schema (Resolver QUERY event m))+     , EncodeCon QUERY event m query+     )+  => schema (Resolver QUERY event m)+  -> EncodeOperator QUERY event m query+encodeQuery schema = encodeOperationWith+  (objectResolvers (Proxy :: Proxy (CUSTOM (schema (Resolver QUERY event m))))+                   schema+  ) -encodeMutation ::-     forall m event mut. (Monad m, EncodeCon MUTATION m event mut, Resolving MUTATION m event)-  => EncodeOperator MUTATION m event mut+encodeMutation+  :: forall event m mut+   . (Monad m, EncodeCon MUTATION event m mut)+  => EncodeOperator MUTATION event m mut encodeMutation = encodeOperationWith [] -encodeSubscription ::-     forall m event mut. (Monad m, EncodeCon SUBSCRIPTION m event mut, Resolving SUBSCRIPTION m event)-  => EncodeOperator SUBSCRIPTION m event mut+encodeSubscription+  :: forall m event mut+   . (Monad m, EncodeCon SUBSCRIPTION event m mut)+  => EncodeOperator SUBSCRIPTION event m mut encodeSubscription = encodeOperationWith [] -encodeOperationWith ::-     forall o m e a . (Monad m, EncodeCon o m e a, Resolving o m e, PureOperation o)-  => [FieldRes o m e]-  -> EncodeOperator o m e a-encodeOperationWith externalRes rootResolver Operation {operationSelection} = resolveObject operationSelection resolvers-    where-       resolvers = externalRes <> objectResolvers (Proxy :: Proxy (CUSTOM a)) rootResolver+encodeOperationWith+  :: forall o e m a+   . (Monad m, EncodeCon o e m a, LiftEither o ResolvingStrategy)+  => [FieldRes o e m]+  -> EncodeOperator o e m a+encodeOperationWith externalRes rootResolver Operation { operationSelection } =+  resolveObject operationSelection resolvers+ where+  resolvers =+    externalRes <> objectResolvers (Proxy :: Proxy (CUSTOM a)) rootResolver
src/Data/Morpheus/Execution/Server/Generics/EnumRep.hs view
@@ -6,16 +6,20 @@  module Data.Morpheus.Execution.Server.Generics.EnumRep   ( EnumRep(..)-  ) where+  )+where -import           Data.Proxy                              (Proxy (..))-import           Data.Semigroup                          ((<>))-import           Data.Text                               (Text, pack)+import           Data.Proxy                     ( Proxy(..) )+import           Data.Semigroup                 ( (<>) )+import           Data.Text                      ( Text+                                                , pack+                                                ) import           GHC.Generics  -- MORPHEUS-import           Data.Morpheus.Error.Internal            (internalError)-import           Data.Morpheus.Types.Internal.Validation (Validation)+import           Data.Morpheus.Error.Internal   ( internalError )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Validation )  class EnumRep f where   encodeRep :: f a -> Text@@ -38,6 +42,6 @@   decodeEnum name     | name `elem` enumTags (Proxy @a) = L1 <$> decodeEnum name     | name `elem` enumTags (Proxy @b) = R1 <$> decodeEnum name-    | otherwise =-      internalError ("Constructor \"" <> name <> "\" could not find in Union")+    | otherwise = internalError+      ("Constructor \"" <> name <> "\" could not find in Union")   enumTags _ = enumTags (Proxy @a) ++ enumTags (Proxy @b)
src/Data/Morpheus/Execution/Server/Interpreter.hs view
@@ -5,22 +5,44 @@  module Data.Morpheus.Execution.Server.Interpreter   ( Interpreter(..)-  ) where+  )+where -import           Data.Aeson                                          (encode)-import           Data.ByteString                                     (ByteString)-import qualified Data.ByteString.Lazy.Char8                          as LB (ByteString, fromStrict, toStrict)-import           Data.Text                                           (Text)-import qualified Data.Text.Lazy                                      as LT (Text, fromStrict, toStrict)-import           Data.Text.Lazy.Encoding                             (decodeUtf8, encodeUtf8)+import           Data.Aeson                     ( encode )+import           Data.ByteString                ( ByteString )+import qualified Data.ByteString.Lazy.Char8    as LB+                                                ( ByteString+                                                , fromStrict+                                                , toStrict+                                                )+import           Data.Text                      ( Text )+import qualified Data.Text.Lazy                as LT+                                                ( Text+                                                , fromStrict+                                                , toStrict+                                                )+import           Data.Text.Lazy.Encoding        ( decodeUtf8+                                                , encodeUtf8+                                                )  -- MORPHEUS-import           Data.Morpheus.Execution.Server.Resolve              (RootResCon, byteStringIO, statefulResolver,-                                                                      statelessResolver, streamResolver)-import           Data.Morpheus.Execution.Subscription.ClientRegister (GQLState)-import           Data.Morpheus.Types.Internal.Resolver               (GQLRootResolver (..))-import           Data.Morpheus.Types.Internal.Stream                 (ResponseStream)-import           Data.Morpheus.Types.IO                              (GQLRequest, GQLResponse)+import           Data.Morpheus.Execution.Server.Resolve+                                                ( RootResCon+                                                , byteStringIO+                                                , statefulResolver+                                                , statelessResolver+                                                , streamResolver+                                                , coreResolver+                                                )+import           Data.Morpheus.Execution.Subscription.ClientRegister+                                                ( GQLState )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( GQLRootResolver(..)+                                                , ResponseStream+                                                )+import           Data.Morpheus.Types.IO         ( GQLRequest+                                                , GQLResponse+                                                )  -- | main query processor and resolver --  possible versions of interpreter@@ -50,7 +72,7 @@ -} type StateLess m a = a -> m a -instance Interpreter (GQLRequest -> m GQLResponse) m e  where+instance Interpreter (GQLRequest -> m GQLResponse) m e   where   interpreter = statelessResolver  instance Interpreter (StateLess m LB.ByteString) m e  where@@ -60,11 +82,11 @@   interpreter root request =     decodeUtf8 <$> interpreter root (encodeUtf8 request) -instance Interpreter (StateLess m ByteString) m e where+instance Interpreter (StateLess m ByteString) m e  where   interpreter root request =     LB.toStrict <$> interpreter root (LB.fromStrict request) -instance Interpreter (StateLess m Text) m e where+instance Interpreter (StateLess m Text) m e  where   interpreter root request =     LT.toStrict <$> interpreter root (LT.fromStrict request) @@ -72,17 +94,16 @@    HTTP Interpreter with state and side effects, every mutation will    trigger subscriptions in  shared `GQLState` -}-type WSPub m e  a = GQLState m e -> a -> m a+type WSPub m e a = GQLState m e -> a -> m a -instance Interpreter (WSPub IO e LB.ByteString) IO e  where-  interpreter root state =-    statefulResolver state (byteStringIO (streamResolver root))+instance Interpreter (WSPub IO e LB.ByteString) IO e where+  interpreter root state = statefulResolver state (coreResolver root) -instance Interpreter (WSPub IO e  LT.Text) IO e  where+instance Interpreter (WSPub IO e  LT.Text) IO e where   interpreter root state request =     decodeUtf8 <$> interpreter root state (encodeUtf8 request) -instance Interpreter (WSPub IO e  ByteString) IO e  where+instance Interpreter (WSPub IO e  ByteString) IO e where   interpreter root state request =     LB.toStrict <$> interpreter root state (LB.fromStrict request) @@ -94,22 +115,22 @@    WebSocket Interpreter without state and side effects, mutations and subscription will return Actions    that will be executed in WebSocket server -}-type WSSub m e a = a -> ResponseStream m e a+type WSSub m e a = a -> ResponseStream e m a -instance Interpreter (GQLRequest -> ResponseStream m e  LB.ByteString) m e where+instance Interpreter (GQLRequest -> ResponseStream e m LB.ByteString) m e where   interpreter root request = encode <$> streamResolver root request -instance Interpreter (WSSub m e  LB.ByteString) m e  where+instance Interpreter (WSSub m e  LB.ByteString) m e where   interpreter root = byteStringIO (streamResolver root) -instance Interpreter (WSSub m e  LT.Text) m e  where+instance Interpreter (WSSub m e  LT.Text)  m e where   interpreter root request =     decodeUtf8 <$> interpreter root (encodeUtf8 request) -instance Interpreter (WSSub m e ByteString) m e  where+instance Interpreter (WSSub m e ByteString) m e where   interpreter root request =     LB.toStrict <$> interpreter root (LB.fromStrict request) -instance Interpreter (WSSub m e Text) m e where+instance Interpreter (WSSub m e Text)  m e where   interpreter root request =     LT.toStrict <$> interpreter root (LT.fromStrict request)
src/Data/Morpheus/Execution/Server/Introspect.hs view
@@ -21,28 +21,54 @@   , IntroCon   , updateLib   , buildType-  ) where+  )+where -import           Data.Map                                        (Map)-import           Data.Proxy                                      (Proxy (..))-import           Data.Semigroup                                  ((<>))-import           Data.Set                                        (Set)-import           Data.Text                                       (Text, pack)+import           Data.Map                       ( Map )+import           Data.Proxy                     ( Proxy(..) )+import           Data.Set                       ( Set )+import           Data.Text                      ( Text+                                                , pack+                                                ) import           GHC.Generics  -- MORPHEUS-import           Data.Morpheus.Error.Schema                      (nameCollisionError)-import           Data.Morpheus.Execution.Internal.GraphScanner   (LibUpdater, resolveUpdates)-import           Data.Morpheus.Execution.Server.Generics.EnumRep (EnumRep (..))-import           Data.Morpheus.Kind                              (Context (..), ENUM, GQL_KIND, INPUT_OBJECT,-                                                                  INPUT_UNION, OBJECT, SCALAR, UNION)-import           Data.Morpheus.Types.Custom                      (MapKind, Pair)-import           Data.Morpheus.Types.GQLScalar                   (GQLScalar (..))-import           Data.Morpheus.Types.GQLType                     (GQLType (..))-import           Data.Morpheus.Types.Internal.Data               (DataArguments, DataField (..), DataType (..),-                                                                  DataTyCon (..), DataTypeLib, TypeAlias (..),-                                                                  defineType, isTypeDefined, toListField,-                                                                  toNullableField)+import           Data.Morpheus.Error.Schema     ( nameCollisionError )+import           Data.Morpheus.Execution.Server.Generics.EnumRep+                                                ( EnumRep(..) )+import           Data.Morpheus.Kind             ( Context(..)+                                                , ENUM+                                                , GQL_KIND+                                                , INPUT_OBJECT+                                                , INPUT_UNION+                                                , OBJECT+                                                , SCALAR+                                                , UNION+                                                )+import           Data.Morpheus.Types.Types     ( MapKind+                                                , Pair+                                                )+import           Data.Morpheus.Types.GQLScalar  ( GQLScalar(..) )+import           Data.Morpheus.Types.GQLType    ( GQLType(..) )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Failure(..)+                                                , resolveUpdates+                                                )+import           Data.Morpheus.Types.Internal.AST+                                                ( DataArguments+                                                , Meta(..)+                                                , DataField(..)+                                                , DataTyCon(..)+                                                , DataType(..)+                                                , Key+                                                , createAlias+                                                , defineType+                                                , isTypeDefined+                                                , toListField+                                                , toNullableField+                                                , createEnumValue+                                                , TypeUpdater+                                                )   type IntroCon a = (GQLType a, ObjectFields (CUSTOM a) a)@@ -86,11 +112,14 @@  -- Resolver : a -> Resolver b instance (ObjectFields 'False a, Introspect b) => Introspect (a -> m b) where-  field _ name = (field (Proxy @b) name) {fieldArgs = fst $ objectFields (Proxy :: Proxy 'False) (Proxy @a)}-  introspect _ typeLib = resolveUpdates typeLib (introspect (Proxy @b) : argTypes)-    where-      argTypes :: [TypeUpdater]-      argTypes = snd $ objectFields (Proxy :: Proxy 'False) (Proxy @a)+  field _ name = (field (Proxy @b) name)+    { fieldArgs = fst $ objectFields (Proxy :: Proxy 'False) (Proxy @a)+    }+  introspect _ typeLib = resolveUpdates typeLib+                                        (introspect (Proxy @b) : argTypes)+   where+    argTypes :: [TypeUpdater]+    argTypes = snd $ objectFields (Proxy :: Proxy 'False) (Proxy @a)  -- | Introspect With specific Kind: 'kind': object, scalar, enum ... class IntrospectKind (kind :: GQL_KIND) a where@@ -99,72 +128,56 @@ -- SCALAR instance (GQLType a, GQLScalar a) => IntrospectKind SCALAR a where   introspectKind _ = updateLib scalarType [] (Proxy @a)-    where-      scalarType = DataScalar . buildType (scalarValidator (Proxy @a))+    where scalarType = DataScalar . buildType (scalarValidator (Proxy @a))  -- ENUM instance (GQL_TYPE a, EnumRep (Rep a)) => IntrospectKind ENUM a where   introspectKind _ = updateLib enumType [] (Proxy @a)-    where-      enumType = DataEnum . buildType (enumTags (Proxy @(Rep a)))+   where+    enumType =+      DataEnum . buildType (map createEnumValue $ enumTags (Proxy @(Rep a)))  -- INPUT_OBJECT instance (GQL_TYPE a, ObjectFields (CUSTOM a) a) => IntrospectKind INPUT_OBJECT a where-  introspectKind _ = updateLib (DataInputObject . buildType fields) types (Proxy @a)-    where-      (fields, types) = objectFields (Proxy @(CUSTOM a)) (Proxy @a)+  introspectKind _ = updateLib (DataInputObject . buildType fields)+                               types+                               (Proxy @a)+    where (fields, types) = objectFields (Proxy @(CUSTOM a)) (Proxy @a)  -- OBJECTS instance (GQL_TYPE a, ObjectFields (CUSTOM a) a) => IntrospectKind OBJECT a where-  introspectKind _ = updateLib (DataObject . buildType (__typename : fields)) types (Proxy @a)-    where-      __typename =-        ( "__typename"-        , DataField-            { fieldName = "__typename"-            , fieldArgs = []-            , fieldArgsType = Nothing-            , fieldType = buildAlias "String"-            , fieldHidden = True-            })-      (fields, types) = objectFields (Proxy @(CUSTOM a)) (Proxy @a)+  introspectKind _ = updateLib (DataObject . buildType (__typename : fields))+                               types+                               (Proxy @a)+   where+    __typename =+      ( "__typename"+      , DataField { fieldName     = "__typename"+                  , fieldArgs     = []+                  , fieldArgsType = Nothing+                  , fieldType     = createAlias "String"+                  , fieldMeta     = Nothing+                  }+      )+    (fields, types) = objectFields (Proxy @(CUSTOM a)) (Proxy @a)  -- UNION instance (GQL_TYPE a, GQLRep UNION (Rep a)) => IntrospectKind UNION a where-  introspectKind _ = updateLib (DataUnion . buildType fields) stack (Proxy @a)-    where-      (fields, stack) = unzip $ gqlRep (Context :: Context UNION (Rep a))+  introspectKind _ = updateLib (DataUnion . buildType memberTypes)+                               stack+                               (Proxy @a)+   where+    (memberTypes, stack) = unzip $ gqlRep (Context :: Context UNION (Rep a))  -- INPUT_UNION instance (GQL_TYPE a, GQLRep UNION (Rep a)) => IntrospectKind INPUT_UNION a where-  introspectKind _ = updateLib (DataInputUnion . buildType (fieldTag : fields)) (tagsEnumType : stack) (Proxy @a)-    where-      (inputUnions, stack) = unzip $ gqlRep (Context :: Context UNION (Rep a))-      fields = map toNullableField inputUnions-      -- for every input Union 'User' adds enum type of possible TypeNames 'UserTags'-      tagsEnumType :: TypeUpdater-      tagsEnumType x = pure $ defineType (typeName, DataEnum tagsEnum) x-        where-          tagsEnum =-            DataTyCon-              { typeName-                -- has same fingerprint as object because it depends on it-              , typeFingerprint = __typeFingerprint (Proxy @a)-              , typeDescription = Nothing-              , typeData = map fieldName inputUnions-              }-      typeName = __typeName (Proxy @a) <> "Tags"-      fieldTag =-        DataField-          { fieldName = "tag"-          , fieldArgs = []-          , fieldArgsType = Nothing-          , fieldType = buildAlias typeName-          , fieldHidden = False-          }+  introspectKind _ = updateLib (DataInputUnion . buildType memberTypes)+                               stack+                               (Proxy @a)+   where+    (memberTypes, stack) = unzip $ gqlRep (Context :: Context UNION (Rep a))  -- Types-type TypeUpdater = LibUpdater DataTypeLib  type GQL_TYPE a = (Generic a, GQLType a) @@ -179,7 +192,7 @@  type instance GQLRepResult OBJECT = (Text, DataField) -type instance GQLRepResult UNION = DataField+type instance GQLRepResult UNION = Key  --  GENERIC UNION class GQLRep (kind :: GQL_KIND) f where@@ -193,45 +206,55 @@  -- | recursion for Object types, both of them : 'UNION' and 'INPUT_UNION' instance (GQLRep UNION a, GQLRep UNION b) => GQLRep UNION (a :+: b) where-  gqlRep _ = gqlRep (Context :: Context UNION a) ++ gqlRep (Context :: Context UNION b)+  gqlRep _ =+    gqlRep (Context :: Context UNION a) ++ gqlRep (Context :: Context UNION b)  instance (GQL_TYPE a, Introspect a) => GQLRep UNION (M1 S s (Rec0 a)) where-  gqlRep _ = [(buildField (Proxy @a) [] (__typeName (Proxy @a)), introspect (Proxy @a))]+  gqlRep _ = [(__typeName (Proxy @a), introspect (Proxy @a))]  -- | recursion for Object types, both of them : 'INPUT_OBJECT' and 'OBJECT' instance (GQLRep OBJECT a, GQLRep OBJECT b) => GQLRep OBJECT (a :*: b) where-  gqlRep _ = gqlRep (Context :: Context OBJECT a) ++ gqlRep (Context :: Context OBJECT b)+  gqlRep _ =+    gqlRep (Context :: Context OBJECT a) ++ gqlRep (Context :: Context OBJECT b)  instance (Selector s, Introspect a) => GQLRep OBJECT (M1 S s (Rec0 a)) where   gqlRep _ = [((name, field (Proxy @a) name), introspect (Proxy @a))]-    where-      name = pack $ selName (undefined :: M1 S s (Rec0 ()) ())+    where name = pack $ selName (undefined :: M1 S s (Rec0 ()) ())  instance GQLRep OBJECT U1 where   gqlRep _ = [] -buildAlias :: Text -> TypeAlias-buildAlias aliasTyCon = TypeAlias {aliasTyCon, aliasWrappers = [], aliasArgs = Nothing}  buildField :: GQLType a => Proxy a -> DataArguments -> Text -> DataField-buildField proxy fieldArgs fieldName =-  DataField-    {fieldName, fieldArgs, fieldArgsType = Nothing, fieldType = buildAlias $ __typeName proxy, fieldHidden = False}+buildField proxy fieldArgs fieldName = DataField+  { fieldName+  , fieldArgs+  , fieldArgsType = Nothing+  , fieldType     = createAlias $ __typeName proxy+  , fieldMeta     = Nothing+  }  buildType :: GQLType a => t -> Proxy a -> DataTyCon t-buildType typeData proxy =-  DataTyCon-    { typeName = __typeName proxy-    , typeFingerprint = __typeFingerprint proxy-    , typeDescription = description proxy-    , typeData-    }+buildType typeData proxy = DataTyCon+  { typeName        = __typeName proxy+  , typeFingerprint = __typeFingerprint proxy+  , typeMeta        = Just Meta { metaDescription = description proxy+                                , metaDirectives  = []+                                }+  , typeData+  } -updateLib :: GQLType a => (Proxy a -> DataType) -> [TypeUpdater] -> Proxy a -> TypeUpdater+updateLib+  :: GQLType a+  => (Proxy a -> DataType)+  -> [TypeUpdater]+  -> Proxy a+  -> TypeUpdater updateLib typeBuilder stack proxy lib' =   case isTypeDefined (__typeName proxy) lib' of-    Nothing -> resolveUpdates (defineType (__typeName proxy, typeBuilder proxy) lib') stack-    Just fingerprint'-      | fingerprint' == __typeFingerprint proxy -> return lib'+    Nothing -> resolveUpdates+      (defineType (__typeName proxy, typeBuilder proxy) lib')+      stack+    Just fingerprint' | fingerprint' == __typeFingerprint proxy -> return lib'     -- throw error if 2 different types has same name-    Just _ -> Left $ nameCollisionError (__typeName proxy)+    Just _ -> failure $ nameCollisionError (__typeName proxy)
src/Data/Morpheus/Execution/Server/Resolve.hs view
@@ -14,138 +14,214 @@   , statefulResolver   , RootResCon   , fullSchema-  ) where+  , coreResolver+  )+where -import           Control.Monad.Except                                (liftEither)-import           Control.Monad.Trans.Except                          (runExceptT)-import           Data.Aeson                                          (encode)-import           Data.Aeson.Internal                                 (formatError, ifromJSON)-import           Data.Aeson.Parser                                   (eitherDecodeWith, jsonNoDup)-import qualified Data.ByteString.Lazy.Char8                          as L-import           Data.Functor.Identity                               (Identity (..))-import           Data.Proxy                                          (Proxy (..))+import           Data.Aeson                     ( encode )+import           Data.Aeson.Internal            ( formatError+                                                , ifromJSON+                                                )+import           Data.Aeson.Parser              ( eitherDecodeWith+                                                , jsonNoDup+                                                )+import qualified Data.ByteString.Lazy.Char8    as L+import           Data.Functor.Identity          ( Identity(..) )+import           Data.Proxy                     ( Proxy(..) )  -- MORPHEUS-import           Data.Morpheus.Error.Utils                           (badRequestError)-import           Data.Morpheus.Execution.Internal.GraphScanner       (resolveUpdates)-import           Data.Morpheus.Execution.Server.Encode               (EncodeCon, encodeMutation, encodeQuery,-                                                                      encodeSubscription)-import           Data.Morpheus.Execution.Server.Introspect           (IntroCon, ObjectFields (..))-import           Data.Morpheus.Execution.Subscription.ClientRegister (GQLState, publishUpdates)-import           Data.Morpheus.Parsing.Request.Parser                (parseGQL)+import           Data.Morpheus.Error.Utils      ( badRequestError )+import           Data.Morpheus.Execution.Server.Encode+                                                ( EncodeCon+                                                , encodeMutation+                                                , encodeQuery+                                                , encodeSubscription+                                                )+import           Data.Morpheus.Execution.Server.Introspect+                                                ( IntroCon+                                                , ObjectFields(..)+                                                )+import           Data.Morpheus.Execution.Subscription.ClientRegister+                                                ( GQLState+                                                , publishUpdates+                                                )+import           Data.Morpheus.Parsing.Request.Parser+                                                ( parseGQL ) --import           Data.Morpheus.Schema.Schema                         (Root)-import           Data.Morpheus.Schema.SchemaAPI                      (defaultTypes, hiddenRootFields, schemaAPI)-import           Data.Morpheus.Types.GQLType                         (GQLType (CUSTOM))-import           Data.Morpheus.Types.Internal.AST.Operation          (Operation (..), ValidOperation)-import           Data.Morpheus.Types.Internal.Data                   (DataFingerprint (..), DataTyCon (..),-                                                                      DataTypeLib (..), MUTATION, OperationType (..),-                                                                      QUERY, SUBSCRIPTION, initTypeLib)-import           Data.Morpheus.Types.Internal.Resolver               (GQLRootResolver (..), Resolver (..), ResponseT,-                                                                      toResponseRes)-import           Data.Morpheus.Types.Internal.Stream                 (GQLChannel (..), ResponseEvent (..),-                                                                      ResponseStream, closeStream)-import           Data.Morpheus.Types.Internal.Validation             (Validation)-import           Data.Morpheus.Types.IO                              (GQLRequest (..), GQLResponse (..), renderResponse)-import           Data.Morpheus.Validation.Internal.Utils             (VALIDATION_MODE (..))-import           Data.Morpheus.Validation.Query.Validation           (validateRequest)-import           Data.Typeable                                       (Typeable)+import           Data.Morpheus.Schema.SchemaAPI ( defaultTypes+                                                , hiddenRootFields+                                                , schemaAPI+                                                )+import           Data.Morpheus.Types.GQLType    ( GQLType(CUSTOM) )+import           Data.Morpheus.Types.Internal.AST+                                                ( Operation(..)+                                                , ValidOperation+                                                , DataFingerprint(..)+                                                , DataTyCon(..)+                                                , DataTypeLib(..)+                                                , MUTATION+                                                , OperationType(..)+                                                , QUERY+                                                , SUBSCRIPTION+                                                , initTypeLib+                                                , Value+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( GQLRootResolver(..)+                                                , Resolver(..)+                                                , toResponseRes+                                                , GQLChannel(..)+                                                , ResponseEvent(..)+                                                , ResponseStream+                                                , Validation+                                                , cleanEvents+                                                , ResultT(..)+                                                , unpackEvents+                                                , Failure(..)+                                                , resolveUpdates+                                                )+import           Data.Morpheus.Types.IO         ( GQLRequest(..)+                                                , GQLResponse(..)+                                                , renderResponse+                                                )+import           Data.Morpheus.Validation.Internal.Utils+                                                ( VALIDATION_MODE(..) )+import           Data.Morpheus.Validation.Query.Validation+                                                ( validateRequest )+import           Data.Typeable                  ( Typeable ) -type EventCon event = (Eq (StreamChannel event), Typeable event, GQLChannel event) -type IntrospectConstraint  m event query mutation subscription = (-                                  IntroCon (query (Resolver QUERY m event))-                                 , IntroCon (mutation (Resolver MUTATION m event))-                                 , IntroCon (subscription (Resolver SUBSCRIPTION m event)))+type EventCon event+  = (Eq (StreamChannel event), Typeable event, GQLChannel event) +type IntrospectConstraint m event query mutation subscription+  = ( IntroCon (query (Resolver QUERY event m))+    , IntroCon (mutation (Resolver MUTATION event m))+    , IntroCon (subscription (Resolver SUBSCRIPTION event m))+    )+ type RootResCon m event query mutation subscription-   = ( EventCon event-     , Typeable m-     , IntrospectConstraint m event query mutation subscription-    -- , OBJ_RES m (Root (Resolver m)) Value-     -- Resolving-     , EncodeCon QUERY m event (query (Resolver QUERY m event))-     , EncodeCon MUTATION m event (mutation (Resolver MUTATION m event))-     , EncodeCon SUBSCRIPTION m event (subscription (Resolver SUBSCRIPTION m event)))+  = ( EventCon event+    , Typeable m+    , IntrospectConstraint m event query mutation subscription+    , EncodeCon QUERY event m (query (Resolver QUERY event m))+    , EncodeCon MUTATION event m (mutation (Resolver MUTATION event m))+    , EncodeCon+        SUBSCRIPTION+        event+        m+        (subscription (Resolver SUBSCRIPTION event m))+    ) -decodeNoDup :: L.ByteString -> Either String GQLRequest-decodeNoDup str =-  case eitherDecodeWith jsonNoDup ifromJSON str of-    Left (path, x) -> Left $ formatError path x-    Right value    -> Right value+decodeNoDup :: Failure String m => L.ByteString -> m GQLRequest+decodeNoDup str = case eitherDecodeWith jsonNoDup ifromJSON str of+  Left  (path, x) -> failure $ formatError path x+  Right value     -> pure value -byteStringIO :: Monad m => (GQLRequest -> m GQLResponse) -> L.ByteString -> m L.ByteString-byteStringIO resolver request =-  case decodeNoDup request of-    Left aesonError' -> return $ badRequestError aesonError'-    Right req        -> encode <$> resolver req -statelessResolver ::-     (Monad m, RootResCon m event query mut sub)-  => GQLRootResolver m event  query mut sub+byteStringIO+  :: Monad m => (GQLRequest -> m GQLResponse) -> L.ByteString -> m L.ByteString+byteStringIO resolver request = case decodeNoDup request of+  Left  aesonError' -> return $ badRequestError aesonError'+  Right req         -> encode <$> resolver req++statelessResolver+  :: (Monad m, RootResCon m event query mut sub)+  => GQLRootResolver m event query mut sub   -> GQLRequest   -> m GQLResponse-statelessResolver root = fmap snd . closeStream . streamResolver root+statelessResolver root req =+  renderResponse <$> runResultT (coreResolver root req) -streamResolver ::-     (Monad m, RootResCon m event  query mut sub)+streamResolver+  :: forall event m query mut sub+   . (Monad m, RootResCon m event query mut sub)   => GQLRootResolver m event query mut sub   -> GQLRequest-  -> ResponseStream m event GQLResponse-streamResolver root@GQLRootResolver {queryResolver, mutationResolver, subscriptionResolver} request =-  renderResponse <$> runExceptT (validRequest >>= execOperator)-  -------------------------------------------------------------  where-    ----------------------------------------------------------    validRequest :: Monad m => ResponseT m event (DataTypeLib, ValidOperation)-    validRequest =-      liftEither $ do-        schema <- fullSchema $ Identity root-        query <- parseGQL request >>= validateRequest schema FULL_VALIDATION-        Right (schema, query)-    -----------------------------------------------------------    execOperator (schema, operation@Operation {operationType = Query}) =-        toResponseRes (encodeQuery (schemaAPI schema) queryResolver operation)-    execOperator (_, operation@Operation {operationType = Mutation}) = toResponseRes (encodeMutation mutationResolver operation)-    execOperator (_, operation@Operation {operationType = Subscription}) = response-        where-         response = toResponseRes (encodeSubscription subscriptionResolver operation)+  -> ResponseStream event m GQLResponse+streamResolver root req =+  ResultT $ pure . renderResponse <$> runResultT (coreResolver root req) -statefulResolver ::-     EventCon s-  => GQLState IO s-  -> (L.ByteString -> ResponseStream IO s  L.ByteString)+coreResolver+  :: forall event m query mut sub+   . (Monad m, RootResCon m event query mut sub)+  => GQLRootResolver m event query mut sub+  -> GQLRequest+  -> ResponseStream event m Value+coreResolver root@GQLRootResolver { queryResolver, mutationResolver, subscriptionResolver } request+  = validRequest >>= execOperator+ where+  validRequest+    :: Monad m => ResponseStream event m (DataTypeLib, ValidOperation)+  validRequest = cleanEvents $ ResultT $ pure $ do+    schema <- fullSchema $ Identity root+    query  <- parseGQL request >>= validateRequest schema FULL_VALIDATION+    pure (schema, query)+  ----------------------------------------------------------+  execOperator (schema, operation@Operation { operationType = Query }) =+    toResponseRes (encodeQuery (schemaAPI schema) queryResolver operation)+  execOperator (_, operation@Operation { operationType = Mutation }) =+    toResponseRes (encodeMutation mutationResolver operation)+  execOperator (_, operation@Operation { operationType = Subscription }) =+    response+   where+    response =+      toResponseRes (encodeSubscription subscriptionResolver operation)++statefulResolver+  :: EventCon event+  => GQLState IO event+  -> (GQLRequest -> ResponseStream event IO Value)   -> L.ByteString   -> IO L.ByteString-statefulResolver state streamApi request = do-  (actions, value) <- closeStream (streamApi request)-  mapM_ execute actions-  pure value-  where-    execute (Publish updates) = publishUpdates state updates-    execute Subscribe {}      = pure ()+statefulResolver state streamApi requestText = do+  res <- runResultT (decodeNoDup requestText >>= streamApi)+  mapM_ execute (unpackEvents res)+  pure $ encode $ renderResponse res+ where+  execute (Publish updates) = publishUpdates state updates+  execute Subscribe{}       = pure () -fullSchema ::-     forall proxy m event query mutation subscription. (IntrospectConstraint m event query mutation subscription)++fullSchema+  :: forall proxy m event query mutation subscription+   . (IntrospectConstraint m event query mutation subscription)   => proxy (GQLRootResolver m event query mutation subscription)   -> Validation DataTypeLib fullSchema _ = querySchema >>= mutationSchema >>= subscriptionSchema-  where-    querySchema =-      resolveUpdates (initTypeLib (operatorType (hiddenRootFields ++ fields) "Query")) (defaultTypes : types)-      where-        (fields, types) = objectFields (Proxy @(CUSTOM (query (Resolver QUERY m event)))) (Proxy @(query (Resolver QUERY m event)))-    -------------------------------    mutationSchema lib = resolveUpdates (lib {mutation = maybeOperator fields "Mutation"}) types-      where-        (fields, types) = objectFields (Proxy @(CUSTOM (mutation (Resolver MUTATION m event)))) (Proxy @(mutation (Resolver MUTATION m event)))-    -------------------------------    subscriptionSchema lib = resolveUpdates (lib {subscription = maybeOperator fields "Subscription"}) types-      where-        (fields, types) = objectFields (Proxy @(CUSTOM (subscription (Resolver SUBSCRIPTION m event)))) (Proxy @(subscription (Resolver SUBSCRIPTION m event)))-     -- maybeOperator :: [a] -> Text -> Maybe (Text, DataTyCon[a])-    maybeOperator []     = const Nothing-    maybeOperator fields = Just . operatorType fields-    -- operatorType :: [a] -> Text -> (Text, DataTyCon[a])-    operatorType typeData typeName =-      ( typeName-      , DataTyCon {typeData, typeName, typeFingerprint = SystemFingerprint typeName, typeDescription = Nothing})+ where+  querySchema = resolveUpdates+    (initTypeLib (operatorType (hiddenRootFields ++ fields) "Query"))+    (defaultTypes : types)+   where+    (fields, types) = objectFields+      (Proxy @(CUSTOM (query (Resolver QUERY event m))))+      (Proxy @(query (Resolver QUERY event m)))+  ------------------------------+  mutationSchema lib = resolveUpdates+    (lib { mutation = maybeOperator fields "Mutation" })+    types+   where+    (fields, types) = objectFields+      (Proxy @(CUSTOM (mutation (Resolver MUTATION event m))))+      (Proxy @(mutation (Resolver MUTATION event m)))+  ------------------------------+  subscriptionSchema lib = resolveUpdates+    (lib { subscription = maybeOperator fields "Subscription" })+    types+   where+    (fields, types) = objectFields+      (Proxy @(CUSTOM (subscription (Resolver SUBSCRIPTION event m))))+      (Proxy @(subscription (Resolver SUBSCRIPTION event m)))+   -- maybeOperator :: [a] -> Text -> Maybe (Text, DataTyCon[a])+  maybeOperator []     = const Nothing+  maybeOperator fields = Just . operatorType fields+  -- operatorType :: [a] -> Text -> (Text, DataTyCon[a])+  operatorType typeData typeName =+    ( typeName+    , DataTyCon { typeData+                , typeName+                , typeFingerprint = SystemFingerprint typeName+                , typeMeta        = Nothing+                }+    )
src/Data/Morpheus/Execution/Subscription/ClientRegister.hs view
@@ -10,25 +10,41 @@   , publishUpdates   , addClientSubscription   , removeClientSubscription-  ) where+  )+where -import           Control.Concurrent                          (MVar, modifyMVar, modifyMVar_, newMVar, readMVar)-import           Data.Foldable                               (traverse_)-import           Data.List                                   (intersect)-import           Data.Text                                   (Text)-import           Data.UUID.V4                                (nextRandom)-import           Network.WebSockets                          (Connection, sendTextData)- +import           Control.Concurrent             ( MVar+                                                , modifyMVar+                                                , modifyMVar_+                                                , newMVar+                                                , readMVar+                                                )+import           Data.Foldable                  ( traverse_ )+import           Data.List                      ( intersect )+import           Data.Text                      ( Text )+import           Data.UUID.V4                   ( nextRandom )+import           Network.WebSockets             ( Connection+                                                , sendTextData+                                                ) -- MORPHEUS-import           Data.Morpheus.Execution.Subscription.Apollo (toApolloResponse)-import           Data.Morpheus.Types.Internal.Stream         (Event (..),GQLChannel(..),  SubEvent)-import           Data.Morpheus.Types.Internal.WebSocket      (ClientID, ClientSession (..), GQLClient (..))+import           Data.Morpheus.Execution.Subscription.Apollo+                                                ( toApolloResponse )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Event(..)+                                                , GQLChannel(..)+                                                , SubEvent+                                                )+import           Data.Morpheus.Types.Internal.WebSocket+                                                ( ClientID+                                                , ClientSession(..)+                                                , GQLClient(..)+                                                ) -type ClientRegister m e  = [(ClientID, GQLClient m e)]+type ClientRegister m e = [(ClientID, GQLClient m e)]  -- | shared GraphQL state between __websocket__ and __http__ server, -- stores information about subscriptions-type GQLState m e  = MVar (ClientRegister m e ) -- SharedState+type GQLState m e = MVar (ClientRegister m e) -- SharedState  -- | initializes empty GraphQL state initGQLState :: IO (GQLState m e)@@ -39,71 +55,70 @@   client' <- newClient   modifyMVar_ varState' (addClient client')   return (snd client')-  where-    newClient = do-      clientID <- nextRandom-      return-        (clientID, GQLClient {clientID, clientConnection, clientSessions = []})-    addClient client' state' = return (client' : state')+ where+  newClient = do+    clientID <- nextRandom+    return+      (clientID, GQLClient { clientID, clientConnection, clientSessions = [] })+  addClient client' state' = return (client' : state') -disconnectClient ::-     GQLClient m e  -> GQLState m e -> IO (ClientRegister m e)+disconnectClient :: GQLClient m e -> GQLState m e -> IO (ClientRegister m e) disconnectClient client state = modifyMVar state removeUser-  where-    removeUser state' =-      let s' = removeClient state'-       in return (s', s')-    removeClient :: ClientRegister m e  -> ClientRegister m e-    removeClient = filter ((/= clientID client) . fst)+ where+  removeUser state' = let s' = removeClient state' in return (s', s')+  removeClient :: ClientRegister m e -> ClientRegister m e+  removeClient = filter ((/= clientID client) . fst) -updateClientByID ::-     ClientID+updateClientByID+  :: ClientID   -> (GQLClient m e -> GQLClient m e)-  -> MVar (ClientRegister m e )+  -> MVar (ClientRegister m e)   -> IO ()-updateClientByID id' updateFunc state =-  modifyMVar_ state (return . map updateClient)-  where-    updateClient (key', client')-      | key' == id' = (key', updateFunc client')-    updateClient state' = state'+updateClientByID id' updateFunc state = modifyMVar_+  state+  (return . map updateClient)+ where+  updateClient (key, client') | key == id' = (key, updateFunc client')+  updateClient state'                      = state' -publishUpdates :: (Eq (StreamChannel e), GQLChannel e) => GQLState IO e -> e -> IO ()+publishUpdates+  :: (Eq (StreamChannel e), GQLChannel e) => GQLState IO e -> e -> IO () publishUpdates state event = do   state' <- readMVar state   traverse_ sendMessage state'-  where-    sendMessage (_, GQLClient {clientSessions = []}) = return ()-    sendMessage (_, GQLClient {clientSessions, clientConnection}) =-      mapM_ __send (filterByChannels clientSessions)-      where-        __send ClientSession { sessionId-                             , sessionSubscription = Event {content = subscriptionRes}-                             } =-          subscriptionRes event >>=-          sendTextData clientConnection . toApolloResponse sessionId-        filterByChannels =-          filter-            (not . null .-             intersect (streamChannels event) . channels . sessionSubscription)+ where+  sendMessage (_, GQLClient { clientSessions = [] }             ) = return ()+  sendMessage (_, GQLClient { clientSessions, clientConnection }) = mapM_+    __send+    (filterByChannels clientSessions)+   where+    __send ClientSession { sessionId, sessionSubscription = Event { content = subscriptionRes } }+      = subscriptionRes event+        >>= sendTextData clientConnection+        .   toApolloResponse sessionId+    ---------------------------+    filterByChannels = filter+      ( not+      . null+      . intersect (streamChannels event)+      . channels+      . sessionSubscription+      ) -removeClientSubscription :: ClientID -> Text -> GQLState m e  -> IO ()+removeClientSubscription :: ClientID -> Text -> GQLState m e -> IO () removeClientSubscription id' sid' = updateClientByID id' stopSubscription-  where-    stopSubscription client' =-      client'-        { clientSessions =-            filter ((sid' /=) . sessionId) (clientSessions client')-        }+ where+  stopSubscription client' = client'+    { clientSessions = filter ((sid' /=) . sessionId) (clientSessions client')+    } -addClientSubscription ::-     ClientID -> SubEvent m e  -> Text -> GQLState m e  -> IO ()-addClientSubscription id' sessionSubscription sessionId =-  updateClientByID id' startSubscription-  where-    startSubscription client' =-      client'-        { clientSessions =-            ClientSession {sessionId, sessionSubscription} :-            clientSessions client'-        }+addClientSubscription+  :: ClientID -> SubEvent m e -> Text -> GQLState m e -> IO ()+addClientSubscription id' sessionSubscription sessionId = updateClientByID+  id'+  startSubscription+ where+  startSubscription client' = client'+    { clientSessions = ClientSession { sessionId, sessionSubscription }+                         : clientSessions client'+    }
src/Data/Morpheus/Kind.hs view
@@ -16,9 +16,11 @@   , Context(..)   , VContext(..)   , ResContext(..)-  ) where+  )+where -import           Data.Morpheus.Types.Internal.Data (OperationType (..))+import           Data.Morpheus.Types.Internal.AST+                                                ( OperationType(..) )  data GQL_KIND   = SCALAR@@ -30,7 +32,7 @@   | WRAPPER  -data ResContext (kind :: GQL_KIND) (operation:: OperationType) (m :: * -> * ) event value = ResContext+data ResContext (kind :: GQL_KIND) (operation:: OperationType) event (m :: * -> * )  value = ResContext  --type ObjectConstraint a = -- | context , like Proxy with multiple parameters
src/Data/Morpheus/Parsing/Document/Parser.hs view
@@ -1,28 +1,37 @@-{-# LANGUAGE NamedFieldPuns    #-} {-# LANGUAGE OverloadedStrings #-}  module Data.Morpheus.Parsing.Document.Parser   ( parseTypes-  ) where+  )+where -import           Data.Text                                 (Text)-import           Text.Megaparsec                           (eof, label, manyTill, runParser)+import           Data.Text                      ( Text )+import           Text.Megaparsec                ( eof+                                                , label+                                                , manyTill+                                                , runParser+                                                )  -- MORPHEUS-import           Data.Morpheus.Parsing.Document.TypeSystem (parseDataType)-import           Data.Morpheus.Parsing.Internal.Internal   (processErrorBundle)-import           Data.Morpheus.Parsing.Internal.Terms      (spaceAndComments)-import           Data.Morpheus.Types.Internal.Data         (RawDataType)-import           Data.Morpheus.Types.Internal.Validation   (Validation)+import           Data.Morpheus.Parsing.Document.TypeSystem+                                                ( parseDataType )+import           Data.Morpheus.Parsing.Internal.Internal+                                                ( processErrorBundle )+import           Data.Morpheus.Parsing.Internal.Terms+                                                ( spaceAndComments )+import           Data.Morpheus.Types.Internal.AST+                                                ( RawDataType )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Validation+                                                , Failure(..)+                                                )  parseTypes :: Text -> Validation [(Text, RawDataType)]-parseTypes doc =-  case parseDoc of-    Right root      -> Right root-    Left parseError -> Left $ processErrorBundle parseError-  where-    parseDoc = runParser request "<input>" doc-    request =-      label "DocumentTypes" $ do-        spaceAndComments-        manyTill parseDataType eof+parseTypes doc = case parseDoc of+  Right root       -> pure root+  Left  parseError -> failure (processErrorBundle parseError)+ where+  parseDoc = runParser request "<input>" doc+  request  = label "DocumentTypes" $ do+    spaceAndComments+    manyTill parseDataType eof
src/Data/Morpheus/Parsing/Document/TypeSystem.hs view
@@ -3,20 +3,44 @@  module Data.Morpheus.Parsing.Document.TypeSystem   ( parseDataType-  ) where+  )+where -import           Data.Text                               (Text)-import           Text.Megaparsec                         (label, sepBy1, (<|>))+import           Data.Text                      ( Text )+import           Text.Megaparsec                ( label+                                                , sepBy1+                                                , (<|>)+                                                )  -- MORPHEUS-import           Data.Morpheus.Parsing.Internal.Create   (createField)-import           Data.Morpheus.Parsing.Internal.Internal (Parser)-import           Data.Morpheus.Parsing.Internal.Pattern  (fieldsDefinition, inputValueDefinition, optionalDirectives,-                                                          typDeclaration)-import           Data.Morpheus.Parsing.Internal.Terms    (keyword, operator, optDescription, parseName, pipeLiteral,-                                                          sepByAnd, setOf)-import           Data.Morpheus.Types.Internal.Data       (DataField, DataFingerprint (..), DataType (..),-                                                          DataTyCon (..), DataValidator (..), Key, RawDataType (..))+import           Data.Morpheus.Parsing.Internal.Internal+                                                ( Parser )+import           Data.Morpheus.Parsing.Internal.Pattern+                                                ( fieldsDefinition+                                                , inputValueDefinition+                                                , optionalDirectives+                                                , typDeclaration+                                                , enumValueDefinition+                                                )+import           Data.Morpheus.Parsing.Internal.Terms+                                                ( keyword+                                                , operator+                                                , optDescription+                                                , parseName+                                                , pipeLiteral+                                                , sepByAnd+                                                , setOf+                                                )+import           Data.Morpheus.Types.Internal.AST+                                                ( DataField+                                                , DataFingerprint(..)+                                                , DataTyCon(..)+                                                , DataType(..)+                                                , DataValidator(..)+                                                , Key+                                                , RawDataType(..)+                                                , Meta(..)+                                                )   -- Scalars : https://graphql.github.io/graphql-spec/June2018/#sec-Scalars@@ -25,20 +49,18 @@ --    Description(opt) scalar Name Directives(Const)(opt) -- scalarTypeDefinition :: Maybe Text -> Parser (Text, DataType)-scalarTypeDefinition typeDescription =-  label "ScalarTypeDefinition" $ do-    typeName <- typDeclaration "scalar"-    -- TODO: handle directives-    _ <- optionalDirectives-    pure (-          typeName,-          DataScalar DataTyCon {-            typeName,-            typeDescription,-            typeFingerprint = SystemFingerprint typeName,-            typeData = DataValidator pure-          }-        )+scalarTypeDefinition metaDescription = label "ScalarTypeDefinition" $ do+  typeName       <- typDeclaration "scalar"+  metaDirectives <- optionalDirectives+  pure+    ( typeName+    , DataScalar DataTyCon+      { typeName+      , typeMeta        = Just Meta { metaDescription, metaDirectives }+      , typeFingerprint = SystemFingerprint typeName+      , typeData        = DataValidator pure+      }+    )  -- Objects : https://graphql.github.io/graphql-spec/June2018/#sec-Objects --@@ -56,27 +78,27 @@ --    Description(opt) Name ArgumentsDefinition(opt) : Type Directives(Const)(opt) -- objectTypeDefinition :: Maybe Text -> Parser (Text, RawDataType)-objectTypeDefinition typeDescription =-  label "ObjectTypeDefinition" $ do-    name <- typDeclaration "type"-    interfaces <- optionalImplementsInterfaces-    -- TODO: handle directives-    _directives <- optionalDirectives-    fields <- fieldsDefinition-    ---------------------------    pure (name,-         Implements interfaces $ DataTyCon {-           typeName = name,-           typeDescription,-           typeFingerprint = SystemFingerprint name,-           typeData = fields-         }-      )+objectTypeDefinition metaDescription = label "ObjectTypeDefinition" $ do+  name           <- typDeclaration "type"+  interfaces     <- optionalImplementsInterfaces+  metaDirectives <- optionalDirectives+  fields         <- fieldsDefinition+  --------------------------+  pure+    ( name+    , Implements interfaces $ DataTyCon+      { typeName        = name+      , typeMeta        = Just Meta { metaDescription, metaDirectives }+      , typeFingerprint = SystemFingerprint name+      , typeData        = fields+      }+    )  optionalImplementsInterfaces :: Parser [Text] optionalImplementsInterfaces = implements <|> pure []-  where-    implements = label "ImplementsInterfaces" $ keyword "implements" *> sepByAnd parseName+ where+  implements =+    label "ImplementsInterfaces" $ keyword "implements" *> sepByAnd parseName  -- Interfaces: https://graphql.github.io/graphql-spec/June2018/#sec-Interfaces --@@ -84,21 +106,19 @@ --    Description(opt) interface Name Directives(Const)(opt) FieldsDefinition(opt) -- interfaceTypeDefinition :: Maybe Text -> Parser (Text, RawDataType)-interfaceTypeDefinition typeDescription =-  label "InterfaceTypeDefinition" $ do-    typeName <- typDeclaration "interface"-    -- TODO: handle directives-    _directives <- optionalDirectives-    fields <- fieldsDefinition-    pure (-        typeName,-        Interface DataTyCon {-           typeName,-           typeDescription,-           typeFingerprint = SystemFingerprint typeName,-           typeData = fields-           }-        )+interfaceTypeDefinition metaDescription = label "InterfaceTypeDefinition" $ do+  typeName       <- typDeclaration "interface"+  metaDirectives <- optionalDirectives+  fields         <- fieldsDefinition+  pure+    ( typeName+    , Interface DataTyCon+      { typeName+      , typeMeta        = Just Meta { metaDescription, metaDirectives }+      , typeFingerprint = SystemFingerprint typeName+      , typeData        = fields+      }+    )   -- Unions : https://graphql.github.io/graphql-spec/June2018/#sec-Unions@@ -110,25 +130,21 @@ --    = |(opt) NamedType --      UnionMemberTypes | NamedType ---unionTypeDefinition :: Maybe Text ->  Parser (Text, DataType)-unionTypeDefinition typeDescription =-  label "UnionTypeDefinition" $ do-    typeName <- typDeclaration "union"-    -- TODO: handle directives-    _directives <- optionalDirectives-    memberTypes <- unionMemberTypes-    pure (-        typeName,-        DataUnion DataTyCon {-             typeName,-             typeDescription,-             typeFingerprint = SystemFingerprint typeName,-             typeData = map unionField memberTypes-           }-        )-  where-    unionField fieldType = createField [] "" ([], fieldType)-    unionMemberTypes = operator '=' *> parseName `sepBy1` pipeLiteral+unionTypeDefinition :: Maybe Text -> Parser (Text, DataType)+unionTypeDefinition metaDescription = label "UnionTypeDefinition" $ do+  typeName       <- typDeclaration "union"+  metaDirectives <- optionalDirectives+  memberTypes    <- unionMemberTypes+  pure+    ( typeName+    , DataUnion DataTyCon+      { typeName+      , typeMeta        = Just Meta { metaDescription, metaDirectives }+      , typeFingerprint = SystemFingerprint typeName+      , typeData        = memberTypes+      }+    )+  where unionMemberTypes = operator '=' *> parseName `sepBy1` pipeLiteral  -- Enums : https://graphql.github.io/graphql-spec/June2018/#sec-Enums --@@ -142,30 +158,21 @@ --    Description(opt) EnumValue Directives(Const)(opt) -- enumTypeDefinition :: Maybe Text -> Parser (Text, DataType)-enumTypeDefinition typeDescription =-  label "EnumTypeDefinition" $ do-    typeName <- typDeclaration "enum"-    -- TODO: handle directives-    _directives <- optionalDirectives-    enumValuesDefinition <- setOf enumValueDefinition-    pure (-           typeName,-           DataEnum DataTyCon {-             typeName,-             typeDescription,-             typeFingerprint = SystemFingerprint typeName,-             typeData = enumValuesDefinition-           }-        )-    where-        enumValueDefinition = label "EnumValueDefinition" $ do-            -- TODO: handle Description-            _fieldDescription <- optDescription-            enumValueName <- parseName-            -- TODO: handle directives-            _directive <- optionalDirectives-            return enumValueName+enumTypeDefinition metaDescription = label "EnumTypeDefinition" $ do+  typeName              <- typDeclaration "enum"+  metaDirectives        <- optionalDirectives+  enumValuesDefinitions <- setOf enumValueDefinition+  pure+    ( typeName+    , DataEnum DataTyCon+      { typeName+      , typeMeta        = Just Meta { metaDescription, metaDirectives }+      , typeFingerprint = SystemFingerprint typeName+      , typeData        = enumValuesDefinitions+      }+    ) + -- Input Objects : https://graphql.github.io/graphql-spec/June2018/#sec-Input-Objects -- --   InputObjectTypeDefinition@@ -175,43 +182,44 @@ --     { InputValueDefinition(list) } -- inputObjectTypeDefinition :: Maybe Text -> Parser (Text, DataType)-inputObjectTypeDefinition typeDescription =+inputObjectTypeDefinition metaDescription =   label "InputObjectTypeDefinition" $ do-    typeName <- typDeclaration "input"-    -- TODO: handle directives-    _directives <- optionalDirectives-    fields <- inputFieldsDefinition+    typeName       <- typDeclaration "input"+    metaDirectives <- optionalDirectives+    fields         <- inputFieldsDefinition     pure-       (-         typeName,-         DataInputObject DataTyCon {-           typeName,-           typeDescription,-           typeFingerprint = SystemFingerprint typeName,-           typeData = fields-         }-       )-    where-      inputFieldsDefinition :: Parser [(Key, DataField)]-      inputFieldsDefinition = label "InputFieldsDefinition" $ setOf inputValueDefinition+      ( typeName+      , DataInputObject DataTyCon+        { typeName+        , typeMeta        = Just Meta { metaDescription, metaDirectives }+        , typeFingerprint = SystemFingerprint typeName+        , typeData        = fields+        }+      )+ where+  inputFieldsDefinition :: Parser [(Key, DataField)]+  inputFieldsDefinition =+    label "InputFieldsDefinition" $ setOf inputValueDefinition   parseFinalDataType :: Maybe Text -> Parser (Text, DataType)-parseFinalDataType description = label "TypeDefinition" $-        inputObjectTypeDefinition description+parseFinalDataType description =+  label "TypeDefinition"+    $   inputObjectTypeDefinition description     <|> unionTypeDefinition description     <|> enumTypeDefinition description     <|> scalarTypeDefinition description  parseDataType :: Parser (Text, RawDataType) parseDataType = label "TypeDefinition" $ do-    description <- optDescription-    types description-    where-      types description = interfaceTypeDefinition description <|>-              objectTypeDefinition description <|>-              finalDataT-              where-                finalDataT = do-                  (name, datatype) <- parseFinalDataType description-                  pure (name, FinalDataType datatype)+  description <- optDescription+  types description+ where+  types description =+    interfaceTypeDefinition description+      <|> objectTypeDefinition description+      <|> finalDataT+   where+    finalDataT = do+      (name, datatype) <- parseFinalDataType description+      pure (name, FinalDataType datatype)
− src/Data/Morpheus/Parsing/Internal/Create.hs
@@ -1,67 +0,0 @@-{-# LANGUAGE NamedFieldPuns    #-}-{-# LANGUAGE OverloadedStrings #-}--module Data.Morpheus.Parsing.Internal.Create-  ( createField-  , createArgument-  , createType-  , createScalarType-  , createEnumType-  , createUnionType-  , createDataTypeLib-  ) where--import           Data.Text                               (Text)---- MORPHEUS-import           Data.Morpheus.Error.Internal            (internalError)-import           Data.Morpheus.Types.Internal.Data       (DataArguments, DataField (..), DataFingerprint (..),-                                                          DataTyCon (..), DataType (..), DataTypeLib (..),-                                                          DataValidator (..), TypeAlias (..), WrapperD, defineType,-                                                          initTypeLib)-import           Data.Morpheus.Types.Internal.Validation (Validation)---createField :: DataArguments -> Text -> ([WrapperD], Text) -> DataField-createField fieldArgs fieldName (aliasWrappers, aliasTyCon) =-  DataField-    { fieldArgs-    , fieldArgsType = Nothing-    , fieldName-    , fieldType = TypeAlias {aliasTyCon, aliasWrappers, aliasArgs = Nothing}-    , fieldHidden = False-    }--createArgument :: Text -> ([WrapperD], Text) -> (Text, DataField)-createArgument fieldName x = (fieldName, createField [] fieldName x)--createType :: Text -> a -> DataTyCon a-createType typeName typeData =-  DataTyCon {typeName, typeDescription = Nothing, typeFingerprint = SystemFingerprint "", typeData}--createScalarType :: Text -> (Text, DataType)-createScalarType typeName = (typeName, DataScalar $ createType typeName (DataValidator pure))--createEnumType :: Text -> [Text] -> (Text, DataType)-createEnumType typeName typeData = (typeName, DataEnum $ createType typeName typeData)--createUnionType :: Text -> [Text] -> (Text, DataType)-createUnionType typeName typeData = (typeName, DataUnion $ createType typeName $ map unionField typeData)-  where-    unionField fieldType = createField [] "" ([], fieldType)--createDataTypeLib :: [(Text, DataType)] -> Validation DataTypeLib-createDataTypeLib types =-  case takeByKey "Query" types of-    (Just query, lib1) ->-      case takeByKey "Mutation" lib1 of-        (mutation, lib2) ->-          case takeByKey "Subscription" lib2 of-            (subscription, lib3) -> pure ((foldr defineType (initTypeLib query) lib3) {mutation, subscription})-    _ -> internalError "Query Not Defined"-  -----------------------------------------------------------------------------  where-    takeByKey key lib =-      case lookup key lib of-        Just (DataObject value) -> (Just (key, value), filter ((/= key) . fst) lib)-        _                       -> (Nothing, lib)
src/Data/Morpheus/Parsing/Internal/Internal.hs view
@@ -5,31 +5,52 @@   , Position   , processErrorBundle   , getLocation-  ) where+  )+where -import qualified Data.List.NonEmpty                      as NonEmpty-import           Data.Morpheus.Error.Utils               (toLocation)-import           Data.Morpheus.Types.Internal.Base       (Location)-import           Data.Morpheus.Types.Internal.Validation (GQLError (..), GQLErrors)-import           Data.Text                               (Text, pack)-import           Data.Void                               (Void)-import           Text.Megaparsec                         (ParseError, ParseErrorBundle (ParseErrorBundle), Parsec,-                                                          SourcePos, attachSourcePos, bundleErrors, bundlePosState,-                                                          errorOffset, getSourcePos, parseErrorPretty)+import qualified Data.List.NonEmpty            as NonEmpty+import           Data.Morpheus.Error.Utils      ( toLocation )+import           Data.Morpheus.Types.Internal.AST+                                                ( Position )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( GQLError(..)+                                                , GQLErrors+                                                )+import           Data.Text                      ( Text+                                                , pack+                                                )+import           Data.Void                      ( Void )+import           Text.Megaparsec                ( ParseError+                                                , ParseErrorBundle+                                                  ( ParseErrorBundle+                                                  )+                                                , Parsec+                                                , SourcePos+                                                , attachSourcePos+                                                , bundleErrors+                                                , bundlePosState+                                                , errorOffset+                                                , getSourcePos+                                                , parseErrorPretty+                                                ) -type Position = Location -getLocation :: Parser Location+getLocation :: Parser Position getLocation = fmap toLocation getSourcePos  type Parser = Parsec Void Text  processErrorBundle :: ParseErrorBundle Text Void -> GQLErrors processErrorBundle = fmap parseErrorToGQLError . bundleToErrors-  where-    parseErrorToGQLError :: (ParseError Text Void, SourcePos) -> GQLError-    parseErrorToGQLError (err, position) =-      GQLError {desc = pack (parseErrorPretty err), positions = [toLocation position]}-    bundleToErrors :: ParseErrorBundle Text Void -> [(ParseError Text Void, SourcePos)]-    bundleToErrors ParseErrorBundle {bundleErrors, bundlePosState} =-      NonEmpty.toList $ fst $ attachSourcePos errorOffset bundleErrors bundlePosState+ where+  parseErrorToGQLError :: (ParseError Text Void, SourcePos) -> GQLError+  parseErrorToGQLError (err, position) = GQLError+    { message   = pack (parseErrorPretty err)+    , locations = [toLocation position]+    }+  bundleToErrors+    :: ParseErrorBundle Text Void -> [(ParseError Text Void, SourcePos)]+  bundleToErrors ParseErrorBundle { bundleErrors, bundlePosState } =+    NonEmpty.toList $ fst $ attachSourcePos errorOffset+                                            bundleErrors+                                            bundlePosState
src/Data/Morpheus/Parsing/Internal/Pattern.hs view
@@ -1,38 +1,89 @@+{-# LANGUAGE NamedFieldPuns #-}+ module Data.Morpheus.Parsing.Internal.Pattern-  ( inputValueDefinition-  , fieldsDefinition-  , typDeclaration-  , optionalDirectives-  ) where+    ( inputValueDefinition+    , fieldsDefinition+    , typDeclaration+    , optionalDirectives+    , enumValueDefinition+    )+where  -import           Text.Megaparsec                         (label, many)+import           Text.Megaparsec                ( label+                                                , many+                                                )  -- MORPHEUS-import           Data.Morpheus.Parsing.Internal.Create   (createField)-import           Data.Morpheus.Parsing.Internal.Internal (Parser)-import           Data.Morpheus.Parsing.Internal.Terms    (keyword, optDescription, litAssignment, operator, parseAssignment,-                                                          parseMaybeTuple, parseName, parseType, setOf)-import           Data.Morpheus.Parsing.Internal.Value    (parseDefaultValue, parseValue)-import           Data.Morpheus.Types.Internal.Data       (DataField, Key, Name)+import           Data.Morpheus.Parsing.Internal.Internal+                                                ( Parser )+import           Data.Morpheus.Parsing.Internal.Terms+                                                ( keyword+                                                , litAssignment+                                                , operator+                                                , optDescription+                                                , parseAssignment+                                                , parseMaybeTuple+                                                , parseName+                                                , parseType+                                                , setOf+                                                )+import           Data.Morpheus.Parsing.Internal.Value+                                                ( parseDefaultValue+                                                , parseValue+                                                )+import           Data.Morpheus.Types.Internal.AST+                                                ( DataField(..)+                                                , Directive(..)+                                                , Key+                                                , Meta(..)+                                                , DataEnumValue(..)+                                                , Name+                                                , TypeAlias(..)+                                                )  +--  EnumValueDefinition: https://graphql.github.io/graphql-spec/June2018/#EnumValueDefinition+--+--  EnumValueDefinition+--    Description(opt) EnumValue Directives(Const)(opt)+--+enumValueDefinition :: Parser DataEnumValue+enumValueDefinition = label "EnumValueDefinition" $ do+    metaDescription <- optDescription+    enumName        <- parseName+    metaDirectives  <- optionalDirectives+    return $ DataEnumValue+        { enumName+        , enumMeta = Just Meta { metaDescription, metaDirectives }+        }+ -- InputValue : https://graphql.github.io/graphql-spec/June2018/#InputValueDefinition -- -- InputValueDefinition --   Description(opt) Name : Type DefaultValue(opt) Directives (Const)(opt) ---inputValueDefinition ::  Parser (Key, DataField)+inputValueDefinition :: Parser (Key, DataField) inputValueDefinition = label "InputValueDefinition" $ do-    -- TODO: handle Description(opt)-    _description <- optDescription-    name <- parseName+    metaDescription <- optDescription+    fieldName       <- parseName     litAssignment -- ':'-    type_ <- parseType-    -- TODO: handle default value-    _ <- parseDefaultValue-    _ <- optionalDirectives-    pure (name, createField [] name type_)+    (aliasWrappers, aliasTyCon) <- parseType+    _                           <- parseDefaultValue+    metaDirectives              <- optionalDirectives+    pure+        ( fieldName+        , DataField+            { fieldArgs     = []+            , fieldArgsType = Nothing+            , fieldName+            , fieldType     = TypeAlias { aliasTyCon+                                        , aliasWrappers+                                        , aliasArgs     = Nothing+                                        }+            , fieldMeta     = Just Meta { metaDescription, metaDirectives }+            }+        )  -- Field Arguments: https://graphql.github.io/graphql-spec/June2018/#sec-Field-Arguments --@@ -40,7 +91,8 @@ --   ( InputValueDefinition(list) ) -- argumentsDefinition :: Parser [(Key, DataField)]-argumentsDefinition = label "ArgumentsDefinition" $  parseMaybeTuple inputValueDefinition+argumentsDefinition =+    label "ArgumentsDefinition" $ parseMaybeTuple inputValueDefinition   --  FieldsDefinition : https://graphql.github.io/graphql-spec/June2018/#FieldsDefinition@@ -55,17 +107,27 @@ --  FieldDefinition --    Description(opt) Name ArgumentsDefinition(opt) : Type Directives(Const)(opt) ---fieldDefinition ::  Parser (Key, DataField)-fieldDefinition  = label "FieldDefinition" $ do-    -- TODO: handle Description(opt)-    _description <- optDescription-    name <- parseName-    args <- argumentsDefinition+fieldDefinition :: Parser (Key, DataField)+fieldDefinition = label "FieldDefinition" $ do+    metaDescription <- optDescription+    fieldName       <- parseName+    fieldArgs       <- argumentsDefinition     litAssignment -- ':'-    type_ <- parseType-    -- TODO: handle directives-    _ <- optionalDirectives-    pure (name, createField args name type_)+    (aliasWrappers, aliasTyCon) <- parseType+    metaDirectives              <- optionalDirectives+    pure+        ( fieldName+        , DataField+            { fieldName+            , fieldArgs+            , fieldArgsType = Nothing+            , fieldType     = TypeAlias { aliasTyCon+                                        , aliasWrappers+                                        , aliasArgs     = Nothing+                                        }+            , fieldMeta     = Just Meta { metaDescription, metaDirectives }+            }+        )  -- Directives : https://graphql.github.io/graphql-spec/June2018/#sec-Language.Directives --@@ -74,19 +136,18 @@ -- Directives[Const] -- Directive[Const](list) ---optionalDirectives :: Parser [()]+optionalDirectives :: Parser [Directive] optionalDirectives = label "Directives" $ many directive  -- Directive[Const] -- -- @ Name Arguments[Const](opt)--- TODO:  returns real DataType-directive :: Parser ()+directive :: Parser Directive directive = label "Directive" $ do     operator '@'-    _name <- parseName-    _args <- parseMaybeTuple (parseAssignment parseName parseValue)-    pure ()+    directiveName <- parseName+    directiveArgs <- parseMaybeTuple (parseAssignment parseName parseValue)+    pure Directive { directiveName, directiveArgs }   -- typDeclaration : Not in spec ,start part of type definitions@@ -96,5 +157,5 @@ -- typDeclaration :: Name -> Parser Name typDeclaration kind = do-  keyword kind-  parseName+    keyword kind+    parseName
src/Data/Morpheus/Parsing/Internal/Terms.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE NamedFieldPuns    #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TupleSections     #-} @@ -27,19 +26,52 @@   , keyword   , operator   , optDescription-  ) where+  )+where -import           Data.Functor                            (($>))-import           Data.Text                               (Text, pack)-import           Text.Megaparsec                         (between, label,try, many, manyTill, optional, sepBy, sepEndBy,-                                                          skipMany, skipManyTill, try, (<?>), (<|>))-import           Text.Megaparsec.Char                    (char, digitChar, letterChar, newline, printChar, space,-                                                          space1, string)+import           Data.Functor                   ( ($>) )+import           Data.Text                      ( Text+                                                , pack+                                                , strip+                                                )+import           Text.Megaparsec                ( between+                                                , label+                                                , try+                                                , many+                                                , manyTill+                                                , optional+                                                , sepBy+                                                , sepEndBy+                                                , skipMany+                                                , skipManyTill+                                                , try+                                                , (<?>)+                                                , (<|>)+                                                )+import           Text.Megaparsec.Char           ( char+                                                , digitChar+                                                , letterChar+                                                , newline+                                                , printChar+                                                , space+                                                , space1+                                                , string+                                                )  -- MORPHEUS-import           Data.Morpheus.Parsing.Internal.Internal (Parser, Position, getLocation)-import           Data.Morpheus.Types.Internal.Data       (DataTypeWrapper (..), Key, Description , Name, WrapperD (..), toHSWrappers)-import           Data.Morpheus.Types.Internal.Value      (convertToHaskellName)+import           Data.Morpheus.Parsing.Internal.Internal+                                                ( Parser+                                                , Position+                                                , getLocation+                                                )+import           Data.Morpheus.Types.Internal.AST+                                                ( DataTypeWrapper(..)+                                                , Key+                                                , Description+                                                , Name+                                                , TypeWrapper(..)+                                                , toHSWrappers+                                                , convertToHaskellName )   -- Name : https://graphql.github.io/graphql-spec/June2018/#sec-Names@@ -57,7 +89,8 @@  -- LITERALS setLiteral :: Parser [a] -> Parser [a]-setLiteral = between (char '{' *> spaceAndComments) (char '}' *> spaceAndComments)+setLiteral =+  between (char '{' *> spaceAndComments) (char '}' *> spaceAndComments)  pipeLiteral :: Parser () pipeLiteral = char '|' *> spaceAndComments@@ -71,19 +104,17 @@ -- PRIMITIVE ------------------------------------ token :: Parser Text-token =-  label "token" $ do-    firstChar <- letterChar <|> char '_'-    restToken <- many $ letterChar <|> char '_' <|> digitChar-    spaceAndComments-    return $ convertToHaskellName $ pack $ firstChar : restToken+token = label "token" $ do+  firstChar <- letterChar <|> char '_'+  restToken <- many $ letterChar <|> char '_' <|> digitChar+  spaceAndComments+  return $ convertToHaskellName $ pack $ firstChar : restToken  qualifier :: Parser (Text, Position)-qualifier =-  label "qualifier" $ do-    position <- getLocation-    value <- token-    return (value, position)+qualifier = label "qualifier" $ do+  position <- getLocation+  value    <- token+  return (value, position)   -- Variable : https://graphql.github.io/graphql-spec/June2018/#Variable@@ -91,12 +122,11 @@ -- Variable :  $Name -- variable :: Parser (Text, Position)-variable =-  label "variable" $ do-    position' <- getLocation-    _ <- char '$'-    varName' <- token-    return (varName', position')+variable = label "variable" $ do+  position' <- getLocation+  _         <- char '$'+  varName'  <- token+  return (varName', position')  spaceAndComments1 :: Parser () spaceAndComments1 = space1 *> spaceAndComments@@ -111,15 +141,18 @@ optDescription = optional parseDescription  parseDescription :: Parser Text-parseDescription = pack <$> (blockDescription <|> singleLine) <* spaceAndComments-    where-      blockDescription = blockQuotes *> manyTill (printChar <|> newline)   blockQuotes <* spaceAndComments-        where-         blockQuotes = string "\"\"\""-      -----------------------------      singleLine = stringQuote *> manyTill printChar  stringQuote <* spaceAndComments-        where-            stringQuote = char '"'+parseDescription =+  strip . pack <$> (blockDescription <|> singleLine) <* spaceAndComments+ where+  blockDescription =+    blockQuotes+      *> manyTill (printChar <|> newline) blockQuotes+      <* spaceAndComments+    where blockQuotes = string "\"\"\""+  ----------------------------+  singleLine =+    stringQuote *> manyTill printChar stringQuote <* spaceAndComments+    where stringQuote = char '"'  -- Ignored Tokens : https://graphql.github.io/graphql-spec/June2018/#sec-Source-Text.Ignored-Tokens --  Ignored:@@ -133,9 +166,9 @@ spaceAndComments = ignoredTokens  ignoredTokens :: Parser ()-ignoredTokens = label "IgnoredTokens" $ space *> skipMany inlineComment *> space-  where-    inlineComment = char '#' *> skipManyTill printChar newline *> space+ignoredTokens =+  label "IgnoredTokens" $ space *> skipMany inlineComment *> space+  where inlineComment = char '#' *> skipManyTill printChar newline *> space     ------------------------------------------------------------------------  -- COMPLEX@@ -156,20 +189,18 @@ parseMaybeTuple parser = parseTuple parser <|> pure []  parseTuple :: Parser a -> Parser [a]-parseTuple parser =-  label "Tuple" $-  between-    (char '(' *> spaceAndComments)-    (char ')' *> spaceAndComments)-    (parser `sepBy` (many (char ',') *> spaceAndComments) <?> "empty Tuple value!")+parseTuple parser = label "Tuple" $ between+  (char '(' *> spaceAndComments)+  (char ')' *> spaceAndComments)+  (parser `sepBy` (many (char ',') *> spaceAndComments) <?> "empty Tuple value!"+  )  parseAssignment :: (Show a, Show b) => Parser a -> Parser b -> Parser (a, b)-parseAssignment nameParser valueParser =-  label "assignment" $ do-    name' <- nameParser-    litAssignment-    value' <- valueParser-    pure (name', value')+parseAssignment nameParser valueParser = label "assignment" $ do+  name' <- nameParser+  litAssignment+  value' <- valueParser+  pure (name', value')  -- Type Conditions: https://graphql.github.io/graphql-spec/June2018/#sec-Type-Conditions --@@ -185,36 +216,36 @@ spreadLiteral :: Parser Position spreadLiteral = do   index <- getLocation-  _ <- string "..."+  _     <- string "..."   space   return index  parseWrappedType :: Parser ([DataTypeWrapper], Text) parseWrappedType = (unwrapped <|> wrapped) <* spaceAndComments-  where-    unwrapped :: Parser ([DataTypeWrapper], Text)-    unwrapped = ([], ) <$> token <* spaceAndComments-    -----------------------------------------------    wrapped :: Parser ([DataTypeWrapper], Text)-    wrapped =-      between-        (char '[' *> spaceAndComments)-        (char ']' *> spaceAndComments)-        (do (wrappers, name) <- unwrapped <|> wrapped-            nonNull' <- parseNonNull-            return ((ListType : nonNull') ++ wrappers, name))+ where+  unwrapped :: Parser ([DataTypeWrapper], Text)+  unwrapped = ([], ) <$> token <* spaceAndComments+  ----------------------------------------------+  wrapped :: Parser ([DataTypeWrapper], Text)+  wrapped = between+    (char '[' *> spaceAndComments)+    (char ']' *> spaceAndComments)+    (do+      (wrappers, name) <- unwrapped <|> wrapped+      nonNull'         <- parseNonNull+      return ((ListType : nonNull') ++ wrappers, name)+    )  -- Field Alias : https://graphql.github.io/graphql-spec/June2018/#sec-Field-Alias -- Alias --  Name: parseAlias :: Parser (Maybe Key) parseAlias = try (optional alias) <|> pure Nothing-    where-        alias = label "alias" $ token <* char ':' <* spaceAndComments+  where alias = label "alias" $ token <* char ':' <* spaceAndComments  -parseType :: Parser ([WrapperD],Key)+parseType :: Parser ([TypeWrapper], Key) parseType = do-    (wrappers, fieldType) <- parseWrappedType-    nonNull <- parseNonNull-    pure (toHSWrappers $ nonNull ++ wrappers, fieldType)+  (wrappers, fieldType) <- parseWrappedType+  nonNull               <- parseNonNull+  pure (toHSWrappers $ nonNull ++ wrappers, fieldType)
src/Data/Morpheus/Parsing/Internal/Value.hs view
@@ -5,49 +5,68 @@   ( parseValue   , enumValue   , parseDefaultValue-  ) where+  )+where -import           Data.Functor                            (($>))-import           Data.Text                               (pack)-import           Text.Megaparsec                         (anySingleBut, between, choice, label, many, optional, sepBy,-                                                          (<|>))-import           Text.Megaparsec.Char                    (char, string)-import           Text.Megaparsec.Char.Lexer              (scientific)+import           Data.Functor                   ( ($>) )+import           Data.Text                      ( pack )+import           Text.Megaparsec                ( anySingleBut+                                                , between+                                                , choice+                                                , label+                                                , many+                                                , optional+                                                , sepBy+                                                , (<|>)+                                                )+import           Text.Megaparsec.Char           ( char+                                                , string+                                                )+import           Text.Megaparsec.Char.Lexer     ( scientific )  -- -- MORPHEUS-import           Data.Morpheus.Parsing.Internal.Internal (Parser)-import           Data.Morpheus.Parsing.Internal.Terms    (litEquals, parseAssignment, setOf, spaceAndComments, token)-import           Data.Morpheus.Types.Internal.Value      (ScalarValue (..), Value (..), decodeScientific)+import           Data.Morpheus.Parsing.Internal.Internal+                                                ( Parser )+import           Data.Morpheus.Parsing.Internal.Terms+                                                ( litEquals+                                                , parseAssignment+                                                , setOf+                                                , spaceAndComments+                                                , token+                                                )+import           Data.Morpheus.Types.Internal.AST+                                                ( ScalarValue(..)+                                                , Value(..)+                                                , decodeScientific+                                                )  parseDefaultValue :: Parser (Maybe Value)-parseDefaultValue =-  optional $ do-    litEquals-    parseValue+parseDefaultValue = optional $ do+  litEquals+  parseValue  parseValue :: Parser Value-parseValue =-  label "value" $ do-    value <- -        valueNull -        <|> booleanValue -        <|> valueNumber -        <|> enumValue -        <|> stringValue -        <|> objectValue -        <|> listValue-    spaceAndComments-    return value+parseValue = label "value" $ do+  value <-+    valueNull+    <|> booleanValue+    <|> valueNumber+    <|> enumValue+    <|> stringValue+    <|> objectValue+    <|> listValue+  spaceAndComments+  return value  valueNull :: Parser Value valueNull = string "null" $> Null  booleanValue :: Parser Value booleanValue = boolTrue <|> boolFalse-  where-    boolTrue = string "true" $> Scalar (Boolean True)-    boolFalse = string "false" $> Scalar (Boolean False)+ where+  boolTrue  = string "true" $> Scalar (Boolean True)+  boolFalse = string "false" $> Scalar (Boolean False)  valueNumber :: Parser Value valueNumber = Scalar . decodeScientific <$> scientific@@ -59,30 +78,26 @@   return enum  escaped :: Parser Char-escaped =-  label "escaped" $ do-    x <- anySingleBut '\"'-    if x == '\\'-      then choice (zipWith escapeChar codes replacements)-      else pure x-  where-    replacements = ['\b', '\n', '\f', '\r', '\t', '\\', '\"', '/']-    codes = ['b', 'n', 'f', 'r', 't', '\\', '\"', '/']-    escapeChar code replacement = char code >> return replacement+escaped = label "escaped" $ do+  x <- anySingleBut '\"'+  if x == '\\' then choice (zipWith escapeChar codes replacements) else pure x+ where+  replacements = ['\b', '\n', '\f', '\r', '\t', '\\', '\"', '/']+  codes        = ['b', 'n', 'f', 'r', 't', '\\', '\"', '/']+  escapeChar code replacement = char code >> return replacement  stringValue :: Parser Value-stringValue = label "stringValue" $ Scalar . String . pack <$> between (char '"') (char '"') (many escaped)+stringValue = label "stringValue" $ Scalar . String . pack <$> between+  (char '"')+  (char '"')+  (many escaped)  listValue :: Parser Value-listValue =-  label "listValue" $-  List <$>-  between-    (char '[' *> spaceAndComments)-    (char ']' *> spaceAndComments)-    (parseValue `sepBy` (char ',' *> spaceAndComments))+listValue = label "listValue" $ List <$> between+  (char '[' *> spaceAndComments)+  (char ']' *> spaceAndComments)+  (parseValue `sepBy` (char ',' *> spaceAndComments))  objectValue :: Parser Value objectValue = label "objectValue" $ Object <$> setOf entry-  where-    entry = parseAssignment token parseValue+  where entry = parseAssignment token parseValue
src/Data/Morpheus/Parsing/JSONSchema/Parse.hs view
@@ -6,73 +6,100 @@  module Data.Morpheus.Parsing.JSONSchema.Parse   ( decodeIntrospection-  ) where+  )+where  import           Data.Aeson-import           Data.ByteString.Lazy                    (ByteString)-import           Data.Morpheus.Error.Internal            (internalError)-import           Data.Morpheus.Parsing.Internal.Create   (createArgument, createDataTypeLib, createEnumType,-                                                          createField, createScalarType, createType, createUnionType)-import           Data.Morpheus.Parsing.JSONSchema.Types  (EnumValue (..), Field (..), InputValue (..),-                                                          Introspection (..), Schema (..), Type (..))-import           Data.Morpheus.Schema.TypeKind           (TypeKind (..))-import           Data.Morpheus.Types.Internal.Data       (DataField, DataType (..), DataTypeLib,-                                                          DataTypeWrapper (..), Key, WrapperD, toHSWrappers)-import           Data.Morpheus.Types.Internal.Validation (Validation)-import           Data.Morpheus.Types.IO                  (JSONResponse (..))-import           Data.Semigroup                          ((<>))-import           Data.Text                               (Text, pack)+import           Data.ByteString.Lazy           ( ByteString )+import           Data.Morpheus.Error.Internal   ( internalError )+import           Data.Morpheus.Parsing.JSONSchema.Types+                                                ( EnumValue(..)+                                                , Field(..)+                                                , InputValue(..)+                                                , Introspection(..)+                                                , Schema(..)+                                                , Type(..)+                                                )+import           Data.Morpheus.Schema.TypeKind  ( TypeKind(..) )+import           Data.Morpheus.Types.Internal.AST+                                                ( DataField+                                                , DataType(..)+                                                , DataTypeLib+                                                , DataTypeWrapper(..)+                                                , Key+                                                , TypeWrapper+                                                , createArgument+                                                , createDataTypeLib+                                                , createEnumType+                                                , createField+                                                , createScalarType+                                                , createType+                                                , createUnionType+                                                , toHSWrappers+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Validation )+import           Data.Morpheus.Types.IO         ( JSONResponse(..) )+import           Data.Semigroup                 ( (<>) )+import           Data.Text                      ( Text+                                                , pack+                                                )  decodeIntrospection :: ByteString -> Validation DataTypeLib-decodeIntrospection jsonDoc =-  case jsonSchema of-    Left errors -> internalError $ pack errors-    Right JSONResponse {responseData = Just Introspection {__schema = Schema {types}}} ->-      traverse parse types >>= createDataTypeLib-    Right res -> internalError (pack $ show res)-  where-    jsonSchema :: Either String (JSONResponse Introspection)-    jsonSchema = eitherDecode jsonDoc+decodeIntrospection jsonDoc = case jsonSchema of+  Left errors -> internalError $ pack errors+  Right JSONResponse { responseData = Just Introspection { __schema = Schema { types } } }+    -> traverse parse types >>= createDataTypeLib . concat+  Right res -> internalError (pack $ show res)+ where+  jsonSchema :: Either String (JSONResponse Introspection)+  jsonSchema = eitherDecode jsonDoc  class ParseJSONSchema a b where-  parse :: a -> Validation (Key, b)+  parse :: a -> Validation b -instance ParseJSONSchema Type DataType where-  parse Type {name = Just typeName, kind = SCALAR} = pure $ createScalarType typeName-  parse Type {name = Just typeName, kind = ENUM, enumValues = Just enums} =-    pure $ createEnumType typeName (map enumName enums)-  parse Type {name = Just typeName, kind = UNION, possibleTypes = Just unions} =-    case traverse name unions of+instance ParseJSONSchema Type [(Key,DataType)] where+  parse Type { name = Just typeName, kind = SCALAR } =+    pure [createScalarType typeName]+  parse Type { name = Just typeName, kind = ENUM, enumValues = Just enums } =+    pure [createEnumType typeName (map enumName enums)]+  parse Type { name = Just typeName, kind = UNION, possibleTypes = Just unions }+    = case traverse name unions of       Nothing  -> internalError "ERROR: GQL ERROR"-      Just uni -> pure $ createUnionType typeName uni-  parse Type {name = Just typeName, kind = INPUT_OBJECT, inputFields = Just iFields} = do-    fields <- traverse parse iFields-    pure (typeName, DataInputObject $ createType typeName fields)-  parse Type {name = Just typeName, kind = OBJECT, fields = Just oFields} = do-    fields <- traverse parse oFields-    pure (typeName, DataObject $ createType typeName fields)-  parse x = internalError $ "Unsuported type" <> pack (show x)+      Just uni -> pure [createUnionType typeName uni]+  parse Type { name = Just typeName, kind = INPUT_OBJECT, inputFields = Just iFields }+    = do+      fields <- traverse parse iFields+      pure [(typeName, DataInputObject $ createType typeName fields)]+  parse Type { name = Just typeName, kind = OBJECT, fields = Just oFields } =+    do+      fields <- traverse parse oFields+      pure [(typeName, DataObject $ createType typeName fields)]+  parse _ = pure [] -instance ParseJSONSchema Field DataField where-  parse Field {fieldName, fieldArgs, fieldType} = do+instance ParseJSONSchema Field (Key,DataField) where+  parse Field { fieldName, fieldArgs, fieldType } = do     fType <- fieldTypeFromJSON fieldType-    args <- traverse genArg fieldArgs+    args  <- traverse genArg fieldArgs     pure (fieldName, createField args fieldName fType)-    where-      genArg InputValue {inputName = argName, inputType = argType} =-        createArgument argName <$> fieldTypeFromJSON argType+   where+    genArg InputValue { inputName = argName, inputType = argType } =+      createArgument argName <$> fieldTypeFromJSON argType -instance ParseJSONSchema InputValue DataField where-  parse InputValue {inputName, inputType} = do+instance ParseJSONSchema InputValue (Key,DataField) where+  parse InputValue { inputName, inputType } = do     fieldType <- fieldTypeFromJSON inputType     pure (inputName, createField [] inputName fieldType) -fieldTypeFromJSON :: Type -> Validation ([WrapperD], Text)+fieldTypeFromJSON :: Type -> Validation ([TypeWrapper], Text) fieldTypeFromJSON = fmap toHs . fieldTypeRec []-  where-    toHs (w, t) = (toHSWrappers w, t)-    fieldTypeRec :: [DataTypeWrapper] -> Type -> Validation ([DataTypeWrapper], Text)-    fieldTypeRec acc Type {kind = LIST, ofType = Just ofType} = fieldTypeRec (ListType : acc) ofType-    fieldTypeRec acc Type {kind = NON_NULL, ofType = Just ofType} = fieldTypeRec (NonNullType : acc) ofType-    fieldTypeRec acc Type {name = Just name} = pure (acc, name)-    fieldTypeRec _ x = internalError $ "Unsuported Field" <> pack (show x)+ where+  toHs (w, t) = (toHSWrappers w, t)+  fieldTypeRec+    :: [DataTypeWrapper] -> Type -> Validation ([DataTypeWrapper], Text)+  fieldTypeRec acc Type { kind = LIST, ofType = Just ofType } =+    fieldTypeRec (ListType : acc) ofType+  fieldTypeRec acc Type { kind = NON_NULL, ofType = Just ofType } =+    fieldTypeRec (NonNullType : acc) ofType+  fieldTypeRec acc Type { name = Just name } = pure (acc, name)+  fieldTypeRec _ x = internalError $ "Unsuported Field" <> pack (show x)
src/Data/Morpheus/Parsing/Request/Arguments.hs view
@@ -2,17 +2,35 @@  module Data.Morpheus.Parsing.Request.Arguments   ( maybeArguments-  ) where+  )+where -import           Text.Megaparsec                               (label, (<|>))+import           Text.Megaparsec                ( label+                                                , (<|>)+                                                )  -- MORPHEUS-import           Data.Morpheus.Parsing.Internal.Internal       (Parser, getLocation)-import           Data.Morpheus.Parsing.Internal.Terms          (parseAssignment, parseMaybeTuple, token, variable)-import           Data.Morpheus.Parsing.Internal.Value          (enumValue, parseValue)-import           Data.Morpheus.Types.Internal.AST.RawSelection (Argument (..), RawArgument (..), RawArguments)-import           Data.Morpheus.Types.Internal.AST.Selection    (ArgumentOrigin (..))-import           Data.Morpheus.Types.Internal.Base             (Reference (..))+import           Data.Morpheus.Parsing.Internal.Internal+                                                ( Parser+                                                , getLocation+                                                )+import           Data.Morpheus.Parsing.Internal.Terms+                                                ( parseAssignment+                                                , parseMaybeTuple+                                                , token+                                                , variable+                                                )+import           Data.Morpheus.Parsing.Internal.Value+                                                ( enumValue+                                                , parseValue+                                                )+import           Data.Morpheus.Types.Internal.AST+                                                ( ValueOrigin(..)+                                                , Argument(..)+                                                , RawArgument(..)+                                                , RawArguments+                                                , Ref(..)+                                                )   -- Arguments : https://graphql.github.io/graphql-spec/June2018/#sec-Language.Arguments@@ -24,19 +42,19 @@ --  Name : Value[Const] -- TODO: move variable to Value valueArgument :: Parser RawArgument-valueArgument =-  label "valueArgument" $ do-    argumentPosition <- getLocation-    argumentValue <- parseValue <|> enumValue-    pure $ RawArgument $ Argument {argumentValue, argumentOrigin = INLINE, argumentPosition}+valueArgument = label "valueArgument" $ do+  argumentPosition <- getLocation+  argumentValue    <- parseValue <|> enumValue+  pure $ RawArgument $ Argument { argumentValue+                                , argumentOrigin   = INLINE+                                , argumentPosition+                                }  variableArgument :: Parser RawArgument-variableArgument =-  label "variableArgument" $ do-    (referenceName, referencePosition) <- variable-    pure $ VariableReference $ Reference {referenceName, referencePosition}+variableArgument = label "variableArgument" $ do+  (refName, refPosition) <- variable+  pure $ VariableRef $ Ref { refName, refPosition }  maybeArguments :: Parser RawArguments maybeArguments = label "maybeArguments" $ parseMaybeTuple argument-  where-    argument = parseAssignment token (valueArgument <|> variableArgument)+  where argument = parseAssignment token (valueArgument <|> variableArgument)
src/Data/Morpheus/Parsing/Request/Operation.hs view
@@ -2,24 +2,47 @@ {-# LANGUAGE OverloadedStrings #-}  module Data.Morpheus.Parsing.Request.Operation-  (parseOperation-  ) where+  ( parseOperation+  )+where -import           Data.Functor                               (($>))-import           Data.Text                                  (Text)-import           Text.Megaparsec                            (label, optional, (<?>), (<|>))-import           Text.Megaparsec.Char                       (string)+import           Data.Functor                   ( ($>) )+import           Data.Text                      ( Text )+import           Text.Megaparsec                ( label+                                                , optional+                                                , (<?>)+                                                , (<|>)+                                                )+import           Text.Megaparsec.Char           ( string )  -- -- MORPHEUS-import           Data.Morpheus.Parsing.Internal.Internal    (Parser, getLocation)-import           Data.Morpheus.Parsing.Internal.Pattern     (optionalDirectives)-import           Data.Morpheus.Parsing.Internal.Terms       (operator, parseMaybeTuple, parseName, parseType,-                                                             spaceAndComments1, variable)-import           Data.Morpheus.Parsing.Internal.Value       (parseDefaultValue)-import           Data.Morpheus.Parsing.Request.Selection    (parseSelectionSet)-import           Data.Morpheus.Types.Internal.AST.Operation (DefaultValue, Operation (..), RawOperation, Variable (..))-import           Data.Morpheus.Types.Internal.Data          (OperationType (..), isNullable)+import           Data.Morpheus.Parsing.Internal.Internal+                                                ( Parser+                                                , getLocation+                                                )+import           Data.Morpheus.Parsing.Internal.Pattern+                                                ( optionalDirectives )+import           Data.Morpheus.Parsing.Internal.Terms+                                                ( operator+                                                , parseMaybeTuple+                                                , parseName+                                                , parseType+                                                , spaceAndComments1+                                                , variable+                                                )+import           Data.Morpheus.Parsing.Internal.Value+                                                ( parseDefaultValue )+import           Data.Morpheus.Parsing.Request.Selection+                                                ( parseSelectionSet )+import           Data.Morpheus.Types.Internal.AST+                                                ( DefaultValue+                                                , Operation(..)+                                                , RawOperation+                                                , Variable(..)+                                                , OperationType(..)+                                                , isNullable+                                                )   -- Variables :  https://graphql.github.io/graphql-spec/June2018/#VariableDefinition@@ -28,21 +51,20 @@ --    Variable : Type DefaultValue(opt) -- variableDefinition :: Parser (Text, Variable DefaultValue)-variableDefinition =-  label "VariableDefinition" $ do-    (name, variablePosition) <- variable-    operator ':'-    (variableTypeWrappers, variableType) <- parseType-    defaultValue <- parseDefaultValue-    pure-      ( name-      , Variable-          { variableType-          , isVariableRequired = not (isNullable variableTypeWrappers)-          , variableTypeWrappers-          , variablePosition-          , variableValue = defaultValue-          })+variableDefinition = label "VariableDefinition" $ do+  (name, variablePosition) <- variable+  operator ':'+  (variableTypeWrappers, variableType) <- parseType+  defaultValue                         <- parseDefaultValue+  pure+    ( name+    , Variable { variableType+               , isVariableRequired   = not (isNullable variableTypeWrappers)+               , variableTypeWrappers+               , variablePosition+               , variableValue        = defaultValue+               }+    )  -- Operations : https://graphql.github.io/graphql-spec/June2018/#sec-Language.Operations --@@ -52,38 +74,45 @@ --   OperationType: one of --     query, mutation,    subscription parseOperationDefinition :: Parser RawOperation-parseOperationDefinition =-  label "OperationDefinition" $ do-    operationPosition <- getLocation-    operationType <- parseOperationType-    operationName <- optional parseName-    operationArgs <- parseMaybeTuple variableDefinition-    -- TODO: handle directives-    _directives <- optionalDirectives-    operationSelection <- parseSelectionSet-    pure (Operation {operationName, operationType, operationArgs, operationSelection, operationPosition})+parseOperationDefinition = label "OperationDefinition" $ do+  operationPosition  <- getLocation+  operationType      <- parseOperationType+  operationName      <- optional parseName+  operationArgs      <- parseMaybeTuple variableDefinition+  -- TODO: handle directives+  _directives        <- optionalDirectives+  operationSelection <- parseSelectionSet+  pure+    (Operation { operationName+               , operationType+               , operationArgs+               , operationSelection+               , operationPosition+               }+    )  parseOperationType :: Parser OperationType-parseOperationType =-  label "OperationType" $ do-    kind <- (string "query" $> Query) <|> (string "mutation" $> Mutation) <|> (string "subscription" $> Subscription)-    spaceAndComments1-    return kind+parseOperationType = label "OperationType" $ do+  kind <-+    (string "query" $> Query)+    <|> (string "mutation" $> Mutation)+    <|> (string "subscription" $> Subscription)+  spaceAndComments1+  return kind  parseAnonymousQuery :: Parser RawOperation-parseAnonymousQuery =-  label "AnonymousQuery" $ do-    operationPosition <- getLocation-    operationSelection <- parseSelectionSet-    pure-      (Operation-         { operationName = Nothing-         , operationType = Query-         , operationArgs = []-         , operationSelection-         , operationPosition-         }) <?>-      "can't parse AnonymousQuery"+parseAnonymousQuery = label "AnonymousQuery" $ do+  operationPosition  <- getLocation+  operationSelection <- parseSelectionSet+  pure+      (Operation { operationName      = Nothing+                 , operationType      = Query+                 , operationArgs      = []+                 , operationSelection+                 , operationPosition+                 }+      )+    <?> "can't parse AnonymousQuery"  parseOperation :: Parser RawOperation parseOperation = parseAnonymousQuery <|> parseOperationDefinition
src/Data/Morpheus/Parsing/Request/Parser.hs view
@@ -3,44 +3,61 @@  module Data.Morpheus.Parsing.Request.Parser   ( parseGQL-  ) where+  )+where -import qualified Data.Aeson                              as Aeson (Value (..))-import           Data.HashMap.Lazy                       (toList)-import           Data.Text                               (Text)-import           Data.Void                               (Void)-import           Text.Megaparsec                         (ParseErrorBundle, eof, label, manyTill, runParser)+import qualified Data.Aeson                    as Aeson+                                                ( Value(..) )+import           Data.HashMap.Lazy              ( toList )+import           Data.Text                      ( Text )+import           Data.Void                      ( Void )+import           Text.Megaparsec                ( ParseErrorBundle+                                                , eof+                                                , label+                                                , manyTill+                                                , runParser+                                                )  -- -- MORPHEUS-import           Data.Morpheus.Parsing.Internal.Internal (Parser, processErrorBundle)-import           Data.Morpheus.Parsing.Internal.Terms    (spaceAndComments)-import           Data.Morpheus.Parsing.Request.Operation (parseOperation)-import           Data.Morpheus.Parsing.Request.Selection (parseFragmentDefinition)-import           Data.Morpheus.Types.Internal.Validation (Validation)-import           Data.Morpheus.Types.Internal.Value      (Value (..), replaceValue)-import           Data.Morpheus.Types.IO                  (GQLRequest (..))-import           Data.Morpheus.Types.Types               (GQLQueryRoot (..))+import           Data.Morpheus.Parsing.Internal.Internal+                                                ( Parser+                                                , processErrorBundle+                                                )+import           Data.Morpheus.Parsing.Internal.Terms+                                                ( spaceAndComments )+import           Data.Morpheus.Parsing.Request.Operation+                                                ( parseOperation )+import           Data.Morpheus.Parsing.Request.Selection+                                                ( parseFragmentDefinition )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Validation+                                                , Failure(..)+                                                )+import           Data.Morpheus.Types.Internal.AST+                                                ( Value(..)+                                                , replaceValue+                                                , GQLQuery(..)+                                                )+import           Data.Morpheus.Types.IO         ( GQLRequest(..) ) -parseGQLSyntax :: Text -> Either (ParseErrorBundle Text Void) GQLQueryRoot++parseGQLSyntax :: Text -> Either (ParseErrorBundle Text Void) GQLQuery parseGQLSyntax = runParser request "<input>"-  where-    request :: Parser GQLQueryRoot-    request =-      label "GQLQueryRoot" $ do-        spaceAndComments-        operation <- parseOperation-        fragments <- manyTill parseFragmentDefinition eof-        pure GQLQueryRoot {operation, fragments, inputVariables = []}+ where+  request :: Parser GQLQuery+  request = label "GQLQuery" $ do+    spaceAndComments+    operation <- parseOperation+    fragments <- manyTill parseFragmentDefinition eof+    pure GQLQuery { operation, fragments, inputVariables = [] } -parseGQL :: GQLRequest -> Validation GQLQueryRoot-parseGQL GQLRequest {query, variables} =-  case parseGQLSyntax query of-    Right root      -> Right $ root {inputVariables = toVariableMap variables}-    Left parseError -> Left $ processErrorBundle parseError-  where-    toVariableMap :: Maybe Aeson.Value -> [(Text, Value)]-    toVariableMap (Just (Aeson.Object x)) = map toMorpheusValue (toList x)-      where-        toMorpheusValue (key, value) = (key, replaceValue value)-    toVariableMap _ = []+parseGQL :: GQLRequest -> Validation GQLQuery+parseGQL GQLRequest { query, variables } = case parseGQLSyntax query of+  Right root       -> pure $ root { inputVariables = toVariableMap variables }+  Left  parseError -> failure $ processErrorBundle parseError+ where+  toVariableMap :: Maybe Aeson.Value -> [(Text, Value)]+  toVariableMap (Just (Aeson.Object x)) = map toMorpheusValue (toList x)+    where toMorpheusValue (key, value) = (key, replaceValue value)+  toVariableMap _ = []
src/Data/Morpheus/Parsing/Request/Selection.hs view
@@ -4,21 +4,42 @@ module Data.Morpheus.Parsing.Request.Selection   ( parseSelectionSet   , parseFragmentDefinition-  ) where+  )+where -import           Data.Text                                     (Text)-import           Text.Megaparsec                               (label, try, (<|>))+import           Data.Text                      ( Text )+import           Text.Megaparsec                ( label+                                                , try+                                                , (<|>)+                                                )  -- -- MORPHEUS-import           Data.Morpheus.Parsing.Internal.Internal       (Parser, getLocation)-import           Data.Morpheus.Parsing.Internal.Pattern        (optionalDirectives)-import           Data.Morpheus.Parsing.Internal.Terms          (keyword, parseAlias, parseName, parseTypeCondition,-                                                                setOf, spreadLiteral, token)-import           Data.Morpheus.Parsing.Request.Arguments       (maybeArguments)-import           Data.Morpheus.Types.Internal.AST.RawSelection (Fragment (..), RawArguments, RawSelection (..),-                                                                RawSelectionSet, Reference (..))-import           Data.Morpheus.Types.Internal.AST.Selection    (Selection (..))+import           Data.Morpheus.Parsing.Internal.Internal+                                                ( Parser+                                                , getLocation+                                                )+import           Data.Morpheus.Parsing.Internal.Pattern+                                                ( optionalDirectives )+import           Data.Morpheus.Parsing.Internal.Terms+                                                ( keyword+                                                , parseAlias+                                                , parseName+                                                , parseTypeCondition+                                                , setOf+                                                , spreadLiteral+                                                , token+                                                )+import           Data.Morpheus.Parsing.Request.Arguments+                                                ( maybeArguments )+import           Data.Morpheus.Types.Internal.AST+                                                ( Selection(..)+                                                , Fragment(..)+                                                , RawArguments+                                                , RawSelection(..)+                                                , RawSelectionSet+                                                , Ref(..)+                                                )   -- Selection Sets : https://graphql.github.io/graphql-spec/June2018/#sec-Selection-Sets@@ -33,11 +54,12 @@ -- parseSelectionSet :: Parser RawSelectionSet parseSelectionSet = label "SelectionSet" $ setOf parseSelection-  where-    parseSelection = label "Selection" $-            try inlineFragment-        <|> try spread-        <|> parseSelectionField+ where+  parseSelection =+    label "Selection"+      $   try inlineFragment+      <|> try spread+      <|> parseSelectionField  -- Fields: https://graphql.github.io/graphql-spec/June2018/#sec-Language.Fields --@@ -45,27 +67,37 @@ -- Alias(opt) Name Arguments(opt) Directives(opt) SelectionSet(opt) -- parseSelectionField :: Parser (Text, RawSelection)-parseSelectionField =-  label "SelectionField" $ do-    position <- getLocation-    aliasName  <- parseAlias-    name <- parseName-    arguments <- maybeArguments-    -- TODO: handle Directives-    _directives <- optionalDirectives-    value <- selSet aliasName arguments <|> buildField aliasName arguments position-    return (name, value)-  where+parseSelectionField = label "SelectionField" $ do+  position    <- getLocation+  aliasName   <- parseAlias+  name        <- parseName+  arguments   <- maybeArguments+  -- TODO: handle Directives+  _directives <- optionalDirectives+  value       <-+    selSet aliasName arguments <|> buildField aliasName arguments position+  return (name, value)+ where     -----------------------------------------    buildField selectionAlias selectionArguments selectionPosition =-       pure (RawSelectionField $ Selection { selectionAlias , selectionArguments,  selectionRec = (), selectionPosition})-    ------------------------------------------    selSet :: Maybe Text -> RawArguments -> Parser RawSelection-    selSet selectionAlias selectionArguments =-      label "body" $ do-        selectionPosition <- getLocation-        selectionRec <- parseSelectionSet-        return (RawSelectionSet $ Selection {selectionAlias , selectionArguments, selectionRec, selectionPosition})+  buildField selectionAlias selectionArguments selectionPosition = pure+    (RawSelectionField $ Selection { selectionAlias+                                   , selectionArguments+                                   , selectionRec       = ()+                                   , selectionPosition+                                   }+    )+  -----------------------------------------+  selSet :: Maybe Text -> RawArguments -> Parser RawSelection+  selSet selectionAlias selectionArguments = label "body" $ do+    selectionPosition <- getLocation+    selectionRec      <- parseSelectionSet+    return+      (RawSelectionSet $ Selection { selectionAlias+                                   , selectionArguments+                                   , selectionRec+                                   , selectionPosition+                                   }+      )   --@@ -78,13 +110,12 @@ --    ...FragmentName Directives(opt) -- spread :: Parser (Text, RawSelection)-spread =-  label "FragmentSpread" $ do-    referencePosition <- spreadLiteral-    referenceName <- token-    -- TODO: handle Directives-    _directives <- optionalDirectives-    return (referenceName, Spread $ Reference {referenceName, referencePosition})+spread = label "FragmentSpread" $ do+  refPosition <- spreadLiteral+  refName     <- token+  -- TODO: handle Directives+  _directives <- optionalDirectives+  return (refName, Spread $ Ref { refName, refPosition })  -- FragmentDefinition : https://graphql.github.io/graphql-spec/June2018/#FragmentDefinition --@@ -92,16 +123,15 @@ --   fragment FragmentName TypeCondition Directives(opt) SelectionSet -- parseFragmentDefinition :: Parser (Text, Fragment)-parseFragmentDefinition =-  label "FragmentDefinition" $ do-    keyword "fragment"-    fragmentPosition <- getLocation-    name <- parseName-    fragmentType <- parseTypeCondition-    -- TODO: handle Directives-    _directives <- optionalDirectives-    fragmentSelection <- parseSelectionSet-    pure (name, Fragment {fragmentType, fragmentSelection, fragmentPosition})+parseFragmentDefinition = label "FragmentDefinition" $ do+  keyword "fragment"+  fragmentPosition  <- getLocation+  name              <- parseName+  fragmentType      <- parseTypeCondition+  -- TODO: handle Directives+  _directives       <- optionalDirectives+  fragmentSelection <- parseSelectionSet+  pure (name, Fragment { fragmentType, fragmentSelection, fragmentPosition })  -- Inline Fragments : https://graphql.github.io/graphql-spec/June2018/#sec-Inline-Fragments --@@ -109,12 +139,15 @@ --  ... TypeCondition(opt) Directives(opt) SelectionSet -- inlineFragment :: Parser (Text, RawSelection)-inlineFragment =-  label "InlineFragment" $ do-    fragmentPosition <- spreadLiteral-    -- TODO: optional-    fragmentType <- parseTypeCondition-    -- TODO: handle Directives-    _directives <- optionalDirectives-    fragmentSelection <- parseSelectionSet-    pure ("INLINE_FRAGMENT", InlineFragment $ Fragment {fragmentType, fragmentSelection, fragmentPosition})+inlineFragment = label "InlineFragment" $ do+  fragmentPosition  <- spreadLiteral+  -- TODO: optional+  fragmentType      <- parseTypeCondition+  -- TODO: handle Directives+  _directives       <- optionalDirectives+  fragmentSelection <- parseSelectionSet+  pure+    ( "INLINE_FRAGMENT"+    , InlineFragment+      $ Fragment { fragmentType, fragmentSelection, fragmentPosition }+    )
− src/Data/Morpheus/Rendering/Haskell/Render.hs
@@ -1,87 +0,0 @@-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE NamedFieldPuns    #-}-{-# LANGUAGE OverloadedStrings #-}--module Data.Morpheus.Rendering.Haskell.Render-  ( renderHaskellDocument-  ) where--import           Data.ByteString.Lazy.Char8             (ByteString)-import           Data.Semigroup                         ((<>))-import           Data.Text                              (Text, intercalate, pack)-import qualified Data.Text                              as T (concat)-import qualified Data.Text.Lazy                         as LT (fromStrict)-import           Data.Text.Lazy.Encoding                (encodeUtf8)---- MORPHEUS-import           Data.Morpheus.Rendering.Haskell.Terms  (Context (..), renderExtension)-import           Data.Morpheus.Rendering.Haskell.Types  (renderType)-import           Data.Morpheus.Rendering.Haskell.Values (Scope (..), renderResolver, renderRootResolver)-import           Data.Morpheus.Types.Internal.Data      (DataTypeLib (..), allDataTypes)--renderHaskellDocument :: String -> DataTypeLib -> ByteString-renderHaskellDocument modName lib =-  encodeText $-  renderLanguageExtensions context <> renderExports context <>-  renderImports context <>-  onSub renderApiEvents "" <>-  renderRootResolver context lib <>-  types-  where-    encodeText = encodeUtf8 . LT.fromStrict-    onSub onS els =-      case subscription lib of-        Nothing -> els-        _       -> onS-    renderApiEvents =-      "data Channel = Channel -- ChannelA | ChannelB" <> "\n\n" <>-      "data Content = Content -- ContentA Int | ContentB String" <>-      "\n\n"-    types = intercalate "\n\n" $ map renderFullType (allDataTypes lib)-      where-        renderFullType x = renderType cont x <> "\n\n" <> renderResolver cont x-          where-            cont = context {scope = getScope $ fst x}-            getScope "Mutation"     = Mutation-            getScope "Subscription" = Subscription-            getScope _              = Query-    context =-      Context-        { moduleName = pack modName-        , imports =-            [ ("GHC.Generics", ["Generic"])-            , ( "Data.Morpheus.Kind"-              , ["SCALAR", "ENUM", "INPUT_OBJECT", "OBJECT", "UNION"])-            , ( "Data.Morpheus.Types"-              , [ "GQLRootResolver(..)"-                , "toMutResolver"-                , "IORes"-                , "IOMutRes"-                , "IOSubRes"-                , "Event(..)"-                , "SubRootRes"-                , "GQLType(..)"-                , "GQLScalar(..)"-                , "ScalarValue(..)"-                ])-            , ("Data.Text", ["Text"])-            ]-        , extensions = ["OverloadedStrings", "DeriveGeneric", "TypeFamilies"]-        , scope = Query-        , pubSub = onSub ("Channel", "Content") ("()", "()")-        }--renderLanguageExtensions :: Context -> Text-renderLanguageExtensions Context {extensions} =-  T.concat (map renderExtension extensions) <> "\n"--renderExports :: Context -> Text-renderExports Context {moduleName} =-  "-- generated by 'Morpheus' CLI\n" <> "module " <> moduleName <>-  " (rootResolver) where\n\n"--renderImports :: Context -> Text-renderImports Context {imports} = T.concat (map renderImport imports) <> "\n"-  where-    renderImport (src, list) =-      "import  " <> src <> "  (" <> intercalate ", " list <> ")\n"
− src/Data/Morpheus/Rendering/Haskell/Terms.hs
@@ -1,85 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Data.Morpheus.Rendering.Haskell.Terms-  ( indent-  , renderReturn-  , renderData-  , renderCon-  , renderMaybe-  , renderList-  , renderTuple-  , renderAssignment-  , renderExtension-  , renderWrapped-  , renderSet-  , renderUnionCon-  , renderEqual-  , Scope(..)-  , Context(..)-  ) where--import           Data.Semigroup                    ((<>))-import           Data.Text                         (Text, intercalate, toUpper)---- MORPHEUS-import           Data.Morpheus.Types.Internal.Data (WrapperD (..))--indent :: Text-indent = "  "--renderEqual :: Text -> Text -> Text-renderEqual key value = key <> " = " <> value--renderReturn :: Text-renderReturn = "return "--renderData :: Text -> Text-renderData name = "data " <> name <> " = "--renderCon :: Text -> Text-renderCon name = name <> " "--renderMaybe :: Text -> Text-renderMaybe typeName = "Maybe " <> typeName--renderList :: Text -> Text-renderList typeName = "[" <> typeName <> "]"--renderTuple :: Text -> Text-renderTuple typeName = "(" <> typeName <> ")"--renderSet :: [Text] -> Text-renderSet fields = bracket "{ " <> intercalate ("\n  ," <> indent) fields <> bracket "}\n"-  where-    bracket x = "\n    " <> x--renderAssignment :: Text -> Text -> Text-renderAssignment key value = key <> " :: " <> value--renderExtension :: Text -> Text-renderExtension name = "{-# LANGUAGE " <> name <> " #-}\n"--renderWrapped :: [WrapperD] -> Text -> Text-renderWrapped (ListD:xs)  = renderList . renderWrapped xs-renderWrapped (MaybeD:xs) = renderMaybe . renderWrapped xs-renderWrapped []          = strToText--strToText :: Text -> Text-strToText "String" = "Text"-strToText x        = x--renderUnionCon :: Text -> Text -> Text-renderUnionCon typeName conName = renderCon (typeName <> "_" <> toUpper conName)--data Scope-  = Mutation-  | Subscription-  | Query--data Context = Context-  { moduleName :: Text-  , imports    :: [(Text, [Text])]-  , extensions :: [Text]-  , scope      :: Scope-  , pubSub     :: (Text, Text)-  }
− src/Data/Morpheus/Rendering/Haskell/Types.hs
@@ -1,93 +0,0 @@-{-# LANGUAGE NamedFieldPuns    #-}-{-# LANGUAGE OverloadedStrings #-}--module Data.Morpheus.Rendering.Haskell.Types-  ( renderType-  ) where--import           Data.Maybe                            (catMaybes)-import           Data.Semigroup                        ((<>))-import           Data.Text                             (Text, intercalate, pack, toUpper)-import qualified Data.Text                             as T (head, tail)---- MORPHEUS-import           Data.Morpheus.Rendering.Haskell.Terms (Context (..), Scope (..), indent, renderAssignment, renderCon,-                                                        renderData, renderSet, renderTuple, renderUnionCon,-                                                        renderWrapped)-import           Data.Morpheus.Types.Internal.Data     (DataArgument, DataField (..), DataType (..), DataTyCon (..),-                                                        TypeAlias (..), isNullable)--renderType :: Context -> (Text, DataType) -> Text-renderType context (name, dataType) = typeIntro <> renderData name <> renderT dataType-  where-    renderT (DataScalar _) = renderCon name <> "Int Int" <> defineTypeClass "SCALAR" <> renderGQLScalar name-    renderT (DataEnum DataTyCon {typeData}) = unionType typeData <> defineTypeClass "ENUM"-    renderT (DataUnion DataTyCon {typeData}) = renderUnion name typeData <> defineTypeClass "UNION"-    renderT (DataInputObject DataTyCon {typeData}) =-      renderCon name <> renderObject renderInputField typeData <> defineTypeClass "INPUT_OBJECT"-    renderT (DataInputUnion _) = "\n -- Error: Input Union Not Supported"-    renderT (DataObject DataTyCon {typeData}) =-      renderCon name <> renderObject (renderField context) typeData <> defineTypeClass "OBJECT"-    -----------------------------------------------------------------------------------------------------------    typeIntro = "\n\n---- GQL " <> name <> " ------------------------------- \n"-    -----------------------------------------------------------------------------------------------------------    defineTypeClass kind =-      "\n\n" <> renderTypeInstanceHead "GQLType" name <> indent <> "type KIND " <> name <> " = " <> kind <> "\n\n"-    ------------------------------------------------------------------------------------------------------------renderTypeInstanceHead :: Text -> Text -> Text-renderTypeInstanceHead className name = "instance " <> className <> " " <> name <> " where\n"--renderGQLScalar :: Text -> Text-renderGQLScalar name = renderTypeInstanceHead "GQLScalar " name <> renderParse <> renderSerialize <> "\n\n"-  where-    renderParse = indent <> "parseValue _ = pure (" <> name <> " 0 0 )" <> "\n"-    renderSerialize = indent <> "serialize (" <> name <> " x y ) = Int (x + y)"--renderUnion :: Text -> [DataField] -> Text-renderUnion typeName = unionType . map renderElem-  where-    renderElem DataField {fieldType = TypeAlias {aliasTyCon}} = renderUnionCon typeName aliasTyCon <> aliasTyCon--unionType :: [Text] -> Text-unionType ls = "\n" <> indent <> intercalate ("\n" <> indent <> "| ") ls <> " deriving (Generic)"--renderObject :: (a -> (Text, Maybe Text)) -> [a] -> Text-renderObject f list = intercalate "\n\n" $ renderMainType : catMaybes types-  where-    renderMainType = renderSet fields <> " deriving (Generic)"-    (fields, types) = unzip (map f list)--renderInputField :: (Text, DataField) -> (Text, Maybe Text)-renderInputField (key, DataField {fieldType = TypeAlias {aliasTyCon, aliasWrappers}}) =-  (key `renderAssignment` renderWrapped aliasWrappers aliasTyCon, Nothing)--renderField :: Context -> (Text, DataField) -> (Text, Maybe Text)-renderField Context {scope, pubSub = (channel, content)} (key, DataField { fieldType = TypeAlias { aliasWrappers-                                                                                                 , aliasTyCon-                                                                                                 }-                                                                         , fieldArgs-                                                                         }) =-  (key `renderAssignment` argTypeName <> " -> " <> renderMonad scope <> result aliasWrappers, argTypes)-  where-    renderMonad Subscription = "IOSubRes " <> channel <> " " <> content <> " "-    renderMonad Mutation =-      case channel of-        "()" -> "IORes "-        _    -> "IOMutRes " <> channel <> " " <> content <> " "-    renderMonad _ = "IORes "-    ------------------------------------------------------------------    result wrappers-      | isNullable wrappers = renderTuple (renderWrapped wrappers aliasTyCon)-      | otherwise = renderWrapped wrappers aliasTyCon-    (argTypeName, argTypes) = renderArguments fieldArgs-    renderArguments :: [(Text, DataArgument)] -> (Text, Maybe Text)-    renderArguments [] = ("()", Nothing)-    renderArguments list =-      ( fieldArgTypeName-      , Just (renderData fieldArgTypeName <> renderCon fieldArgTypeName <> renderObject renderInputField list))-      where-        fieldArgTypeName = "Arg" <> camelCase key-        camelCase :: Text -> Text-        camelCase ""   = ""-        camelCase text = toUpper (pack [T.head text]) <> T.tail text
− src/Data/Morpheus/Rendering/Haskell/Values.hs
@@ -1,84 +0,0 @@-{-# LANGUAGE NamedFieldPuns    #-}-{-# LANGUAGE OverloadedStrings #-}--module Data.Morpheus.Rendering.Haskell.Values-  ( renderRootResolver-  , renderResolver-  , Scope(..)-  ) where--import           Data.Semigroup                        ((<>))-import           Data.Text                             (Text)---- MORPHEUS-import           Data.Morpheus.Rendering.Haskell.Terms (Context (..), Scope (..), renderAssignment, renderCon,-                                                        renderEqual, renderReturn, renderSet, renderUnionCon)-import           Data.Morpheus.Types.Internal.Data     (DataField (..), DataType (..), DataTyCon (..),-                                                        DataTypeLib (..), TypeAlias (..), WrapperD (..))--renderRootResolver :: Context -> DataTypeLib -> Text-renderRootResolver _ DataTypeLib {mutation, subscription} = renderSignature <> renderBody <> "\n\n"-  where-    renderSignature = "rootResolver :: " <> renderRootSig (fst <$> subscription) <> "\n"-      where-        renderRootSig (Just sub) = "GQLRootResolver IO Channel Content Query " <> maybeOperator mutation <> " " <> sub-        renderRootSig Nothing    = "GQLRootResolver IO () () Query " <> maybeOperator mutation <> " ()"-        -----------------------        maybeOperator (Just (name, _)) = name-        maybeOperator Nothing          = "()"-    renderBody = "rootResolver =\n  GQLRootResolver" <> renderResObject fields-      where-        fields =-          [ ("queryResolver", "resolveQuery")-          , ("mutationResolver", maybeRes mutation)-          , ("subscriptionResolver", maybeRes subscription)-          ]-      ----------------------------------------------        maybeRes (Just (name, _)) = "resolve" <> name-        maybeRes Nothing          = "return ()"--renderResolver :: Context -> (Text, DataType) -> Text-renderResolver Context {scope, pubSub = (channel, content)} (name, dataType) = renderSig dataType-  where-    renderSig DataScalar {} = defFunc <> renderReturn <> "$ " <> renderCon name <> "0 0"-    renderSig (DataEnum DataTyCon {typeData}) = defFunc <> renderReturn <> renderCon (head typeData)-    renderSig (DataUnion DataTyCon {typeData}) = defFunc <> renderUnionCon name typeCon <> " <$> " <> "resolve" <> typeCon-      where-        typeCon = aliasTyCon $ fieldType $ head typeData-    renderSig (DataObject DataTyCon {typeData}) = defFunc <> renderReturn <> renderCon name <> renderObjFields-      where-        renderObjFields = renderResObject (map renderFieldRes typeData)-        renderFieldRes (key, DataField {fieldType = TypeAlias {aliasWrappers, aliasTyCon}}) =-          (key, "const " <> withScope scope (renderValue aliasWrappers aliasTyCon))-          where-            renderValue (MaybeD:_) = const $ "$ " <> renderReturn <> "Nothing"-            renderValue (ListD:_)  = const $ "$ " <> renderReturn <> "[]"-            renderValue []         = fieldValue-            -----------------------------------------------------------------------------            fieldValue "String" = "$ return \"\""-            fieldValue "Int"    = "$ return 0"-            fieldValue fName    = "resolve" <> fName-            --------------------------------------------            withScope Subscription x = "$ Event { channels = [Channel], content = const " <> x <> " }"-            withScope Mutation x =-              case (channel, content) of-                ("()", "()") -> x-                _            -> "$ toMutResolver [Event {channels = [Channel], content = Content}] " <> x-            withScope _ x = x-    renderSig _ = "" -- INPUT Types Does not Need Resolvers-    ---------------------------------    defFunc = renderSignature <> renderFunc-    -----------------------------------------------------------------------------------------------------------    renderSignature = renderAssignment ("resolve" <> name) (renderMonad name) <> "\n"-    ----------------------------------------------------------------------------------    renderMonad "Mutation"     = "IOMutRes " <> channel <> " " <> content <> " Mutation"-    renderMonad "Subscription" = "SubRootRes IO " <> channel <> " Subscription"-    renderMonad tName          = "IORes " <> tName-    -----------------------------------------------------------------------------------------------------------    renderFunc = "resolve" <> name <> " = "-    -----------------------------------------renderResObject :: [(Text, Text)] -> Text-renderResObject = renderSet . map renderEntry-  where-    renderEntry (key, value) = renderEqual key value
src/Data/Morpheus/Rendering/RenderGQL.hs view
@@ -2,34 +2,51 @@ {-# LANGUAGE FlexibleInstances    #-} {-# LANGUAGE NamedFieldPuns       #-} {-# LANGUAGE OverloadedStrings    #-}-{-# LANGUAGE TypeSynonymInstances #-}  module Data.Morpheus.Rendering.RenderGQL   ( RenderGQL(..)   , renderGraphQLDocument-  ) where+  )+where -import           Data.ByteString.Lazy.Char8         (ByteString)-import           Data.Semigroup                     ((<>))-import           Data.Text                          (Text, intercalate)-import qualified Data.Text.Lazy                     as LT (fromStrict)-import           Data.Text.Lazy.Encoding            (encodeUtf8)+import           Data.ByteString.Lazy.Char8     ( ByteString )+import           Data.Semigroup                 ( (<>) )+import           Data.Text                      ( Text+                                                , intercalate+                                                )+import qualified Data.Text.Lazy                as LT+                                                ( fromStrict )+import           Data.Text.Lazy.Encoding        ( encodeUtf8 )  -- MORPHEUS-import           Data.Morpheus.Types.Internal.Data  (DataField (..), DataTyCon (..), DataType (..), DataTypeLib,-                                                     DataTypeWrapper (..), Key, TypeAlias (..), WrapperD (..),-                                                     allDataTypes, isDefaultTypeName, toGQLWrapper)-import           Data.Morpheus.Types.Internal.Value (convertToJSONName)+import           Data.Morpheus.Types.Internal.AST+                                                ( DataField(..)+                                                , DataTyCon(..)+                                                , DataType(..)+                                                , DataTypeLib+                                                , DataTypeWrapper(..)+                                                , Key+                                                , TypeAlias(..)+                                                , TypeWrapper(..)+                                                , allDataTypes+                                                , createInputUnionFields+                                                , fieldVisibility+                                                , isDefaultTypeName+                                                , toGQLWrapper+                                                , DataEnumValue(..)+                                                , convertToJSONName ) + renderGraphQLDocument :: DataTypeLib -> ByteString-renderGraphQLDocument lib = encodeUtf8 $ LT.fromStrict $ intercalate "\n\n" $ map render visibleTypes-  where-    visibleTypes = filter (not . isDefaultTypeName . fst) (allDataTypes lib)+renderGraphQLDocument lib =+  encodeUtf8 $ LT.fromStrict $ intercalate "\n\n" $ map render visibleTypes+ where+  visibleTypes = filter (not . isDefaultTypeName . fst) (allDataTypes lib)  class RenderGQL a where   render :: a -> Key-  renderWrapped :: a -> [WrapperD] -> Key-  default renderWrapped :: a -> [WrapperD] -> Key+  renderWrapped :: a -> [TypeWrapper] -> Key+  default renderWrapped :: a -> [TypeWrapper] -> Key   renderWrapped x wrappers = showGQLWrapper (toGQLWrapper wrappers)     where       showGQLWrapper []               = render x@@ -40,44 +57,56 @@   render = id  instance RenderGQL TypeAlias where-  render TypeAlias {aliasTyCon, aliasWrappers} = renderWrapped aliasTyCon aliasWrappers+  render TypeAlias { aliasTyCon, aliasWrappers } =+    renderWrapped aliasTyCon aliasWrappers  instance RenderGQL DataType where-  render (DataScalar x)      = typeName x-  render (DataEnum x)        = typeName x-  render (DataUnion x)       = typeName x+  render (DataScalar      x) = typeName x+  render (DataEnum        x) = typeName x+  render (DataUnion       x) = typeName x   render (DataInputObject x) = typeName x-  render (DataInputUnion x)  = typeName x-  render ( DataObject x)     = typeName x+  render (DataInputUnion  x) = typeName x+  render (DataObject      x) = typeName x +instance RenderGQL DataEnumValue where+  render DataEnumValue { enumName } = enumName+ instance RenderGQL (Key, DataType) where-  render (name, DataScalar {}) = "scalar " <> name-  render (name, DataEnum DataTyCon {typeData}) = "enum " <> name <> renderObject id typeData-  render (name, DataUnion DataTyCon {typeData}) =-    "union " <> name <> " =\n    " <> intercalate ("\n" <> renderIndent <> "| ") (map (render . fieldType) typeData)-  render (name, DataInputObject DataTyCon {typeData}) = "input " <> name <> render typeData-  render (name, DataInputUnion DataTyCon {typeData}) = "input " <> name <> render (mapKeys typeData)-  render (name, DataObject DataTyCon {typeData}) = "type " <> name <> render typeData+  render (name, DataScalar{}) = "scalar " <> name+  render (name, DataEnum DataTyCon { typeData }) =+    "enum " <> name <> renderObject render typeData+  render (name, DataUnion DataTyCon { typeData }) =+    "union "+      <> name+      <> " =\n    "+      <> intercalate ("\n" <> renderIndent <> "| ") typeData+  render (name, DataInputObject DataTyCon { typeData }) =+    "input " <> name <> render typeData+  render (name, DataInputUnion DataTyCon { typeData }) =+    "input " <> name <> render fields+    where fields = createInputUnionFields name typeData+  render (name, DataObject DataTyCon { typeData }) =+    "type " <> name <> render typeData -mapKeys :: [DataField] -> [(Text, DataField)]-mapKeys = map (\x -> (fieldName x, x)) + -- OBJECT instance RenderGQL [(Text, DataField)] where   render = renderObject renderField . ignoreHidden-    where-      renderField :: (Text, DataField) -> Text-      renderField (key, DataField {fieldType, fieldArgs}) =-        convertToJSONName key <> renderArgs fieldArgs <> ": " <> render fieldType-        where-          renderArgs []   = ""-          renderArgs list = "(" <> intercalate ", " (map renderField list) <> ")"-      ------------------------------------------------------------      ignoreHidden :: [(Text, DataField)] -> [(Text, DataField)]-      ignoreHidden = filter (not . fieldHidden . snd)+   where+    renderField :: (Text, DataField) -> Text+    renderField (key, DataField { fieldType, fieldArgs }) =+      convertToJSONName key <> renderArgs fieldArgs <> ": " <> render fieldType+     where+      renderArgs []   = ""+      renderArgs list = "(" <> intercalate ", " (map renderField list) <> ")"+    -----------------------------------------------------------+    ignoreHidden :: [(Text, DataField)] -> [(Text, DataField)]+    ignoreHidden = filter fieldVisibility  renderIndent :: Text renderIndent = "  "  renderObject :: (a -> Text) -> [a] -> Text-renderObject f list = " { \n  " <> intercalate ("\n" <> renderIndent) (map f list) <> "\n}"+renderObject f list =+  " { \n  " <> intercalate ("\n" <> renderIndent) (map f list) <> "\n}"
src/Data/Morpheus/Rendering/RenderIntrospection.hs view
@@ -2,24 +2,43 @@ {-# LANGUAGE NamedFieldPuns        #-} {-# LANGUAGE OverloadedStrings     #-} {-# LANGUAGE TypeOperators         #-}+{-# LANGUAGE FlexibleContexts      #-}  module Data.Morpheus.Rendering.RenderIntrospection   ( render   , createObjectType-  ) where+  )+where -import           Control.Monad.Fail                 (MonadFail)-import           Data.Semigroup                     ((<>))-import           Data.Text                          (Text, unpack)+import           Data.Semigroup                 ( (<>) )+import           Data.Text                      ( Text )+import           Data.Maybe                     ( isJust ) -import           Data.Morpheus.Schema.Schema  -- Morpheus-import           Data.Morpheus.Schema.TypeKind      (TypeKind (..))-import           Data.Morpheus.Types.Internal.Data  (DataField (..), DataObject, DataTyCon (..), DataType (..),-                                                     DataTypeKind (..), DataTypeLib, DataTypeWrapper (..), DataUnion,-                                                     TypeAlias (..), kindOf, lookupDataType, toGQLWrapper)-import           Data.Morpheus.Types.Internal.Value (convertToJSONName)+import           Data.Morpheus.Schema.Schema+import           Data.Morpheus.Schema.TypeKind  ( TypeKind(..) )+import           Data.Morpheus.Types.Internal.AST+                                                ( DataField(..)+                                                , DataTyCon(..)+                                                , DataType(..)+                                                , DataTypeKind(..)+                                                , DataTypeLib+                                                , DataTypeWrapper(..)+                                                , DataUnion+                                                , Meta(..)+                                                , TypeAlias(..)+                                                , createInputUnionFields+                                                , fieldVisibility+                                                , kindOf+                                                , lookupDataType+                                                , toGQLWrapper+                                                , DataEnumValue(..)+                                                , lookupDeprecated+                                                , lookupDeprecatedReason+                                                , convertToJSONName )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Failure(..) )  constRes :: Applicative m => a -> b -> m a constRes = const . pure@@ -27,27 +46,54 @@ type Result m a = DataTypeLib -> m a  class RenderSchema a b where-  render :: (Monad m, MonadFail m) => (Text, a) -> DataTypeLib -> m (b m)+  render :: (Monad m, Failure Text m) => (Text, a) -> DataTypeLib -> m (b m)  instance RenderSchema DataType S__Type where-  render (key, DataScalar DataTyCon {typeDescription})  =-    constRes $ createLeafType SCALAR key typeDescription Nothing-  render (key, DataEnum DataTyCon {typeDescription, typeData})  =-    constRes $ createLeafType ENUM key typeDescription (Just $ map createEnumValue typeData)-  render (name, DataInputObject iObject) = renderInputObject (name, iObject)+  render (key, DataScalar DataTyCon { typeMeta }) =+    constRes $ createLeafType SCALAR key typeMeta Nothing+  render (key, DataEnum DataTyCon { typeMeta, typeData }) =+    constRes+      $ createLeafType ENUM key typeMeta (Just $ map createEnumValue typeData)+  render (name, DataInputObject DataTyCon { typeData, typeMeta }) =+    renderInputObject+   where+    renderInputObject lib = do+      fields <- traverse (`renderinputValue` lib) typeData+      pure $ createInputObject name typeMeta fields   render (name, DataObject object') = typeFromObject (name, object')-    where-      typeFromObject (key, DataTyCon {typeData, typeDescription}) lib =-        createObjectType key typeDescription <$>-        (Just <$> traverse (`render` lib) (filter (not . fieldHidden . snd) typeData))-  render (name, DataUnion union') = const $ pure $ typeFromUnion (name, union')+   where+    typeFromObject (key, DataTyCon { typeData, typeMeta }) lib =+      createObjectType key (typeMeta >>= metaDescription)+        <$> (Just <$> traverse (`render` lib) (filter fieldVisibility typeData))+  render (name, DataUnion union) = constRes $ typeFromUnion (name, union)   render (name, DataInputUnion inpUnion') = renderInputUnion (name, inpUnion') +createEnumValue :: Monad m => DataEnumValue -> S__EnumValue m+createEnumValue DataEnumValue { enumName, enumMeta } = S__EnumValue+  { s__EnumValueName              = constRes enumName+  , s__EnumValueDescription       = constRes (enumMeta >>= metaDescription)+  , s__EnumValueIsDeprecated      = constRes (isJust deprecated)+  , s__EnumValueDeprecationReason = constRes+                                      (deprecated >>= lookupDeprecatedReason)+  }+  where deprecated = enumMeta >>= lookupDeprecated+ instance RenderSchema DataField S__Field where-  render (key, field@DataField {fieldType = TypeAlias {aliasTyCon}, fieldArgs}) lib = do-    kind <- renderTypeKind <$> lookupKind aliasTyCon lib-    createFieldWith key (wrap field $ createType kind aliasTyCon Nothing $ Just []) <$>-      traverse (`inputValueFromArg` lib) fieldArgs+  render (name, field@DataField { fieldType = TypeAlias { aliasTyCon }, fieldArgs, fieldMeta }) lib+    = do+      kind <- renderTypeKind <$> lookupKind aliasTyCon lib+      args <- traverse (`renderinputValue` lib) fieldArgs+      pure S__Field+        { s__FieldName              = constRes (convertToJSONName name)+        , s__FieldDescription       = constRes (fieldMeta >>= metaDescription)+        , s__FieldArgs              = constRes args+        , s__FieldType'             =+          constRes (wrap field $ createType kind aliasTyCon Nothing $ Just [])+        , s__FieldIsDeprecated      = constRes (isJust deprecated)+        , s__FieldDeprecationReason = constRes+                                        (deprecated >>= lookupDeprecatedReason)+        }+    where deprecated = fieldMeta >>= lookupDeprecated  renderTypeKind :: DataTypeKind -> TypeKind renderTypeKind KindScalar      = SCALAR@@ -60,147 +106,140 @@ renderTypeKind KindNonNull     = NON_NULL  wrap :: Monad m => DataField -> S__Type m -> S__Type m-wrap DataField {fieldType = TypeAlias {aliasWrappers}} typ = foldr wrapByTypeWrapper typ (toGQLWrapper aliasWrappers)+wrap DataField { fieldType = TypeAlias { aliasWrappers } } typ =+  foldr wrapByTypeWrapper typ (toGQLWrapper aliasWrappers)  wrapByTypeWrapper :: Monad m => DataTypeWrapper -> S__Type m -> S__Type m wrapByTypeWrapper ListType    = wrapAs LIST wrapByTypeWrapper NonNullType = wrapAs NON_NULL -lookupKind :: (Monad m, MonadFail m) => Text -> Result m DataTypeKind-lookupKind name lib =-  case lookupDataType name lib of-    Nothing    -> fail $ unpack ("Kind Not Found: " <> name)-    Just value -> pure (kindOf value)+lookupKind :: (Monad m, Failure Text m) => Text -> Result m DataTypeKind+lookupKind name lib = case lookupDataType name lib of+  Nothing    -> failure $ "Kind Not Found: " <> name+  Just value -> pure (kindOf value) -inputValueFromArg :: (Monad m,MonadFail m) => (Text, DataField) -> Result m (S__InputValue m)-inputValueFromArg (key, input) = fmap (createInputValueWith key) . createInputObjectType input+renderinputValue+  :: (Monad m, Failure Text m)+  => (Text, DataField)+  -> Result m (S__InputValue m)+renderinputValue (key, input) =+  fmap (createInputValueWith key (fieldMeta input))+    . createInputObjectType input -createInputObjectType :: (Monad m, MonadFail m) => DataField -> Result m (S__Type m)-createInputObjectType field@DataField {fieldType = TypeAlias {aliasTyCon}} lib = do-  kind <- renderTypeKind <$> lookupKind aliasTyCon lib-  pure $ wrap field $ createType kind aliasTyCon Nothing $ Just []+createInputObjectType+  :: (Monad m, Failure Text m) => DataField -> Result m (S__Type m)+createInputObjectType field@DataField { fieldType = TypeAlias { aliasTyCon } } lib+  = do+    kind <- renderTypeKind <$> lookupKind aliasTyCon lib+    pure $ wrap field $ createType kind aliasTyCon Nothing $ Just [] -renderInputObject :: (Monad m, MonadFail m) => (Text, DataObject) -> Result m (S__Type m)-renderInputObject (key, DataTyCon {typeData, typeDescription}) lib = do-  fields <- traverse (`inputValueFromArg` lib) typeData-  pure $ createInputObject key typeDescription fields -renderInputUnion :: (Monad m, MonadFail m) => (Text, DataUnion) -> Result m (S__Type m)-renderInputUnion (key', DataTyCon {typeData, typeDescription}) lib =-  createInputObject key' typeDescription <$> traverse createField typeData-  where-    createField field = createInputValueWith (fieldName field) <$> createInputObjectType field lib+renderInputUnion+  :: (Monad m, Failure Text m) => (Text, DataUnion) -> Result m (S__Type m)+renderInputUnion (key, DataTyCon { typeData, typeMeta }) lib =+  createInputObject key typeMeta+    <$> traverse createField (createInputUnionFields key typeData)+ where+  createField (name, field) =+    createInputValueWith name Nothing <$> createInputObjectType field lib -createLeafType :: Monad m => TypeKind -> Text -> Maybe Text -> Maybe [S__EnumValue m] -> S__Type m-createLeafType kind name description enums =-  S__Type-    { s__TypeKind = constRes kind-    , s__TypeName = constRes $ Just name-    , s__TypeDescription = constRes description-    , s__TypeFields = constRes Nothing-    , s__TypeOfType = constRes Nothing-    , s__TypeInterfaces = constRes Nothing-    , s__TypePossibleTypes = constRes Nothing-    , s__TypeEnumValues = constRes enums-    , s__TypeInputFields = constRes Nothing-    }+createLeafType+  :: Monad m+  => TypeKind+  -> Text+  -> Maybe Meta+  -> Maybe [S__EnumValue m]+  -> S__Type m+createLeafType kind name meta enums = S__Type+  { s__TypeKind          = constRes kind+  , s__TypeName          = constRes $ Just name+  , s__TypeDescription   = constRes (meta >>= metaDescription)+  , s__TypeFields        = constRes Nothing+  , s__TypeOfType        = constRes Nothing+  , s__TypeInterfaces    = constRes Nothing+  , s__TypePossibleTypes = constRes Nothing+  , s__TypeEnumValues    = constRes enums+  , s__TypeInputFields   = constRes Nothing+  }  typeFromUnion :: Monad m => (Text, DataUnion) -> S__Type m-typeFromUnion (name, DataTyCon {typeData, typeDescription}) =-  S__Type-    { s__TypeKind = constRes UNION-    , s__TypeName = constRes $ Just name-    , s__TypeDescription = constRes typeDescription-    , s__TypeFields = constRes Nothing-    , s__TypeOfType = constRes Nothing-    , s__TypeInterfaces = constRes Nothing-    , s__TypePossibleTypes =-        constRes $ Just (map (\x -> createObjectType (aliasTyCon $ fieldType x) Nothing $ Just []) typeData)-    , s__TypeEnumValues = constRes Nothing-    , s__TypeInputFields = constRes Nothing-    }+typeFromUnion (name, DataTyCon { typeData, typeMeta }) = S__Type+  { s__TypeKind          = constRes UNION+  , s__TypeName          = constRes $ Just name+  , s__TypeDescription   = constRes (typeMeta >>= metaDescription)+  , s__TypeFields        = constRes Nothing+  , s__TypeOfType        = constRes Nothing+  , s__TypeInterfaces    = constRes Nothing+  , s__TypePossibleTypes =+    constRes $ Just (map (\x -> createObjectType x Nothing $ Just []) typeData)+  , s__TypeEnumValues    = constRes Nothing+  , s__TypeInputFields   = constRes Nothing+  } -createObjectType :: Monad m => Text -> Maybe Text -> Maybe [S__Field m] -> S__Type m-createObjectType name description fields =-  S__Type-    { s__TypeKind = constRes OBJECT-    , s__TypeName = constRes $ Just name-    , s__TypeDescription = constRes description-    , s__TypeFields = constRes fields-    , s__TypeOfType = constRes Nothing-    , s__TypeInterfaces = constRes $ Just []-    , s__TypePossibleTypes = constRes Nothing-    , s__TypeEnumValues = constRes Nothing-    , s__TypeInputFields = constRes Nothing-    }+createObjectType+  :: Monad m => Text -> Maybe Text -> Maybe [S__Field m] -> S__Type m+createObjectType name description fields = S__Type+  { s__TypeKind          = constRes OBJECT+  , s__TypeName          = constRes $ Just name+  , s__TypeDescription   = constRes description+  , s__TypeFields        = constRes fields+  , s__TypeOfType        = constRes Nothing+  , s__TypeInterfaces    = constRes $ Just []+  , s__TypePossibleTypes = constRes Nothing+  , s__TypeEnumValues    = constRes Nothing+  , s__TypeInputFields   = constRes Nothing+  } -createInputObject :: Monad m => Text -> Maybe Text -> [S__InputValue m] -> S__Type m-createInputObject name description fields =-  S__Type-    { s__TypeKind = constRes INPUT_OBJECT-    , s__TypeName = constRes $ Just name-    , s__TypeDescription = constRes description-    , s__TypeFields = constRes Nothing-    , s__TypeOfType = constRes Nothing-    , s__TypeInterfaces = constRes Nothing-    , s__TypePossibleTypes = constRes Nothing-    , s__TypeEnumValues = constRes Nothing-    , s__TypeInputFields = constRes $ Just fields-    }+createInputObject+  :: Monad m => Text -> Maybe Meta -> [S__InputValue m] -> S__Type m+createInputObject name meta fields = S__Type+  { s__TypeKind          = constRes INPUT_OBJECT+  , s__TypeName          = constRes $ Just name+  , s__TypeDescription   = constRes (meta >>= metaDescription)+  , s__TypeFields        = constRes Nothing+  , s__TypeOfType        = constRes Nothing+  , s__TypeInterfaces    = constRes Nothing+  , s__TypePossibleTypes = constRes Nothing+  , s__TypeEnumValues    = constRes Nothing+  , s__TypeInputFields   = constRes $ Just fields+  } -createType :: Monad m => TypeKind -> Text -> Maybe Text -> Maybe [S__Field m] -> S__Type m-createType kind name description fields' =-  S__Type-    { s__TypeKind = constRes kind-    , s__TypeName = constRes $ Just name-    , s__TypeDescription = constRes description-    , s__TypeFields = constRes fields'-    , s__TypeOfType = constRes Nothing-    , s__TypeInterfaces = constRes Nothing-    , s__TypePossibleTypes = constRes Nothing-    , s__TypeEnumValues = constRes $ Just []-    , s__TypeInputFields = constRes Nothing-    }+createType+  :: Monad m+  => TypeKind+  -> Text+  -> Maybe Text+  -> Maybe [S__Field m]+  -> S__Type m+createType kind name description fields = S__Type+  { s__TypeKind          = constRes kind+  , s__TypeName          = constRes $ Just name+  , s__TypeDescription   = constRes description+  , s__TypeFields        = constRes fields+  , s__TypeOfType        = constRes Nothing+  , s__TypeInterfaces    = constRes Nothing+  , s__TypePossibleTypes = constRes Nothing+  , s__TypeEnumValues    = constRes $ Just []+  , s__TypeInputFields   = constRes Nothing+  }  wrapAs :: Monad m => TypeKind -> S__Type m -> S__Type m-wrapAs kind contentType =-  S__Type-    { s__TypeKind = constRes kind-    , s__TypeName = constRes Nothing-    , s__TypeDescription = constRes Nothing-    , s__TypeFields = constRes Nothing-    , s__TypeOfType = constRes $ Just contentType-    , s__TypeInterfaces = constRes Nothing-    , s__TypePossibleTypes = constRes Nothing-    , s__TypeEnumValues = constRes Nothing-    , s__TypeInputFields = constRes Nothing-    }--createFieldWith :: Monad m => Text -> S__Type m -> [S__InputValue m] -> S__Field m-createFieldWith _name fieldType fieldArgs =-  S__Field-    { s__FieldName = constRes (convertToJSONName _name)-    , s__FieldDescription = constRes Nothing-    , s__FieldArgs = constRes fieldArgs-    , s__FieldType' = constRes fieldType-    , s__FieldIsDeprecated = constRes False-    , s__FieldDeprecationReason = constRes Nothing-    }--createInputValueWith :: Monad m => Text -> S__Type m -> S__InputValue m-createInputValueWith name ivType =-  S__InputValue-    { s__InputValueName = constRes (convertToJSONName name)-    , s__InputValueDescription = constRes Nothing-    , s__InputValueType' = constRes ivType-    , s__InputValueDefaultValue = constRes Nothing-    }+wrapAs kind contentType = S__Type { s__TypeKind          = constRes kind+                                  , s__TypeName          = constRes Nothing+                                  , s__TypeDescription   = constRes Nothing+                                  , s__TypeFields        = constRes Nothing+                                  , s__TypeOfType = constRes $ Just contentType+                                  , s__TypeInterfaces    = constRes Nothing+                                  , s__TypePossibleTypes = constRes Nothing+                                  , s__TypeEnumValues    = constRes Nothing+                                  , s__TypeInputFields   = constRes Nothing+                                  } -createEnumValue :: Monad m => Text -> S__EnumValue m-createEnumValue name =-  S__EnumValue-    { s__EnumValueName = constRes name-    , s__EnumValueDescription = constRes Nothing-    , s__EnumValueIsDeprecated = constRes False-    , s__EnumValueDeprecationReason = constRes Nothing-    }+createInputValueWith+  :: Monad m => Text -> Maybe Meta -> S__Type m -> S__InputValue m+createInputValueWith name meta ivType = S__InputValue+  { s__InputValueName         = constRes (convertToJSONName name)+  , s__InputValueDescription  = constRes (meta >>= metaDescription)+  , s__InputValueType'        = constRes ivType+  , s__InputValueDefaultValue = constRes Nothing+  }
src/Data/Morpheus/Schema/Schema.hs view
@@ -8,8 +8,9 @@ {-# LANGUAGE TemplateHaskell       #-} {-# LANGUAGE TypeFamilies          #-} {-# LANGUAGE TypeOperators         #-}-{-# LANGUAGE TypeSynonymInstances , FlexibleContexts  #-}+{-# LANGUAGE FlexibleContexts      #-} + module Data.Morpheus.Schema.Schema   ( Root(..)   , Root__typeArgs(..)@@ -18,13 +19,15 @@   , S__Field(..)   , S__EnumValue(..)   , S__InputValue(..)-  ) where+  )+where -import           Data.Text                                (Text)+import           Data.Text                      ( Text )  -- MORPHEUS-import           Data.Morpheus.Execution.Document.Compile (gqlDocumentNamespace)-import           Data.Morpheus.Schema.TypeKind            (TypeKind)+import           Data.Morpheus.Execution.Document.Compile+                                                ( gqlDocumentNamespace )+import           Data.Morpheus.Schema.TypeKind  ( TypeKind )  type S__TypeKind = TypeKind 
src/Data/Morpheus/Schema/SchemaAPI.hs view
@@ -7,66 +7,93 @@   ( hiddenRootFields   , defaultTypes   , schemaAPI-  ) where+  )+where  import           Data.Proxy-import           Data.Text                                     (Text)+import           Data.Text                      ( Text )  -- MORPHEUS-import           Data.Morpheus.Execution.Internal.GraphScanner (resolveUpdates)-import           Data.Morpheus.Execution.Server.Introspect     (ObjectFields (..), TypeUpdater, introspect)-import           Data.Morpheus.Rendering.RenderIntrospection   (createObjectType, render)-import           Data.Morpheus.Schema.Schema                   (Root (..), Root__typeArgs (..), S__Schema (..), S__Type)-import           Data.Morpheus.Types                           (constRes)-import           Data.Morpheus.Types.GQLType                   (CUSTOM)-import           Data.Morpheus.Types.ID                        (ID)-import           Data.Morpheus.Types.Internal.Data             (DataField (..), DataObject, DataTypeLib (..), QUERY,-                                                                allDataTypes)-import           Data.Morpheus.Types.Internal.Resolver         (Resolver (..))+import           Data.Morpheus.Execution.Server.Introspect+                                                ( ObjectFields(..)+                                                , TypeUpdater+                                                , introspect+                                                )+import           Data.Morpheus.Rendering.RenderIntrospection+                                                ( createObjectType+                                                , render+                                                )+import           Data.Morpheus.Schema.Schema    ( Root(..)+                                                , Root__typeArgs(..)+                                                , S__Schema(..)+                                                , S__Type+                                                )+import           Data.Morpheus.Types            ( constRes )+import           Data.Morpheus.Types.GQLType    ( CUSTOM )+import           Data.Morpheus.Types.ID         ( ID )+import           Data.Morpheus.Types.Internal.AST+                                                ( DataField(..)+                                                , DataObject+                                                , DataTypeLib(..)+                                                , QUERY+                                                , allDataTypes+                                                , lookupDataType+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Resolver(..)+                                                , resolveUpdates+                                                ) -convertTypes :: Monad m => DataTypeLib -> Resolver QUERY m e [S__Type (Resolver QUERY m e )]++convertTypes+  :: Monad m => DataTypeLib -> Resolver QUERY e m [S__Type (Resolver QUERY e m)] convertTypes lib = traverse (`render` lib) (allDataTypes lib) -buildSchemaLinkType :: Monad m => (Text, DataObject) -> S__Type (Resolver QUERY m e )+buildSchemaLinkType+  :: Monad m => (Text, DataObject) -> S__Type (Resolver QUERY e m) buildSchemaLinkType (key', _) = createObjectType key' Nothing $ Just [] -findType :: Monad m => Text -> DataTypeLib -> Resolver QUERY m e (Maybe (S__Type (Resolver QUERY m e )))-findType name lib = renderT (lookup name (allDataTypes lib))-  where-    renderT (Just datatype) = Just <$> render (name,datatype) lib-    renderT Nothing         = pure Nothing--initSchema :: Monad m => DataTypeLib -> Resolver QUERY m e (S__Schema (Resolver QUERY m e ))-initSchema lib =-  pure-    S__Schema-      { s__SchemaTypes = const $ convertTypes lib-      , s__SchemaQueryType = constRes $ buildSchemaLinkType $ query lib-      , s__SchemaMutationType = constRes $ buildSchemaLinkType <$> mutation lib-      , s__SchemaSubscriptionType = constRes $ buildSchemaLinkType <$> subscription lib-      , s__SchemaDirectives = constRes []-      }+findType+  :: Monad m+  => Text+  -> DataTypeLib+  -> Resolver QUERY e m (Maybe (S__Type (Resolver QUERY e m)))+findType name lib = renderT (lookupDataType name lib)+ where+  renderT (Just datatype) = Just <$> render (name, datatype) lib+  renderT Nothing         = pure Nothing -hideFields :: (Text, DataField) -> (Text, DataField)-hideFields (key', field) = (key', field {fieldHidden = True})+initSchema+  :: Monad m+  => DataTypeLib+  -> Resolver QUERY e m (S__Schema (Resolver QUERY e m))+initSchema lib = pure S__Schema+  { s__SchemaTypes            = const $ convertTypes lib+  , s__SchemaQueryType        = constRes $ buildSchemaLinkType $ query lib+  , s__SchemaMutationType     = constRes $ buildSchemaLinkType <$> mutation lib+  , s__SchemaSubscriptionType = constRes+                                $   buildSchemaLinkType+                                <$> subscription lib+  , s__SchemaDirectives       = constRes []+  }  hiddenRootFields :: [(Text, DataField)]-hiddenRootFields = map hideFields $ fst $ objectFields (Proxy :: Proxy (CUSTOM (Root Maybe))) (Proxy @(Root Maybe))+hiddenRootFields = fst+  $ objectFields (Proxy :: Proxy (CUSTOM (Root Maybe))) (Proxy @(Root Maybe))  defaultTypes :: TypeUpdater-defaultTypes =-  flip-    resolveUpdates-    [ introspect (Proxy @Bool)-    , introspect (Proxy @Int)-    , introspect (Proxy @Float)-    , introspect (Proxy @Text)-    , introspect (Proxy @ID)-    , introspect (Proxy @(S__Schema Maybe))-    ]+defaultTypes = flip+  resolveUpdates+  [ introspect (Proxy @Bool)+  , introspect (Proxy @Int)+  , introspect (Proxy @Float)+  , introspect (Proxy @Text)+  , introspect (Proxy @ID)+  , introspect (Proxy @(S__Schema Maybe))+  ] -schemaAPI :: Monad m => DataTypeLib -> Root (Resolver QUERY m e)-schemaAPI lib = Root {root__type, root__schema}-  where-    root__type (Root__typeArgs name) = findType name lib-    root__schema _ = initSchema lib+schemaAPI :: Monad m => DataTypeLib -> Root (Resolver QUERY e m)+schemaAPI lib = Root { root__type, root__schema }+ where+  root__type (Root__typeArgs name) = findType name lib+  root__schema _ = initSchema lib
src/Data/Morpheus/Schema/TypeKind.hs view
@@ -5,11 +5,12 @@  module Data.Morpheus.Schema.TypeKind   ( TypeKind(..)-  ) where+  )+where -import           Data.Aeson                  (FromJSON (..))-import           Data.Morpheus.Kind          (ENUM)-import           Data.Morpheus.Types.GQLType (GQLType (KIND, __typeName))+import           Data.Aeson                     ( FromJSON(..) )+import           Data.Morpheus.Kind             ( ENUM )+import           Data.Morpheus.Types.GQLType    ( GQLType(KIND, __typeName) ) import           GHC.Generics  instance GQLType TypeKind where
src/Data/Morpheus/Server.hs view
@@ -9,67 +9,93 @@   ( gqlSocketApp   , initGQLState   , GQLState-  ) where+  )+where -import           Control.Exception                                   (finally)-import           Control.Monad                                       (forever)-import           Data.Text                                           (Text)-import           Network.WebSockets                                  (ServerApp, acceptRequestWith, forkPingThread,-                                                                      pendingRequest, receiveData, sendTextData)+import           Control.Exception              ( finally )+import           Control.Monad                  ( forever )+import           Data.Text                      ( Text )+import           Network.WebSockets             ( ServerApp+                                                , acceptRequestWith+                                                , forkPingThread+                                                , pendingRequest+                                                , receiveData+                                                , sendTextData+                                                )  -- MORPHEUS-import           Data.Morpheus.Execution.Server.Resolve              (RootResCon, streamResolver)-import           Data.Morpheus.Execution.Subscription.Apollo         (SubAction (..), acceptApolloSubProtocol,-                                                                      apolloFormat, toApolloResponse)-import           Data.Morpheus.Execution.Subscription.ClientRegister (GQLState, addClientSubscription, connectClient,-                                                                      disconnectClient, initGQLState, publishUpdates,-                                                                      removeClientSubscription)-import           Data.Morpheus.Types.Internal.Resolver               (GQLRootResolver (..))-import           Data.Morpheus.Types.Internal.Stream                 (GQLChannel (..), ResponseEvent (..),-                                                                      ResponseStream, closeStream)-import           Data.Morpheus.Types.Internal.WebSocket              (GQLClient (..))-import           Data.Morpheus.Types.IO                              (GQLResponse (..))+import           Data.Morpheus.Execution.Server.Resolve+                                                ( RootResCon+                                                , coreResolver+                                                )+import           Data.Morpheus.Execution.Subscription.Apollo+                                                ( SubAction(..)+                                                , acceptApolloSubProtocol+                                                , apolloFormat+                                                , toApolloResponse+                                                )+import           Data.Morpheus.Execution.Subscription.ClientRegister+                                                ( GQLState+                                                , addClientSubscription+                                                , connectClient+                                                , disconnectClient+                                                , initGQLState+                                                , publishUpdates+                                                , removeClientSubscription+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( GQLRootResolver(..)+                                                , GQLChannel(..)+                                                , ResponseEvent(..)+                                                , ResponseStream+                                                , runResultT+                                                , Result(..)+                                                )+import           Data.Morpheus.Types.Internal.WebSocket+                                                ( GQLClient(..) )+import           Data.Morpheus.Types.IO         ( GQLResponse(..) )+import           Data.Morpheus.Types.Internal.AST+                                                ( Value ) -handleSubscription :: (Eq (StreamChannel e), GQLChannel e) => GQLClient IO e+handleSubscription+  :: (Eq (StreamChannel e), GQLChannel e)+  => GQLClient IO e   -> GQLState IO e   -> Text-  -> ResponseStream IO e  GQLResponse+  -> ResponseStream e IO Value   -> IO ()-handleSubscription GQLClient {clientConnection, clientID} state sessionId stream = do-  (actions, response) <- closeStream stream-  case response of-    Data _ -> mapM_ execute actions-    Errors _ ->-      sendTextData clientConnection (toApolloResponse sessionId response)-  where-    execute (Publish pub)   = publishUpdates state pub-    execute (Subscribe sub) = addClientSubscription clientID sub sessionId state+handleSubscription GQLClient { clientConnection, clientID } state sessionId stream+  = do+    response <- runResultT stream+    case response of+      Success { events } -> mapM_ execute events+      Failure errors     -> sendTextData+        clientConnection+        (toApolloResponse sessionId $ Errors errors)+ where+  execute (Publish   pub) = publishUpdates state pub+  execute (Subscribe sub) = addClientSubscription clientID sub sessionId state  -- | Wai WebSocket Server App for GraphQL subscriptions-gqlSocketApp ::-     RootResCon IO e  que mut sub-  => GQLRootResolver IO e  que mut sub+gqlSocketApp+  :: RootResCon IO e que mut sub+  => GQLRootResolver IO e que mut sub   -> GQLState IO e   -> ServerApp gqlSocketApp gqlRoot state pending = do-  connection <--    acceptRequestWith pending $ acceptApolloSubProtocol (pendingRequest pending)+  connection <- acceptRequestWith pending+    $ acceptApolloSubProtocol (pendingRequest pending)   forkPingThread connection 30   client <- connectClient connection state   finally (queryHandler client) (disconnectClient client state)-  where-    queryHandler client = forever handleRequest-      where-        handleRequest =-          receiveData (clientConnection client) >>=-          resolveMessage . apolloFormat-          where-            resolveMessage (SubError x) = print x-            resolveMessage (AddSub sessionId request) =-              handleSubscription-                client-                state-                sessionId-                (streamResolver gqlRoot request)-            resolveMessage (RemoveSub sessionId) =-              removeClientSubscription (clientID client) sessionId state+ where+  queryHandler client = forever handleRequest+   where+    handleRequest =+      receiveData (clientConnection client) >>= resolveMessage . apolloFormat+     where+      resolveMessage (SubError x) = print x+      resolveMessage (AddSub sessionId request) =+        handleSubscription client state sessionId (coreResolver gqlRoot request)+      resolveMessage (RemoveSub sessionId) =+        removeClientSubscription (clientID client) sessionId state
src/Data/Morpheus/Types.hs view
@@ -1,11 +1,11 @@-{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE DataKinds  #-} -- | GQL Types module Data.Morpheus.Types   ( Event(..)   -- Type Classes   , GQLType(KIND, description)   , GQLScalar(parseValue, serialize)-  -- Values   , GQLRequest(..)   , GQLResponse(..)   , ID(..)@@ -24,31 +24,55 @@   , QUERY   , MUTATION   , SUBSCRIPTION-  , liftEitherM-  , liftM-  ) where+  , liftEither+  , lift+  , ResolveQ+  , ResolveM+  , ResolveS+  )+where -import           Data.Morpheus.Types.GQLScalar         (GQLScalar (parseValue, serialize))-import           Data.Morpheus.Types.GQLType           (GQLType (KIND, description))-import           Data.Morpheus.Types.ID                (ID (..))-import           Data.Morpheus.Types.Internal.Data     (MUTATION, QUERY, SUBSCRIPTION)-import           Data.Morpheus.Types.Internal.Resolver (Event (..), GQLRootResolver (..), PureOperation, Resolver (..),-                                                        liftEitherM, liftM)-import           Data.Morpheus.Types.Internal.Value    (ScalarValue (..))-import           Data.Morpheus.Types.IO                (GQLRequest (..), GQLResponse (..))-import           Data.Morpheus.Types.Types             (Undefined (..))+import           Data.Morpheus.Types.GQLScalar  ( GQLScalar+                                                  ( parseValue+                                                  , serialize+                                                  )+                                                )+import           Data.Morpheus.Types.GQLType    ( GQLType(KIND, description) )+import           Data.Morpheus.Types.ID         ( ID(..) )+import           Data.Morpheus.Types.Internal.AST+                                                ( MUTATION+                                                , QUERY+                                                , SUBSCRIPTION+                                                , ScalarValue(..)+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Event(..)+                                                , GQLRootResolver(..)+                                                , Resolver(..)+                                                , LiftEither(..)+                                                , lift+                                                )+import           Data.Morpheus.Types.IO         ( GQLRequest(..)+                                                , GQLResponse(..)+                                                )+import           Data.Morpheus.Types.Types      ( Undefined(..) )  type Res = Resolver QUERY type MutRes = Resolver MUTATION type SubRes = Resolver SUBSCRIPTION -type IORes = Res IO-type IOMutRes = MutRes IO-type IOSubRes = SubRes IO+type IORes e = Res e IO+type IOMutRes e = MutRes e IO+type IOSubRes e = SubRes e IO +-- Recursive Resolvers+type ResolveQ e m a = Res e m (a (Res e m))+type ResolveM e m a = MutRes e m (a (MutRes e m))+type ResolveS e m a = SubRes e m (a (Res e m))+ -- resolves constant value on any argument-constRes :: (PureOperation o ,Monad m) => b -> a -> Resolver o m e b+constRes :: (LiftEither o Resolver, Monad m) => b -> a -> Resolver o e m b constRes = const . pure -constMutRes :: Monad m =>  [e] -> a -> args -> MutRes m e a-constMutRes list value = const $ MutResolver list $ pure value+constMutRes :: Monad m => [e] -> a -> args -> MutRes e m a+constMutRes events value = const $ MutResolver $ pure (events, value)
− src/Data/Morpheus/Types/Custom.hs
@@ -1,44 +0,0 @@-{-# LANGUAGE DeriveGeneric       #-}-{-# LANGUAGE RankNTypes          #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies        #-}-{-# LANGUAGE TypeOperators       #-}--module Data.Morpheus.Types.Custom-  ( Pair(..)-  , MapKind(..)-  , MapArgs(..)-  , mapKindFromList-  ) where--import           GHC.Generics (Generic)--data Pair k v =-  Pair-    { key   :: k-    , value :: v-    }-  deriving (Generic)--newtype MapArgs k =-  MapArgs-    { oneOf :: Maybe [k]-    }-  deriving (Generic)--data MapKind k v m =-  MapKind-    { size  :: Int-    , pairs :: MapArgs k -> m [Pair k v]-    }-  deriving (Generic)--mapKindFromList :: (Eq k, Applicative m) => [(k, v)] -> MapKind k v m-mapKindFromList inputPairs =-  MapKind {size = length inputPairs, pairs = resolvePairs}-  where-    filterBy MapArgs {oneOf = Just list} =-      filter ((`elem` list) . fst) inputPairs-    filterBy _ = inputPairs-    resolvePairs = pure . (map toGQLTuple . filterBy)-    toGQLTuple (x, y) = Pair x y
src/Data/Morpheus/Types/GQLScalar.hs view
@@ -5,12 +5,17 @@ module Data.Morpheus.Types.GQLScalar   ( GQLScalar(..)   , toScalar-  ) where+  )+where -import           Data.Morpheus.Types.Internal.Data  (DataValidator (..))-import           Data.Morpheus.Types.Internal.Value (ScalarValue (..), Value (..))-import           Data.Proxy                         (Proxy (..))-import           Data.Text                          (Text)+import           Data.Morpheus.Types.Internal.AST.Data+                                                ( DataValidator(..) )+import           Data.Morpheus.Types.Internal.AST.Value+                                                ( ScalarValue(..)+                                                , Value(..)+                                                )+import           Data.Proxy                     ( Proxy(..) )+import           Data.Text                      ( Text )  toScalar :: Value -> Either Text ScalarValue toScalar (Scalar x) = pure x
src/Data/Morpheus/Types/GQLType.hs view
@@ -2,55 +2,69 @@ {-# LANGUAGE DefaultSignatures    #-} {-# LANGUAGE FlexibleContexts     #-} {-# LANGUAGE FlexibleInstances    #-}-{-# LANGUAGE NamedFieldPuns       #-} {-# LANGUAGE OverloadedStrings    #-} {-# LANGUAGE ScopedTypeVariables  #-} {-# LANGUAGE TypeApplications     #-} {-# LANGUAGE TypeFamilies         #-} {-# LANGUAGE TypeOperators        #-}-{-# LANGUAGE TypeSynonymInstances #-}  module Data.Morpheus.Types.GQLType   ( GQLType(..)   , TRUE   , FALSE-  ) where+  )+where -import           Data.Map                              (Map)-import           Data.Proxy                            (Proxy (..))-import           Data.Set                              (Set)-import           Data.Text                             (Text, intercalate, pack)-import           Data.Typeable                         (TyCon, TypeRep, Typeable, splitTyConApp, tyConFingerprint,-                                                        tyConName, typeRep, typeRepTyCon)+import           Data.Map                       ( Map )+import           Data.Proxy                     ( Proxy(..) )+import           Data.Set                       ( Set )+import           Data.Text                      ( Text+                                                , intercalate+                                                , pack+                                                )+import           Data.Typeable                  ( TyCon+                                                , TypeRep+                                                , Typeable+                                                , splitTyConApp+                                                , tyConFingerprint+                                                , tyConName+                                                , typeRep+                                                , typeRepTyCon+                                                )  -- MORPHEUS import           Data.Morpheus.Kind-import           Data.Morpheus.Types.Custom            (MapKind, Pair)-import           Data.Morpheus.Types.Internal.Data     (DataFingerprint (..), QUERY)-import           Data.Morpheus.Types.Internal.Resolver (Resolver (..))-import           Data.Morpheus.Types.Types             (Undefined (..))+import           Data.Morpheus.Types.Types      ( MapKind+                                                , Pair+                                                , Undefined(..)+                                                )+import           Data.Morpheus.Types.Internal.AST.Data+                                                ( DataFingerprint(..)+                                                , QUERY+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Resolver(..) )  type TRUE = 'True  type FALSE = 'False  resolverCon :: TyCon-resolverCon = typeRepTyCon $ typeRep $ Proxy @(Resolver QUERY Maybe)+resolverCon = typeRepTyCon $ typeRep $ Proxy @(Resolver QUERY () Maybe)  -- | replaces typeName (A,B) with Pair_A_B replacePairCon :: TyCon -> TyCon-replacePairCon x-  | hsPair == x = gqlPair-  where-    hsPair = typeRepTyCon $ typeRep $ Proxy @(Int, Int)-    gqlPair = typeRepTyCon $ typeRep $ Proxy @(Pair Int Int)+replacePairCon x | hsPair == x = gqlPair+ where+  hsPair  = typeRepTyCon $ typeRep $ Proxy @(Int, Int)+  gqlPair = typeRepTyCon $ typeRep $ Proxy @(Pair Int Int) replacePairCon x = x  -- Ignores Resolver name  from typeName ignoreResolver :: (TyCon, [TypeRep]) -> [TyCon]-ignoreResolver (con, _)-  | con == resolverCon = []-ignoreResolver (con, args) = con : concatMap (ignoreResolver . splitTyConApp) args+ignoreResolver (con, _) | con == resolverCon = []+ignoreResolver (con, args) =+  con : concatMap (ignoreResolver . splitTyConApp) args  -- | GraphQL type, every graphQL type should have an instance of 'GHC.Generics.Generic' and 'GQLType'. --@@ -82,7 +96,7 @@   __typeFingerprint :: Proxy a -> DataFingerprint   default __typeFingerprint :: (Typeable a) =>     Proxy a -> DataFingerprint-  __typeFingerprint _ = TypeableFingerprint $ conFingerprints (Proxy @a)+  __typeFingerprint _ = TypeableFingerprint $ map show $ conFingerprints (Proxy @a)     where       conFingerprints = fmap (map tyConFingerprint) (ignoreResolver . splitTyConApp . typeRep) @@ -144,10 +158,10 @@   __typeName _ = __typeName (Proxy @a)   __typeFingerprint _ = __typeFingerprint (Proxy @a) -instance GQLType a => GQLType (Resolver o m e a) where-      type KIND (Resolver o m e a) = WRAPPER-      __typeName _ = __typeName (Proxy @a)-      __typeFingerprint _ = __typeFingerprint (Proxy @a)+instance GQLType a => GQLType (Resolver o e m a) where+  type KIND (Resolver o e m a) = WRAPPER+  __typeName _ = __typeName (Proxy @a)+  __typeFingerprint _ = __typeFingerprint (Proxy @a)  instance GQLType b => GQLType (a -> b) where   type KIND (a -> b) = WRAPPER
src/Data/Morpheus/Types/ID.hs view
@@ -4,14 +4,18 @@  module Data.Morpheus.Types.ID   ( ID(..)-  ) where+  )+where -import           Data.Morpheus.Kind                 (SCALAR)-import           Data.Morpheus.Types.GQLScalar      (GQLScalar (..))-import           Data.Morpheus.Types.GQLType        (GQLType (KIND))-import           Data.Morpheus.Types.Internal.Value (ScalarValue (..))-import           Data.Text                          (Text, pack)-import           GHC.Generics                       (Generic)+import           Data.Morpheus.Kind             ( SCALAR )+import           Data.Morpheus.Types.GQLScalar  ( GQLScalar(..) )+import           Data.Morpheus.Types.GQLType    ( GQLType(KIND) )+import           Data.Morpheus.Types.Internal.AST.Value+                                                ( ScalarValue(..) )+import           Data.Text                      ( Text+                                                , pack+                                                )+import           GHC.Generics                   ( Generic )  -- | default GraphQL type, -- parses only 'String' and 'Int' values,@@ -24,7 +28,7 @@   type KIND ID = SCALAR  instance GQLScalar ID where-  parseValue (Int x)    = return (ID $ pack $ show x)+  parseValue (Int    x) = return (ID $ pack $ show x)   parseValue (String x) = return (ID x)   parseValue _          = Left ""   serialize (ID x) = String x
src/Data/Morpheus/Types/IO.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE NamedFieldPuns    #-} {-# LANGUAGE DeriveAnyClass    #-} {-# LANGUAGE DeriveGeneric     #-} {-# LANGUAGE OverloadedStrings #-}@@ -7,31 +8,44 @@   , GQLResponse(..)   , JSONResponse(..)   , renderResponse-  ) where+  )+where -import           Data.Aeson                              (FromJSON (..), ToJSON (..), pairs, withObject, (.:?), (.=))-import qualified Data.Aeson                              as Aeson (Value (..))-import qualified Data.HashMap.Lazy                       as LH (toList)-import           GHC.Generics                            (Generic)+import           Data.Aeson                     ( FromJSON(..)+                                                , ToJSON(..)+                                                , pairs+                                                , withObject+                                                , (.:?)+                                                , (.=)+                                                )+import qualified Data.Aeson                    as Aeson+                                                ( Value(..) )+import qualified Data.HashMap.Lazy             as LH+                                                ( toList )+import           GHC.Generics                   ( Generic )  -- MORPHEUS-import           Data.Morpheus.Types.Internal.Base       (Key)-import           Data.Morpheus.Types.Internal.Validation (JSONError (..),Validation)-import           Data.Morpheus.Types.Internal.Value      (Value)-import           Data.Morpheus.Error.Utils               ( renderErrors)+import           Data.Morpheus.Types.Internal.AST.Base+                                                ( Key )+import           Data.Morpheus.Types.Internal.Resolving.Core+                                                ( GQLError(..)+                                                , Result(..)+                                                )+import           Data.Morpheus.Types.Internal.AST.Value+                                                ( Value ) -renderResponse :: Validation Value -> GQLResponse -renderResponse (Left errors) = Errors $ renderErrors errors-renderResponse (Right value) = Data value +renderResponse :: Result e GQLError con Value -> GQLResponse+renderResponse (Failure errors)   = Errors errors+renderResponse Success { result } = Data result+ instance FromJSON a => FromJSON (JSONResponse a) where   parseJSON = withObject "JSONResponse" objectParser-    where-      objectParser o = JSONResponse <$> o .:? "data" <*> o .:? "errors"+    where objectParser o = JSONResponse <$> o .:? "data" <*> o .:? "errors"  data JSONResponse a = JSONResponse   { responseData   :: Maybe a-  , responseErrors :: Maybe [JSONError]+  , responseErrors :: Maybe [GQLError]   } deriving (Generic, Show, ToJSON)  -- | GraphQL HTTP Request Body@@ -44,17 +58,16 @@ -- | GraphQL Response data GQLResponse   = Data Value-  | Errors [JSONError]+  | Errors [GQLError]   deriving (Show, Generic)  instance FromJSON GQLResponse where-  parseJSON (Aeson.Object hm) =-    case LH.toList hm of-      [("data", value)]   -> Data <$> parseJSON value-      [("errors", value)] -> Errors <$> parseJSON value-      _                   -> fail "Invalid GraphQL Response"+  parseJSON (Aeson.Object hm) = case LH.toList hm of+    [("data"  , value)] -> Data <$> parseJSON value+    [("errors", value)] -> Errors <$> parseJSON value+    _                   -> fail "Invalid GraphQL Response"   parseJSON _ = fail "Invalid GraphQL Response"  instance ToJSON GQLResponse where-  toEncoding (Data _data)     = pairs $ "data" .= _data+  toEncoding (Data   _data  ) = pairs $ "data" .= _data   toEncoding (Errors _errors) = pairs $ "errors" .= _errors
+ src/Data/Morpheus/Types/Internal/AST.hs view
@@ -0,0 +1,162 @@+{-# LANGUAGE DeriveLift       #-}++module Data.Morpheus.Types.Internal.AST+  (+    -- BASE+    Key+  , Collection+  , Ref(..)+  , Position(..)+  , Message+  , anonymousRef+  , Name+  , Description++  -- VALUE+  , Value(..)+  , ScalarValue(..)+  , Object+  , GQLValue(..)+  , replaceValue+  , decodeScientific+  , convertToJSONName+  , convertToHaskellName++  -- Selection+  , Argument(..)+  , Arguments+  , SelectionSet+  , SelectionRec(..)+  , ValueOrigin(..)+  , ValidSelection+  , Selection(..)+  , RawSelection'+  , FragmentLib+  , RawArguments+  , RawSelectionSet+  , Fragment(..)+  , RawArgument(..)+  , RawSelection(..)++  -- OPERATION+  , Operation(..)+  , Variable(..)+  , ValidOperation+  , RawOperation+  , VariableDefinitions+  , ValidVariables+  , DefaultValue+  , getOperationName+  , getOperationDataType+++  -- DSL+  , DataScalar+  , DataEnum+  , DataObject+  , DataArgument+  , DataUnion+  , DataArguments+  , DataField(..)+  , DataTyCon(..)+  , DataType(..)+  , DataTypeLib(..)+  , DataTypeWrapper(..)+  , DataValidator(..)+  , DataTypeKind(..)+  , DataFingerprint(..)+  , RawDataType(..)+  , ResolverKind(..)+  , TypeWrapper(..)+  , TypeAlias(..)+  , ArgsType(..)+  , DataEnumValue(..)+  , isTypeDefined+  , initTypeLib+  , defineType+  , isFieldNullable+  , allDataTypes+  , lookupDataType+  , kindOf+  , toNullableField+  , toListField+  , isObject+  , isInput+  , toHSWrappers+  , isNullable+  , toGQLWrapper+  , isWeaker+  , isSubscription+  , isOutputObject+  , sysTypes+  , isDefaultTypeName+  , isSchemaTypeName+  , isPrimitiveTypeName+  , OperationType(..)+  , QUERY+  , MUTATION+  , SUBSCRIPTION+  , isEntNode+  , lookupInputType+  , coerceDataObject+  , getDataType+  , lookupDataObject+  , lookupDataUnion+  , lookupType+  , lookupField+  , lookupUnionTypes+  , lookupSelectionField+  , lookupFieldAsSelectionSet+  , createField+  , createArgument+  , createDataTypeLib+  , createEnumType+  , createScalarType+  , createType+  , createUnionType+  , createAlias+  , createInputUnionFields+  , fieldVisibility+  , Meta(..)+  , Directive(..)+  , createEnumValue+  , fromDataType+  , insertType+  , TypeUpdater+  , lookupDeprecated+  , lookupDeprecatedReason+  , TypeD(..)+  , ConsD(..)+  , ClientQuery(..)+  , GQLTypeD(..)+  , ClientType(..)+  -- LOCAL+  , GQLQuery(..)+  , Variables+  )+where++import           Data.Map                       ( Map )+import           Language.Haskell.TH.Syntax     ( Lift )+import           Instances.TH.Lift              ( )++-- Morpheus+import           Data.Morpheus.Types.Internal.AST.Data+++import           Data.Morpheus.Types.Internal.AST.Operation++import           Data.Morpheus.Types.Internal.AST.Selection++import           Data.Morpheus.Types.Internal.AST.Base++import           Data.Morpheus.Types.Internal.AST.Value+++type Variables = Map Key Value++data GQLQuery = GQLQuery+  { fragments      :: FragmentLib+  , operation      :: RawOperation+  , inputVariables :: [(Key, Value)]+  } deriving (Show,Lift)
+ src/Data/Morpheus/Types/Internal/AST/Base.hs view
@@ -0,0 +1,55 @@+{-# LANGUAGE DeriveAnyClass  #-}+{-# LANGUAGE DeriveGeneric   #-}+{-# LANGUAGE DeriveLift      #-}+{-# LANGUAGE NamedFieldPuns  #-}++module Data.Morpheus.Types.Internal.AST.Base+  ( Key+  , Collection+  , Ref(..)+  , Position(..)+  , Message+  , anonymousRef+  , Name+  , Description+  )+where++import           Data.Aeson                     ( FromJSON+                                                , ToJSON+                                                )+import           Data.Text                      ( Text )+import           GHC.Generics                   ( Generic )+import           Language.Haskell.TH.Syntax     ( Lift )+import           Instances.TH.Lift              ( )+++type Key = Text+type Message = Text+type Name = Key+type Description = Key++type Collection a = [(Key, a)]++data Position = Position+  { line   :: Int+  , column :: Int+  } deriving (Show, Generic, FromJSON, ToJSON, Lift)++-- Refference with Position information  +--+-- includes position for debugging, where Ref "a" 1 === Ref "a" 3+--+data Ref = Ref+  { refName     :: Key+  , refPosition :: Position+  } deriving (Show,Lift)++instance Eq Ref where+  (Ref id1 _) == (Ref id2 _) = id1 == id2++instance Ord Ref where+  compare (Ref x _) (Ref y _) = compare x y++anonymousRef :: Key -> Ref+anonymousRef refName = Ref { refName, refPosition = Position 0 0 }
+ src/Data/Morpheus/Types/Internal/AST/Data.hs view
@@ -0,0 +1,659 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE DeriveLift            #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE GADTs                 #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NamedFieldPuns        #-}+{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE PolyKinds             #-}+{-# LANGUAGE RankNTypes            #-}++module Data.Morpheus.Types.Internal.AST.Data+  ( +    DataScalar+  , DataEnum+  , DataObject+  , DataArgument+  , DataUnion+  , DataArguments+  , DataField(..)+  , DataTyCon(..)+  , DataType(..)+  , DataTypeLib(..)+  , DataTypeWrapper(..)+  , DataValidator(..)+  , DataTypeKind(..)+  , DataFingerprint(..)+  , RawDataType(..)+  , ResolverKind(..)+  , TypeWrapper(..)+  , TypeAlias(..)+  , ArgsType(..)+  , DataEnumValue(..)+  , isTypeDefined+  , initTypeLib+  , defineType+  , isFieldNullable+  , allDataTypes+  , lookupDataType+  , kindOf+  , toNullableField+  , toListField+  , isObject+  , isInput+  , toHSWrappers+  , isNullable+  , toGQLWrapper+  , isWeaker+  , isSubscription+  , isOutputObject+  , sysTypes+  , isDefaultTypeName+  , isSchemaTypeName+  , isPrimitiveTypeName+  , OperationType(..)+  , QUERY+  , MUTATION+  , SUBSCRIPTION+  , isEntNode+  , lookupInputType+  , coerceDataObject+  , getDataType+  , lookupDataObject+  , lookupDataUnion+  , lookupType+  , lookupField+  , lookupUnionTypes+  , lookupSelectionField+  , lookupFieldAsSelectionSet+  , createField+  , createArgument+  , createDataTypeLib+  , createEnumType+  , createScalarType+  , createType+  , createUnionType+  , createAlias+  , createInputUnionFields+  , fieldVisibility+  , Meta(..)+  , Directive(..)+  , createEnumValue+  , fromDataType+  , insertType+  , TypeUpdater+  , lookupDeprecated+  , lookupDeprecatedReason+  , TypeD(..)+  , ConsD(..)+  , ClientQuery(..)+  , GQLTypeD(..)+  , ClientType(..)+  )+where++import           Data.HashMap.Lazy              ( HashMap+                                                , empty+                                                , fromList+                                                , insert+                                                , toList+                                                , union+                                                )+import qualified Data.HashMap.Lazy             as HM+                                                ( lookup )+import           Data.Semigroup                 ( (<>) )+import           Language.Haskell.TH.Syntax     ( Lift )+import           Instances.TH.Lift              ( )+import           Data.List                      ( find )++-- MORPHEUS+import           Data.Morpheus.Error.Internal   ( internalError )+import           Data.Morpheus.Error.Selection  ( cannotQueryField+                                                , hasNoSubfields+                                                )+import           Data.Morpheus.Types.Internal.AST.Base+                                                ( Key+                                                , Position+                                                , Name+                                                , Description+                                                )+import           Data.Morpheus.Types.Internal.Resolving.Core+                                                ( Validation+                                                , Failure(..)+                                                , GQLErrors+                                                , LibUpdater+                                                , resolveUpdates+                                                )+import           Data.Morpheus.Types.Internal.AST.Value+                                                ( Value(..)+                                                , ScalarValue(..)+                                                )+import           Data.Morpheus.Error.Schema     ( nameCollisionError )++type QUERY = 'Query+type MUTATION = 'Mutation+type SUBSCRIPTION = 'Subscription++isDefaultTypeName :: Key -> Bool+isDefaultTypeName x = isSchemaTypeName x || isPrimitiveTypeName x++isSchemaTypeName :: Key -> Bool+isSchemaTypeName = (`elem` sysTypes)++isPrimitiveTypeName :: Key -> Bool+isPrimitiveTypeName = (`elem` ["String", "Float", "Int", "Boolean", "ID"])++sysTypes :: [Key]+sysTypes =+  [ "__Schema"+  , "__Type"+  , "__Directive"+  , "__TypeKind"+  , "__Field"+  , "__DirectiveLocation"+  , "__InputValue"+  , "__EnumValue"+  ]++data OperationType+  = Query+  | Subscription+  | Mutation+  deriving (Show, Eq, Lift)++isSubscription :: DataTypeKind -> Bool+isSubscription (KindObject (Just Subscription)) = True+isSubscription _ = False++isOutputObject :: DataTypeKind -> Bool+isOutputObject (KindObject _) = True+isOutputObject _              = False++isObject :: DataTypeKind -> Bool+isObject (KindObject _)  = True+isObject KindInputObject = True+isObject _               = False++isInput :: DataTypeKind -> Bool+isInput KindInputObject = True+isInput _               = False++data DataTypeKind+  = KindScalar+  | KindObject (Maybe OperationType)+  | KindUnion+  | KindEnum+  | KindInputObject+  | KindList+  | KindNonNull+  | KindInputUnion+  deriving (Eq, Show, Lift)++data ResolverKind+  = PlainResolver+  | TypeVarResolver+  | ExternalResolver+  deriving (Show, Eq, Lift)++data TypeWrapper+  = TypeList+  | TypeMaybe+  deriving (Show, Lift)++isFieldNullable :: DataField -> Bool+isFieldNullable = isNullable . aliasWrappers . fieldType++isNullable :: [TypeWrapper] -> Bool+isNullable (TypeMaybe : _) = True+isNullable _               = False++isWeaker :: [TypeWrapper] -> [TypeWrapper] -> Bool+isWeaker (TypeMaybe : xs1) (TypeMaybe : xs2) = isWeaker xs1 xs2+isWeaker (TypeMaybe : _  ) _                 = True+isWeaker (_         : xs1) (_ : xs2)         = isWeaker xs1 xs2+isWeaker _                 _                 = False++toGQLWrapper :: [TypeWrapper] -> [DataTypeWrapper]+toGQLWrapper (TypeMaybe : (TypeMaybe : tw)) = toGQLWrapper (TypeMaybe : tw)+toGQLWrapper (TypeMaybe : (TypeList  : tw)) = ListType : toGQLWrapper tw+toGQLWrapper (TypeList : tw) = [NonNullType, ListType] <> toGQLWrapper tw+toGQLWrapper [TypeMaybe                   ] = []+toGQLWrapper []                             = [NonNullType]++toHSWrappers :: [DataTypeWrapper] -> [TypeWrapper]+toHSWrappers (NonNullType : (NonNullType : xs)) =+  toHSWrappers (NonNullType : xs)+toHSWrappers (NonNullType : (ListType : xs)) = TypeList : toHSWrappers xs+toHSWrappers (ListType : xs) = [TypeMaybe, TypeList] <> toHSWrappers xs+toHSWrappers []                              = [TypeMaybe]+toHSWrappers [NonNullType]                   = []++data DataFingerprint = SystemFingerprint Key | TypeableFingerprint [String]+  deriving (Show, Eq, Ord, Lift)+++newtype DataValidator = DataValidator+  { validateValue :: Value -> Either Key Value+  }++instance Show DataValidator where+  show _ = "DataValidator"++type DataScalar = DataTyCon DataValidator++type DataEnum = DataTyCon [DataEnumValue]++type DataObject = DataTyCon [(Key, DataField)]++type DataArgument = DataField++type DataUnion = DataTyCon [Key]++type DataArguments = [(Key, DataArgument)]++data DataTypeWrapper+  = ListType+  | NonNullType+  deriving (Show, Lift)++data TypeAlias = TypeAlias+  { aliasTyCon    :: Key+  , aliasArgs     :: Maybe Key+  , aliasWrappers :: [TypeWrapper]+  } deriving (Show,Lift)++data ArgsType = ArgsType+  { argsTypeName :: Key+  , resKind      :: ResolverKind+  } deriving (Show,Lift)++data Directive = Directive {+  directiveName :: Name,+  directiveArgs :: [(Name,Value)]+} deriving (Show,Lift)++-- META+data Meta = Meta {+    metaDescription:: Maybe Description,+    metaDirectives  :: [Directive]+} deriving (Show,Lift)++lookupDeprecated :: Meta -> Maybe Directive+lookupDeprecated Meta { metaDirectives } = find isDeprecation metaDirectives+ where+  isDeprecation Directive { directiveName = "deprecated" } = True+  isDeprecation _ = False++lookupDeprecatedReason :: Directive -> Maybe Key+lookupDeprecatedReason Directive { directiveArgs } =+  maybeString . snd <$> find isReason directiveArgs+ where+  maybeString (Scalar (String x)) = x+  maybeString _                   = "can't read deprecated Reason Value"+  isReason ("reason", _) = True+  isReason _             = False++-- ENUM VALUE+data DataEnumValue = DataEnumValue{+    enumName :: Name,+    enumMeta :: Maybe Meta+} deriving (Show, Lift)++--------------------------------------------------------------------------------------------------+data DataField = DataField+  { fieldName     :: Key+  , fieldArgs     :: [(Key, DataArgument)]+  , fieldArgsType :: Maybe ArgsType+  , fieldType     :: TypeAlias+  , fieldMeta     :: Maybe Meta+  } deriving (Show,Lift)++fieldVisibility :: (Key, DataField) -> Bool+fieldVisibility ("__typename", _) = False+fieldVisibility ("__schema"  , _) = False+fieldVisibility ("__type"    , _) = False+fieldVisibility _                 = True++createField :: DataArguments -> Key -> ([TypeWrapper], Key) -> DataField+createField fieldArgs fieldName (aliasWrappers, aliasTyCon) = DataField+  { fieldArgs+  , fieldArgsType = Nothing+  , fieldName+  , fieldType     = TypeAlias { aliasTyCon, aliasWrappers, aliasArgs = Nothing }+  , fieldMeta     = Nothing+  }++createArgument :: Key -> ([TypeWrapper], Key) -> (Key, DataField)+createArgument fieldName x = (fieldName, createField [] fieldName x)+++toNullableField :: DataField -> DataField+toNullableField dataField+  | isNullable (aliasWrappers $ fieldType dataField) = dataField+  | otherwise = dataField { fieldType = nullable (fieldType dataField) }+ where+  nullable alias@TypeAlias { aliasWrappers } =+    alias { aliasWrappers = TypeMaybe : aliasWrappers }++toListField :: DataField -> DataField+toListField dataField = dataField { fieldType = listW (fieldType dataField) }+ where+  listW alias@TypeAlias { aliasWrappers } =+    alias { aliasWrappers = TypeList : aliasWrappers }++lookupField :: Failure error m => Key -> [(Key, field)] -> error -> m field+lookupField key fields gqlError = case lookup key fields of+  Nothing    -> failure gqlError+  Just field -> pure field++lookupSelectionField+  :: Failure GQLErrors Validation+  => Position+  -> Key+  -> DataObject+  -> Validation DataField+lookupSelectionField position fieldName DataTyCon { typeData, typeName } =+  lookupField fieldName typeData gqlError+  where gqlError = cannotQueryField fieldName typeName position++--+-- TYPE CONSTRUCTOR+--------------------------------------------------------------------------------------------------+data DataTyCon a = DataTyCon+  { typeName        :: Key+  , typeFingerprint :: DataFingerprint+  , typeMeta :: Maybe Meta+  , typeData        :: a+  } deriving (Show, Lift)+++data RawDataType+  = FinalDataType DataType+  | Interface DataObject+  | Implements { implementsInterfaces :: [Key]+               , unImplements         :: DataObject }+  deriving (Show)++--+-- DATA TYPE+--------------------------------------------------------------------------------------------------+data DataType+  = DataScalar DataScalar+  | DataEnum DataEnum+  | DataInputObject DataObject+  | DataObject DataObject+  | DataUnion DataUnion+  | DataInputUnion DataUnion+  deriving (Show)++createType :: Key -> a -> DataTyCon a+createType typeName typeData = DataTyCon+  { typeName+  , typeMeta        = Nothing+  , typeFingerprint = SystemFingerprint ""+  , typeData+  }++createScalarType :: Key -> (Key, DataType)+createScalarType typeName =+  (typeName, DataScalar $ createType typeName (DataValidator pure))++createEnumType :: Key -> [Key] -> (Key, DataType)+createEnumType typeName typeData =+  (typeName, DataEnum $ createType typeName enumValues)+  where enumValues = map createEnumValue typeData++createEnumValue :: Key -> DataEnumValue+createEnumValue enumName = DataEnumValue { enumName, enumMeta = Nothing }++createUnionType :: Key -> [Key] -> (Key, DataType)+createUnionType typeName typeData =+  (typeName, DataUnion $ createType typeName typeData)+++isEntNode :: DataType -> Bool+isEntNode DataScalar{} = True+isEntNode DataEnum{}   = True+isEntNode _            = False++isInputDataType :: DataType -> Bool+isInputDataType DataScalar{}      = True+isInputDataType DataEnum{}        = True+isInputDataType DataInputObject{} = True+isInputDataType DataInputUnion{}  = True+isInputDataType _                 = False++coerceDataObject :: Failure error m => error -> DataType -> m DataObject+coerceDataObject _        (DataObject object) = pure object+coerceDataObject gqlError _                   = failure gqlError++coerceDataUnion :: Failure error m => error -> DataType -> m DataUnion+coerceDataUnion _        (DataUnion object) = pure object+coerceDataUnion gqlError _                  = failure gqlError++kindOf :: DataType -> DataTypeKind+kindOf (DataScalar      _) = KindScalar+kindOf (DataEnum        _) = KindEnum+kindOf (DataInputObject _) = KindInputObject+kindOf (DataObject      _) = KindObject Nothing+kindOf (DataUnion       _) = KindUnion+kindOf (DataInputUnion  _) = KindInputUnion++fromDataType :: (DataTyCon () -> v) -> DataType -> v+fromDataType f (DataScalar      dt) = f dt { typeData = () }+fromDataType f (DataEnum        dt) = f dt { typeData = () }+fromDataType f (DataUnion       dt) = f dt { typeData = () }+fromDataType f (DataInputObject dt) = f dt { typeData = () }+fromDataType f (DataInputUnion  dt) = f dt { typeData = () }+fromDataType f (DataObject      dt) = f dt { typeData = () }++--+-- Type Register+--------------------------------------------------------------------------------------------------+data DataTypeLib = DataTypeLib+  { types        :: HashMap Key DataType+  , query        :: (Key,  DataObject)+  , mutation     :: Maybe (Key, DataObject)+  , subscription :: Maybe (Key, DataObject)+  } deriving (Show)++type TypeRegister = HashMap Key DataType++initTypeLib :: (Key, DataObject) -> DataTypeLib+initTypeLib query = DataTypeLib { types        = empty+                                , query        = query+                                , mutation     = Nothing+                                , subscription = Nothing+                                }++allDataTypes :: DataTypeLib -> [(Key, DataType)]+allDataTypes DataTypeLib { types, query, mutation, subscription } =+  concatMap fromOperation [Just query, mutation, subscription] <> toList types++typeRegister :: DataTypeLib -> TypeRegister+typeRegister DataTypeLib { types, query, mutation, subscription } =+  types `union` fromList+    (concatMap fromOperation [Just query, mutation, subscription])++fromOperation :: Maybe (Key, DataObject) -> [(Key, DataType)]+fromOperation (Just (key', dataType')) = [(key', DataObject dataType')]+fromOperation Nothing                  = []++lookupDataType :: Key -> DataTypeLib -> Maybe DataType+lookupDataType name lib = name `HM.lookup` typeRegister lib++getDataType :: Failure error m => Key -> DataTypeLib -> error -> m DataType+getDataType name lib gqlError = case lookupDataType name lib of+  Just x -> pure x+  _      -> failure gqlError++lookupDataObject+  :: (Monad m, Failure e m) => e -> Key -> DataTypeLib -> m DataObject+lookupDataObject validationError name lib =+  getDataType name lib validationError >>= coerceDataObject validationError++lookupDataUnion+  :: (Monad m, Failure e m) => e -> Key -> DataTypeLib -> m DataUnion+lookupDataUnion validationError name lib =+  getDataType name lib validationError >>= coerceDataUnion validationError++lookupUnionTypes+  :: (Monad m, Failure GQLErrors m)+  => Position+  -> Key+  -> DataTypeLib+  -> DataField+  -> m [DataObject]+lookupUnionTypes position key lib DataField { fieldType = TypeAlias { aliasTyCon = typeName } }+  = lookupDataUnion gqlError typeName lib+    >>= mapM (flip (lookupDataObject gqlError) lib)+    .   typeData+  where gqlError = hasNoSubfields key typeName position++lookupFieldAsSelectionSet+  :: (Monad m, Failure GQLErrors m)+  => Position+  -> Key+  -> DataTypeLib+  -> DataField+  -> m DataObject+lookupFieldAsSelectionSet position key lib DataField { fieldType = TypeAlias { aliasTyCon } }+  = lookupDataObject gqlError aliasTyCon lib+  where gqlError = hasNoSubfields key aliasTyCon position++lookupInputType :: Failure e m => Key -> DataTypeLib -> e -> m DataType+lookupInputType name lib errors = case lookupDataType name lib of+  Just x | isInputDataType x -> pure x+  _                          -> failure errors++isTypeDefined :: Key -> DataTypeLib -> Maybe DataFingerprint+isTypeDefined name lib =+  fromDataType typeFingerprint <$> lookupDataType name lib++defineType :: (Key, DataType) -> DataTypeLib -> DataTypeLib+defineType (key, datatype@(DataInputUnion DataTyCon { typeName, typeData = enumKeys, typeFingerprint })) lib+  = lib { types = insert name unionTags (insert key datatype (types lib)) }+ where+  name      = typeName <> "Tags"+  unionTags = DataEnum DataTyCon { typeName        = name+                                 , typeFingerprint+                                 , typeMeta        = Nothing+                                 , typeData = map createEnumValue enumKeys+                                 }+defineType (key, datatype) lib =+  lib { types = insert key datatype (types lib) }++lookupType :: Failure e m => e -> [(Key, a)] -> Key -> m a+lookupType err lib typeName = case lookup typeName lib of+  Nothing -> failure err+  Just x  -> pure x++createDataTypeLib :: [(Key, DataType)] -> Validation DataTypeLib+createDataTypeLib types = case takeByKey "Query" types of+  (Just query, lib1) -> case takeByKey "Mutation" lib1 of+    (mutation, lib2) -> case takeByKey "Subscription" lib2 of+      (subscription, lib3) ->+        pure+          ((foldr defineType (initTypeLib query) lib3) { mutation+                                                       , subscription+                                                       }+          )+  _ -> internalError "Query Not Defined"+  ----------------------------------------------------------------------------+++++++++++++++ where+  takeByKey key lib = case lookup key lib of+    Just (DataObject value) -> (Just (key, value), filter ((/= key) . fst) lib)+    _                       -> (Nothing, lib)+++createInputUnionFields :: Key -> [Key] -> [(Key, DataField)]+createInputUnionFields name members = fieldTag : map unionField members+ where+  fieldTag =+    ( "tag"+    , DataField { fieldName     = "tag"+                , fieldArgs     = []+                , fieldArgsType = Nothing+                , fieldType     = createAlias (name <> "Tags")+                , fieldMeta     = Nothing+                }+    )+  unionField memberName =+    ( memberName+    , DataField+      { fieldArgs     = []+      , fieldArgsType = Nothing+      , fieldName     = memberName+      , fieldType     = TypeAlias { aliasTyCon    = memberName+                                  , aliasWrappers = [TypeMaybe]+                                  , aliasArgs     = Nothing+                                  }+      , fieldMeta     = Nothing+      }+    )++createAlias :: Key -> TypeAlias+createAlias aliasTyCon =+  TypeAlias { aliasTyCon, aliasWrappers = [], aliasArgs = Nothing }+++type TypeUpdater = LibUpdater DataTypeLib++insertType :: (Key, DataType) -> TypeUpdater+insertType nextType@(name, datatype) lib = case isTypeDefined name lib of+  Nothing -> resolveUpdates (defineType nextType lib) []+  Just fingerprint+    | fingerprint == fromDataType typeFingerprint datatype -> return lib+    |+      -- throw error if 2 different types has same name+      otherwise -> failure $ nameCollisionError name+++-- TEMPLATE HASKELL DATA TYPES++-- CLIENT                                                +data ClientQuery = ClientQuery+  { queryText     :: String+  , queryTypes    :: [ClientType]+  , queryArgsType :: Maybe TypeD+  } deriving (Show)++data ClientType = ClientType {+  clientType :: TypeD,+  clientKind :: DataTypeKind+} deriving (Show)++-- Document+data GQLTypeD = GQLTypeD+  { typeD     :: TypeD+  , typeKindD :: DataTypeKind+  , typeArgD  :: [TypeD]+  , typeOriginal:: (Name,DataType)+  } deriving (Show)++data TypeD = TypeD+  { tName      :: String+  , tNamespace :: [String]+  , tCons      :: [ConsD]+  , tMeta      :: Maybe Meta+  } deriving (Show)++data ConsD = ConsD+  { cName   :: String+  , cFields :: [DataField]+  } deriving (Show)
src/Data/Morpheus/Types/Internal/AST/Operation.hs view
@@ -1,7 +1,7 @@-{-# LANGUAGE DeriveLift        #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell   #-}+{-# LANGUAGE DeriveLift         #-}+{-# LANGUAGE NamedFieldPuns     #-}+{-# LANGUAGE FlexibleInstances  #-}+{-# LANGUAGE OverloadedStrings  #-}  module Data.Morpheus.Types.Internal.AST.Operation   ( Operation(..)@@ -12,19 +12,39 @@   , ValidVariables   , DefaultValue   , getOperationName-  ) where+  , getOperationDataType+  )+where -import           Data.Maybe                                    (fromMaybe)-import           Language.Haskell.TH.Syntax                    (Lift (..))+import           Data.Maybe                     ( fromMaybe )+import           Language.Haskell.TH.Syntax     ( Lift(..) )  -- MORPHEUS-import           Data.Morpheus.Types.Internal.AST.RawSelection (RawSelectionSet)-import           Data.Morpheus.Types.Internal.AST.Selection    (Arguments, SelectionSet)-import           Data.Morpheus.Types.Internal.Base             (Collection, Key, Position)-import           Data.Morpheus.Types.Internal.Data             (OperationType, WrapperD)-import           Data.Morpheus.Types.Internal.TH               (apply, liftMaybeText, liftText, liftTextMap)-import           Data.Morpheus.Types.Internal.Value            (Value)+import           Data.Morpheus.Error.Mutation   ( mutationIsNotDefined )+import           Data.Morpheus.Error.Subscription+                                                ( subscriptionIsNotDefined )+import           Data.Morpheus.Types.Internal.AST.Selection+                                                ( Arguments+                                                , SelectionSet+                                                , RawSelectionSet+                                                ) +import           Data.Morpheus.Types.Internal.Resolving.Core+                                                ( Validation ,Failure(..) )+import           Data.Morpheus.Types.Internal.AST.Base+                                                ( Collection+                                                , Key+                                                , Position+                                                )+import           Data.Morpheus.Types.Internal.AST.Data+                                                ( OperationType(..)+                                                , TypeWrapper+                                                , DataTypeLib(..)+                                                , DataObject+                                                )+import           Data.Morpheus.Types.Internal.AST.Value+                                                ( Value )+ type DefaultValue = Maybe Value  type VariableDefinitions = Collection (Variable DefaultValue)@@ -44,19 +64,25 @@   , operationArgs      :: args   , operationSelection :: sel   , operationPosition  :: Position-  } deriving (Show)--instance Lift (Operation VariableDefinitions RawSelectionSet) where-  lift (Operation name kind args sel pos) =-    apply 'Operation [liftMaybeText name, lift kind, liftTextMap args, liftTextMap sel, lift pos]+  } deriving (Show,Lift)  data Variable a = Variable   { variableType         :: Key   , isVariableRequired   :: Bool-  , variableTypeWrappers :: [WrapperD]+  , variableTypeWrappers :: [TypeWrapper]   , variablePosition     :: Position   , variableValue        :: a-  } deriving (Show)+  } deriving (Show,Lift) -instance Lift a => Lift (Variable a) where-  lift (Variable t ir w p v) = apply 'Variable [liftText t, lift ir, lift w, lift p, lift v]+getOperationDataType :: Operation a b -> DataTypeLib -> Validation DataObject+getOperationDataType Operation { operationType = Query } lib =+  pure $ snd $ query lib+getOperationDataType Operation { operationType = Mutation, operationPosition } lib+  = case mutation lib of+    Just (_, mutation') -> pure mutation'+    Nothing             -> failure $ mutationIsNotDefined operationPosition+getOperationDataType Operation { operationType = Subscription, operationPosition } lib+  = case subscription lib of+    Just (_, subscription') -> pure subscription'+    Nothing                 -> failure $ subscriptionIsNotDefined operationPosition+
− src/Data/Morpheus/Types/Internal/AST/RawSelection.hs
@@ -1,61 +0,0 @@-{-# LANGUAGE DeriveLift        #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TemplateHaskell   #-}--module Data.Morpheus.Types.Internal.AST.RawSelection-  ( Reference(..)-  , Argument(..)-  , RawArgument(..)-  , RawSelection(..)-  , Fragment(..)-  , FragmentLib-  , RawArguments-  , RawSelectionSet-  , Selection (..)-  ) where--import           Language.Haskell.TH.Syntax                 (Lift (..))---- MORPHEUS-import           Data.Morpheus.Types.Internal.AST.Selection (Argument (..), Selection (..))-import           Data.Morpheus.Types.Internal.Base          (Collection, Key, Position, Reference (..))-import           Data.Morpheus.Types.Internal.TH            (apply, liftMaybeText, liftText, liftTextMap)--data Fragment = Fragment-  { fragmentType      :: Key-  , fragmentPosition  :: Position-  , fragmentSelection :: RawSelectionSet-  } deriving (Show)--instance Lift Fragment where-  lift (Fragment t p sel) = apply 'Fragment [liftText t, lift p, liftTextMap sel]--type RawSelection' a = Selection RawArguments a--instance Lift a => Lift (RawSelection' a) where-  lift (Selection t p alias sel) = apply 'Selection [liftTextMap t, lift p, liftMaybeText alias , lift sel]--type FragmentLib = [(Key, Fragment)]--data RawArgument-  = VariableReference Reference-  | RawArgument Argument-  deriving (Show, Lift)--type RawArguments = Collection RawArgument--type RawSelectionSet = Collection RawSelection--instance Lift RawSelection where-  lift (RawSelectionSet (Selection t p alias sel)) =-    apply 'RawSelectionSet [apply 'Selection [liftTextMap t, lift p, liftMaybeText alias,liftTextMap sel]]-  lift (RawSelectionField p) = apply 'RawSelectionField [lift p]-  lift (InlineFragment f) = apply 'InlineFragment [lift f]-  lift (Spread f) = apply 'Spread [lift f]--data RawSelection-  = RawSelectionSet (RawSelection' RawSelectionSet)-  | RawSelectionField (RawSelection' ())-  | InlineFragment Fragment-  | Spread Reference-  deriving (Show)
src/Data/Morpheus/Types/Internal/AST/Selection.hs view
@@ -5,26 +5,63 @@   , Arguments   , SelectionSet   , SelectionRec(..)-  , ArgumentOrigin(..)+  , ValueOrigin(..)   , ValidSelection   , Selection(..)-  ) where+  , RawSelection'+  , FragmentLib+  , RawArguments+  , RawSelectionSet+  , Fragment(..)+  , RawArgument(..)+  , RawSelection(..)+  )+where -import           Data.Morpheus.Types.Internal.Base  (Collection, Key, Position)-import           Data.Morpheus.Types.Internal.Value (Value)-import           Language.Haskell.TH.Syntax         (Lift (..))+import           Language.Haskell.TH.Syntax     ( Lift ) -data ArgumentOrigin-  = VARIABLE-  | INLINE-  deriving (Show, Lift) -data Argument = Argument-  { argumentValue    :: Value-  , argumentOrigin   :: ArgumentOrigin-  , argumentPosition :: Position+-- MORPHEUS+import           Data.Morpheus.Types.Internal.AST.Base+                                                ( Collection+                                                , Key+                                                , Position+                                                , Ref(..)+                                                )++import           Data.Morpheus.Types.Internal.AST.Value+                                                ( Value )+++-- RAW SELECTION++type RawSelection' a = Selection RawArguments a++type FragmentLib = [(Key, Fragment)]++type RawArguments = Collection RawArgument++type RawSelectionSet = Collection RawSelection++data Fragment = Fragment+  { fragmentType      :: Key+  , fragmentPosition  :: Position+  , fragmentSelection :: RawSelectionSet   } deriving (Show, Lift) +data RawArgument+  = VariableRef Ref+  | RawArgument Argument+  deriving (Show, Lift)++data RawSelection+  = RawSelectionSet (RawSelection' RawSelectionSet)+  | RawSelectionField (RawSelection' ())+  | InlineFragment Fragment+  | Spread Ref+  deriving (Show,Lift)++-- VALID SELECTION  type Arguments = Collection Argument  type SelectionSet = Collection ValidSelection@@ -33,12 +70,23 @@  type UnionSelection = Collection SelectionSet +data ValueOrigin+  = VARIABLE+  | INLINE+  deriving (Show, Lift)++data Argument = Argument+  { argumentValue    :: Value+  , argumentOrigin   :: ValueOrigin+  , argumentPosition :: Position+  } deriving (Show, Lift)+ data Selection args rec = Selection   { selectionArguments :: args   , selectionPosition  :: Position   , selectionAlias     :: Maybe Key   , selectionRec       :: rec-  } deriving (Show)+  } deriving (Show,Lift)  data SelectionRec   = SelectionSet SelectionSet
+ src/Data/Morpheus/Types/Internal/AST/Value.hs view
@@ -0,0 +1,156 @@+{-# LANGUAGE DeriveGeneric       #-}+{-# LANGUAGE DeriveLift          #-}+{-# LANGUAGE FlexibleInstances   #-}+{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Data.Morpheus.Types.Internal.AST.Value+  ( Value(..)+  , ScalarValue(..)+  , Object+  , GQLValue(..)+  , replaceValue+  , decodeScientific+  , convertToJSONName+  , convertToHaskellName+  )+where++import qualified Data.Aeson                    as A+                                                ( FromJSON(..)+                                                , ToJSON(..)+                                                , Value(..)+                                                , object+                                                , pairs+                                                , (.=)+                                                )+import qualified Data.HashMap.Strict           as M+                                                ( toList )+import           Data.Scientific                ( Scientific+                                                , floatingOrInteger+                                                )+import           Data.Semigroup                 ( (<>) )+import           Data.Text                      ( Text )+import qualified Data.Text                     as T+import qualified Data.Vector                   as V+                                                ( toList )+import           GHC.Generics                   ( Generic )+import           Instances.TH.Lift              ( )+import           Language.Haskell.TH.Syntax     ( Lift )+++isReserved :: Text -> Bool+isReserved "case"     = True+isReserved "class"    = True+isReserved "data"     = True+isReserved "default"  = True+isReserved "deriving" = True+isReserved "do"       = True+isReserved "else"     = True+isReserved "foreign"  = True+isReserved "if"       = True+isReserved "import"   = True+isReserved "in"       = True+isReserved "infix"    = True+isReserved "infixl"   = True+isReserved "infixr"   = True+isReserved "instance" = True+isReserved "let"      = True+isReserved "module"   = True+isReserved "newtype"  = True+isReserved "of"       = True+isReserved "then"     = True+isReserved "type"     = True+isReserved "where"    = True+isReserved "_"        = True+isReserved _          = False++{-# INLINE isReserved #-}+convertToJSONName :: Text -> Text+convertToJSONName hsName+  | not (T.null hsName) && isReserved name && (T.last hsName == '\'') = name+  | otherwise = hsName+  where name = T.init hsName++convertToHaskellName :: Text -> Text+convertToHaskellName name | isReserved name = name <> "'"+                          | otherwise       = name++-- | Primitive Values for GQLScalar: 'Int', 'Float', 'String', 'Boolean'.+-- for performance reason type 'Text' represents GraphQl 'String' value+data ScalarValue+  = Int Int+  | Float Float+  | String Text+  | Boolean Bool+  deriving (Show, Generic,Lift)+++instance A.ToJSON ScalarValue where+  toJSON (Float   x) = A.toJSON x+  toJSON (Int     x) = A.toJSON x+  toJSON (Boolean x) = A.toJSON x+  toJSON (String  x) = A.toJSON x++instance A.FromJSON ScalarValue where+  parseJSON (A.Bool   v) = pure $ Boolean v+  parseJSON (A.Number v) = pure $ decodeScientific v+  parseJSON (A.String v) = pure $ String v+  parseJSON notScalar    = fail $ "Expected Scalar got :" <> show notScalar+++type Object = [(Text, Value)]++data Value+  = Object Object+  | List [Value]+  | Enum Text+  | Scalar ScalarValue+  | Null+  deriving (Show, Generic,Lift)++instance A.ToJSON Value where+  toEncoding Null        = A.toEncoding A.Null+  toEncoding (Enum   x ) = A.toEncoding x+  toEncoding (List   x ) = A.toEncoding x+  toEncoding (Scalar x ) = A.toEncoding x+  toEncoding (Object []) = A.toEncoding $ A.object []+  toEncoding (Object x ) = A.pairs $ foldl1 (<>) $ map encodeField x+    where encodeField (key, value) = convertToJSONName key A..= value++decodeScientific :: Scientific -> ScalarValue+decodeScientific v = case floatingOrInteger v of+  Left  float -> Float float+  Right int   -> Int int++replaceValue :: A.Value -> Value+replaceValue (A.Bool   v) = gqlBoolean v+replaceValue (A.Number v) = Scalar $ decodeScientific v+replaceValue (A.String v) = gqlString v+replaceValue (A.Object v) = gqlObject $ map replace (M.toList v)+ where+  replace :: (a, A.Value) -> (a, Value)+  replace (key, val) = (key, replaceValue val)+replaceValue (A.Array li) = gqlList (map replaceValue (V.toList li))+replaceValue A.Null       = gqlNull++instance A.FromJSON Value where+  parseJSON = pure . replaceValue++-- DEFAULT VALUES+class GQLValue a where+  gqlNull :: a+  gqlScalar :: ScalarValue -> a+  gqlBoolean :: Bool -> a+  gqlString :: Text -> a+  gqlList :: [a] -> a+  gqlObject :: [(Text, a)] -> a++-- build GQL Values for Subscription Resolver+instance GQLValue Value where+  gqlNull    = Null+  gqlScalar  = Scalar+  gqlBoolean = Scalar . Boolean+  gqlString  = Scalar . String+  gqlList    = List+  gqlObject  = Object
− src/Data/Morpheus/Types/Internal/Base.hs
@@ -1,58 +0,0 @@-{-# LANGUAGE DeriveAnyClass  #-}-{-# LANGUAGE DeriveGeneric   #-}-{-# LANGUAGE DeriveLift      #-}-{-# LANGUAGE TemplateHaskell #-}--module Data.Morpheus.Types.Internal.Base-  ( Key-  , Collection-  , Reference (..)-  , Position-  , EnhancedKey(..)-  , Location(..)-  , Message-  , enhanceKeyWithNull-  ) where--import           Data.Aeson                      (FromJSON, ToJSON)-import           Data.Text                       (Text)-import           GHC.Generics                    (Generic)-import           Language.Haskell.TH.Syntax      (Lift (..))---- MORPHEUS-import           Data.Morpheus.Types.Internal.TH (apply, liftText)--type Position = Location--data Location = Location-  { line   :: Int-  , column :: Int-  } deriving (Show, Generic, FromJSON, ToJSON, Lift)--type Key = Text-type Message = Text--type Collection a = [(Key, a)]--data Reference = Reference-  { referenceName     :: Key-  , referencePosition :: Position-  } deriving (Show)--instance Lift Reference where-  lift (Reference name pos) = apply 'Reference [liftText name, lift pos]---- Text value that includes position for debugging, where EnhancedKey "a" 1 === EnhancedKey "a" 3-data EnhancedKey = EnhancedKey-  { uid      :: Text-  , location :: Position-  } deriving (Show)--instance Eq EnhancedKey where-  (EnhancedKey id1 _) == (EnhancedKey id2 _) = id1 == id2--instance Ord EnhancedKey where-  compare (EnhancedKey x _) (EnhancedKey y _) = compare x y--enhanceKeyWithNull :: Key -> EnhancedKey-enhanceKeyWithNull text = EnhancedKey {uid = text, location = Location 0 0}
− src/Data/Morpheus/Types/Internal/Data.hs
@@ -1,338 +0,0 @@-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE DefaultSignatures     #-}-{-# LANGUAGE DeriveLift            #-}-{-# LANGUAGE FlexibleInstances     #-}-{-# LANGUAGE GADTs                 #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE NamedFieldPuns        #-}-{-# LANGUAGE OverloadedStrings     #-}-{-# LANGUAGE PolyKinds             #-}-{-# LANGUAGE RankNTypes            #-}-{-# LANGUAGE TemplateHaskell       #-}-{-# LANGUAGE TypeSynonymInstances  #-}--module Data.Morpheus.Types.Internal.Data-  ( Key-  , DataScalar-  , DataEnum-  , DataObject-  , DataArgument-  , DataUnion-  , DataArguments-  , DataField(..)-  , DataTyCon(..)-  , DataType(..)-  , DataTypeLib(..)-  , DataTypeWrapper(..)-  , DataValidator(..)-  , DataTypeKind(..)-  , DataFingerprint(..)-  , RawDataType(..)-  , ResolverKind(..)-  , WrapperD(..)-  , TypeAlias(..)-  , ArgsType(..)-  , isTypeDefined-  , initTypeLib-  , defineType-  , isFieldNullable-  , allDataTypes-  , lookupDataType-  , kindOf-  , toNullableField-  , toListField-  , isObject-  , isInput-  , toHSWrappers-  , isNullable-  , toGQLWrapper-  , isWeaker-  , isSubscription-  , isOutputObject-  , sysTypes-  , isDefaultTypeName-  , isSchemaTypeName-  , isPrimitiveTypeName-  , OperationType(..)-  , QUERY-  , MUTATION-  , SUBSCRIPTION-  , Name-  , Description-  , isEntNode-  ) where--import           Data.Semigroup                     ((<>))-import qualified Data.Text                          as T (pack, unpack)-import           GHC.Fingerprint.Type               (Fingerprint)-import           Language.Haskell.TH.Syntax         (Lift (..))---- MORPHEUS-import           Data.Morpheus.Types.Internal.Base  (Key)-import           Data.Morpheus.Types.Internal.TH    (apply, liftText, liftTextMap)-import           Data.Morpheus.Types.Internal.Value (Value (..))--type Name = Key-type Description = Key--type QUERY = 'Query-type MUTATION = 'Mutation-type SUBSCRIPTION = 'Subscription--isDefaultTypeName :: Key -> Bool-isDefaultTypeName x = isSchemaTypeName x || isPrimitiveTypeName x--isSchemaTypeName :: Key -> Bool-isSchemaTypeName = (`elem` sysTypes)--isPrimitiveTypeName :: Key -> Bool-isPrimitiveTypeName = (`elem` ["String", "Float", "Int", "Boolean", "ID"])--sysTypes :: [Key]-sysTypes =-  ["__Schema", "__Type", "__Directive", "__TypeKind", "__Field", "__DirectiveLocation", "__InputValue", "__EnumValue"]--data OperationType-  = Query-  | Subscription-  | Mutation-  deriving (Show, Eq, Lift)--isSubscription :: DataTypeKind -> Bool-isSubscription (KindObject (Just Subscription)) = True-isSubscription _                                = False--isOutputObject :: DataTypeKind -> Bool-isOutputObject (KindObject _) = True-isOutputObject _              = False--isObject :: DataTypeKind -> Bool-isObject (KindObject _)  = True-isObject KindInputObject = True-isObject _               = False--isInput :: DataTypeKind -> Bool-isInput KindInputObject = True-isInput _               = False--data DataTypeKind-  = KindScalar-  | KindObject (Maybe OperationType)-  | KindUnion-  | KindEnum-  | KindInputObject-  | KindList-  | KindNonNull-  | KindInputUnion-  deriving (Eq, Show, Lift)--data ResolverKind-  = PlainResolver-  | TypeVarResolver-  | ExternalResolver-  deriving (Show, Eq, Lift)--data WrapperD-  = ListD-  | MaybeD-  deriving (Show, Lift)--isFieldNullable :: DataField -> Bool-isFieldNullable = isNullable . aliasWrappers . fieldType--isNullable :: [WrapperD] -> Bool-isNullable (MaybeD:_) = True-isNullable _          = False--isWeaker :: [WrapperD] -> [WrapperD] -> Bool-isWeaker (MaybeD:xs1) (MaybeD:xs2) = isWeaker xs1 xs2-isWeaker (MaybeD:_) _              = True-isWeaker (_:xs1) (_:xs2)           = isWeaker xs1 xs2-isWeaker _ _                       = False--toGQLWrapper :: [WrapperD] -> [DataTypeWrapper]-toGQLWrapper (MaybeD:(MaybeD:tw)) = toGQLWrapper (MaybeD : tw)-toGQLWrapper (MaybeD:(ListD:tw))  = ListType : toGQLWrapper tw-toGQLWrapper (ListD:tw)           = [NonNullType, ListType] <> toGQLWrapper tw-toGQLWrapper [MaybeD]             = []-toGQLWrapper []                   = [NonNullType]--toHSWrappers :: [DataTypeWrapper] -> [WrapperD]-toHSWrappers (NonNullType:(NonNullType:xs)) = toHSWrappers (NonNullType : xs)-toHSWrappers (NonNullType:(ListType:xs))    = ListD : toHSWrappers xs-toHSWrappers (ListType:xs)                  = [MaybeD, ListD] <> toHSWrappers xs-toHSWrappers []                             = [MaybeD]-toHSWrappers [NonNullType]                  = []--data DataFingerprint-  = SystemFingerprint Key-  | TypeableFingerprint [Fingerprint]-  deriving (Show, Eq, Ord)--newtype DataValidator = DataValidator-  { validateValue :: Value -> Either Key Value-  }--instance Show DataValidator where-  show _ = "DataValidator"--type DataScalar = DataTyCon DataValidator--type DataEnum = DataTyCon [Key]--type DataObject = DataTyCon [(Key, DataField)]--type DataArgument = DataField--type DataUnion = DataTyCon [DataField]--type DataArguments = [(Key, DataArgument)]--data DataTypeWrapper-  = ListType-  | NonNullType-  deriving (Show, Lift)--data TypeAlias = TypeAlias-  { aliasTyCon    :: Key-  , aliasArgs     :: Maybe Key-  , aliasWrappers :: [WrapperD]-  } deriving (Show)--instance Lift TypeAlias where-  lift TypeAlias {aliasTyCon = x, aliasArgs, aliasWrappers} =-    [|TypeAlias {aliasTyCon = name, aliasArgs = T.pack <$> args, aliasWrappers}|]-    where-      name = T.unpack x-      args = T.unpack <$> aliasArgs--data ArgsType = ArgsType-  { argsTypeName :: Key-  , resKind      :: ResolverKind-  } deriving (Show)--instance Lift ArgsType where-  lift (ArgsType argT kind) = apply 'ArgsType [liftText argT, lift kind]--data DataField = DataField-  { fieldName     :: Key-  , fieldArgs     :: [(Key, DataArgument)]-  , fieldArgsType :: Maybe ArgsType-  , fieldType     :: TypeAlias-  , fieldHidden   :: Bool-  } deriving (Show)--instance Lift DataField where-  lift (DataField name args argsT ft hid) =-    apply 'DataField [liftText name, liftTextMap args, lift argsT, lift ft, lift hid]--data DataTyCon a = DataTyCon-  { typeName        :: Key-  , typeFingerprint :: DataFingerprint-  , typeDescription :: Maybe Key-  , typeData        :: a-  } deriving (Show)--data RawDataType-  = FinalDataType DataType-  | Interface DataObject-  | Implements { implementsInterfaces :: [Key]-               , unImplements         :: DataObject }-  deriving (Show)--isEntNode :: DataType -> Bool-isEntNode DataScalar {} = True-isEntNode DataEnum {}   = True-isEntNode _             = False--data DataType-  = DataScalar DataScalar-  | DataEnum DataEnum-  | DataInputObject DataObject-  | DataObject DataObject-  | DataUnion DataUnion-  | DataInputUnion DataUnion-  deriving (Show)--data DataTypeLib = DataTypeLib-  { scalar       :: [(Key, DataScalar)]-  , enum         :: [(Key, DataEnum)]-  , inputObject  :: [(Key, DataObject)]-  , object       :: [(Key, DataObject)]-  , union        :: [(Key, DataUnion)]-  , inputUnion   :: [(Key, DataUnion)]-  , query        :: (Key,  DataObject)-  , mutation     :: Maybe (Key, DataObject)-  , subscription :: Maybe (Key, DataObject)-  } deriving (Show)--initTypeLib :: (Key, DataObject) -> DataTypeLib-initTypeLib query =-  DataTypeLib-    { scalar = []-    , enum = []-    , inputObject = []-    , query = query-    , object = []-    , union = []-    , inputUnion = []-    , mutation = Nothing-    , subscription = Nothing-    }--allDataTypes :: DataTypeLib -> [(Key, DataType)]-allDataTypes DataTypeLib { scalar, enum , inputObject, object, union, inputUnion, query, mutation, subscription } =-  packType DataObject query :-  fromMaybeType mutation ++-  fromMaybeType subscription ++-  map (packType DataScalar) scalar ++-  map (packType DataEnum) enum ++-  map (packType DataInputObject) inputObject ++-  map (packType DataInputUnion) inputUnion ++ map (packType DataObject) object ++ map (packType DataUnion) union-  where-    packType f (x, y) = (x, f y)-    fromMaybeType :: Maybe (Key, DataObject) -> [(Key, DataType)]-    fromMaybeType (Just (key', dataType')) = [(key', DataObject dataType')]-    fromMaybeType Nothing                  = []--lookupDataType :: Key -> DataTypeLib -> Maybe DataType-lookupDataType name lib = name `lookup` allDataTypes lib--kindOf :: DataType -> DataTypeKind-kindOf (DataScalar _)      = KindScalar-kindOf (DataEnum _)        = KindEnum-kindOf (DataInputObject _) = KindInputObject-kindOf (DataObject _)      = KindObject Nothing-kindOf (DataUnion _)       = KindUnion-kindOf (DataInputUnion _)  = KindInputUnion--fromDataType :: (DataTyCon () -> v) -> DataType -> v-fromDataType f (DataScalar dt)      = f dt {typeData = ()}-fromDataType f (DataEnum dt)        = f dt {typeData = ()}-fromDataType f (DataUnion dt)       = f dt {typeData = ()}-fromDataType f (DataInputObject dt) = f dt {typeData = ()}-fromDataType f (DataInputUnion dt)  = f dt {typeData = ()}-fromDataType f (DataObject dt)      = f dt {typeData = ()}--isTypeDefined :: Key -> DataTypeLib -> Maybe DataFingerprint-isTypeDefined name lib = fromDataType typeFingerprint <$> lookupDataType name lib--defineType :: (Key, DataType) -> DataTypeLib -> DataTypeLib-defineType (key', DataScalar type') lib      = lib {scalar = (key', type') : scalar lib}-defineType (key', DataEnum type') lib        = lib {enum = (key', type') : enum lib}-defineType (key', DataInputObject type') lib = lib {inputObject = (key', type') : inputObject lib}-defineType (key', DataObject type') lib      = lib {object = (key', type') : object lib}-defineType (key', DataUnion type') lib       = lib {union = (key', type') : union lib}-defineType (key', DataInputUnion type') lib  = lib {inputUnion = (key', type') : inputUnion lib}--toNullableField :: DataField -> DataField-toNullableField dataField-  | isNullable (aliasWrappers $ fieldType dataField) = dataField-  | otherwise = dataField {fieldType = nullable (fieldType dataField)}-  where-    nullable alias@TypeAlias {aliasWrappers} = alias {aliasWrappers = MaybeD : aliasWrappers}--toListField :: DataField -> DataField-toListField dataField = dataField {fieldType = listW (fieldType dataField)}-  where-    listW alias@TypeAlias {aliasWrappers} = alias {aliasWrappers = ListD : aliasWrappers}
− src/Data/Morpheus/Types/Internal/DataD.hs
@@ -1,37 +0,0 @@-{-# LANGUAGE DeriveLift #-}--module Data.Morpheus.Types.Internal.DataD-  ( TypeD(..)-  , ConsD(..)-  , QueryD(..)-  , GQLTypeD(..)-  ) where--import           Language.Haskell.TH.Syntax        (Lift (..))------- MORPHEUS-import           Data.Morpheus.Types.Internal.Data (DataField, DataTypeKind)--data QueryD = QueryD-  { queryText     :: String-  , queryTypes    :: [GQLTypeD]-  , queryArgsType :: Maybe TypeD-  } deriving (Show, Lift)--data GQLTypeD = GQLTypeD-  { typeD     :: TypeD-  , typeKindD :: DataTypeKind-  , typeArgD  :: [TypeD]-  } deriving (Show, Lift)--data TypeD = TypeD-  { tName      :: String-  , tNamespace :: [String]-  , tCons      :: [ConsD]-  } deriving (Show, Lift)--data ConsD = ConsD-  { cName   :: String-  , cFields :: [DataField]-  } deriving (Show, Lift)
− src/Data/Morpheus/Types/Internal/Resolver.hs
@@ -1,263 +0,0 @@-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE FlexibleInstances     #-}-{-# LANGUAGE GADTs                 #-}-{-# LANGUAGE InstanceSigs          #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE NamedFieldPuns        #-}-{-# LANGUAGE OverloadedStrings     #-}-{-# LANGUAGE PolyKinds             #-}-{-# LANGUAGE ScopedTypeVariables   #-}-{-# LANGUAGE TupleSections         #-}-{-# LANGUAGE TypeFamilies          #-}-{-# LANGUAGE TypeOperators         #-}--module Data.Morpheus.Types.Internal.Resolver-  ( ResolveT-  , Event(..)-  , GQLRootResolver(..)-  , UnSubResolver-  , ResponseT-  , Resolver(..)-  , ResolvingStrategy(..)-  , MapGraphQLT(..)-  , PureOperation(..)-  , resolveObject-  , toResponseRes-  , withObject-  , Resolving(..)-  , liftM-  , liftEitherM-  ) where--import           Control.Monad.Fail                         (MonadFail (..))-import           Control.Monad.Trans.Except                 (ExceptT (..), runExceptT, withExceptT)-import           Data.Maybe                                 (fromMaybe)-import           Data.Semigroup                             ((<>))---- MORPHEUS-import           Data.Morpheus.Error.Selection              (resolverError, subfieldsNotSelected)-import           Data.Morpheus.Types.Internal.AST.Selection (Selection (..), SelectionRec (..), SelectionSet,-                                                             ValidSelection)-import           Data.Morpheus.Types.Internal.Data          (Key, MUTATION, OperationType, QUERY, SUBSCRIPTION)-import           Data.Morpheus.Types.Internal.Stream        (Channel (..), Event (..), ResponseEvent (..),-                                                             ResponseStream, StreamChannel, StreamState (..),-                                                             StreamT (..), closeStream, injectEvents, mapS, pushEvents)-import           Data.Morpheus.Types.Internal.Validation    (GQLErrors, Validation)-import           Data.Morpheus.Types.Internal.Value         (GQLValue (..), Value)-import           Data.Morpheus.Types.IO                     (renderResponse)--withObject :: ( SelectionSet -> ResolvingStrategy o m e value) -> (Key,ValidSelection)  -> ResolvingStrategy o m e value-withObject f (_, Selection {selectionRec = SelectionSet selection}) = f selection-withObject _ (key, Selection {selectionPosition}) = Fail $ subfieldsNotSelected key "" selectionPosition--liftM :: (PureOperation o, Monad m) => m a -> Resolver o m e a-liftM = liftEither . fmap pure--liftEitherM :: (PureOperation o, Monad m) => m (Either String a) -> Resolver o m e a-liftEitherM = liftEither------------------------------------------------------------------------------------------type ResolveT = ExceptT GQLErrors-type ResponseT m e  = ResolveT (ResponseStream m e)--instance Monad m => MonadFail (Resolver QUERY m e) where-  fail = FailedResolver------- Recursive Resolver-newtype RecResolver m a b = RecResolver {-  unRecResolver :: a -> ResolveT m b-}--instance Functor m => Functor (RecResolver m a) where-  fmap f (RecResolver x) = RecResolver eventFmap-    where-      eventFmap  event = fmap f (x event)--instance Monad m => Applicative (RecResolver m a) where-  pure = RecResolver . const . pure-  (RecResolver f) <*> (RecResolver res) = RecResolver recX-    where-      recX event = f event <*>  res event--instance Monad m => Monad (RecResolver m a) where-  (RecResolver x) >>= next = RecResolver recX-    where-        recX event = x event >>= (\v-> v event) . unRecResolver . next-------------------------------------------------------------------- GraphQLT--data ResolvingStrategy  (o::OperationType) (m:: * -> *) event value where-    QueryResolving :: { unQueryT :: ResolveT m value } -> ResolvingStrategy QUERY m event value-    MutationResolving :: { unMutationT :: ResolveT (StreamT m event) value } -> ResolvingStrategy MUTATION m event value-    SubscriptionResolving :: { unSubscriptionT :: ResolveT (StreamT m (Channel event)) (RecResolver m event value) } -> ResolvingStrategy SUBSCRIPTION m event value-    -- SubscriptionRecT :: RecResolver m event value -> GraphQLT SUBSCRIPTION m event value-    Fail :: GQLErrors -> ResolvingStrategy o m event  value---- GraphQLT Functor-instance Monad m => Functor (ResolvingStrategy o m e) where-    fmap _ (Fail mErrors)                    = Fail mErrors-    fmap f (QueryResolving mResolver)        = QueryResolving $ f <$> mResolver-    fmap f (MutationResolving mResolver)     = MutationResolving $  f <$> mResolver-    fmap f (SubscriptionResolving mResolver) = SubscriptionResolving $ fmap f <$> mResolver---- GraphQLT Applicative-instance (PureOperation o, Monad m) => Applicative (ResolvingStrategy o m e) where-    pure = pureGraphQLT-    --------------------------------------    _ <*> (Fail mErrors) = Fail mErrors-    (Fail mErrors) <*> _ = Fail mErrors-    --------------------------------------    (QueryResolving f) <*> (QueryResolving res) = QueryResolving (f <*> res)-    -------------------------------------------------------------------------    (MutationResolving f) <*> (MutationResolving res) = MutationResolving (f <*> res)-    ---------------------------------------------------------------    (SubscriptionResolving f) <*> (SubscriptionResolving res) = SubscriptionResolving $ do-                       f1 <- f-                       res1 <- res-                       pure (f1 <*> res1)---- GADTResolver-----------------------------------------------------------------data Resolver (o::OperationType) (m :: * -> * ) event value where-    FailedResolver :: { unFailedResolver :: String } -> Resolver o m event value-    QueryResolver:: { unQueryResolver :: ExceptT String m value } -> Resolver QUERY m  event value-    MutResolver :: {-            mutEvents :: [event] ,-            mutResolver :: ExceptT String m value-        } -> Resolver MUTATION m event value-    SubResolver :: {-            subChannels :: [StreamChannel event] ,-            subResolver :: event -> Resolver QUERY m  event value-        } -> Resolver SUBSCRIPTION m event value---- GADTResolver Functor-instance Functor m => Functor (Resolver o m e) where-    fmap _ (FailedResolver mErrors) = FailedResolver mErrors-    fmap f (QueryResolver mResolver) = QueryResolver $ fmap f mResolver-    fmap f (MutResolver events mResolver) = MutResolver events $ fmap f mResolver-    fmap f (SubResolver events mResolver) = SubResolver events (eventFmap mResolver)-            where-                eventFmap res event = fmap f (res event)---- GADTResolver Applicative-instance (PureOperation o ,Monad m) => Applicative (Resolver o m e) where-    pure = liftEither . pure . pure-    --------------------------------------    _ <*> (FailedResolver mErrors) = FailedResolver mErrors-    (FailedResolver mErrors) <*> _ = FailedResolver mErrors-    --------------------------------------    (QueryResolver f) <*> (QueryResolver res) = QueryResolver (f <*> res)-    ----------------------------------------------------------------------    (MutResolver events1 f) <*> (MutResolver events2 res) = MutResolver (events1 <> events2) (f <*> res)-    ---------------------------------------------------------------    (SubResolver e1 f) <*> (SubResolver e2 res) = SubResolver (e1<>e2) $-                       \event -> f event <*>  res event--instance (Monad m) => Monad (Resolver QUERY m e) where-    return = pure-    --------------------------------------    (FailedResolver mErrors) >>= _ = FailedResolver mErrors-    --------------------------------------    (QueryResolver f) >>= nextM = QueryResolver (f >>= unQueryResolver. nextM)---- Pure Operation-class PureOperation (o::OperationType) where-    liftEither :: Monad m => m (Either String a) -> Resolver o m event a-    pureGraphQLT :: Monad m => a -> ResolvingStrategy o m event a-    eitherGraphQLT :: Monad m => Validation a -> ResolvingStrategy o m event a--instance PureOperation QUERY where-   liftEither = QueryResolver . ExceptT-   pureGraphQLT = QueryResolving . pure-   eitherGraphQLT = QueryResolving . ExceptT . pure--instance PureOperation MUTATION where-   liftEither = MutResolver [] . ExceptT-   pureGraphQLT = MutationResolving . pure-   eitherGraphQLT = MutationResolving . ExceptT . pure--instance PureOperation SUBSCRIPTION where-   liftEither = SubResolver [] . const . liftEither-   pureGraphQLT = SubscriptionResolving . pure . pure-   eitherGraphQLT = SubscriptionResolving . fmap pure  . ExceptT . pure---resolveObject :: (Monad m , PureOperation o ) => SelectionSet -> [FieldRes o m e] -> ResolvingStrategy o m e Value-resolveObject selectionSet fieldResolvers = gqlObject <$> traverse selectResolver selectionSet-  where-    selectResolver (key, selection@Selection { selectionAlias }) = (fromMaybe key selectionAlias,) <$> lookupRes selection-      where-        lookupRes  sel =  (fromMaybe (const $ pure  gqlNull) $ lookup key fieldResolvers) (key, sel)--class Resolving o m e where-     getArgs :: Validation args ->  (args -> Resolver o m e value) -> Resolver o m e value-     resolving :: Monad m => (value -> (Key,ValidSelection) -> ResolvingStrategy o m e Value) -> Resolver o m e value ->  (Key, ValidSelection) -> ResolvingStrategy o m e Value--type FieldRes o m e = (Key, (Key, ValidSelection) -> ResolvingStrategy o m e Value)--instance Resolving o m e where-   getArgs (Right x) f = f x-   getArgs (Left _) _  = FailedResolver ""-   ----------------------------------------------------------------------------------------------------------------------------------------   resolving encode gResolver selection@(fieldName,Selection { selectionPosition }) = __resolving gResolver-        where-          __resolving (FailedResolver message) = Fail $ resolverError selectionPosition fieldName message-          __resolving (QueryResolver res) =-            QueryResolving $ withExceptT (resolverError selectionPosition fieldName) res >>= unQueryT . (`encode` selection)-   ----------------------------------------------------------------------------------------------------------------------------------------          __resolving (MutResolver events res)  =-            MutationResolving $ pushEvents events $ withExceptT (resolverError selectionPosition fieldName) (injectEvents [] res)  >>= unMutationT . (`encode` selection)-   ---------------------------------------------------------------------------------------------------------------------------------          __resolving (SubResolver subChannels res) =-               SubscriptionResolving $ ExceptT $ StreamT $ pure $ StreamState { streamEvents , streamValue }-                              where-                                streamValue  = pure $ RecResolver $ \event -> withExceptT (resolverError selectionPosition fieldName) ( unQueryResolver $ res event)  >>= unPub event . (`encode` selection)-                                streamEvents :: [Channel e]-                                streamEvents = map Channel subChannels--unPub :: Monad m => event -> ResolvingStrategy SUBSCRIPTION m event a -> ResolveT m a-unPub event x = do-    func <- unPureSub x-    func event--unPureSub :: Monad m => ResolvingStrategy SUBSCRIPTION m event a -> ResolveT m (event -> ResolveT m a)-unPureSub = ExceptT . fmap (fmap unRecResolver . streamValue) . runStreamT . runExceptT . unSubscriptionT--class MapGraphQLT (fromO :: OperationType) (toO :: OperationType) where-   mapGraphQLT :: Monad m => ResolvingStrategy fromO m e a -> ResolvingStrategy toO m e a--instance MapGraphQLT fromO fromO where-    mapGraphQLT = id--instance MapGraphQLT QUERY SUBSCRIPTION where-    mapGraphQLT (QueryResolving x) = SubscriptionResolving $ injectEvents [] (fmap pure x)-    mapGraphQLT (Fail x)           = Fail x--toResponseRes :: Monad m =>  ResolvingStrategy o m event Value -> ResponseT m event Value-toResponseRes (Fail errors) = ExceptT $ StreamT $ pure $ StreamState [] $ Left errors-toResponseRes (QueryResolving resT) =  ExceptT $ StreamT $ StreamState [] <$> runExceptT resT-toResponseRes (MutationResolving resT) = ExceptT $ mapS Publish (runExceptT resT)-toResponseRes (SubscriptionResolving resT)  =-      ExceptT $ StreamT $ handleActions <$> closeStream (runExceptT resT)-      where-        handleActions (_, Left gqlError) = StreamState [] (Left gqlError)-        handleActions (channels, Right subResolver) =-          StreamState [Subscribe $ Event channels handleRes] (Right  gqlNull)-          where-            handleRes event = renderResponse <$> runExceptT (unRecResolver subResolver event)--type family UnSubResolver (a :: * -> *) :: (* -> *)--type instance UnSubResolver (Resolver SUBSCRIPTION m e) = Resolver QUERY m e------------------------------------------------------------------------ | GraphQL Root resolver, also the interpreter generates a GQL schema from it.---  'queryResolver' is required, 'mutationResolver' and 'subscriptionResolver' are optional,---  if your schema does not supports __mutation__ or __subscription__ , you acn use __()__ for it.-data GQLRootResolver (m :: * -> *) event (query :: (* -> *) -> * ) (mut :: (* -> *) -> * )  (sub :: (* -> *) -> * )  = GQLRootResolver-  { queryResolver        :: query (Resolver QUERY m  event)-  , mutationResolver     :: mut (Resolver MUTATION m event)-  , subscriptionResolver :: sub (Resolver SUBSCRIPTION  m event)-  }
+ src/Data/Morpheus/Types/Internal/Resolving.hs view
@@ -0,0 +1,34 @@+module Data.Morpheus.Types.Internal.Resolving+    ( Event(..)+    , GQLRootResolver(..)+    , UnSubResolver+    , Resolver(..)+    , ResolvingStrategy(..)+    , MapStrategy(..)+    , LiftEither(..)+    , resolveObject+    , toResponseRes+    , withObject+    , resolving+    , toResolver+    , lift+    , SubEvent+    , Validation+    , Failure(..)+    , GQLChannel(..)+    , ResponseEvent(..)+    , ResponseStream+    , cleanEvents+    , Result(..)+    , ResultT(..)+    , unpackEvents+    , LibUpdater+    , resolveUpdates+    , GQLErrors+    , GQLError(..)+    , Position+    )+where++import           Data.Morpheus.Types.Internal.Resolving.Resolver+import           Data.Morpheus.Types.Internal.Resolving.Core
+ src/Data/Morpheus/Types/Internal/Resolving/Core.hs view
@@ -0,0 +1,160 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE DeriveFunctor      #-}+{-# LANGUAGE DeriveAnyClass     #-}+{-# LANGUAGE DeriveGeneric      #-}+{-# LANGUAGE DataKinds          #-}+{-# LANGUAGE PolyKinds          #-}+{-# LANGUAGE NamedFieldPuns     #-}++module Data.Morpheus.Types.Internal.Resolving.Core+  ( GQLError(..)+  , Position(..)+  , GQLErrors+  , Validation+  , Result(..)+  , Failure(..)+  , ResultT(..)+  , fromEither+  , fromEitherSingle+  , unpackEvents+  , LibUpdater+  , resolveUpdates+  , mapEvent+  , mapFailure+  , cleanEvents+  , StatelessResT+  )+where++import           Control.Monad                  ( foldM )+import           Data.Function                  ( (&) )+import           Control.Monad.Trans.Class      ( MonadTrans(..) )+import           Control.Applicative            ( liftA2 )+import           Data.Aeson                     ( FromJSON+                                                , ToJSON+                                                )+import           Data.Morpheus.Types.Internal.AST.Base+                                                ( Position(..) )+import           Data.Text                      ( Text+                                                , pack+                                                )+import           GHC.Generics                   ( Generic )+import           Data.Semigroup                 ( (<>) )+++class Applicative f => Failure error (f :: * -> *) where+  failure :: error -> f v++instance Failure error (Either error) where+  failure = Left++data GQLError = GQLError+  { message      :: Text+  , locations :: [Position]+  } deriving (Show, Generic, FromJSON, ToJSON)++type GQLErrors = [GQLError]++type StatelessResT = ResultT () GQLError 'True+type Validation = Result () GQLError 'True++--+-- Result+--+--+data Result events error (concurency :: Bool)  a =+  Success { result :: a , warnings :: [error] , events:: [events] }+  | Failure [error] deriving (Functor)++instance Applicative (Result e cocnurency  error) where+  pure x = Success x [] []+  Success f w1 e1 <*> Success x w2 e2 = Success (f x) (w1 <> w2) (e1 <> e2)+  Failure e1      <*> Failure e2      = Failure (e1 <> e2)+  Failure e       <*> Success _ w _   = Failure (e <> w)+  Success _ w _   <*> Failure e       = Failure (e <> w)++instance Monad (Result e  cocnurency error)  where+  return = pure+  Success v w1 e1 >>= fm = case fm v of+    (Success x w2 e2) -> Success x (w1 <> w2) (e1 <> e2)+    (Failure e      ) -> Failure (e <> w1)+  Failure e >>= _ = Failure e++instance Failure [error] (Result ev error con) where+  failure = Failure++unpackEvents :: Result event c e a -> [event]+unpackEvents Success { events } = events+unpackEvents _                  = []++fromEither :: Either [er] a -> Result ev er co a+fromEither (Left  e) = Failure e+fromEither (Right a) = Success a [] []++fromEitherSingle :: Either er a -> Result ev er co a+fromEitherSingle (Left  e) = Failure [e]+fromEitherSingle (Right a) = Success a [] []++-- ResultT+newtype ResultT event error (concurency :: Bool)  (m :: * -> * ) a = ResultT { runResultT :: m (Result event error concurency a )  }+  deriving (Functor)++instance Applicative m => Applicative (ResultT event error concurency m) where+  pure = ResultT . pure . pure+  ResultT app1 <*> ResultT app2 = ResultT $ liftA2 (<*>) app1 app2++instance Monad m => Monad (ResultT event error concurency m) where+  return = pure+  (ResultT m1) >>= mFunc = ResultT $ do+    result1 <- m1+    case result1 of+      Failure errors       -> pure $ Failure errors+      Success value1 w1 e1 -> do+        result2 <- runResultT (mFunc value1)+        case result2 of+          Failure errors   -> pure $ Failure (errors <> w1)+          Success v2 w2 e2 -> return $ Success v2 (w1 <> w2) (e1 <> e2)++instance MonadTrans (ResultT event error concurency) where+  lift = ResultT . fmap pure++instance Applicative m => Failure String (ResultT ev GQLError con m) where+  failure x =+    ResultT $ pure $ Failure [GQLError { message = pack x, locations = [] }]++cleanEvents+  :: Functor m+  => ResultT e1 error concurency m a+  -> ResultT e2 error concurency m a+cleanEvents resT = ResultT $ replace <$> runResultT resT+ where+  replace (Success v w _) = Success v w []+  replace (Failure e    ) = Failure e++mapEvent+  :: Monad m+  => (ea -> eb)+  -> ResultT ea er con m value+  -> ResultT eb er con m value+mapEvent func (ResultT ma) = ResultT $ do+  state <- ma+  return $ state { events = map func (events state) }++mapFailure+  :: Monad m+  => (er1 -> er2)+  -> ResultT ev er1 con m value+  -> ResultT ev er2 con m value+mapFailure f (ResultT ma) = ResultT $ do+  state <- ma+  case state of+    Failure x     -> pure $ Failure (map f x)+    Success x w e -> pure $ Success x (map f w) e+++-- Helper Functions+type LibUpdater lib = lib -> Validation lib++resolveUpdates :: lib -> [LibUpdater lib] -> Validation lib+resolveUpdates = foldM (&)
+ src/Data/Morpheus/Types/Internal/Resolving/Resolver.hs view
@@ -0,0 +1,382 @@+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE GADTs                 #-}+{-# LANGUAGE InstanceSigs          #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NamedFieldPuns        #-}+{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE PolyKinds             #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE TupleSections         #-}+{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeOperators         #-}+{-# LANGUAGE UndecidableInstances  #-}++module Data.Morpheus.Types.Internal.Resolving.Resolver+  ( +    Event(..)+  , GQLRootResolver(..)+  , UnSubResolver+  , Resolver(..)+  , ResolvingStrategy(..)+  , MapStrategy(..)+  , LiftEither(..)+  , resolveObject+  , toResponseRes+  , withObject+  , resolving+  , toResolver+  , lift+  , SubEvent+  , GQLChannel(..)+  , ResponseEvent(..)+  , ResponseStream+  )+where++import           Control.Monad.Trans.Class      ( MonadTrans(..) )+import           Data.Maybe                     ( fromMaybe )+import           Data.Semigroup                 ( (<>) )+import           Data.Text                      ( unpack+                                                , pack+                                                )++-- MORPHEUS+import           Data.Morpheus.Error.Selection  ( resolvingFailedError+                                                , subfieldsNotSelected+                                                )+import           Data.Morpheus.Types.Internal.AST.Selection+                                                ( Selection(..)+                                                , SelectionRec(..)+                                                , SelectionSet+                                                , ValidSelection+                                                )+import           Data.Morpheus.Types.Internal.AST.Base+                                                ( Message , Key )+import           Data.Morpheus.Types.Internal.AST.Data+                                                ( +                                                  MUTATION+                                                , OperationType+                                                , QUERY+                                                , SUBSCRIPTION+                                                )+import           Data.Morpheus.Types.Internal.Resolving.Core+                                                ( GQLErrors+                                                , GQLError+                                                , Validation+                                                , Result(..)+                                                , Failure(..)+                                                , ResultT(..)+                                                , fromEither+                                                , fromEitherSingle+                                                , cleanEvents+                                                , mapFailure+                                                , mapEvent+                                                , StatelessResT+                                                )+import           Data.Morpheus.Types.Internal.AST.Value+                                                ( GQLValue(..)+                                                , Value+                                                )+import           Data.Morpheus.Types.IO         (renderResponse, GQLResponse)+-- MORPHEUS++class LiftEither (o::OperationType) res where+  type ResError res :: *+  liftEither :: Monad m => m (Either (ResError res) a) -> res o event m  a++type ResponseStream event m = ResultT (ResponseEvent m event) GQLError 'True m++data ResponseEvent m event+  = Publish event+  | Subscribe (SubEvent m event)++type SubEvent m event = Event (Channel event) (event -> m GQLResponse)++----------------------------------------------------------------------------------------+-- Recursive Resolver+newtype RecResolver m a b = RecResolver {+  unRecResolver :: a -> StatelessResT m b+}++instance Functor m => Functor (RecResolver m a) where+  fmap f (RecResolver x) = RecResolver recX where recX event = f <$> x event++instance Monad m => Applicative (RecResolver m a) where+  pure = RecResolver . const . pure+  (RecResolver f) <*> (RecResolver res) = RecResolver recX+    where recX event = f event <*> res event++instance Monad m => Monad (RecResolver m a) where+  (RecResolver x) >>= next = RecResolver recX+    where recX event = x event >>= (\v -> v event) . unRecResolver . next+------------------------------------------------------------++--- GraphQLT+data ResolvingStrategy  (o::OperationType) event (m:: * -> *) value where+  ResolveQ ::{ unResolveQ :: ResultT () GQLError 'True m value } -> ResolvingStrategy QUERY event m  value+  ResolveM ::{ unResolveM :: ResultT event GQLError 'True m value } -> ResolvingStrategy MUTATION event m  value+  ResolveS ::{ unResolveS :: ResultT (Channel event) GQLError 'True m (RecResolver m event value) } -> ResolvingStrategy SUBSCRIPTION event m value++-- Functor+instance Monad m => Functor (ResolvingStrategy o e m) where+  fmap f (ResolveQ res) = ResolveQ $ f <$> res+  fmap f (ResolveM res) = ResolveM $ f <$> res+  fmap f (ResolveS res) = ResolveS $ (<$>) f <$> res++-- Applicative+instance (LiftEither o ResolvingStrategy, Monad m) => Applicative (ResolvingStrategy o e m) where+  pure = liftEither . pure . pure+  -------------------------------------+  (ResolveQ f) <*> (ResolveQ res) = ResolveQ (f <*> res)+  ------------------------------------------------------------------------+  (ResolveM f) <*> (ResolveM res) = ResolveM (f <*> res)+  --------------------------------------------------------------+  (ResolveS f) <*> (ResolveS res) = ResolveS $ (<*>) <$> f <*> res++-- LiftEither+instance LiftEither QUERY ResolvingStrategy where+  type ResError ResolvingStrategy = GQLErrors+  liftEither = ResolveQ . ResultT . fmap fromEither++instance LiftEither MUTATION ResolvingStrategy where+  type ResError ResolvingStrategy = GQLErrors+  liftEither = ResolveM . ResultT . fmap fromEither++instance LiftEither SUBSCRIPTION ResolvingStrategy where+  type ResError ResolvingStrategy = GQLErrors+  liftEither = ResolveS . ResultT . fmap (fromEither . fmap pure)++ -- Failure+instance (LiftEither o ResolvingStrategy, Monad m) => Failure GQLErrors (ResolvingStrategy o e m) where+  failure = liftEither . pure . Left++-- helper functins+withObject+  :: (LiftEither o ResolvingStrategy, Monad m)+  => (SelectionSet -> ResolvingStrategy o e m value)+  -> (Key, ValidSelection)+  -> ResolvingStrategy o e m value+withObject f (_, Selection { selectionRec = SelectionSet selection }) =+  f selection+withObject _ (key, Selection { selectionPosition }) =+  failure (subfieldsNotSelected key "" selectionPosition)++resolveObject+  :: (Monad m, LiftEither o ResolvingStrategy)+  => SelectionSet+  -> [FieldRes o e m]+  -> ResolvingStrategy o e m Value+resolveObject selectionSet fieldResolvers =+  gqlObject <$> traverse selectResolver selectionSet+ where+  selectResolver (key, selection@Selection { selectionAlias }) =+    (fromMaybe key selectionAlias, ) <$> lookupRes selection+   where+    lookupRes sel =+      (fromMaybe (const $ pure gqlNull) $ lookup key fieldResolvers) (key, sel)++toResponseRes+  :: Monad m+  => ResolvingStrategy o event m Value+  -> ResponseStream event m Value+toResponseRes (ResolveQ resT) = cleanEvents resT+toResponseRes (ResolveM resT) = mapEvent Publish resT+toResponseRes (ResolveS resT) = ResultT $ handleActions <$> runResultT resT+ where+  handleActions (Failure gqlError                ) = Failure gqlError+  handleActions (Success subRes warnings channels) = Success+    { result   = gqlNull+    , warnings+    , events   = [Subscribe $ Event channels eventResolver]+    }+   where+    eventResolver event = renderResponse <$> runResultT  (unRecResolver subRes event) ++--+--     +-- GraphQL Field Resolver+--+--+--ResultT  GQLError 'True m (RecResolver m event value)+---------------------------------------------------------------+data Resolver (o::OperationType) event (m :: * -> * )  value where+    QueryResolver::{ unQueryResolver :: ResultT () String 'True m value } -> Resolver QUERY   event m value+    MutResolver ::{ unMutResolver :: ResultT event String 'True m ([event],value) } -> Resolver MUTATION event m  value+    SubResolver ::{+            subChannels :: [StreamChannel event] ,+            subResolver :: event -> Resolver QUERY event m value+        } -> Resolver SUBSCRIPTION event m  value++-- Functor+instance Functor m => Functor (Resolver o e m) where+  fmap f (QueryResolver res) = QueryResolver $ fmap f res+  fmap f (MutResolver   res) = MutResolver $ tupleMap <$> res+    where tupleMap (e, v) = (e, f v)+  fmap f (SubResolver events mResolver) = SubResolver events+                                                      (eventFmap mResolver)+    where eventFmap res event = fmap f (res event)++-- Applicative+instance (LiftEither o Resolver ,Monad m) => Applicative (Resolver o e m) where+  pure = liftEither . pure . pure+  -------------------------------------+  (QueryResolver f) <*> (QueryResolver res) = QueryResolver (f <*> res)+  ---------------------------------------------------------------------+  MutResolver res1 <*> MutResolver res2 = MutResolver $ join <$> res1 <*> res2+    where join (e1, f) (e2, v) = (e1 <> e2, f v)+  --------------------------------------------------------------+  (SubResolver e1 f) <*> (SubResolver e2 res) = SubResolver (e1 <> e2) subRes+    where subRes event = f event <*> res event++-- Monad +instance (Monad m) => Monad (Resolver QUERY e m) where+  return = pure+  -----------------------------------------------------+  (QueryResolver f) >>= nextM = QueryResolver (f >>= unQueryResolver . nextM)++instance (Monad m) => Monad (Resolver MUTATION e m) where+  return = pure+  -----------------------------------------------------+  (MutResolver m1) >>= mFunc = MutResolver $ do+    (e1, v1) <- m1+    (e2, v2) <- unMutResolver $ mFunc v1+    pure (e1 <> e2, v2)++-- Monad Transformers    +instance MonadTrans (Resolver QUERY e) where+  lift = liftEither . fmap pure++instance MonadTrans (Resolver MUTATION e) where+  lift = liftEither . fmap pure++-- LiftEither+instance LiftEither QUERY Resolver where+  type ResError Resolver = String+  liftEither = QueryResolver . ResultT . fmap fromEitherSingle++instance LiftEither MUTATION Resolver where+  type ResError Resolver = String+  liftEither = MutResolver . ResultT . fmap (fromEitherSingle . fmap ([], ))++instance LiftEither SUBSCRIPTION Resolver where+  type ResError Resolver = String+  liftEither = SubResolver [] . const . liftEither++-- Failure+instance (LiftEither o Resolver, Monad m) => Failure Message (Resolver o e m) where+  failure = liftEither . pure . Left . unpack++-- Type Helpers  +type family UnSubResolver (a :: * -> *) :: (* -> *)++type instance UnSubResolver (Resolver SUBSCRIPTION m e) = Resolver QUERY m e+++-- RESOLVING+type FieldRes o e m+  = (Key, (Key, ValidSelection) -> ResolvingStrategy o e m Value)++toResolver+  :: (LiftEither o Resolver, Monad m)+  => Validation a+  -> (a -> Resolver o e m b)+  -> Resolver o e m b+toResolver Success { result } f = f result+toResolver (Failure errors) _ =+  failure ("TODO: errors" <> pack (show errors) :: Message)++resolving+  :: forall o e m value+   . Monad m+  => (value -> (Key, ValidSelection) -> ResolvingStrategy o e m Value)+  -> Resolver o e m value+  -> (Key, ValidSelection)+  -> ResolvingStrategy o e m Value+resolving encode gResolver selection@(fieldName, Selection { selectionPosition })+  = _resolve gResolver+ where+  convert :: Monad m => ResultT ev String con m a -> ResultT ev GQLError con m a+  convert =+    mapFailure (resolvingFailedError selectionPosition fieldName . pack)+  ------------------------------+  _encode = (`encode` selection)+  -------------------------------------------------------------------+  _resolve (QueryResolver res) =+    ResolveQ $ convert res >>= unResolveQ . _encode+  ---------------------------------------------------------------------------------------------------------------------------------------+  _resolve (MutResolver res) =+    ResolveM $ replace (convert res) >>= unResolveM . _encode+   where+    replace (ResultT mx) = ResultT $ do+      value <- mx+      pure $ case value of+        Success { warnings, events, result = (events2, result) } ->+          Success { result, warnings, events = events <> events2 }+        Failure x -> Failure x+  --------------------------------------------------------------------------------------------------------------------------------+  _resolve (SubResolver subChannels res) = ResolveS $ ResultT $ pure $ Success+    { events   = map Channel subChannels+    , result   = RecResolver eventResolver+    , warnings = []+    }+   where+    eventResolver :: e -> StatelessResT m Value+    eventResolver event =+      convert (unQueryResolver $ res event) >>= unPureSub . _encode+     where+      unPureSub+        :: Monad m+        => ResolvingStrategy SUBSCRIPTION e m Value+        -> StatelessResT m Value+      unPureSub (ResolveS x) = cleanEvents x >>= passEvent+       where+          passEvent (RecResolver f) = f event++-- map Resolving strategies +class MapStrategy (from :: OperationType) (to :: OperationType) where+   mapStrategy :: Monad m => ResolvingStrategy from e m a -> ResolvingStrategy to e m a++instance MapStrategy o o where+  mapStrategy = id++instance MapStrategy QUERY SUBSCRIPTION where+  mapStrategy (ResolveQ x) = ResolveS $ pure <$> cleanEvents x++-------------------------------------------------------------------+-- | GraphQL Root resolver, also the interpreter generates a GQL schema from it.+--  'queryResolver' is required, 'mutationResolver' and 'subscriptionResolver' are optional,+--  if your schema does not supports __mutation__ or __subscription__ , you acn use __()__ for it.+data GQLRootResolver (m :: * -> *) event (query :: (* -> *) -> * ) (mut :: (* -> *) -> * )  (sub :: (* -> *) -> * )  = GQLRootResolver+  { queryResolver        :: query (Resolver QUERY event m)+  , mutationResolver     :: mut (Resolver MUTATION event m)+  , subscriptionResolver :: sub (Resolver SUBSCRIPTION  event m)+  }++ -- EVENTS+++-- Channel++newtype Channel event = Channel {+  unChannel :: StreamChannel event+}++instance (Eq (StreamChannel event)) => Eq (Channel event) where+  Channel x == Channel y = x == y++class GQLChannel a where+  type StreamChannel a :: *+  streamChannels :: a -> [Channel a]++instance GQLChannel () where+  type StreamChannel () = ()+  streamChannels _ = []++instance GQLChannel (Event channel content)  where+  type StreamChannel (Event channel content) = channel+  streamChannels Event { channels } = map Channel channels++data Event e c = Event+  { channels :: [e], content  :: c}
− src/Data/Morpheus/Types/Internal/Stream.hs
@@ -1,117 +0,0 @@-{-# LANGUAGE DataKinds            #-}-{-# LANGUAGE DeriveFunctor        #-}-{-# LANGUAGE FlexibleContexts     #-}-{-# LANGUAGE FlexibleInstances    #-}-{-# LANGUAGE GADTs                #-}-{-# LANGUAGE NamedFieldPuns       #-}-{-# LANGUAGE TypeFamilies         #-}-{-# LANGUAGE UndecidableInstances #-}--module Data.Morpheus.Types.Internal.Stream-  ( StreamState(..)-  , ResponseEvent(..)-  , SubEvent-  , Event(..)-  -- STREAMS-  , StreamT(..)-  , ResponseStream-  , closeStream-  , mapS-  , injectEvents-  , initExceptStream-  , pushEvents- -- , GQLMonad(..)-  , GQLChannel(..)-  , Channel(..)-  ) where--import           Control.Monad.Trans.Except (ExceptT (..), runExceptT)-import           Data.Semigroup ((<>))---- MORPHEUS-import           Data.Morpheus.Types.IO     (GQLResponse)---- EVENTS-data ResponseEvent m event-  = Publish event-  | Subscribe (SubEvent m event)---- STREAMS-type ResponseStream m event = StreamT m (ResponseEvent m event)--type SubEvent m event = Event (Channel event) (event-> m GQLResponse)--newtype Channel event = Channel {-  unChannel :: StreamChannel event-}--instance (Eq (StreamChannel event)) => Eq (Channel event) where-  Channel x == Channel y = x == y---class GQLChannel a where-    type StreamChannel a :: *-    streamChannels :: a -> [Channel a]--instance GQLChannel () where-    type StreamChannel () = ()-    streamChannels _ = []--instance GQLChannel (Event channel content)  where-   type StreamChannel (Event channel content)  = channel-   streamChannels Event { channels } =  map Channel channels--data Event e c = Event-  { channels :: [e]-  , content  :: c-  }--data StreamState c v = StreamState-  { streamEvents :: [c]-  , streamValue  :: v-  } deriving (Functor)---- | Monad Transformer that sums all effect Together-newtype StreamT m s a = StreamT-  { runStreamT :: m (StreamState s a)-  } deriving (Functor)--instance Monad m => Applicative (StreamT m c) where-  pure = StreamT . return . StreamState []-  StreamT app1 <*> StreamT app2 =-    StreamT $ do-      (StreamState effect1 func) <- app1-      (StreamState effect2 val) <- app2-      return $ StreamState (effect1 ++ effect2) (func val)--instance Monad m => Monad (StreamT m c) where-  return = pure-  (StreamT m1) >>= mFunc =-    StreamT $ do-      (StreamState e1 v1) <- m1-      (StreamState e2 v2) <- runStreamT $ mFunc v1-      return $ StreamState (e1 ++ e2) v2---- Helper Functions-toTuple :: StreamState s a -> ([s], a)-toTuple StreamState {streamEvents, streamValue} = (streamEvents, streamValue)--closeStream :: Monad m => (StreamT m s) v -> m ([s], v)-closeStream resolver = toTuple <$> runStreamT resolver--mapS :: Monad m => (a -> b) -> StreamT m a value -> StreamT m b value-mapS func (StreamT ma) =-  StreamT $ do-    state <- ma-    return $ state {streamEvents = map func (streamEvents state)}--pushEvents :: Functor m => [event] -> ExceptT e (StreamT m event) a -> ExceptT e (StreamT m event) a-pushEvents events = ExceptT . StreamT . fmap updateState . runStreamT . runExceptT-    where-        updateState x = x { streamEvents = events <> streamEvents x }--injectEvents :: Functor m => [event] -> ExceptT e m a -> ExceptT e (StreamT m event) a-injectEvents states = ExceptT . StreamT . fmap (StreamState states) . runExceptT--initExceptStream :: Applicative m => [event] -> a -> ExceptT e (StreamT m event) a-initExceptStream events = ExceptT . StreamT . pure . StreamState events . Right
src/Data/Morpheus/Types/Internal/TH.hs view
@@ -1,26 +1,10 @@-{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE CPP #-}   module Data.Morpheus.Types.Internal.TH where -import           Data.Text                  (Text, pack, unpack) import           Language.Haskell.TH-import           Language.Haskell.TH.Syntax -liftMaybeText :: Maybe Text -> ExpQ-liftMaybeText (Just x) = appE  (conE 'Just) (liftText x)-liftMaybeText Nothing  = conE 'Nothing--liftText :: Text -> ExpQ-liftText x = appE (varE 'pack) (lift (unpack x))--liftTextTuple :: Lift a => (Text, a) -> ExpQ-liftTextTuple (name, x) = tupE [liftText name, lift x]--liftTextMap :: Lift a => [(Text, a)] -> ExpQ-liftTextMap = listE . map liftTextTuple- apply :: Name -> [Q Exp] -> Q Exp apply n = foldl appE (conE n) @@ -33,11 +17,15 @@ instanceHeadT :: Name -> String -> [String] -> Q Type instanceHeadT cName iType tArgs = applyT cName [applyT (mkName iType) (map (varT . mkName) tArgs)] -instanceFunD :: Name -> [String] -> Q Exp -> Q Dec+instanceProxyFunD :: (Name,ExpQ) -> DecQ+instanceProxyFunD (name,body)  = instanceFunD name ["_"] body++instanceFunD :: Name -> [String] -> ExpQ -> Q Dec instanceFunD name args body = funD name [clause (map (varP . mkName) args) (normalB body) []]  instanceHeadMultiT :: Name -> Q Type -> [Q Type] -> Q Type instanceHeadMultiT className iType li = applyT className (iType : li)+  -- "User" -> ["name","id"] -> (User name id) destructRecord :: String -> [String] -> PatQ
− src/Data/Morpheus/Types/Internal/Validation.hs
@@ -1,34 +0,0 @@-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveGeneric  #-}--module Data.Morpheus.Types.Internal.Validation-  ( GQLError(..)-  , Location(..)-  , GQLErrors-  , JSONError(..)-  , Validation-  , ResolveValue-  ) where--import           Control.Monad.Trans.Except         (ExceptT (..))-import           Data.Aeson                         (FromJSON, ToJSON)-import           Data.Morpheus.Types.Internal.Base  (Location (..))-import           Data.Morpheus.Types.Internal.Value (Value)-import           Data.Text                          (Text)-import           GHC.Generics                       (Generic)--data GQLError = GQLError-  { desc      :: Text-  , positions :: [Location]-  } deriving (Show)--type GQLErrors = [GQLError]--data JSONError = JSONError-  { message   :: Text-  , locations :: [Location]-  } deriving (Show, Generic, FromJSON, ToJSON)--type Validation = Either GQLErrors--type ResolveValue m = ExceptT GQLErrors m Value
− src/Data/Morpheus/Types/Internal/Value.hs
@@ -1,195 +0,0 @@-{-# LANGUAGE DeriveGeneric       #-}-{-# LANGUAGE DeriveLift          #-}-{-# LANGUAGE FlexibleInstances   #-}-{-# LANGUAGE OverloadedStrings   #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TemplateHaskell     #-}-{-# LANGUAGE TupleSections       #-}--module Data.Morpheus.Types.Internal.Value-  ( Value(..)-  , ScalarValue(..)-  , Object-  , GQLValue(..)-  , replaceValue-  , decodeScientific-  , convertToJSONName-  , convertToHaskellName-  ) where--import qualified Data.Aeson                      as A (FromJSON (..), ToJSON (..), Value (..), object, pairs, (.=))-import           Data.Function                   ((&))-import qualified Data.HashMap.Strict             as M (toList)-import           Data.Scientific                 (Scientific, floatingOrInteger)-import           Data.Semigroup                  ((<>))-import           Data.Text                       (Text)-import qualified Data.Text                       as T-import qualified Data.Vector                     as V (toList)-import           GHC.Generics                    (Generic)-import           Language.Haskell.TH-import           Language.Haskell.TH.Syntax---- MORPHEUS-import           Data.Morpheus.Types.Internal.TH (apply, liftText, liftTextMap)--isReserved :: Text -> Bool-isReserved "case"     = True-isReserved "class"    = True-isReserved "data"     = True-isReserved "default"  = True-isReserved "deriving" = True-isReserved "do"       = True-isReserved "else"     = True-isReserved "foreign"  = True-isReserved "if"       = True-isReserved "import"   = True-isReserved "in"       = True-isReserved "infix"    = True-isReserved "infixl"   = True-isReserved "infixr"   = True-isReserved "instance" = True-isReserved "let"      = True-isReserved "module"   = True-isReserved "newtype"  = True-isReserved "of"       = True-isReserved "then"     = True-isReserved "type"     = True-isReserved "where"    = True-isReserved "_"        = True-isReserved _          = False--{-# INLINE isReserved #-}-convertToJSONName :: Text -> Text-convertToJSONName hsName-  | not (T.null hsName) && isReserved name && (T.last hsName == '\'') = name-  | otherwise = hsName-  where-    name = T.init hsName--convertToHaskellName :: Text -> Text-convertToHaskellName name-  | isReserved name = name <> "'"-  | otherwise = name---- | Primitive Values for GQLScalar: 'Int', 'Float', 'String', 'Boolean'.--- for performance reason type 'Text' represents GraphQl 'String' value-data ScalarValue-  = Int Int-  | Float Float-  | String Text-  | Boolean Bool-  deriving (Show, Generic)--instance Lift ScalarValue where-  lift (String n)  = apply 'String [liftText n]-  lift (Int n)     = apply 'Int [lift n]-  lift (Float n)   = apply 'Float [lift n]-  lift (Boolean n) = apply 'Boolean [lift n]--instance A.ToJSON ScalarValue where-  toJSON (Float x)   = A.toJSON x-  toJSON (Int x)     = A.toJSON x-  toJSON (Boolean x) = A.toJSON x-  toJSON (String x)  = A.toJSON x--instance A.FromJSON ScalarValue where-  parseJSON (A.Bool v)   = pure $ Boolean v-  parseJSON (A.Number v) = pure $ decodeScientific v-  parseJSON (A.String v) = pure $ String v-  parseJSON notScalar    = fail $ "Expected Scalar got :" <> show notScalar--instance Lift Value where-  lift (Object ls) = apply 'Object [liftTextMap ls]-  lift (List n)    = apply 'List [lift n]-  lift (Enum n)    = apply 'Enum [liftText n]-  lift (Scalar n)  = apply 'Scalar [lift n]-  lift Null        = varE 'Null--type Object = [(Text, Value)]--data Value-  = Object Object-  | List [Value]-  | Enum Text-  | Scalar ScalarValue-  | Null-  deriving (Show, Generic)--instance A.ToJSON Value where-  toEncoding Null = A.toEncoding A.Null-  toEncoding (Enum x) = A.toEncoding x-  toEncoding (List x) = A.toEncoding x-  toEncoding (Scalar x) = A.toEncoding x-  toEncoding (Object []) = A.toEncoding $ A.object []-  toEncoding (Object x) = A.pairs $ foldl1 (<>) $ map encodeField x-    where-      encodeField (key, value) = convertToJSONName key A..= value--decodeScientific :: Scientific -> ScalarValue-decodeScientific v =-  case floatingOrInteger v of-    Left float -> Float float-    Right int  -> Int int--replaceValue :: A.Value -> Value-replaceValue (A.Bool v) = gqlBoolean v-replaceValue (A.Number v) = Scalar $ decodeScientific v-replaceValue (A.String v) = gqlString v-replaceValue (A.Object v) = gqlObject $ map replace (M.toList v)-  where-    replace :: (a, A.Value) -> (a, Value)-    replace (key, val) = (key, replaceValue val)-replaceValue (A.Array li) = gqlList (map replaceValue (V.toList li))-replaceValue A.Null = gqlNull--instance A.FromJSON Value where-  parseJSON = pure . replaceValue---- DEFAULT VALUES-class GQLValue a where-  gqlNull :: a-  gqlScalar :: ScalarValue -> a-  gqlBoolean :: Bool -> a-  gqlString :: Text -> a-  gqlList :: [a] -> a-  gqlObject :: [(Text, a)] -> a---- build GQL Values for Subscription Resolver-instance GQLValue Value where-  gqlNull = Null-  gqlScalar = Scalar-  gqlBoolean = Scalar . Boolean-  gqlString = Scalar . String-  gqlList = List-  gqlObject = Object--instance Monad m => GQLValue (m Value) where-  gqlNull = pure gqlNull-  gqlScalar = pure . gqlScalar-  gqlBoolean = pure . gqlBoolean-  gqlString = pure . gqlString-  ------------------------------------------  -- listValue :: [m Value] -> m Value-  gqlList = fmap gqlList . sequence-  ------------------------------------------  -- objectValue :: [(Text, m Value )] -> m Value-  gqlObject = fmap gqlObject . traverse keyVal-    where-      keyVal :: Monad m => (Text, m Value) -> m (Text, Value)-      keyVal (key, valFunc) = (key, ) <$> valFunc---- build GQL Values for Subscription Resolver-instance Monad m => GQLValue (args -> m Value) where-  gqlNull = const gqlNull-  gqlScalar = const . gqlScalar-  gqlBoolean = pure . gqlBoolean-  gqlString = const . gqlString-  -----------------------------------------   -- listValue :: [args -> m Value] -> ( args -> m Value )-  gqlList res args = gqlList <$> traverse (args &) res-  -----------------------------------------  -- objectValue :: [(Text, args -> m Value )] -> ( args -> m Value )-  gqlObject res args = gqlObject <$> traverse keyVal res-    where-      keyVal :: Monad m => (Text, args -> m Value) -> m (Text, Value)-      keyVal (key, valFunc) = (key, ) <$> valFunc args
src/Data/Morpheus/Types/Internal/WebSocket.hs view
@@ -4,15 +4,17 @@   ( GQLClient(..)   , ClientID   , ClientSession(..)-  ) where+  )+where -import           Data.Semigroup                      ((<>))-import           Data.Text                           (Text)-import           Data.UUID                           (UUID)-import           Network.WebSockets                  (Connection)+import           Data.Semigroup                 ( (<>) )+import           Data.Text                      ( Text )+import           Data.UUID                      ( UUID )+import           Network.WebSockets             ( Connection )  -- MORPHEUS-import           Data.Morpheus.Types.Internal.Stream (SubEvent)+import           Data.Morpheus.Types.Internal.Resolving+                                                ( SubEvent )  type ClientID = UUID @@ -23,7 +25,7 @@     }  instance (Show e) => Show (ClientSession m e ) where-  show ClientSession {sessionId} =+  show ClientSession { sessionId } =     "GQLSession { id: " <> show sessionId <> ", sessions: " <> "" <> " }"  data GQLClient m e  =@@ -34,6 +36,9 @@     }  instance (Show e) => Show (GQLClient m e) where-  show GQLClient {clientID, clientSessions} =-    "GQLClient {id:" <> show clientID <> ", sessions:" <> show clientSessions <>-    "}"+  show GQLClient { clientID, clientSessions } =+    "GQLClient {id:"+      <> show clientID+      <> ", sessions:"+      <> show clientSessions+      <> "}"
src/Data/Morpheus/Types/Types.hs view
@@ -1,33 +1,46 @@-{-# LANGUAGE DeriveGeneric   #-}-{-# LANGUAGE KindSignatures  #-}-{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE DeriveGeneric    #-}+{-# LANGUAGE KindSignatures   #-}  module Data.Morpheus.Types.Types-  ( GQLQueryRoot(..)-  , Variables-  , Undefined(..)-  ) where--import           Data.Map                                      (Map)-import           GHC.Generics                                  (Generic)-import           Language.Haskell.TH.Syntax                    (Lift (..))+  ( Undefined(..)+  , Pair(..)+  , MapKind(..)+  , MapArgs(..)+  , mapKindFromList+  )+where --- Morpheus-import           Data.Morpheus.Types.Internal.AST.Operation    (RawOperation)-import           Data.Morpheus.Types.Internal.AST.RawSelection (FragmentLib)-import           Data.Morpheus.Types.Internal.Base             (Key)-import           Data.Morpheus.Types.Internal.TH               (apply, liftTextMap)-import           Data.Morpheus.Types.Internal.Value            (Value)+import           GHC.Generics                   ( Generic )  data Undefined (m :: * -> *) = Undefined deriving (Show, Generic) -type Variables = Map Key Value+data Pair k v =+  Pair+    { key   :: k+    , value :: v+    }+  deriving (Generic) -data GQLQueryRoot = GQLQueryRoot-  { fragments      :: FragmentLib-  , operation      :: RawOperation-  , inputVariables :: [(Key, Value)]-  } deriving (Show)+newtype MapArgs k =+  MapArgs+    { oneOf :: Maybe [k]+    }+  deriving (Generic) -instance Lift GQLQueryRoot where-  lift (GQLQueryRoot f o v) = apply 'GQLQueryRoot [liftTextMap f, lift o, liftTextMap v]+data MapKind k v m =+  MapKind+    { size  :: Int+    , pairs :: MapArgs k -> m [Pair k v]+    }+  deriving (Generic)++mapKindFromList :: (Eq k, Applicative m) => [(k, v)] -> MapKind k v m+mapKindFromList inputPairs = MapKind { size  = length inputPairs+                                     , pairs = resolvePairs+                                     }+ where+  filterBy MapArgs { oneOf = Just list } =+    filter ((`elem` list) . fst) inputPairs+  filterBy _ = inputPairs+  resolvePairs = pure . (map toGQLTuple . filterBy)+  toGQLTuple (x, y) = Pair x y
src/Data/Morpheus/Validation/Document/Validation.hs view
@@ -2,52 +2,76 @@  module Data.Morpheus.Validation.Document.Validation   ( validatePartialDocument-  ) where+  )+where  import           Data.Maybe  -- -- Morpheus-import           Data.Morpheus.Error.Document.Interface  (ImplementsError (..), partialImplements, unknownInterface)-import           Data.Morpheus.Rendering.RenderGQL       (RenderGQL (..))-import           Data.Morpheus.Types.Internal.Data       (DataField (..), DataType (..), DataObject, DataTyCon (..),-                                                          Key, RawDataType (..), TypeAlias (..), isWeaker, isWeaker)-import           Data.Morpheus.Types.Internal.Validation (Validation)+import           Data.Morpheus.Error.Document.Interface+                                                ( ImplementsError(..)+                                                , partialImplements+                                                , unknownInterface+                                                )+import           Data.Morpheus.Rendering.RenderGQL+                                                ( RenderGQL(..) )+import           Data.Morpheus.Types.Internal.AST+                                                ( DataField(..)+                                                , DataType(..)+                                                , DataObject+                                                , DataTyCon(..)+                                                , Key+                                                , RawDataType(..)+                                                , TypeAlias(..)+                                                , isWeaker+                                                , isWeaker+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Validation+                                                , Failure(..)+                                                )  validatePartialDocument :: [(Key, RawDataType)] -> Validation [(Key, DataType)] validatePartialDocument lib = catMaybes <$> traverse validateType lib-  where-    validateType :: (Key, RawDataType) -> Validation (Maybe (Key, DataType))-    validateType (name, FinalDataType x)              = pure $ Just (name, x)-    validateType (name, Implements interfaces object) = asTuple name <$> object `mustImplement` interfaces-    validateType _                                    = pure Nothing-    ------------------------------------    asTuple name x = Just (name, x)-    ------------------------------------    mustImplement :: DataObject -> [Key] -> Validation DataType-    mustImplement object interfaceKey = do-      interface <- traverse getInterfaceByKey interfaceKey-      case concatMap (mustBeSubset object) interface of-        []     -> pure $ DataObject object-        errors -> Left $ partialImplements (typeName object) errors-    --------------------------------    mustBeSubset :: DataObject -> DataObject -> [(Key, Key, ImplementsError)]-    mustBeSubset DataTyCon {typeData = objFields} DataTyCon {typeName, typeData = interfaceFields} =-      concatMap checkField interfaceFields-      where-        checkField :: (Key, DataField) -> [(Key, Key, ImplementsError)]-        checkField (key, DataField {fieldType = interfaceT@TypeAlias { aliasTyCon = interfaceTypeName-                                                                     , aliasWrappers = interfaceWrappers-                                                                     }}) =-          case lookup key objFields of-            Just DataField {fieldType = objT@TypeAlias {aliasTyCon, aliasWrappers}}-              | aliasTyCon == interfaceTypeName && not (isWeaker aliasWrappers interfaceWrappers) -> []-              | otherwise ->-                [(typeName, key, UnexpectedType {expectedType = render interfaceT, foundType = render objT})]-            Nothing -> [(typeName, key, UndefinedField)]-    --------------------------------    getInterfaceByKey :: Key -> Validation DataObject-    getInterfaceByKey key =-      case lookup key lib of-        Just (Interface x) -> pure x-        _                  -> Left $ unknownInterface key+ where+  validateType :: (Key, RawDataType) -> Validation (Maybe (Key, DataType))+  validateType (name, FinalDataType x) = pure $ Just (name, x)+  validateType (name, Implements interfaces object) =+    asTuple name <$> object `mustImplement` interfaces+  validateType _ = pure Nothing+  -----------------------------------+  asTuple name x = Just (name, x)+  -----------------------------------+  mustImplement :: DataObject -> [Key] -> Validation DataType+  mustImplement object interfaceKey = do+    interface <- traverse getInterfaceByKey interfaceKey+    case concatMap (mustBeSubset object) interface of+      []     -> pure $ DataObject object+      errors -> failure $ partialImplements (typeName object) errors+  -------------------------------+  mustBeSubset :: DataObject -> DataObject -> [(Key, Key, ImplementsError)]+  mustBeSubset DataTyCon { typeData = objFields } DataTyCon { typeName, typeData = interfaceFields }+    = concatMap checkField interfaceFields+   where+    checkField :: (Key, DataField) -> [(Key, Key, ImplementsError)]+    checkField (key, DataField { fieldType = interfaceT@TypeAlias { aliasTyCon = interfaceTypeName, aliasWrappers = interfaceWrappers } })+      = case lookup key objFields of+        Just DataField { fieldType = objT@TypeAlias { aliasTyCon, aliasWrappers } }+          | aliasTyCon == interfaceTypeName && not+            (isWeaker aliasWrappers interfaceWrappers)+          -> []+          | otherwise+          -> [ ( typeName+               , key+               , UnexpectedType { expectedType = render interfaceT+                                , foundType    = render objT+                                }+               )+             ]+        Nothing -> [(typeName, key, UndefinedField)]+  -------------------------------+  getInterfaceByKey :: Key -> Validation DataObject+  getInterfaceByKey key = case lookup key lib of+    Just (Interface x) -> pure x+    _                  -> failure $ unknownInterface key
src/Data/Morpheus/Validation/Internal/Utils.hs view
@@ -1,77 +1,47 @@+{-# LANGUAGE NamedFieldPuns #-}++ module Data.Morpheus.Validation.Internal.Utils   ( differKeys-  , existsObjectType-  , lookupType-  , getInputType-  , lookupField   , checkNameCollision   , checkForUnknownKeys   , VALIDATION_MODE(..)-  ) where--import           Data.List                               ((\\))-import           Data.Morpheus.Error.Variable            (unknownType)-import           Data.Morpheus.Types.Internal.Base       (EnhancedKey (..), Key, Position, enhanceKeyWithNull)-import           Data.Morpheus.Types.Internal.Data       (DataObject, DataType (..), DataTypeLib (..))-import           Data.Morpheus.Types.Internal.Validation (Validation)-import qualified Data.Set                                as S-import           Data.Text                               (Text)+  )+where -type GenError error a = error -> Either error a+import           Data.List                      ( (\\) )+import           Data.Morpheus.Types.Internal.AST+                                                ( Ref(..)+                                                , Key+                                                , anonymousRef+                                                )+import qualified Data.Set                      as S+import           Data.Text                      ( Text )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Failure(..) )  data VALIDATION_MODE   = WITHOUT_VARIABLES   | FULL_VALIDATION   deriving (Eq, Show) -lookupType :: error -> [(Text, a)] -> Text -> Either error a-lookupType error' lib' typeName' =-  case lookup typeName' lib' of-    Nothing -> Left error'-    Just x  -> pure x--lookupField :: Text -> [(Text, fType)] -> GenError error fType-lookupField id' lib' error' =-  case lookup id' lib' of-    Nothing    -> Left error'-    Just field -> pure field--getInputType :: Text -> DataTypeLib -> GenError error DataType-getInputType name lib gqlError =-  case lookup name (inputObject lib) of-    Just x -> pure (DataInputObject x)-    Nothing ->-      case lookup name (inputUnion lib) of-        Just x -> pure (DataInputUnion x)-        Nothing ->-          case lookup name (scalar lib) of-            Just x   -> pure (DataScalar x)-            Nothing  -> case lookup name (enum lib) of-                    Just x  -> pure (DataEnum x)-                    Nothing -> Left gqlError--existsObjectType :: Position -> Text -> DataTypeLib -> Validation DataObject-existsObjectType position' typeName' lib = lookupType error' (object lib) typeName'-  where-    error' = unknownType typeName' position'--differKeys :: [EnhancedKey] -> [Key] -> [EnhancedKey]-differKeys enhanced keys = enhanced \\ map enhanceKeyWithNull keys+differKeys :: [Ref] -> [Key] -> [Ref]+differKeys enhanced keys = enhanced \\ map anonymousRef keys  removeDuplicates :: Ord a => [a] -> [a] removeDuplicates = S.toList . S.fromList -elementOfKeys :: [Text] -> EnhancedKey -> Bool-elementOfKeys keys' EnhancedKey {uid = id'} = id' `elem` keys'+elementOfKeys :: [Text] -> Ref -> Bool+elementOfKeys keys Ref { refName } = refName `elem` keys -checkNameCollision :: [EnhancedKey] -> ([EnhancedKey] -> error) -> Either error [EnhancedKey]+checkNameCollision :: Failure e m => [Ref] -> ([Ref] -> e) -> m [Ref] checkNameCollision enhancedKeys errorGenerator =   case enhancedKeys \\ removeDuplicates enhancedKeys of     []         -> pure enhancedKeys-    duplicates -> Left $ errorGenerator duplicates+    duplicates -> failure $ errorGenerator duplicates -checkForUnknownKeys :: [EnhancedKey] -> [Text] -> ([EnhancedKey] -> error) -> Either error [EnhancedKey]+checkForUnknownKeys :: Failure e m => [Ref] -> [Text] -> ([Ref] -> e) -> m [Ref] checkForUnknownKeys enhancedKeys' keys' errorGenerator' =   case filter (not . elementOfKeys keys') enhancedKeys' of     []           -> pure enhancedKeys'-    unknownKeys' -> Left $ errorGenerator' unknownKeys'+    unknownKeys' -> failure $ errorGenerator' unknownKeys'
src/Data/Morpheus/Validation/Internal/Value.hs view
@@ -4,74 +4,110 @@ module Data.Morpheus.Validation.Internal.Value   ( validateInputValue   , validateEnum-  ) where+  )+where -import           Data.List                               (elem)+import           Data.List                      ( elem )  -- MORPHEUS-import           Data.Morpheus.Error.Input               (InputError (..), InputValidation, Prop (..))-import           Data.Morpheus.Rendering.RenderGQL       (renderWrapped)-import           Data.Morpheus.Types.Internal.Data       (DataField (..), DataTyCon (..), DataType (..),-                                                          DataTypeLib (..), DataValidator (..), Key, TypeAlias (..),-                                                          WrapperD (..), isNullable)-import           Data.Morpheus.Types.Internal.Value      (Value (..))-import           Data.Morpheus.Validation.Internal.Utils (getInputType, lookupField)+import           Data.Morpheus.Error.Input      ( InputError(..)+                                                , InputValidation+                                                , Prop(..)+                                                )+import           Data.Morpheus.Rendering.RenderGQL+                                                ( renderWrapped )+import           Data.Morpheus.Types.Internal.AST+                                                ( DataField(..)+                                                , DataTyCon(..)+                                                , DataType(..)+                                                , DataTypeLib(..)+                                                , DataValidator(..)+                                                , Key+                                                , TypeAlias(..)+                                                , TypeWrapper(..)+                                                , DataEnumValue(..)+                                                , isNullable+                                                , lookupField+                                                , lookupInputType+                                                , Value(..)+                                                ) +import           Data.Morpheus.Types.Internal.Resolving+                                                ( Failure(..) )+ -- Validate Variable Argument or all Possible input Values-validateInputValue :: DataTypeLib -> [Prop] -> [WrapperD] -> DataType -> (Key, Value) -> InputValidation Value+validateInputValue+  :: DataTypeLib+  -> [Prop]+  -> [TypeWrapper]+  -> DataType+  -> (Key, Value)+  -> InputValidation Value validateInputValue lib prop' = validate-  where-    throwError :: [WrapperD] -> DataType -> Value -> InputValidation Value-    throwError wrappers datatype value = Left $ UnexpectedType prop' (renderWrapped datatype wrappers) value Nothing-    -- VALIDATION-    validate :: [WrapperD] -> DataType -> (Key, Value) -> InputValidation Value-    -- Validate Null. value = null ?-    validate wrappers tName (_, Null)-      | isNullable wrappers = return Null-      | otherwise = throwError wrappers tName Null-    -- Validate LIST-    validate (MaybeD:wrappers) type' value' = validateInputValue lib prop' wrappers type' value'-    validate (ListD:wrappers) type' (key', List list') = List <$> mapM validateElement list'-      where-        validateElement element' = validateInputValue lib prop' wrappers type' (key', element')-    {-- 2. VALIDATE TYPES, all wrappers are already Processed --}-    {-- VALIDATE OBJECT--}-    validate [] (DataInputObject DataTyCon {typeData = parentFields'}) (_, Object fields) =-      Object <$> mapM validateField fields-      where-        validateField (_name, value) = do-          (type', currentProp') <- validationData value-          wrappers' <- aliasWrappers . fieldType <$> getField-          value'' <- validateInputValue lib currentProp' wrappers' type' (_name, value)-          return (_name, value'')-          where-            validationData x = do-              fieldTypeName' <- aliasTyCon . fieldType <$> getField-              let currentProp = prop' ++ [Prop _name fieldTypeName']-              type' <- getInputType fieldTypeName' lib (typeMismatch x fieldTypeName' currentProp)-              return (type', currentProp)-            getField = lookupField _name parentFields' (UnknownField prop' _name)-    -- VALIDATE INPUT UNION-    -- TODO: Validate Union-    validate [] (DataInputUnion DataTyCon {typeData}) (_, Object fields) = return (Object fields)-    {-- VALIDATE SCALAR --}-    validate [] (DataEnum DataTyCon {typeData = tags', typeName = name'}) (_, value') =-      validateEnum (UnexpectedType prop' name' value' Nothing) tags' value'-    {-- VALIDATE ENUM --}-    validate [] (DataScalar DataTyCon {typeName = name', typeData = DataValidator {validateValue = validator'}}) (_, value') =-      case validator' value' of-        Right _           -> return value'-        Left ""           -> Left $ UnexpectedType prop' name' value' Nothing-        Left errorMessage -> Left $ UnexpectedType prop' name' value' (Just errorMessage)-    {-- 3. THROW ERROR: on invalid values --}-    validate wrappers datatype (_, value) = throwError wrappers datatype value+ where+  throwError :: [TypeWrapper] -> DataType -> Value -> InputValidation Value+  throwError wrappers datatype value =+    Left $ UnexpectedType prop' (renderWrapped datatype wrappers) value Nothing+  -- VALIDATION+  validate :: [TypeWrapper] -> DataType -> (Key, Value) -> InputValidation Value+  -- Validate Null. value = null ?+  validate wrappers tName (_, Null) | isNullable wrappers = return Null+                                    | otherwise = throwError wrappers tName Null+  -- Validate LIST+  validate (TypeMaybe : wrappers) type' value' =+    validateInputValue lib prop' wrappers type' value'+  validate (TypeList : wrappers) type' (key', List list') =+    List <$> mapM validateElement list'+   where+    validateElement element' =+      validateInputValue lib prop' wrappers type' (key', element')+  {-- 2. VALIDATE TYPES, all wrappers are already Processed --}+  {-- VALIDATE OBJECT--}+  validate [] (DataInputObject DataTyCon { typeData = parentFields' }) (_, Object fields)+    = Object <$> mapM validateField fields+   where+    validateField (_name, value) = do+      (type', currentProp') <- validationData value+      wrappers'             <- aliasWrappers . fieldType <$> getField+      value''               <- validateInputValue lib+                                                  currentProp'+                                                  wrappers'+                                                  type'+                                                  (_name, value)+      return (_name, value'')+     where+      validationData x = do+        fieldTypeName' <- aliasTyCon . fieldType <$> getField+        let currentProp = prop' ++ [Prop _name fieldTypeName']+        type' <- lookupInputType fieldTypeName'+                                 lib+                                 (typeMismatch x fieldTypeName' currentProp)+        return (type', currentProp)+      getField = lookupField _name parentFields' (UnknownField prop' _name)+  -- VALIDATE INPUT UNION+  -- TODO: Validate Union+  validate [] (DataInputUnion DataTyCon { typeData }) (_, Object fields) =+    return (Object fields)+  {-- VALIDATE SCALAR --}+  validate [] (DataEnum DataTyCon { typeData = tags, typeName = name' }) (_, value')+    = validateEnum (UnexpectedType prop' name' value' Nothing) tags value'+  {-- VALIDATE ENUM --}+  validate [] (DataScalar DataTyCon { typeName = name', typeData = DataValidator { validateValue = validator' } }) (_, value')+    = case validator' value' of+      Right _  -> return value'+      Left  "" -> failure (UnexpectedType prop' name' value' Nothing)+      Left errorMessage ->+        Left $ UnexpectedType prop' name' value' (Just errorMessage)+  {-- 3. THROW ERROR: on invalid values --}+  validate wrappers datatype (_, value) = throwError wrappers datatype value -validateEnum :: error -> [Key] -> Value -> Either error Value-validateEnum error' tags' (Enum enumValue) =-  if enumValue `elem` tags'-    then pure (Enum enumValue)-    else Left error'-validateEnum error' _ _ = Left error'+validateEnum :: error -> [DataEnumValue] -> Value -> Either error Value+validateEnum gqlError enumValues (Enum enumValue)+  | enumValue `elem` tags = pure (Enum enumValue)+  | otherwise             = Left gqlError+  where tags = map enumName enumValues+validateEnum gqlError _ _ = Left gqlError  typeMismatch :: Value -> Key -> [Prop] -> InputError-typeMismatch jsType expected' path' = UnexpectedType path' expected' jsType Nothing+typeMismatch jsType expected' path' =+  UnexpectedType path' expected' jsType Nothing
src/Data/Morpheus/Validation/Query/Arguments.hs view
@@ -3,87 +3,144 @@  module Data.Morpheus.Validation.Query.Arguments   ( validateArguments-  ) where+  )+where -import           Data.Morpheus.Error.Arguments                 (argumentGotInvalidValue, argumentNameCollision,-                                                                undefinedArgument, unknownArguments)-import           Data.Morpheus.Error.Input                     (InputValidation, inputErrorMessage)-import           Data.Morpheus.Error.Internal                  (internalUnknownTypeMessage)-import           Data.Morpheus.Error.Variable                  (incompatibleVariableType, undefinedVariable)-import           Data.Morpheus.Rendering.RenderGQL             (RenderGQL (..))-import           Data.Morpheus.Types.Internal.AST.Operation    (ValidVariables, Variable (..))-import           Data.Morpheus.Types.Internal.AST.RawSelection (RawArgument (..), RawArguments, Reference (..))-import           Data.Morpheus.Types.Internal.AST.Selection    (Argument (..), ArgumentOrigin (..), Arguments)-import           Data.Morpheus.Types.Internal.Base             (EnhancedKey (..), Position)-import           Data.Morpheus.Types.Internal.Data             (DataArgument, DataField (..), DataField, DataTypeLib,-                                                                TypeAlias (..), isFieldNullable, isWeaker)-import           Data.Morpheus.Types.Internal.Validation       (Validation)-import           Data.Morpheus.Types.Internal.Value            (Value (Null))-import           Data.Morpheus.Validation.Internal.Utils       (checkForUnknownKeys, checkNameCollision, getInputType)-import           Data.Morpheus.Validation.Internal.Value       (validateInputValue)-import           Data.Text                                     (Text)+import           Data.Morpheus.Error.Arguments  ( argumentGotInvalidValue+                                                , argumentNameCollision+                                                , undefinedArgument+                                                , unknownArguments+                                                )+import           Data.Morpheus.Error.Input      ( InputValidation+                                                , inputErrorMessage+                                                )+import           Data.Morpheus.Error.Internal   ( internalUnknownTypeMessage )+import           Data.Morpheus.Error.Variable   ( incompatibleVariableType+                                                , undefinedVariable+                                                )+import           Data.Morpheus.Rendering.RenderGQL+                                                ( RenderGQL(..) )+import           Data.Morpheus.Types.Internal.AST+                                                ( ValidVariables+                                                , Variable(..)+                                                , Argument(..)+                                                , ValueOrigin(..)+                                                , Arguments+                                                , RawArgument(..)+                                                , RawArguments+                                                , Ref(..)+                                                , Position+                                                , DataArgument+                                                , DataField(..)+                                                , DataTypeLib+                                                , TypeAlias(..)+                                                , isFieldNullable+                                                , isWeaker+                                                , lookupInputType+                                                , Value(Null)+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Validation+                                                , Failure(..)+                                                )+import           Data.Morpheus.Validation.Internal.Utils+                                                ( checkForUnknownKeys+                                                , checkNameCollision+                                                )+import           Data.Morpheus.Validation.Internal.Value+                                                ( validateInputValue )+import           Data.Text                      ( Text ) -resolveArgumentVariables :: Text -> ValidVariables -> DataField -> RawArguments -> Validation Arguments-resolveArgumentVariables operatorName variables DataField {fieldName, fieldArgs} = mapM resolveVariable-  where-    resolveVariable :: (Text, RawArgument) -> Validation (Text, Argument)-    resolveVariable (key, RawArgument argument) = pure (key, argument)-    resolveVariable (key, VariableReference Reference {referenceName, referencePosition}) =-      (key, ) . toArgument <$> lookupVar-      where-        toArgument argumentValue =-          Argument {argumentValue, argumentOrigin = VARIABLE, argumentPosition = referencePosition}-        lookupVar =-          case lookup referenceName variables of-            Nothing -> Left $ undefinedVariable operatorName referencePosition referenceName-            Just Variable {variableValue, variableType, variableTypeWrappers} ->-              case lookup key fieldArgs of-                Nothing -> Left $ unknownArguments fieldName [EnhancedKey key referencePosition]-                Just DataField {fieldType = fieldT@TypeAlias {aliasTyCon, aliasWrappers}} ->-                  if variableType == aliasTyCon && not (isWeaker variableTypeWrappers aliasWrappers)-                    then return variableValue-                    else Left $ incompatibleVariableType referenceName varSignature fieldSignature referencePosition-                  where varSignature = renderWrapped variableType variableTypeWrappers-                        fieldSignature = render fieldT+resolveArgumentVariables+  :: Text -> ValidVariables -> DataField -> RawArguments -> Validation Arguments+resolveArgumentVariables operatorName variables DataField { fieldName, fieldArgs }+  = mapM resolveVariable+ where+  resolveVariable :: (Text, RawArgument) -> Validation (Text, Argument)+  resolveVariable (key, RawArgument argument) = pure (key, argument)+  resolveVariable (key, VariableRef Ref { refName, refPosition }) =+    (key, ) . toArgument <$> lookupVar+   where+    toArgument argumentValue = Argument { argumentValue+                                        , argumentOrigin   = VARIABLE+                                        , argumentPosition = refPosition+                                        }+    lookupVar = case lookup refName variables of+      Nothing -> failure $ undefinedVariable operatorName refPosition refName+      Just Variable { variableValue, variableType, variableTypeWrappers } ->+        case lookup key fieldArgs of+          Nothing -> failure $ unknownArguments fieldName [Ref key refPosition]+          Just DataField { fieldType = fieldT@TypeAlias { aliasTyCon, aliasWrappers } }+            -> if variableType == aliasTyCon && not+                 (isWeaker variableTypeWrappers aliasWrappers)+              then return variableValue+              else failure $ incompatibleVariableType refName+                                                      varSignature+                                                      fieldSignature+                                                      refPosition+           where+            varSignature   = renderWrapped variableType variableTypeWrappers+            fieldSignature = render fieldT -validateArgument :: DataTypeLib -> Position -> Arguments -> (Text, DataArgument) -> Validation (Text, Argument)-validateArgument lib fieldPosition requestArgs (key, argType@DataField {fieldType = TypeAlias { aliasTyCon-                                                                                              , aliasWrappers-                                                                                              }}) =-  case lookup key requestArgs of-    Nothing                                            -> handleNullable-    Just argument@Argument {argumentOrigin = VARIABLE} -> pure (key, argument) -- Variables are already checked in Variable Validation-    Just Argument {argumentValue = Null}               -> handleNullable-    Just argument                                      -> validateArgumentValue argument-  where-    handleNullable-      | isFieldNullable argType =-        pure (key, Argument {argumentValue = Null, argumentOrigin = INLINE, argumentPosition = fieldPosition})-      | otherwise = Left $ undefinedArgument (EnhancedKey key fieldPosition)-    --------------------------------------------------------------------------    validateArgumentValue :: Argument -> Validation (Text, Argument)-    validateArgumentValue arg@Argument {argumentValue, argumentPosition} =-      getInputType aliasTyCon lib (internalUnknownTypeMessage aliasTyCon) >>= checkType >> pure (key, arg)-      where-        checkType type' = handleInputError (validateInputValue lib [] aliasWrappers type' (key, argumentValue))-        ----------        handleInputError :: InputValidation a -> Validation ()-        handleInputError (Left err) = Left $ argumentGotInvalidValue key (inputErrorMessage err) argumentPosition-        handleInputError _          = pure ()+validateArgument+  :: DataTypeLib+  -> Position+  -> Arguments+  -> (Text, DataArgument)+  -> Validation (Text, Argument)+validateArgument lib fieldPosition requestArgs (key, argType@DataField { fieldType = TypeAlias { aliasTyCon, aliasWrappers } })+  = case lookup key requestArgs of+    Nothing -> handleNullable+    Just argument@Argument { argumentOrigin = VARIABLE } ->+      pure (key, argument) -- Variables are already checked in Variable Validation+    Just Argument { argumentValue = Null } -> handleNullable+    Just argument                          -> validateArgumentValue argument+ where+  handleNullable+    | isFieldNullable argType = pure+      ( key+      , Argument { argumentValue    = Null+                 , argumentOrigin   = INLINE+                 , argumentPosition = fieldPosition+                 }+      )+    | otherwise = failure $ undefinedArgument (Ref key fieldPosition)+  -------------------------------------------------------------------------+  validateArgumentValue :: Argument -> Validation (Text, Argument)+  validateArgumentValue arg@Argument { argumentValue, argumentPosition } =+    lookupInputType aliasTyCon lib (internalUnknownTypeMessage aliasTyCon)+      >>= checkType+      >>  pure (key, arg)+   where+    checkType type' = handleInputError+      (validateInputValue lib [] aliasWrappers type' (key, argumentValue))+    ---------+    handleInputError :: InputValidation a -> Validation ()+    handleInputError (Left err) = failure+      $ argumentGotInvalidValue key (inputErrorMessage err) argumentPosition+    handleInputError _ = pure () -validateArguments ::-     DataTypeLib -> Text -> ValidVariables -> (Text, DataField) -> Position -> RawArguments -> Validation Arguments-validateArguments typeLib operatorName variables (key, field@DataField {fieldArgs}) pos rawArgs = do-  args <- resolveArgumentVariables operatorName variables field rawArgs-  dataArgs <- checkForUnknownArguments args-  mapM (validateArgument typeLib pos args) dataArgs-  where-    checkForUnknownArguments :: Arguments -> Validation [(Text, DataField)]-    checkForUnknownArguments args =-      checkForUnknownKeys enhancedKeys fieldKeys argError >> checkNameCollision enhancedKeys argumentNameCollision >>-      pure fieldArgs-      where-        argError = unknownArguments key-        enhancedKeys = map argToKey args-        argToKey (key', Argument {argumentPosition}) = EnhancedKey key' argumentPosition-        fieldKeys = map fst fieldArgs+validateArguments+  :: DataTypeLib+  -> Text+  -> ValidVariables+  -> (Text, DataField)+  -> Position+  -> RawArguments+  -> Validation Arguments+validateArguments typeLib operatorName variables (key, field@DataField { fieldArgs }) pos rawArgs+  = do+    args     <- resolveArgumentVariables operatorName variables field rawArgs+    dataArgs <- checkForUnknownArguments args+    mapM (validateArgument typeLib pos args) dataArgs+ where+  checkForUnknownArguments :: Arguments -> Validation [(Text, DataField)]+  checkForUnknownArguments args =+    checkForUnknownKeys enhancedKeys fieldKeys argError+      >> checkNameCollision enhancedKeys argumentNameCollision+      >> pure fieldArgs+   where+    argError     = unknownArguments key+    enhancedKeys = map argToKey args+    argToKey (key', Argument { argumentPosition }) = Ref key' argumentPosition+    fieldKeys = map fst fieldArgs
src/Data/Morpheus/Validation/Query/Fragment.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE NamedFieldPuns #-}  module Data.Morpheus.Validation.Query.Fragment@@ -5,97 +6,121 @@   , castFragmentType   , resolveSpread   , getFragment-  ) where+  )+where -import           Data.List                                     ((\\))-import           Data.Semigroup                                ((<>))-import           Data.Text                                     (Text)-import qualified Data.Text                                     as T (concat)+import           Data.List                      ( (\\) )+import           Data.Semigroup                 ( (<>) )+import           Data.Text                      ( Text )+import qualified Data.Text                     as T+                                                ( concat )  -- MORPHEUS-import           Data.Morpheus.Error.Fragment                  (cannotBeSpreadOnType, cannotSpreadWithinItself,-                                                                fragmentNameCollision, unknownFragment, unusedFragment)-import           Data.Morpheus.Types.Internal.AST.RawSelection (Fragment (..), FragmentLib, RawSelection (..),-                                                                Reference (..), Selection (..))-import           Data.Morpheus.Types.Internal.Base             (EnhancedKey (..), Position)-import           Data.Morpheus.Types.Internal.Data             (DataTypeLib)-import           Data.Morpheus.Types.Internal.Validation       (Validation)-import           Data.Morpheus.Validation.Internal.Utils       (checkNameCollision, existsObjectType)+import           Data.Morpheus.Error.Fragment   ( cannotBeSpreadOnType+                                                , cannotSpreadWithinItself+                                                , fragmentNameCollision+                                                , unknownFragment+                                                , unusedFragment+                                                )+import           Data.Morpheus.Error.Variable   ( unknownType )+import           Data.Morpheus.Types.Internal.AST+                                                ( Fragment(..)+                                                , FragmentLib+                                                , RawSelection(..)+                                                , Selection(..)+                                                , Ref(..)+                                                , Position+                                                , DataTypeLib+                                                , lookupDataObject+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Validation+                                                , Failure(..)+                                                )+import           Data.Morpheus.Validation.Internal.Utils+                                                ( checkNameCollision )  -validateFragments :: DataTypeLib -> FragmentLib -> [(Text, RawSelection)] -> Validation ()-validateFragments lib fragments operatorSel = validateNameCollision >> checkLoop >> checkUnusedFragments-  where-    validateNameCollision = checkNameCollision fragmentsKeys fragmentNameCollision-    checkUnusedFragments =-      case fragmentsKeys \\ usedFragments fragments operatorSel of-        []     -> return ()-        unused -> Left $ unusedFragment unused-    checkLoop = mapM (validateFragment lib) fragments >>= detectLoopOnFragments-    fragmentsKeys = map toEnhancedKey fragments-      where-        toEnhancedKey (key, Fragment {fragmentPosition}) = EnhancedKey key fragmentPosition+validateFragments+  :: DataTypeLib -> FragmentLib -> [(Text, RawSelection)] -> Validation ()+validateFragments lib fragments operatorSel =+  validateNameCollision >> checkLoop >> checkUnusedFragments+ where+  validateNameCollision =+    checkNameCollision fragmentsKeys fragmentNameCollision+  checkUnusedFragments =+    case fragmentsKeys \\ usedFragments fragments operatorSel of+      []     -> return ()+      unused -> failure (unusedFragment unused)+  checkLoop = mapM (validateFragment lib) fragments >>= detectLoopOnFragments+  fragmentsKeys = map toRef fragments+    where toRef (key, Fragment { fragmentPosition }) = Ref key fragmentPosition -type Node = EnhancedKey+type Node = Ref  type NodeEdges = (Node, [Node])  type Graph = [NodeEdges] -getFragment :: Reference -> FragmentLib -> Validation Fragment-getFragment Reference {referenceName, referencePosition} lib =-  case lookup referenceName lib of-    Nothing       -> Left $ unknownFragment referenceName referencePosition-    Just fragment -> pure fragment+getFragment :: Ref -> FragmentLib -> Validation Fragment+getFragment Ref { refName, refPosition } lib = case lookup refName lib of+  Nothing       -> failure $ unknownFragment refName refPosition+  Just fragment -> pure fragment -castFragmentType :: Maybe Text -> Position -> [Text] -> Fragment -> Validation Fragment-castFragmentType key' position' targets' fragment@Fragment {fragmentType} =+castFragmentType+  :: Maybe Text -> Position -> [Text] -> Fragment -> Validation Fragment+castFragmentType key' position' targets' fragment@Fragment { fragmentType } =   if fragmentType `elem` targets'     then pure fragment-    else Left $ cannotBeSpreadOnType key' fragmentType position' (T.concat targets')+    else failure+      $ cannotBeSpreadOnType key' fragmentType position' (T.concat targets') -resolveSpread :: FragmentLib -> [Text] -> Reference -> Validation Fragment-resolveSpread fragments allowedTargets reference@Reference {referenceName, referencePosition} =-  getFragment reference fragments >>= castFragmentType (Just referenceName) referencePosition allowedTargets+resolveSpread :: FragmentLib -> [Text] -> Ref -> Validation Fragment+resolveSpread fragments allowedTargets reference@Ref { refName, refPosition } =+  getFragment reference fragments+    >>= castFragmentType (Just refName) refPosition allowedTargets  usedFragments :: FragmentLib -> [(Text, RawSelection)] -> [Node] usedFragments fragments = concatMap findAllUses-  where-    findAllUses :: (Text, RawSelection) -> [Node]-    findAllUses (_, RawSelectionSet Selection {selectionRec}) = concatMap findAllUses selectionRec-    findAllUses (_, InlineFragment Fragment {fragmentSelection}) = concatMap findAllUses fragmentSelection-    findAllUses (_, RawSelectionField {}) = []-    findAllUses (_, Spread Reference {referenceName, referencePosition}) =-      [EnhancedKey referenceName referencePosition] <> searchInFragment-      where-        searchInFragment = maybe [] (concatMap findAllUses . fragmentSelection) (lookup referenceName fragments)+ where+  findAllUses :: (Text, RawSelection) -> [Node]+  findAllUses (_, RawSelectionSet Selection { selectionRec }) =+    concatMap findAllUses selectionRec+  findAllUses (_, InlineFragment Fragment { fragmentSelection }) =+    concatMap findAllUses fragmentSelection+  findAllUses (_, RawSelectionField{}) = []+  findAllUses (_, Spread Ref { refName, refPosition }) =+    [Ref refName refPosition] <> searchInFragment+   where+    searchInFragment = maybe []+                             (concatMap findAllUses . fragmentSelection)+                             (lookup refName fragments)  scanForSpread :: (Text, RawSelection) -> [Node]-scanForSpread (_, RawSelectionSet Selection {selectionRec }) = concatMap scanForSpread selectionRec-scanForSpread (_, InlineFragment Fragment {fragmentSelection = selection'}) = concatMap scanForSpread selection'-scanForSpread (_, RawSelectionField {}) = []-scanForSpread (_, Spread Reference {referenceName = name', referencePosition = position'}) =-  [EnhancedKey name' position']+scanForSpread (_, RawSelectionSet Selection { selectionRec }) =+  concatMap scanForSpread selectionRec+scanForSpread (_, InlineFragment Fragment { fragmentSelection = selection' }) =+  concatMap scanForSpread selection'+scanForSpread (_, RawSelectionField{}) = []+scanForSpread (_, Spread Ref { refName = name', refPosition = position' }) =+  [Ref name' position']  validateFragment :: DataTypeLib -> (Text, Fragment) -> Validation NodeEdges-validateFragment lib (fName, Fragment {fragmentSelection, fragmentType, fragmentPosition}) =-  existsObjectType fragmentPosition fragmentType lib >>-  pure (EnhancedKey fName fragmentPosition, concatMap scanForSpread fragmentSelection)+validateFragment lib (fName, Fragment { fragmentSelection, fragmentType, fragmentPosition })+  = lookupDataObject validationError fragmentType lib >> pure+    (Ref fName fragmentPosition, concatMap scanForSpread fragmentSelection)+  where validationError = unknownType fragmentType fragmentPosition  detectLoopOnFragments :: Graph -> Validation () detectLoopOnFragments lib = mapM_ checkFragment lib-  where-    checkFragment (fragmentID, _) = checkForCycle lib fragmentID [fragmentID]+ where+  checkFragment (fragmentID, _) = checkForCycle lib fragmentID [fragmentID]  checkForCycle :: Graph -> Node -> [Node] -> Validation Graph-checkForCycle lib parentNode history =-  case lookup parentNode lib of-    Just node -> concat <$> mapM checkNode node-    Nothing   -> pure []-  where-    checkNode x =-      if x `elem` history-        then cycleError x-        else recurse x-    recurse node = checkForCycle lib node $ history ++ [node]-    cycleError n = Left $ cannotSpreadWithinItself $ history ++ [n]+checkForCycle lib parentNode history = case lookup parentNode lib of+  Just node -> concat <$> mapM checkNode node+  Nothing   -> pure []+ where+  checkNode x = if x `elem` history then cycleError x else recurse x+  recurse node = checkForCycle lib node $ history ++ [node]+  cycleError n = failure $ cannotSpreadWithinItself (n : history)
src/Data/Morpheus/Validation/Query/Selection.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances   #-} {-# LANGUAGE NamedFieldPuns      #-} {-# LANGUAGE OverloadedStrings   #-}@@ -6,69 +7,101 @@  module Data.Morpheus.Validation.Query.Selection   ( validateSelectionSet-  ) where+  )+where  -import           Data.Maybe                                     (fromMaybe)-import           Data.Text                                      (Text)+import           Data.Maybe                     ( fromMaybe )+import           Data.Text                      ( Text )  -- MORPHEUS-import           Data.Morpheus.Error.Selection                  (cannotQueryField, duplicateQuerySelections,-                                                                 hasNoSubfields, subfieldsNotSelected)-import           Data.Morpheus.Error.Variable                   (unknownType)-import           Data.Morpheus.Types.Internal.AST.Operation     (ValidVariables)-import           Data.Morpheus.Types.Internal.AST.RawSelection  (Fragment (..), FragmentLib, RawSelection (..),-                                                                 RawSelectionSet)-import           Data.Morpheus.Types.Internal.AST.Selection     (Selection (..), SelectionRec (..), SelectionSet)-import           Data.Morpheus.Types.Internal.Base              (EnhancedKey (..))-import           Data.Morpheus.Types.Internal.Data              (DataField (..), DataType (..), DataObject,-                                                                 DataTyCon (..), DataTypeLib (..), TypeAlias (..),-                                                                 allDataTypes, isEntNode)-import           Data.Morpheus.Types.Internal.Validation        (Validation)-import           Data.Morpheus.Validation.Internal.Utils        (checkNameCollision, lookupType)-import           Data.Morpheus.Validation.Query.Arguments       (validateArguments)-import           Data.Morpheus.Validation.Query.Fragment        (castFragmentType, resolveSpread)-import           Data.Morpheus.Validation.Query.Utils.Selection (lookupFieldAsSelectionSet, lookupSelectionField,-                                                                 lookupUnionTypes)+import           Data.Morpheus.Error.Selection  ( cannotQueryField+                                                , duplicateQuerySelections+                                                , hasNoSubfields+                                                , subfieldsNotSelected+                                                )+import           Data.Morpheus.Error.Variable   ( unknownType )+import           Data.Morpheus.Types.Internal.AST+                                                ( ValidVariables +                                                , Selection(..)+                                                , SelectionRec(..)+                                                , SelectionSet+                                                , Fragment(..)+                                                , FragmentLib+                                                , RawSelection(..)+                                                , RawSelectionSet+                                                , DataField(..)+                                                , Ref(..)+                                                , DataObject+                                                , DataTyCon(..)+                                                , DataType(..)+                                                , DataTypeLib(..)+                                                , TypeAlias(..)+                                                , allDataTypes+                                                , isEntNode+                                                , lookupFieldAsSelectionSet+                                                , lookupSelectionField+                                                , lookupType+                                                , lookupUnionTypes+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Validation+                                                , Failure(..)+                                                )+import           Data.Morpheus.Validation.Internal.Utils+                                                ( checkNameCollision )+import           Data.Morpheus.Validation.Query.Arguments+                                                ( validateArguments )+import           Data.Morpheus.Validation.Query.Fragment+                                                ( castFragmentType+                                                , resolveSpread+                                                )  checkDuplicatesOn :: DataObject -> SelectionSet -> Validation SelectionSet-checkDuplicatesOn DataTyCon {typeName = name'} keys = checkNameCollision enhancedKeys selError >> pure keys-  where-    selError = duplicateQuerySelections name'-    enhancedKeys = map selToKey keys-    selToKey (key, Selection {selectionPosition = position' , selectionAlias }) = EnhancedKey (fromMaybe key selectionAlias) position'+checkDuplicatesOn DataTyCon { typeName = name' } keys =+  checkNameCollision enhancedKeys selError >> pure keys+ where+  selError     = duplicateQuerySelections name'+  enhancedKeys = map selToKey keys+  selToKey (key, Selection { selectionPosition = position', selectionAlias }) =+    Ref (fromMaybe key selectionAlias) position' -clusterUnionSelection ::-     FragmentLib -> Text -> [DataObject] -> (Text, RawSelection) -> Validation ([Fragment], SelectionSet)+clusterUnionSelection+  :: FragmentLib+  -> Text+  -> [DataObject]+  -> (Text, RawSelection)+  -> Validation ([Fragment], SelectionSet) clusterUnionSelection fragments type' possibleTypes' = splitFrag-  where-    packFragment fragment = return ([fragment], [])-    typeNames = map typeName possibleTypes'-    splitFrag :: (Text, RawSelection) -> Validation ([Fragment], SelectionSet)-    splitFrag (_, Spread ref) = resolveSpread fragments typeNames ref >>= packFragment-    splitFrag ("__typename", RawSelectionField selection ) = pure ([] ,[-      ( "__typename",-      selection {-        selectionArguments = [] ,-        selectionRec = SelectionField}+ where+  packFragment fragment = return ([fragment], [])+  typeNames = map typeName possibleTypes'+  splitFrag :: (Text, RawSelection) -> Validation ([Fragment], SelectionSet)+  splitFrag (_, Spread ref) =+    resolveSpread fragments typeNames ref >>= packFragment+  splitFrag ("__typename", RawSelectionField selection) = pure+    ( []+    , [ ( "__typename"+        , selection { selectionArguments = [], selectionRec = SelectionField }         )-      ])-    splitFrag (key, RawSelectionSet Selection {selectionPosition}) =-      Left $ cannotQueryField key type' selectionPosition-    splitFrag (key, RawSelectionField Selection {selectionPosition}) =-      Left $ cannotQueryField key type' selectionPosition-  --  splitFrag (key', RawAlias {rawAliasPosition = position'}) = Left $ cannotQueryField key' type' position'-    splitFrag (_, InlineFragment fragment') =-      castFragmentType Nothing (fragmentPosition fragment') typeNames fragment' >>= packFragment+      ]+    )+  splitFrag (key, RawSelectionSet Selection { selectionPosition }) =+    failure $ cannotQueryField key type' selectionPosition+  splitFrag (key, RawSelectionField Selection { selectionPosition }) =+    failure $ cannotQueryField key type' selectionPosition+--  splitFrag (key', RawAlias {rawAliasPosition = position'}) = failure $ cannotQueryField key' type' position'+  splitFrag (_, InlineFragment fragment') =+    castFragmentType Nothing (fragmentPosition fragment') typeNames fragment'+      >>= packFragment  categorizeTypes :: [DataObject] -> [Fragment] -> [(DataObject, [Fragment])] categorizeTypes types fragments = filter notEmpty $ map categorizeType types-  where-    notEmpty = (0 /=) . length . snd-    categorizeType :: DataObject -> (DataObject, [Fragment])-    categorizeType datatype = (datatype, filter matches fragments)-      where-        matches fragment = fragmentType fragment == typeName datatype+ where+  notEmpty = (0 /=) . length . snd+  categorizeType :: DataObject -> (DataObject, [Fragment])+  categorizeType datatype = (datatype, filter matches fragments)+    where matches fragment = fragmentType fragment == typeName datatype  flatTuple :: [([a], [b])] -> ([a], [b]) flatTuple list' = (concatMap fst list', concatMap snd list')@@ -84,77 +117,112 @@       ]  -} -validateSelectionSet ::-     DataTypeLib -> FragmentLib -> Text -> ValidVariables -> DataObject -> RawSelectionSet -> Validation SelectionSet+validateSelectionSet+  :: DataTypeLib+  -> FragmentLib+  -> Text+  -> ValidVariables+  -> DataObject+  -> RawSelectionSet+  -> Validation SelectionSet validateSelectionSet lib fragments' operatorName variables = __validate-  where-    __validate dataType'@DataTyCon {typeName = typeName'} selectionSet' =-      concat <$> mapM validateSelection selectionSet' >>= checkDuplicatesOn dataType'-      where-        validateFragment Fragment {fragmentSelection = selection'} = __validate dataType' selection'-        {-+ where+  __validate dataType'@DataTyCon { typeName = typeName' } selectionSet' =+    concat+      <$> mapM validateSelection selectionSet'+      >>= checkDuplicatesOn dataType'+   where+    validateFragment Fragment { fragmentSelection = selection' } =+      __validate dataType' selection'+    {-             get dataField and validated arguments for RawSelection         -}-        getValidationData key Selection {selectionArguments, selectionPosition} = do-          selectionField <- lookupSelectionField selectionPosition key dataType'-          -- validate field Argument ------          arguments <--            validateArguments-              lib-              operatorName-              variables-              (key, selectionField)-              selectionPosition-              selectionArguments-          -- check field Type existence  ------          fieldDataType <--            lookupType-              (unknownType (aliasTyCon $fieldType selectionField) selectionPosition)-              (allDataTypes lib)-              (aliasTyCon $ fieldType selectionField)-          return (selectionField, fieldDataType, arguments)-        -- validate single selection: InlineFragments and Spreads will Be resolved and included in SelectionSet-        ---        validateSelection :: (Text, RawSelection) -> Validation SelectionSet-        validateSelection (key', RawSelectionSet fullRawSelection@Selection { selectionRec = rawSelection, selectionPosition }) = do-          (dataField, dataType, arguments) <- getValidationData key' fullRawSelection-          case dataType of-            DataUnion _ -> do-              (categories, __typename) <- clusterTypes-              mapM (validateCluster __typename) categories >>= returnSelection arguments . UnionSelection-              where clusterTypes = do-                      unionTypes <- lookupUnionTypes selectionPosition key' lib dataField-                      (spreads, __typename) <--                        flatTuple <$> mapM (clusterUnionSelection fragments' typeName' unionTypes) rawSelection-                      return (categorizeTypes unionTypes spreads, __typename)-                    ---                    --    second arguments will be added to every selection cluster-                    validateCluster :: SelectionSet -> (DataObject, [Fragment]) -> Validation (Text, SelectionSet)-                    validateCluster sysSelection' (type', frags') = do-                      selection' <- __validate type' (concatMap fragmentSelection frags')-                      return (typeName type', sysSelection' ++ selection')-            DataObject _ -> do-              fieldType' <- lookupFieldAsSelectionSet selectionPosition key' lib dataField-              __validate fieldType' rawSelection >>= returnSelection arguments . SelectionSet-            _ -> Left $ hasNoSubfields key' (aliasTyCon $fieldType dataField) selectionPosition-          where-            returnSelection selectionArguments selectionRec =-              pure-                [ ( key'-                  , fullRawSelection-                      { selectionArguments,-                        selectionRec-                      }-                  )-                ]-        validateSelection (key, RawSelectionField rawSelection@Selection{selectionPosition}) = do-          (dataField, datatype, selectionArguments) <- getValidationData key rawSelection-          isLeaf datatype dataField-          pure [( key , rawSelection { selectionArguments  , selectionRec = SelectionField })]-          where-            isLeaf dataType DataField {fieldType = TypeAlias {aliasTyCon}}-                | isEntNode dataType = Right ()-                | otherwise =  Left $ subfieldsNotSelected key aliasTyCon selectionPosition-        validateSelection (_, Spread reference') = resolveSpread fragments' [typeName'] reference' >>= validateFragment-        validateSelection (_, InlineFragment fragment') =-          castFragmentType Nothing (fragmentPosition fragment') [typeName'] fragment' >>= validateFragment+    getValidationData key Selection { selectionArguments, selectionPosition } =+      do+        selectionField <- lookupSelectionField selectionPosition key dataType'+        -- validate field Argument -----+        arguments      <- validateArguments lib+                                            operatorName+                                            variables+                                            (key, selectionField)+                                            selectionPosition+                                            selectionArguments+        -- check field Type existence  -----+        fieldDataType <- lookupType+          (unknownType (aliasTyCon $fieldType selectionField) selectionPosition)+          (allDataTypes lib)+          (aliasTyCon $ fieldType selectionField)+        return (selectionField, fieldDataType, arguments)+    -- validate single selection: InlineFragments and Spreads will Be resolved and included in SelectionSet+    --+    validateSelection :: (Text, RawSelection) -> Validation SelectionSet+    validateSelection (key', RawSelectionSet fullRawSelection@Selection { selectionRec = rawSelection, selectionPosition })+      = do+        (dataField, dataType, arguments) <- getValidationData key'+                                                              fullRawSelection+        case dataType of+          DataUnion _ -> do+            (categories, __typename) <- clusterTypes+            mapM (validateCluster __typename) categories+              >>= returnSelection arguments+              .   UnionSelection+           where+            clusterTypes = do+              unionTypes <- lookupUnionTypes selectionPosition+                                             key'+                                             lib+                                             dataField+              (spreads, __typename) <-+                flatTuple+                  <$> mapM+                        (clusterUnionSelection fragments' typeName' unionTypes)+                        rawSelection+              return (categorizeTypes unionTypes spreads, __typename)+            --+            --    second arguments will be added to every selection cluster+            validateCluster+              :: SelectionSet+              -> (DataObject, [Fragment])+              -> Validation (Text, SelectionSet)+            validateCluster sysSelection' (type', frags') = do+              selection' <- __validate type'+                                       (concatMap fragmentSelection frags')+              return (typeName type', sysSelection' ++ selection')+          DataObject _ -> do+            fieldType' <- lookupFieldAsSelectionSet selectionPosition+                                                    key'+                                                    lib+                                                    dataField+            __validate fieldType' rawSelection+              >>= returnSelection arguments+              .   SelectionSet+          _ -> failure $ hasNoSubfields key'+                                        (aliasTyCon $fieldType dataField)+                                        selectionPosition+     where+      returnSelection selectionArguments selectionRec =+        pure [(key', fullRawSelection { selectionArguments, selectionRec })]+    validateSelection (key, RawSelectionField rawSelection@Selection { selectionPosition })+      = do+        (dataField, datatype, selectionArguments) <- getValidationData+          key+          rawSelection+        isLeaf datatype dataField+        pure+          [ ( key+            , rawSelection { selectionArguments, selectionRec = SelectionField }+            )+          ]+     where+      isLeaf dataType DataField { fieldType = TypeAlias { aliasTyCon } }+        | isEntNode dataType = pure ()+        | otherwise = failure+        $ subfieldsNotSelected key aliasTyCon selectionPosition+    validateSelection (_, Spread reference') =+      resolveSpread fragments' [typeName'] reference' >>= validateFragment+    validateSelection (_, InlineFragment fragment') =+      castFragmentType Nothing+                       (fragmentPosition fragment')+                       [typeName']+                       fragment'+        >>= validateFragment
− src/Data/Morpheus/Validation/Query/Utils/Selection.hs
@@ -1,32 +0,0 @@-{-# LANGUAGE NamedFieldPuns #-}--module Data.Morpheus.Validation.Query.Utils.Selection-  ( lookupFieldAsSelectionSet-  , lookupSelectionField-  , lookupUnionTypes-  ) where--import           Data.Morpheus.Error.Selection           (cannotQueryField, hasNoSubfields)-import           Data.Morpheus.Types.Internal.Base       (Position)-import           Data.Morpheus.Types.Internal.Data       (DataField (..), DataObject, DataTyCon (..), DataTypeLib (..),-                                                          TypeAlias (..))-import           Data.Morpheus.Types.Internal.Validation (Validation)-import           Data.Morpheus.Validation.Internal.Utils (lookupField, lookupType)-import           Data.Text                               (Text)--lookupUnionTypes :: Position -> Text -> DataTypeLib -> DataField -> Validation [DataObject]-lookupUnionTypes position' key' lib DataField {fieldType = TypeAlias {aliasTyCon = type'}} =-  lookupType error' (union lib) type' >>= mapM (lookupType error' (object lib) . aliasTyCon . fieldType) . typeData-  where-    error' = hasNoSubfields key' type' position'--lookupFieldAsSelectionSet :: Position -> Text -> DataTypeLib -> DataField -> Validation DataObject-lookupFieldAsSelectionSet position key' lib DataField {fieldType = TypeAlias {aliasTyCon = type'}} =-  lookupType error' (object lib) type'-  where-    error' = hasNoSubfields key' type' position--lookupSelectionField :: Position -> Text -> DataObject -> Validation DataField-lookupSelectionField position' key' DataTyCon {typeData = fields', typeName = name'} = lookupField key' fields' error'-  where-    error' = cannotQueryField key' name' position'
src/Data/Morpheus/Validation/Query/Validation.hs view
@@ -5,44 +5,51 @@  module Data.Morpheus.Validation.Query.Validation   ( validateRequest-  ) where+  )+where -import           Data.Map                                   (fromList)-import           Data.Morpheus.Error.Mutation               (mutationIsNotDefined)-import           Data.Morpheus.Error.Subscription           (subscriptionIsNotDefined)-import           Data.Morpheus.Types.Internal.AST.Operation (Operation (..), RawOperation, ValidOperation,-                                                             getOperationName)-import           Data.Morpheus.Types.Internal.Data          (DataObject, DataTypeLib (..), OperationType (..))-import           Data.Morpheus.Types.Internal.Validation    (Validation)-import           Data.Morpheus.Types.Types                  (GQLQueryRoot (..))-import           Data.Morpheus.Validation.Internal.Utils    (VALIDATION_MODE)-import           Data.Morpheus.Validation.Query.Fragment    (validateFragments)-import           Data.Morpheus.Validation.Query.Selection   (validateSelectionSet)-import           Data.Morpheus.Validation.Query.Variable    (resolveOperationVariables)+import           Data.Map                       ( fromList )+import           Data.Morpheus.Types.Internal.AST+                                                ( Operation(..)+                                                , ValidOperation+                                                , getOperationName+                                                , getOperationDataType+                                                , DataTypeLib(..)+                                                , GQLQuery(..)+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Validation ) -getOperationDataType :: RawOperation -> DataTypeLib -> Validation DataObject-getOperationDataType Operation {operationType = Query} lib = pure $ snd $ query lib-getOperationDataType Operation {operationType = Mutation, operationPosition} lib =-  case mutation lib of-    Just (_, mutation') -> pure mutation'-    Nothing             -> Left $ mutationIsNotDefined operationPosition-getOperationDataType Operation {operationType = Subscription, operationPosition} lib =-  case subscription lib of-    Just (_, subscription') -> pure subscription'-    Nothing                 -> Left $ subscriptionIsNotDefined operationPosition+import           Data.Morpheus.Validation.Internal.Utils+                                                ( VALIDATION_MODE )+import           Data.Morpheus.Validation.Query.Fragment+                                                ( validateFragments )+import           Data.Morpheus.Validation.Query.Selection+                                                ( validateSelectionSet )+import           Data.Morpheus.Validation.Query.Variable+                                                ( resolveOperationVariables ) -validateRequest :: DataTypeLib -> VALIDATION_MODE -> GQLQueryRoot -> Validation ValidOperation-validateRequest lib validationMode GQLQueryRoot { fragments-                                                , inputVariables-                                                , operation = rawOperation@Operation { operationName-                                                                                     , operationType-                                                                                     , operationSelection-                                                                                     , operationPosition-                                                                                     }-                                                } = do-  operationDataType <- getOperationDataType rawOperation lib-  variables <- resolveOperationVariables lib fragments (fromList inputVariables) validationMode rawOperation-  validateFragments lib fragments operationSelection-  selection <--    validateSelectionSet lib fragments (getOperationName operationName) variables operationDataType operationSelection-  pure $ Operation {operationName, operationType, operationArgs = [], operationSelection = selection, operationPosition}++validateRequest+  :: DataTypeLib -> VALIDATION_MODE -> GQLQuery -> Validation ValidOperation+validateRequest lib validationMode GQLQuery { fragments, inputVariables, operation = rawOperation@Operation { operationName, operationType, operationSelection, operationPosition } }+  = do+    operationDataType <- getOperationDataType rawOperation lib+    variables         <- resolveOperationVariables lib+                                                   fragments+                                                   (fromList inputVariables)+                                                   validationMode+                                                   rawOperation+    validateFragments lib fragments operationSelection+    selection <- validateSelectionSet lib+                                      fragments+                                      (getOperationName operationName)+                                      variables+                                      operationDataType+                                      operationSelection+    pure $ Operation { operationName+                     , operationType+                     , operationArgs      = []+                     , operationSelection = selection+                     , operationPosition+                     }
src/Data/Morpheus/Validation/Query/Variable.hs view
@@ -1,100 +1,147 @@+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE NamedFieldPuns #-}  module Data.Morpheus.Validation.Query.Variable   ( resolveOperationVariables-  ) where+  )+where -import           Data.List                                     ((\\))-import qualified Data.Map                                      as M (lookup)-import           Data.Maybe                                    (maybe)-import           Data.Semigroup                                ((<>))-import           Data.Text                                     (Text)+import           Data.List                      ( (\\) )+import qualified Data.Map                      as M+                                                ( lookup )+import           Data.Maybe                     ( maybe )+import           Data.Semigroup                 ( (<>) )+import           Data.Text                      ( Text )  --- MORPHEUS-import           Data.Morpheus.Error.Input                     (inputErrorMessage)-import           Data.Morpheus.Error.Variable                  (uninitializedVariable, unknownType, unusedVariables,-                                                                variableGotInvalidValue)-import           Data.Morpheus.Types.Internal.AST.Operation    (DefaultValue, Operation (..), RawOperation,-                                                                ValidVariables, Variable (..), getOperationName)-import           Data.Morpheus.Types.Internal.AST.RawSelection (Fragment (..), FragmentLib, RawArgument (..),-                                                                RawSelection (..), RawSelectionSet, Reference (..),-                                                                Selection (..))-import           Data.Morpheus.Types.Internal.Base             (EnhancedKey (..), Position)-import           Data.Morpheus.Types.Internal.Data             (DataType, DataTypeLib)-import           Data.Morpheus.Types.Internal.Validation       (Validation)-import           Data.Morpheus.Types.Internal.Value            (Value (..))-import           Data.Morpheus.Types.Types                     (Variables)-import           Data.Morpheus.Validation.Internal.Utils       (VALIDATION_MODE (..), getInputType)-import           Data.Morpheus.Validation.Internal.Value       (validateInputValue)-import           Data.Morpheus.Validation.Query.Fragment       (getFragment)+import           Data.Morpheus.Error.Input      ( inputErrorMessage )+import           Data.Morpheus.Error.Variable   ( uninitializedVariable+                                                , unknownType+                                                , unusedVariables+                                                , variableGotInvalidValue+                                                )+import           Data.Morpheus.Types.Internal.AST+                                                ( DefaultValue+                                                , Operation(..)+                                                , RawOperation+                                                , ValidVariables+                                                , Variable(..)+                                                , getOperationName+                                                , Fragment(..)+                                                , FragmentLib+                                                , RawArgument(..)+                                                , RawSelection(..)+                                                , RawSelectionSet+                                                , Selection(..)+                                                , Ref(..)+                                                , Position+                                                , DataType+                                                , DataTypeLib+                                                , lookupInputType+                                                , Variables+                                                , Value(..)+                                                )+import           Data.Morpheus.Types.Internal.Resolving+                                                ( Validation+                                                , Failure(..)+                                                )+import           Data.Morpheus.Validation.Internal.Utils+                                                ( VALIDATION_MODE(..) )+import           Data.Morpheus.Validation.Internal.Value+                                                ( validateInputValue )+import           Data.Morpheus.Validation.Query.Fragment+                                                ( getFragment )  getVariableType :: Text -> Position -> DataTypeLib -> Validation DataType-getVariableType type' position' lib' = getInputType type' lib' error'-  where-    error' = unknownType type' position'+getVariableType type' position' lib' = lookupInputType type' lib' error'+  where error' = unknownType type' position'  concatMapM :: Monad m => (a -> m [b]) -> [a] -> m [b] concatMapM f = fmap concat . mapM f -allVariableReferences :: FragmentLib -> [RawSelectionSet] -> Validation [EnhancedKey]-allVariableReferences fragmentLib = concatMapM (concatMapM searchReferences)-  where-    referencesFromArgument :: (Text, RawArgument) -> [EnhancedKey]-    referencesFromArgument (_, RawArgument {}) = []-    referencesFromArgument (_, VariableReference Reference {referenceName, referencePosition}) =-      [EnhancedKey referenceName referencePosition]-    -- | search used variables in every arguments-    searchReferences :: (Text, RawSelection) -> Validation [EnhancedKey]-    searchReferences (_, RawSelectionSet Selection {selectionArguments, selectionRec}) =-      getArgs <$> concatMapM searchReferences selectionRec-      where-        getArgs :: [EnhancedKey] -> [EnhancedKey]-        getArgs x = concatMap referencesFromArgument selectionArguments <> x-    searchReferences (_, InlineFragment Fragment {fragmentSelection}) = concatMapM searchReferences fragmentSelection-    searchReferences (_, RawSelectionField Selection {selectionArguments}) =-      return $ concatMap referencesFromArgument selectionArguments-    searchReferences (_, Spread reference) =-      getFragment reference fragmentLib >>= concatMapM searchReferences . fragmentSelection+allVariableRefs :: FragmentLib -> [RawSelectionSet] -> Validation [Ref]+allVariableRefs fragmentLib = concatMapM (concatMapM searchRefs)+ where+  referencesFromArgument :: (Text, RawArgument) -> [Ref]+  referencesFromArgument (_, RawArgument{}) = []+  referencesFromArgument (_, VariableRef Ref { refName, refPosition }) =+    [Ref refName refPosition]+  -- | search used variables in every arguments+  searchRefs :: (Text, RawSelection) -> Validation [Ref]+  searchRefs (_, RawSelectionSet Selection { selectionArguments, selectionRec })+    = getArgs <$> concatMapM searchRefs selectionRec+   where+    getArgs :: [Ref] -> [Ref]+    getArgs x = concatMap referencesFromArgument selectionArguments <> x+  searchRefs (_, InlineFragment Fragment { fragmentSelection }) =+    concatMapM searchRefs fragmentSelection+  searchRefs (_, RawSelectionField Selection { selectionArguments }) =+    return $ concatMap referencesFromArgument selectionArguments+  searchRefs (_, Spread reference) =+    getFragment reference fragmentLib+      >>= concatMapM searchRefs+      .   fragmentSelection -resolveOperationVariables ::-     DataTypeLib -> FragmentLib -> Variables -> VALIDATION_MODE -> RawOperation -> Validation ValidVariables-resolveOperationVariables typeLib lib root validationMode Operation {operationName, operationSelection, operationArgs} = do-  allVariableReferences lib [operationSelection] >>= checkUnusedVariables-  mapM (lookupAndValidateValueOnBody typeLib root validationMode) operationArgs-  where-    varToKey :: (Text, Variable a) -> EnhancedKey-    varToKey (key', Variable {variablePosition}) = EnhancedKey key' variablePosition-    ---    checkUnusedVariables :: [EnhancedKey] -> Validation ()-    checkUnusedVariables refs =-      case map varToKey operationArgs \\ refs of-        []      -> pure ()-        unused' -> Left $ unusedVariables (getOperationName operationName) unused'+resolveOperationVariables+  :: DataTypeLib+  -> FragmentLib+  -> Variables+  -> VALIDATION_MODE+  -> RawOperation+  -> Validation ValidVariables+resolveOperationVariables typeLib lib root validationMode Operation { operationName, operationSelection, operationArgs }+  = do+    allVariableRefs lib [operationSelection] >>= checkUnusedVariables+    mapM (lookupAndValidateValueOnBody typeLib root validationMode)+         operationArgs+ where+  varToKey :: (Text, Variable a) -> Ref+  varToKey (key', Variable { variablePosition }) = Ref key' variablePosition+  --+  checkUnusedVariables :: [Ref] -> Validation ()+  checkUnusedVariables refs = case map varToKey operationArgs \\ refs of+    [] -> pure ()+    unused' ->+      failure $ unusedVariables (getOperationName operationName) unused' -lookupAndValidateValueOnBody ::-     DataTypeLib -> Variables -> VALIDATION_MODE -> (Text, Variable DefaultValue) -> Validation (Text, Variable Value)-lookupAndValidateValueOnBody typeLib bodyVariables validationMode (key, var@Variable { variableType-                                                                                     , variablePosition-                                                                                     , isVariableRequired-                                                                                     , variableTypeWrappers-                                                                                     , variableValue = defaultValue-                                                                                     }) =-  toVariable <$> (getVariableType variableType variablePosition typeLib >>= checkType getVariable defaultValue)-  where-    toVariable (varKey, variableValue) = (varKey, var {variableValue})-    getVariable = M.lookup key bodyVariables-    -------------------------------------------------------------------    checkType (Just variable) Nothing varType = validator varType variable-    checkType (Just variable) (Just defValue) varType = validator varType defValue >> validator varType variable-    checkType Nothing (Just defValue) varType = validator varType defValue-    checkType Nothing Nothing varType-      | validationMode /= WITHOUT_VARIABLES && isVariableRequired =-        Left $ uninitializedVariable variablePosition variableType key-      | otherwise = returnNull-      where-        returnNull = maybe (pure (key, Null)) (validator varType) (M.lookup key bodyVariables)-    ------------------------------------------------------------------------------------------------    validator varType varValue =-      case validateInputValue typeLib [] variableTypeWrappers varType (key, varValue) of-        Left message -> Left $ variableGotInvalidValue key (inputErrorMessage message) variablePosition-        Right value  -> pure (key, value)+lookupAndValidateValueOnBody+  :: DataTypeLib+  -> Variables+  -> VALIDATION_MODE+  -> (Text, Variable DefaultValue)+  -> Validation (Text, Variable Value)+lookupAndValidateValueOnBody typeLib bodyVariables validationMode (key, var@Variable { variableType, variablePosition, isVariableRequired, variableTypeWrappers, variableValue = defaultValue })+  = toVariable+    <$> (   getVariableType variableType variablePosition typeLib+        >>= checkType getVariable defaultValue+        )+ where+  toVariable (varKey, variableValue) = (varKey, var { variableValue })+  getVariable = M.lookup key bodyVariables+  ------------------------------------------------------------------+  checkType (Just variable) Nothing varType = validator varType variable+  checkType (Just variable) (Just defValue) varType =+    validator varType defValue >> validator varType variable+  checkType Nothing (Just defValue) varType = validator varType defValue+  checkType Nothing Nothing varType+    | validationMode /= WITHOUT_VARIABLES && isVariableRequired+    = failure $ uninitializedVariable variablePosition variableType key+    | otherwise+    = returnNull+   where+    returnNull =+      maybe (pure (key, Null)) (validator varType) (M.lookup key bodyVariables)+  -----------------------------------------------------------------------------------------------+  validator varType varValue =+    case+        validateInputValue typeLib+                           []+                           variableTypeWrappers+                           varType+                           (key, varValue)+      of+        Left message -> failure $ variableGotInvalidValue+          key+          (inputErrorMessage message)+          variablePosition+        Right value -> pure (key, value)
− test/Feature/Holistic/API.gql
@@ -1,51 +0,0 @@-enum TestEnum {-  EnumA-  EnumB-  EnumC-}--input NestedInputObject {-  fieldTestID: ID!-}--input TestInputObject {-  fieldTestScalar: TestScalar!-  fieldNestedInputObject: [NestedInputObject]!-}--input Coordinates {-  latitude: TestScalar!-  longitude: Int!-}--type Address {-  city: String!-  street(-    argInputObject: TestInputObject!-    argMaybeString: String-  ): [[[[String!]!]!]]-  houseNumber: Int!-}--union TestUnion = User | Address--type User {-  name: String!-  email: String!-  address(coordinates: Coordinates!, comment: String): Address!-  office(zipCode: [Int!], cityID: TestEnum!): Address!-  friend: User-}--type Query {-  user: User!-  testUnion: TestUnion-}--type Mutation {-  createUser(userID: String!, userName: String): User!-}--type Subscription {-  newUser: User!-}
test/Feature/Holistic/API.hs view
@@ -12,16 +12,27 @@ module Feature.Holistic.API   ( api   , rootResolver-  ) where+  )+where -import           Data.Morpheus          (interpreter)-import           Data.Morpheus.Document (importGQLDocument)-import           Data.Morpheus.Kind     (SCALAR)-import           Data.Morpheus.Types    (Event, GQLRequest, GQLResponse, GQLRootResolver (..), GQLScalar (..),-                                         GQLType (..), ID (..), ScalarValue (..), Resolver (..), constRes )-import           Data.Text              (Text)-import           GHC.Generics           (Generic)+import           Data.Morpheus                  ( interpreter )+import           Data.Morpheus.Document         ( importGQLDocument )+import           Data.Morpheus.Kind             ( SCALAR )+import           Data.Morpheus.Types            ( Event+                                                , GQLRequest+                                                , GQLResponse+                                                , GQLRootResolver(..)+                                                , GQLScalar(..)+                                                , GQLType(..)+                                                , ID(..)+                                                , ScalarValue(..)+                                                , Resolver(..)+                                                , constRes+                                                )+import           Data.Text                      ( Text )+import           GHC.Generics                   ( Generic ) + data TestScalar =   TestScalar Int              Int@@ -40,29 +51,31 @@  type EVENT = Event Channel () -importGQLDocument "test/Feature/Holistic/API.gql"+importGQLDocument "test/Feature/Holistic/schema.gql" -rootResolver ::-     GQLRootResolver IO EVENT Query Mutation Subscription-rootResolver =-  GQLRootResolver-    { queryResolver = Query {user, testUnion = constRes Nothing}-    , mutationResolver =  Mutation {createUser = user}-    , subscriptionResolver = Subscription {newUser = const SubResolver {subChannels = [Channel], subResolver = user}}-    }-  where-    user _ =-      pure -      User-        { name = constRes "testName"-        , email = constRes ""-        , address = resolveAddress-        , office = resolveAddress-        , friend = constRes Nothing-        }-      where-        resolveAddress _ =-          pure Address {city = constRes "", houseNumber = constRes 0, street = constRes Nothing}+rootResolver :: GQLRootResolver IO EVENT Query Mutation Subscription+rootResolver = GQLRootResolver+  { queryResolver        = Query { user, testUnion = constRes Nothing }+  , mutationResolver     = Mutation { createUser = user }+  , subscriptionResolver = Subscription+                             { newUser = const SubResolver+                                           { subChannels = [Channel]+                                           , subResolver = user+                                           }+                             }+  }+ where+  user _ = pure User { name    = constRes "testName"+                     , email   = constRes ""+                     , address = resolveAddress+                     , office  = resolveAddress+                     , friend  = constRes Nothing+                     }+   where+    resolveAddress _ = pure Address { city        = constRes ""+                                    , houseNumber = constRes 0+                                    , street      = constRes Nothing+                                    }  api :: GQLRequest -> IO GQLResponse api = interpreter rootResolver
test/Feature/Holistic/cases.json view
@@ -198,5 +198,29 @@   {     "path": "parsing/directive/notOnVariable",     "description": "fail when: directive is used in Variable Definition"+  },+  {+    "path": "introspection/description/object",+    "description": "check object descriptions, type, field, args"+  },+  {+    "path": "introspection/description/inputObject",+    "description": "check inputObject descriptions, type, field"+  },+  {+    "path": "introspection/description/union",+    "description": "check union descriptions, type"+  },+  {+    "path": "introspection/description/enum",+    "description": "check enum descriptions, type, enumValue"+  },+  {+    "path": "introspection/deprecated/enumValue",+    "description": "check if deprecated works with enumValue"+  },+  {+    "path": "introspection/deprecated/field",+    "description": "check if deprecated works with object fields"   } ]
test/Feature/Holistic/fragment/loopingFragment/response.json view
@@ -1,20 +1,11 @@ {   "errors": [     {-      "message": "Cannot spread fragment \"A\" within itself via A,C,A.",+      "message": "Cannot spread fragment \"A\" within itself via A,A,C.",       "locations": [-        {-          "line": 7,-          "column": 10-        },-        {-          "line": 9,-          "column": 3-        },-        {-          "line": 17,-          "column": 3-        }+        { "line": 17, "column": 3 },+        { "line": 7, "column": 10 },+        { "line": 9, "column": 3 }       ]     }   ]
+ test/Feature/Holistic/introspection/deprecated/enumValue/query.gql view
@@ -0,0 +1,9 @@+{+  __type(name: "TestEnum") {+    enumValues {+      name+      isDeprecated+      deprecationReason+    }+  }+}
+ test/Feature/Holistic/introspection/deprecated/enumValue/response.json view
@@ -0,0 +1,15 @@+{+  "data": {+    "__type": {+      "enumValues": [+        { "name": "EnumA", "isDeprecated": false, "deprecationReason": null },+        {+          "name": "EnumB",+          "isDeprecated": true,+          "deprecationReason": "test deprecation enumValue"+        },+        { "name": "EnumC", "isDeprecated": true, "deprecationReason": null }+      ]+    }+  }+}
+ test/Feature/Holistic/introspection/deprecated/field/query.gql view
@@ -0,0 +1,9 @@+{+  __type(name: "Address") {+    fields {+      name+      isDeprecated+      deprecationReason+    }+  }+}
+ test/Feature/Holistic/introspection/deprecated/field/response.json view
@@ -0,0 +1,19 @@+{+  "data": {+    "__type": {+      "fields": [+        {+          "name": "city",+          "isDeprecated": true,+          "deprecationReason": "test deprecation field with reason"+        },+        { "name": "street", "isDeprecated": true, "deprecationReason": null },+        {+          "name": "houseNumber",+          "isDeprecated": false,+          "deprecationReason": null+        }+      ]+    }+  }+}
+ test/Feature/Holistic/introspection/description/enum/query.gql view
@@ -0,0 +1,9 @@+{+  __type(name: "TestEnum") {+    description+    enumValues {+      name+      description+    }+  }+}
+ test/Feature/Holistic/introspection/description/enum/response.json view
@@ -0,0 +1,12 @@+{+  "data": {+    "__type": {+      "description": "type Description: TestEnum\n\nsome random enums for test",+      "enumValues": [+        { "name": "EnumA", "description": "enumValue Description: EnumA" },+        { "name": "EnumB", "description": null },+        { "name": "EnumC", "description": "enumValue Description: EnumC" }+      ]+    }+  }+}
+ test/Feature/Holistic/introspection/description/inputObject/query.gql view
@@ -0,0 +1,9 @@+{+  __type(name: "Coordinates") {+    description+    inputFields {+      name+      description+    }+  }+}
+ test/Feature/Holistic/introspection/description/inputObject/response.json view
@@ -0,0 +1,17 @@+{+  "data": {+    "__type": {+      "description": "type Description: Coordinates\n\nsome random text",+      "inputFields": [+        {+          "name": "latitude",+          "description": "inputValue Description: latitude"+        },+        {+          "name": "longitude",+          "description": "inputValue Description: longitude\n  some random inputValue details"+        }+      ]+    }+  }+}
+ test/Feature/Holistic/introspection/description/object/query.gql view
@@ -0,0 +1,13 @@+{+  __type(name: "Address") {+    description+    fields {+      name+      description+      args {+        name+        description+      }+    }+  }+}
+ test/Feature/Holistic/introspection/description/object/response.json view
@@ -0,0 +1,26 @@+{+  "data": {+    "__type": {+      "description": "type Description:\n\n  Address",+      "fields": [+        {+          "name": "city",+          "description": "field Description: city",+          "args": []+        },+        {+          "name": "street",+          "description": null,+          "args": [+            {+              "name": "argInputObject",+              "description": "argument Description: inputObject"+            },+            { "name": "argMaybeString", "description": null }+          ]+        },+        { "name": "houseNumber", "description": null, "args": [] }+      ]+    }+  }+}
+ test/Feature/Holistic/introspection/description/union/query.gql view
@@ -0,0 +1,5 @@+{+  __type(name: "TestUnion") {+    description+  }+}
+ test/Feature/Holistic/introspection/description/union/response.json view
@@ -0,0 +1,7 @@+{+  "data": {+    "__type": {+      "description": "type Description: TestUnion\n\nsome random text for union type"+    }+  }+}
test/Feature/Holistic/introspection/kinds/ENUM/response.json view
@@ -7,21 +7,13 @@       "inputFields": null,       "interfaces": null,       "enumValues": [-        {-          "name": "EnumA",-          "isDeprecated": false,-          "deprecationReason": null-        },+        { "name": "EnumA", "isDeprecated": false, "deprecationReason": null },         {           "name": "EnumB",-          "isDeprecated": false,-          "deprecationReason": null+          "isDeprecated": true,+          "deprecationReason": "test deprecation enumValue"         },-        {-          "name": "EnumC",-          "isDeprecated": false,-          "deprecationReason": null-        }+        { "name": "EnumC", "isDeprecated": true, "deprecationReason": null }       ],       "possibleTypes": null     }
test/Feature/Holistic/introspection/kinds/OBJECT/response.json view
@@ -10,14 +10,10 @@           "type": {             "kind": "NON_NULL",             "name": null,-            "ofType": {-              "kind": "SCALAR",-              "name": "String",-              "ofType": null-            }+            "ofType": { "kind": "SCALAR", "name": "String", "ofType": null }           },-          "isDeprecated": false,-          "deprecationReason": null+          "isDeprecated": true,+          "deprecationReason": "test deprecation field with reason"         },         {           "name": "street",@@ -37,11 +33,7 @@             },             {               "name": "argMaybeString",-              "type": {-                "kind": "SCALAR",-                "name": "String",-                "ofType": null-              },+              "type": { "kind": "SCALAR", "name": "String", "ofType": null },               "defaultValue": null             }           ],@@ -66,10 +58,7 @@                       "ofType": {                         "kind": "NON_NULL",                         "name": null,-                        "ofType": {-                          "kind": "SCALAR",-                          "name": "String"-                        }+                        "ofType": { "kind": "SCALAR", "name": "String" }                       }                     }                   }@@ -77,7 +66,7 @@               }             }           },-          "isDeprecated": false,+          "isDeprecated": true,           "deprecationReason": null         },         {@@ -86,11 +75,7 @@           "type": {             "kind": "NON_NULL",             "name": null,-            "ofType": {-              "kind": "SCALAR",-              "name": "Int",-              "ofType": null-            }+            "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null }           },           "isDeprecated": false,           "deprecationReason": null
test/Feature/Holistic/parsing/complex/response.json view
@@ -2,12 +2,27 @@   "errors": [     {       "message": "Argument coordinates got invalid value ;on longitude Expected type \"Int\" found [null,[[],[{\"uid\":\"1\"}]]].",-      "locations": [-        {-          "line": 8,-          "column": 36-        }-      ]+      "locations": [{ "line": 8, "column": 36 }]+    },+    {+      "message": "Argument coordinates got invalid value ;on longitude Expected type \"Int\" found [].",+      "locations": [{ "line": 11, "column": 36 }]+    },+    {+      "message": "Variable \"$v\" of type \"[[[ID!]]!]\" used in position expecting type \"[Int!]\".",+      "locations": [{ "line": 15, "column": 21 }]+    },+    {+      "message": "Cannot query field \"home\" on type \"User\".",+      "locations": [{ "line": 25, "column": 5 }]+    },+    {+      "message": "Cannot query field \"myUnion\" on type \"User\".",+      "locations": [{ "line": 26, "column": 18 }]+    },+    {+      "message": "Cannot query field \"myUnion\" on type \"User\".",+      "locations": [{ "line": 32, "column": 18 }]     }   ] }
test/Feature/Holistic/parsing/extraCommas/response.json view
@@ -2,12 +2,31 @@   "errors": [     {       "message": "Required Argument: \"coordinates\" was not Defined",-      "locations": [-        {-          "line": 2,-          "column": 18-        }-      ]+      "locations": [{ "line": 2, "column": 18 }]+    },+    {+      "message": "Required Argument: \"coordinates\" was not Defined",+      "locations": [{ "line": 4, "column": 18 }]+    },+    {+      "message": "Required Argument: \"coordinates\" was not Defined",+      "locations": [{ "line": 6, "column": 18 }]+    },+    {+      "message": "Required Argument: \"coordinates\" was not Defined",+      "locations": [{ "line": 10, "column": 9 }]+    },+    {+      "message": "Required Argument: \"coordinates\" was not Defined",+      "locations": [{ "line": 14, "column": 14 }]+    },+    {+      "message": "Required Argument: \"coordinates\" was not Defined",+      "locations": [{ "line": 18, "column": 15 }]+    },+    {+      "message": "Required Argument: \"coordinates\" was not Defined",+      "locations": [{ "line": 22, "column": 15 }]     }   ] }
+ test/Feature/Holistic/schema.gql view
@@ -0,0 +1,103 @@+"""+type Description: TestEnum++some random enums for test+"""+enum TestEnum {+  """+  enumValue Description: EnumA+  """+  EnumA+  EnumB @deprecated(reason: "test deprecation enumValue")+  """+  enumValue Description: EnumC+  """+  EnumC @deprecated+}++input NestedInputObject {+  fieldTestID: ID!+}++input TestInputObject {+  fieldTestScalar: TestScalar!+  fieldNestedInputObject: [NestedInputObject]!+}++"""+type Description: Coordinates++some random text+"""+input Coordinates {+  """+  inputValue Description: latitude+  """+  latitude: TestScalar!+  """+  inputValue Description: longitude+  some random inputValue details+  """+  longitude: Int!+}++"""+type Description:++  Address+"""+type Address {+  """+  field Description: city+  """+  city: String! @deprecated(reason: "test deprecation field with reason")+  street(+    """+    argument Description: inputObject+    """+    argInputObject: TestInputObject!+    argMaybeString: String+  ): [[[[String!]!]!]] @deprecated+  houseNumber: Int!+}++"""+type Description: TestUnion++some random text for union type+"""+union TestUnion = User | Address++"""+User++MultilineDescription++Test+"""+type User {+  """+  field description: name+  """+  name: String!+  """+  field description: email+  """+  email: String!+  address(coordinates: Coordinates!, comment: String): Address!+  office(zipCode: [Int!], cityID: TestEnum!): Address!+  friend: User+}++type Query {+  user: User!+  testUnion: TestUnion+}++type Mutation {+  createUser(userID: String!, userName: String): User!+}++type Subscription {+  newUser: User!+}
test/Feature/InputType/API.hs view
@@ -6,14 +6,20 @@  module Feature.InputType.API   ( api-  ) where+  )+where -import           Data.Morpheus       (interpreter)-import           Data.Morpheus.Kind  (OBJECT)-import           Data.Morpheus.Types (GQLRequest, GQLResponse, GQLRootResolver (..), GQLType (..), IORes,-                                      Undefined (..))-import           Data.Text           (Text)-import           GHC.Generics        (Generic)+import           Data.Morpheus                  ( interpreter )+import           Data.Morpheus.Kind             ( OBJECT )+import           Data.Morpheus.Types            ( GQLRequest+                                                , GQLResponse+                                                , GQLRootResolver(..)+                                                , GQLType(..)+                                                , IORes+                                                , Undefined(..)+                                                )+import           Data.Text                      ( Text )+import           GHC.Generics                   ( Generic )  data F1Args = F1Args   { arg1 :: Text@@ -38,12 +44,15 @@   } deriving (Generic, GQLType)  rootResolver :: GQLRootResolver IO () Query Undefined Undefined-rootResolver =-  GQLRootResolver-    { queryResolver = Query {q1 = A {a1 = const $ return "a1Test", a2 = const $ return 1}}-    , mutationResolver = Undefined-    , subscriptionResolver = Undefined-    }+rootResolver = GQLRootResolver+  { queryResolver        = Query+                             { q1 = A { a1 = const $ return "a1Test"+                                      , a2 = const $ return 1+                                      }+                             }+  , mutationResolver     = Undefined+  , subscriptionResolver = Undefined+  }  api :: GQLRequest -> IO GQLResponse api = interpreter rootResolver
test/Rendering/TestSchemaRendering.hs view
@@ -16,4 +16,4 @@   where     schema = toGraphQLDocument schemaProxy     expected =-        "type Query { \n  user: User!\n  testUnion: TestUnion\n}\n\nscalar TestScalar\n\nenum TestEnum { \n  EnumA\n  EnumB\n  EnumC\n}\n\ninput Coordinates { \n  latitude: TestScalar!\n  longitude: Int!\n}\n\ntype Address { \n  street: [[[[String!]!]!]]\n}\n\ntype User { \n  type: String!\n  address(coordinates: Coordinates!, type: String): Int!\n  friend(id: ID!, cityID: TestEnum): User!\n}\n\nunion TestUnion =\n    User!\n  | Address!"+        "type Query { \n  user: User!\n  testUnion: TestUnion\n}\n\nenum TestEnum { \n  EnumA\n  EnumB\n  EnumC\n}\n\ntype Address { \n  street: [[[[String!]!]!]]\n}\n\ninput Coordinates { \n  latitude: TestScalar!\n  longitude: Int!\n}\n\ntype User { \n  type: String!\n  address(coordinates: Coordinates!, type: String): Int!\n  friend(id: ID!, cityID: TestEnum): User!\n}\n\nunion TestUnion =\n    User\n  | Address\n\nscalar TestScalar"