Implement interface and union type querying

This commit is contained in:
Tobe O 2018-08-03 21:23:45 -04:00
parent 59be67391d
commit d96470a62a
3 changed files with 63 additions and 17 deletions

View file

@ -16,13 +16,6 @@ final Validator graphQlPostBody = new Validator({
'variables': predicate((v) => v == null || v is Map),
});
Map<String, dynamic> _foldToStringDynamic(Map map) {
return map == null
? null
: map.keys.fold<Map<String, dynamic>>(
<String, dynamic>{}, (out, k) => out..[k.toString()] = map[k]);
}
RequestHandler graphQLHttp(GraphQL graphQl) {
return (req, res) async {
try {
@ -41,7 +34,7 @@ RequestHandler graphQLHttp(GraphQL graphQl) {
text,
sourceUrl: 'input',
operationName: operationName,
variableValues: _foldToStringDynamic(variables),
variableValues: foldToStringDynamic(variables),
),
};
}

View file

@ -13,10 +13,12 @@ class GraphQLObjectType
final List<GraphQLObjectType> _possibleTypes = [];
/// A list of other types that this object type is known to implement.
List<GraphQLObjectType> get interfaces => new List<GraphQLObjectType>.unmodifiable(_interfaces);
List<GraphQLObjectType> get interfaces =>
new List<GraphQLObjectType>.unmodifiable(_interfaces);
/// A list of other types that implement this interface.
List<GraphQLObjectType> get possibleTypes => new List<GraphQLObjectType>.unmodifiable(_possibleTypes);
List<GraphQLObjectType> get possibleTypes =>
new List<GraphQLObjectType>.unmodifiable(_possibleTypes);
GraphQLObjectType(this.name, this.description, {this.isInterface: false});
@ -88,6 +90,18 @@ class GraphQLObjectType
return out..[k.toString()] = field.deserialize(value[k]);
});
}
bool isImplementationOf(GraphQLObjectType type) {
if (type == this) {
return true;
} else if (interfaces.contains(type)) {
return true;
} else if (interfaces.isNotEmpty) {
return interfaces.any((t) => t.isImplementationOf(type));
} else {
return false;
}
}
}
Map<String, dynamic> _foldToStringDynamic(Map map) {

View file

@ -5,6 +5,13 @@ import 'package:graphql_schema/graphql_schema.dart';
import 'introspection.dart';
Map<String, dynamic> foldToStringDynamic(Map map) {
return map == null
? null
: map.keys.fold<Map<String, dynamic>>(
<String, dynamic>{}, (out, k) => out..[k.toString()] = map[k]);
}
class GraphQL {
final List<GraphQLType> customTypes = [];
GraphQLSchema _schema;
@ -335,17 +342,48 @@ class GraphQL {
}
}
if (fieldType is GraphQLObjectType) {
var objectType = fieldType;
if (fieldType is GraphQLObjectType || fieldType is GraphQLUnionType) {
GraphQLObjectType objectType;
if (fieldType is GraphQLObjectType && !fieldType.isInterface) {
objectType = fieldType;
} else {
objectType = resolveAbstractType(fieldType, result);
}
var subSelectionSet = mergeSelectionSets(fields);
return await executeSelectionSet(
document, subSelectionSet, objectType, result, variableValues);
}
// TODO: Interface/union type
throw new UnsupportedError('Unsupported type: $fieldType');
}
GraphQLObjectType resolveAbstractType(GraphQLType type, result) {
List<GraphQLObjectType> possibleTypes;
if (type is GraphQLObjectType) {
possibleTypes = type.possibleTypes;
} else if (type is GraphQLUnionType) {
possibleTypes = type.possibleTypes;
} else {
throw new ArgumentError();
}
for (var t in possibleTypes) {
try {
var validation =
t.validate('@root', foldToStringDynamic(result as Map));
if (validation.successful) {
return t;
}
} catch (_) {}
}
throw new StateError('Cannot convert value $result to type $type.');
}
SelectionSetContext mergeSelectionSets(List<SelectionContext> fields) {
var selections = <SelectionContext>[];
@ -451,13 +489,14 @@ class GraphQL {
bool doesFragmentTypeApply(
GraphQLObjectType objectType, TypeConditionContext fragmentType) {
var type = convertType(new TypeContext(fragmentType.typeName, null));
// TODO: Handle interface type, union?
if (type is GraphQLObjectType) {
if (type is GraphQLObjectType && !type.isInterface) {
for (var field in type.fields)
if (!objectType.fields.any((f) => f.name == field.name)) return false;
return true;
} else if (type is GraphQLObjectType && type.isInterface) {
return objectType.isImplementationOf(type);
} else if (type is GraphQLUnionType) {
return type.possibleTypes.any((t) => objectType.isImplementationOf(t));
}
return false;