Merge branch 'master' into 1.2.0
This commit is contained in:
commit
d23f899a6c
9 changed files with 144 additions and 124 deletions
|
@ -1,3 +1,7 @@
|
|||
# 1.0.1
|
||||
* Fix a bug where `globalVariables` were not being properly passed
|
||||
to field resolvers.
|
||||
|
||||
# 1.0.0
|
||||
* Finish testing.
|
||||
* Add `package:pedantic` fixes.
|
||||
|
|
|
@ -23,16 +23,16 @@ void main() {
|
|||
'todos',
|
||||
listOf(todoType),
|
||||
resolve: (_, __) => [
|
||||
new Todo(
|
||||
text: 'Clean your room!',
|
||||
completed: false,
|
||||
)
|
||||
],
|
||||
Todo(
|
||||
text: 'Clean your room!',
|
||||
completed: false,
|
||||
)
|
||||
],
|
||||
),
|
||||
]),
|
||||
);
|
||||
|
||||
var graphql = new GraphQL(schema);
|
||||
var graphql = GraphQL(schema);
|
||||
var result = await graphql.parseAndExecute('{ todos { text } }');
|
||||
|
||||
print(result);
|
||||
|
|
|
@ -45,15 +45,17 @@ class GraphQL {
|
|||
}
|
||||
|
||||
if (_schema.queryType != null) this.customTypes.add(_schema.queryType);
|
||||
if (_schema.mutationType != null)
|
||||
if (_schema.mutationType != null) {
|
||||
this.customTypes.add(_schema.mutationType);
|
||||
if (_schema.subscriptionType != null)
|
||||
}
|
||||
if (_schema.subscriptionType != null) {
|
||||
this.customTypes.add(_schema.subscriptionType);
|
||||
}
|
||||
}
|
||||
|
||||
GraphQLType convertType(TypeContext ctx) {
|
||||
if (ctx.listType != null) {
|
||||
return new GraphQLListType(convertType(ctx.listType.type));
|
||||
return GraphQLListType(convertType(ctx.listType.type));
|
||||
} else if (ctx.typeName != null) {
|
||||
switch (ctx.typeName.name) {
|
||||
case 'Int':
|
||||
|
@ -71,11 +73,11 @@ class GraphQL {
|
|||
return graphQLDate;
|
||||
default:
|
||||
return customTypes.firstWhere((t) => t.name == ctx.typeName.name,
|
||||
orElse: () => throw new ArgumentError(
|
||||
orElse: () => throw ArgumentError(
|
||||
'Unknown GraphQL type: "${ctx.typeName.name}"'));
|
||||
}
|
||||
} else {
|
||||
throw new ArgumentError('Invalid GraphQL type: "${ctx.span.text}"');
|
||||
throw ArgumentError('Invalid GraphQL type: "${ctx.span.text}"');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,13 +88,13 @@ class GraphQL {
|
|||
initialValue,
|
||||
Map<String, dynamic> globalVariables}) {
|
||||
var tokens = scan(text, sourceUrl: sourceUrl);
|
||||
var parser = new Parser(tokens);
|
||||
var parser = Parser(tokens);
|
||||
var document = parser.parseDocument();
|
||||
|
||||
if (parser.errors.isNotEmpty) {
|
||||
throw new GraphQLException(parser.errors
|
||||
.map((e) => new GraphQLExceptionError(e.message, locations: [
|
||||
new GraphExceptionErrorLocation.fromSourceLocation(e.span.start)
|
||||
throw GraphQLException(parser.errors
|
||||
.map((e) => GraphQLExceptionError(e.message, locations: [
|
||||
GraphExceptionErrorLocation.fromSourceLocation(e.span.start)
|
||||
]))
|
||||
.toList());
|
||||
}
|
||||
|
@ -115,10 +117,10 @@ class GraphQL {
|
|||
var operation = getOperation(document, operationName);
|
||||
var coercedVariableValues = coerceVariableValues(
|
||||
schema, operation, variableValues ?? <String, dynamic>{});
|
||||
if (operation.isQuery)
|
||||
if (operation.isQuery) {
|
||||
return await executeQuery(document, operation, schema,
|
||||
coercedVariableValues, initialValue, globalVariables);
|
||||
else if (operation.isSubscription) {
|
||||
} else if (operation.isSubscription) {
|
||||
return await subscribe(document, operation, schema, coercedVariableValues,
|
||||
globalVariables, initialValue);
|
||||
} else {
|
||||
|
@ -129,20 +131,17 @@ class GraphQL {
|
|||
|
||||
OperationDefinitionContext getOperation(
|
||||
DocumentContext document, String operationName) {
|
||||
var ops =
|
||||
document.definitions.where((d) => d is OperationDefinitionContext);
|
||||
var ops = document.definitions.whereType<OperationDefinitionContext>();
|
||||
|
||||
if (operationName == null) {
|
||||
return ops.length == 1
|
||||
? ops.first as OperationDefinitionContext
|
||||
: throw new GraphQLException.fromMessage(
|
||||
? ops.first
|
||||
: throw GraphQLException.fromMessage(
|
||||
'This document does not define any operations.');
|
||||
} else {
|
||||
return ops.firstWhere(
|
||||
(d) => (d as OperationDefinitionContext).name == operationName,
|
||||
orElse: () => throw new GraphQLException.fromMessage(
|
||||
'Missing required operation "$operationName".'))
|
||||
as OperationDefinitionContext;
|
||||
return ops.firstWhere((d) => d.name == operationName,
|
||||
orElse: () => throw GraphQLException.fromMessage(
|
||||
'Missing required operation "$operationName".'));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,7 +163,7 @@ class GraphQL {
|
|||
if (defaultValue != null) {
|
||||
coercedValues[variableName] = defaultValue.value.value;
|
||||
} else if (!variableType.isNullable) {
|
||||
throw new GraphQLException.fromSourceSpan(
|
||||
throw GraphQLException.fromSourceSpan(
|
||||
'Missing required variable "$variableName".',
|
||||
variableDefinition.span);
|
||||
}
|
||||
|
@ -173,9 +172,9 @@ class GraphQL {
|
|||
var validation = type.validate(variableName, value);
|
||||
|
||||
if (!validation.successful) {
|
||||
throw new GraphQLException(validation.errors
|
||||
.map((e) => new GraphQLExceptionError(e, locations: [
|
||||
new GraphExceptionErrorLocation.fromSourceLocation(
|
||||
throw GraphQLException(validation.errors
|
||||
.map((e) => GraphQLExceptionError(e, locations: [
|
||||
GraphExceptionErrorLocation.fromSourceLocation(
|
||||
variableDefinition.span.start)
|
||||
]))
|
||||
.toList());
|
||||
|
@ -211,7 +210,7 @@ class GraphQL {
|
|||
var mutationType = schema.mutationType;
|
||||
|
||||
if (mutationType == null) {
|
||||
throw new GraphQLException.fromMessage(
|
||||
throw GraphQLException.fromMessage(
|
||||
'The schema does not define a mutation type.');
|
||||
}
|
||||
|
||||
|
@ -241,15 +240,17 @@ class GraphQL {
|
|||
initialValue) {
|
||||
var selectionSet = subscription.selectionSet;
|
||||
var subscriptionType = schema.subscriptionType;
|
||||
if (subscriptionType == null)
|
||||
if (subscriptionType == null) {
|
||||
throw GraphQLException.fromSourceSpan(
|
||||
'The schema does not define a subscription type.', subscription.span);
|
||||
}
|
||||
var groupedFieldSet =
|
||||
collectFields(document, subscriptionType, selectionSet, variableValues);
|
||||
if (groupedFieldSet.length != 1)
|
||||
if (groupedFieldSet.length != 1) {
|
||||
throw GraphQLException.fromSourceSpan(
|
||||
'The grouped field set from this query must have exactly one entry.',
|
||||
selectionSet.span);
|
||||
}
|
||||
var fields = groupedFieldSet.entries.first.value;
|
||||
var fieldName = fields.first.field.fieldName.alias?.name ??
|
||||
fields.first.field.fieldName.name;
|
||||
|
@ -284,10 +285,10 @@ class GraphQL {
|
|||
Map<String, dynamic> globalVariables) async {
|
||||
var selectionSet = subscription.selectionSet;
|
||||
var subscriptionType = schema.subscriptionType;
|
||||
if (subscriptionType == null)
|
||||
if (subscriptionType == null) {
|
||||
throw GraphQLException.fromSourceSpan(
|
||||
'The schema does not define a subscription type.', subscription.span);
|
||||
|
||||
}
|
||||
try {
|
||||
var data = await executeSelectionSet(document, selectionSet,
|
||||
subscriptionType, initialValue, variableValues, globalVariables);
|
||||
|
@ -309,10 +310,11 @@ class GraphQL {
|
|||
});
|
||||
var resolver = field.resolve;
|
||||
var result = await resolver(rootValue, argumentValues);
|
||||
if (result is Stream)
|
||||
if (result is Stream) {
|
||||
return result;
|
||||
else
|
||||
} else {
|
||||
return Stream.fromIterable([result]);
|
||||
}
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> executeSelectionSet(
|
||||
|
@ -348,8 +350,7 @@ class GraphQL {
|
|||
objectValue,
|
||||
fields,
|
||||
fieldType,
|
||||
new Map<String, dynamic>.from(
|
||||
globalVariables ?? <String, dynamic>{})
|
||||
Map<String, dynamic>.from(globalVariables ?? <String, dynamic>{})
|
||||
..addAll(variableValues),
|
||||
globalVariables);
|
||||
}
|
||||
|
@ -374,7 +375,11 @@ class GraphQL {
|
|||
var argumentValues =
|
||||
coerceArgumentValues(objectType, field, variableValues);
|
||||
var resolvedValue = await resolveFieldValue(
|
||||
objectType, objectValue, fieldName, argumentValues);
|
||||
objectType,
|
||||
objectValue,
|
||||
fieldName,
|
||||
Map<String, dynamic>.from(globalVariables ?? {})
|
||||
..addAll(argumentValues ?? {}));
|
||||
return completeValue(document, fieldName, fieldType, fields, resolvedValue,
|
||||
variableValues, globalVariables);
|
||||
}
|
||||
|
@ -407,7 +412,7 @@ class GraphQL {
|
|||
} else if (defaultValue != null || argumentDefinition.defaultsToNull) {
|
||||
coercedValues[argumentName] = defaultValue;
|
||||
} else if (argumentType is GraphQLNonNullableType) {
|
||||
throw new GraphQLException.fromSourceSpan(
|
||||
throw GraphQLException.fromSourceSpan(
|
||||
'Missing value for argument "$argumentName" of field "$fieldName".',
|
||||
value.valueOrVariable.span);
|
||||
} else {
|
||||
|
@ -417,7 +422,7 @@ class GraphQL {
|
|||
if (defaultValue != null || argumentDefinition.defaultsToNull) {
|
||||
coercedValues[argumentName] = defaultValue;
|
||||
} else if (argumentType is GraphQLNonNullableType) {
|
||||
throw new GraphQLException.fromMessage(
|
||||
throw GraphQLException.fromMessage(
|
||||
'Missing value for argument "$argumentName" of field "$fieldName".');
|
||||
} else {
|
||||
continue;
|
||||
|
@ -429,10 +434,10 @@ class GraphQL {
|
|||
|
||||
if (!validation.successful) {
|
||||
var errors = <GraphQLExceptionError>[
|
||||
new GraphQLExceptionError(
|
||||
GraphQLExceptionError(
|
||||
'Type coercion error for value of argument "$argumentName" of field "$fieldName".',
|
||||
locations: [
|
||||
new GraphExceptionErrorLocation.fromSourceLocation(
|
||||
GraphExceptionErrorLocation.fromSourceLocation(
|
||||
value.valueOrVariable.span.start)
|
||||
],
|
||||
)
|
||||
|
@ -440,34 +445,34 @@ class GraphQL {
|
|||
|
||||
for (var error in validation.errors) {
|
||||
errors.add(
|
||||
new GraphQLExceptionError(
|
||||
GraphQLExceptionError(
|
||||
error,
|
||||
locations: [
|
||||
new GraphExceptionErrorLocation.fromSourceLocation(
|
||||
GraphExceptionErrorLocation.fromSourceLocation(
|
||||
value.valueOrVariable.span.start)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
throw new GraphQLException(errors);
|
||||
throw GraphQLException(errors);
|
||||
} else {
|
||||
var coercedValue = validation.value;
|
||||
coercedValues[argumentName] = coercedValue;
|
||||
}
|
||||
} on TypeError catch (e) {
|
||||
throw new GraphQLException(<GraphQLExceptionError>[
|
||||
new GraphQLExceptionError(
|
||||
throw GraphQLException(<GraphQLExceptionError>[
|
||||
GraphQLExceptionError(
|
||||
'Type coercion error for value of argument "$argumentName" of field "$fieldName".',
|
||||
locations: [
|
||||
new GraphExceptionErrorLocation.fromSourceLocation(
|
||||
GraphExceptionErrorLocation.fromSourceLocation(
|
||||
value.valueOrVariable.span.start)
|
||||
],
|
||||
),
|
||||
new GraphQLExceptionError(
|
||||
GraphQLExceptionError(
|
||||
e.message.toString(),
|
||||
locations: [
|
||||
new GraphExceptionErrorLocation.fromSourceLocation(
|
||||
GraphExceptionErrorLocation.fromSourceLocation(
|
||||
value.valueOrVariable.span.start)
|
||||
],
|
||||
),
|
||||
|
@ -486,9 +491,10 @@ class GraphQL {
|
|||
if (objectValue is Map) {
|
||||
return objectValue[fieldName] as T;
|
||||
} else if (field.resolve == null) {
|
||||
if (defaultFieldResolver != null)
|
||||
if (defaultFieldResolver != null) {
|
||||
return await defaultFieldResolver(
|
||||
objectValue, fieldName, argumentValues);
|
||||
}
|
||||
|
||||
return null;
|
||||
} else {
|
||||
|
@ -510,7 +516,7 @@ class GraphQL {
|
|||
fields, result, variableValues, globalVariables);
|
||||
|
||||
if (completedResult == null) {
|
||||
throw new GraphQLException.fromMessage(
|
||||
throw GraphQLException.fromMessage(
|
||||
'Null value provided for non-nullable field "$fieldName".');
|
||||
} else {
|
||||
return completedResult;
|
||||
|
@ -523,7 +529,7 @@ class GraphQL {
|
|||
|
||||
if (fieldType is GraphQLListType) {
|
||||
if (result is! Iterable) {
|
||||
throw new GraphQLException.fromMessage(
|
||||
throw GraphQLException.fromMessage(
|
||||
'Value of field "$fieldName" must be a list or iterable, got $result instead.');
|
||||
}
|
||||
|
||||
|
@ -548,7 +554,7 @@ class GraphQL {
|
|||
return validation.value;
|
||||
}
|
||||
} on TypeError {
|
||||
throw new GraphQLException.fromMessage(
|
||||
throw GraphQLException.fromMessage(
|
||||
'Value of field "$fieldName" must be ${fieldType.valueType}, got $result instead.');
|
||||
}
|
||||
}
|
||||
|
@ -567,7 +573,7 @@ class GraphQL {
|
|||
result, variableValues, globalVariables);
|
||||
}
|
||||
|
||||
throw new UnsupportedError('Unsupported type: $fieldType');
|
||||
throw UnsupportedError('Unsupported type: $fieldType');
|
||||
}
|
||||
|
||||
GraphQLObjectType resolveAbstractType(
|
||||
|
@ -583,7 +589,7 @@ class GraphQL {
|
|||
} else if (type is GraphQLUnionType) {
|
||||
possibleTypes = type.possibleTypes;
|
||||
} else {
|
||||
throw new ArgumentError();
|
||||
throw ArgumentError();
|
||||
}
|
||||
|
||||
var errors = <GraphQLExceptionError>[];
|
||||
|
@ -597,19 +603,16 @@ class GraphQL {
|
|||
return t;
|
||||
}
|
||||
|
||||
errors
|
||||
.addAll(validation.errors.map((m) => new GraphQLExceptionError(m)));
|
||||
errors.addAll(validation.errors.map((m) => GraphQLExceptionError(m)));
|
||||
} on GraphQLException catch (e) {
|
||||
errors.addAll(e.errors);
|
||||
}
|
||||
}
|
||||
|
||||
errors.insert(
|
||||
0,
|
||||
new GraphQLExceptionError(
|
||||
'Cannot convert value $result to type $type.'));
|
||||
errors.insert(0,
|
||||
GraphQLExceptionError('Cannot convert value $result to type $type.'));
|
||||
|
||||
throw new GraphQLException(errors);
|
||||
throw GraphQLException(errors);
|
||||
}
|
||||
|
||||
SelectionSetContext mergeSelectionSets(List<SelectionContext> fields) {
|
||||
|
@ -623,7 +626,7 @@ class GraphQL {
|
|||
}
|
||||
}
|
||||
|
||||
return new SelectionSetContext.merged(selections);
|
||||
return SelectionSetContext.merged(selections);
|
||||
}
|
||||
|
||||
Map<String, List<SelectionContext>> collectFields(
|
||||
|
@ -636,10 +639,13 @@ class GraphQL {
|
|||
visitedFragments ??= [];
|
||||
|
||||
for (var selection in selectionSet.selections) {
|
||||
if (getDirectiveValue('skip', 'if', selection, variableValues) == true)
|
||||
if (getDirectiveValue('skip', 'if', selection, variableValues) == true) {
|
||||
continue;
|
||||
}
|
||||
if (getDirectiveValue('include', 'if', selection, variableValues) ==
|
||||
false) continue;
|
||||
false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (selection.field != null) {
|
||||
var responseKey = selection.field.fieldName.alias?.alias ??
|
||||
|
@ -652,11 +658,9 @@ class GraphQL {
|
|||
if (visitedFragments.contains(fragmentSpreadName)) continue;
|
||||
visitedFragments.add(fragmentSpreadName);
|
||||
var fragment = document.definitions
|
||||
.where((d) => d is FragmentDefinitionContext)
|
||||
.firstWhere(
|
||||
(f) =>
|
||||
(f as FragmentDefinitionContext).name == fragmentSpreadName,
|
||||
orElse: () => null) as FragmentDefinitionContext;
|
||||
.whereType<FragmentDefinitionContext>()
|
||||
.firstWhere((f) => f.name == fragmentSpreadName,
|
||||
orElse: () => null);
|
||||
|
||||
if (fragment == null) continue;
|
||||
var fragmentType = fragment.typeCondition;
|
||||
|
@ -708,19 +712,21 @@ class GraphQL {
|
|||
if (vv.value != null) return vv.value.value;
|
||||
|
||||
var vname = vv.variable.name;
|
||||
if (!variableValues.containsKey(vname))
|
||||
throw new GraphQLException.fromSourceSpan(
|
||||
if (!variableValues.containsKey(vname)) {
|
||||
throw GraphQLException.fromSourceSpan(
|
||||
'Unknown variable: "$vname"', vv.span);
|
||||
}
|
||||
|
||||
return variableValues[vname];
|
||||
}
|
||||
|
||||
bool doesFragmentTypeApply(
|
||||
GraphQLObjectType objectType, TypeConditionContext fragmentType) {
|
||||
var type = convertType(new TypeContext(fragmentType.typeName, null));
|
||||
var type = convertType(TypeContext(fragmentType.typeName, null));
|
||||
if (type is GraphQLObjectType && !type.isInterface) {
|
||||
for (var field in type.fields)
|
||||
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);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:graphql_parser/graphql_parser.dart';
|
||||
import 'package:graphql_schema/graphql_schema.dart';
|
||||
|
||||
/// Performs introspection over a GraphQL [schema], and returns a new one, containing
|
||||
/// Performs introspection over a GraphQL [schema], and returns a one, containing
|
||||
/// introspective information.
|
||||
///
|
||||
/// [allTypes] should contain all types, not directly defined in the schema, that you
|
||||
|
@ -79,11 +79,11 @@ GraphQLSchema reflectSchema(GraphQLSchema schema, List<GraphQLType> allTypes) {
|
|||
field(
|
||||
'__type',
|
||||
typeType,
|
||||
inputs: [new GraphQLFieldInput('name', graphQLString.nonNullable())],
|
||||
inputs: [GraphQLFieldInput('name', graphQLString.nonNullable())],
|
||||
resolve: (_, args) {
|
||||
var name = args['name'] as String;
|
||||
return allTypes.firstWhere((t) => t.name == name,
|
||||
orElse: () => throw new GraphQLException.fromMessage(
|
||||
orElse: () => throw GraphQLException.fromMessage(
|
||||
'No type named "$name" exists.'));
|
||||
},
|
||||
),
|
||||
|
@ -91,7 +91,7 @@ GraphQLSchema reflectSchema(GraphQLSchema schema, List<GraphQLType> allTypes) {
|
|||
|
||||
fields.addAll(schema.queryType.fields);
|
||||
|
||||
return new GraphQLSchema(
|
||||
return GraphQLSchema(
|
||||
queryType: objectType(schema.queryType.name, fields: fields),
|
||||
mutationType: schema.mutationType,
|
||||
subscriptionType: schema.subscriptionType,
|
||||
|
@ -108,9 +108,9 @@ GraphQLObjectType _reflectSchemaTypes() {
|
|||
'ofType',
|
||||
_reflectSchemaTypes(),
|
||||
resolve: (type, _) {
|
||||
if (type is GraphQLListType)
|
||||
if (type is GraphQLListType) {
|
||||
return type.ofType;
|
||||
else if (type is GraphQLNonNullableType) return type.ofType;
|
||||
} else if (type is GraphQLNonNullableType) return type.ofType;
|
||||
return null;
|
||||
},
|
||||
),
|
||||
|
@ -213,29 +213,30 @@ GraphQLObjectType _createTypeType() {
|
|||
resolve: (type, _) {
|
||||
var t = type as GraphQLType;
|
||||
|
||||
if (t is GraphQLEnumType)
|
||||
if (t is GraphQLEnumType) {
|
||||
return 'ENUM';
|
||||
else if (t is GraphQLScalarType)
|
||||
} else if (t is GraphQLScalarType) {
|
||||
return 'SCALAR';
|
||||
else if (t is GraphQLInputObjectType)
|
||||
} else if (t is GraphQLInputObjectType) {
|
||||
return 'INPUT_OBJECT';
|
||||
else if (t is GraphQLObjectType)
|
||||
} else if (t is GraphQLObjectType) {
|
||||
return t.isInterface ? 'INTERFACE' : 'OBJECT';
|
||||
else if (t is GraphQLListType)
|
||||
} else if (t is GraphQLListType) {
|
||||
return 'LIST';
|
||||
else if (t is GraphQLNonNullableType)
|
||||
} else if (t is GraphQLNonNullableType) {
|
||||
return 'NON_NULL';
|
||||
else if (t is GraphQLUnionType)
|
||||
} else if (t is GraphQLUnionType) {
|
||||
return 'UNION';
|
||||
else
|
||||
throw new UnsupportedError('Cannot get the kind of $t.');
|
||||
} else {
|
||||
throw UnsupportedError('Cannot get the kind of $t.');
|
||||
}
|
||||
},
|
||||
),
|
||||
field(
|
||||
'fields',
|
||||
listOf(fieldType),
|
||||
inputs: [
|
||||
new GraphQLFieldInput(
|
||||
GraphQLFieldInput(
|
||||
'includeDeprecated',
|
||||
graphQLBoolean,
|
||||
defaultValue: false,
|
||||
|
@ -252,7 +253,7 @@ GraphQLObjectType _createTypeType() {
|
|||
'enumValues',
|
||||
listOf(enumValueType.nonNullable()),
|
||||
inputs: [
|
||||
new GraphQLFieldInput(
|
||||
GraphQLFieldInput(
|
||||
'includeDeprecated',
|
||||
graphQLBoolean,
|
||||
defaultValue: false,
|
||||
|
|
|
@ -7,10 +7,11 @@ import 'package:recase/recase.dart';
|
|||
/// Uses `dart:mirrors` to read field names from items. If they are Maps, performs a regular lookup.
|
||||
T mirrorsFieldResolver<T>(objectValue, String fieldName,
|
||||
[Map<String, dynamic> objectValues]) {
|
||||
if (objectValue is Map)
|
||||
if (objectValue is Map) {
|
||||
return objectValue[fieldName] as T;
|
||||
else
|
||||
} else {
|
||||
return reflect(objectValue).getField(Symbol(fieldName)).reflectee as T;
|
||||
}
|
||||
}
|
||||
|
||||
/// Reflects upon a given [type] and dynamically generates a [GraphQLType] that corresponds to it.
|
||||
|
@ -42,10 +43,10 @@ GraphQLType _objectTypeFromDartType(Type type, [List<Type> typeArguments]) {
|
|||
} else if (type == double) {
|
||||
return graphQLFloat;
|
||||
} else if (type == num) {
|
||||
throw new UnsupportedError(
|
||||
throw UnsupportedError(
|
||||
'Cannot convert `num` to a GraphQL type. Choose `int` or `float` instead.');
|
||||
} else if (type == Null) {
|
||||
throw new UnsupportedError('Cannot convert `Null` to a GraphQL type.');
|
||||
throw UnsupportedError('Cannot convert `Null` to a GraphQL type.');
|
||||
} else if (type == String) {
|
||||
return graphQLString;
|
||||
} else if (type == DateTime) {
|
||||
|
@ -56,7 +57,7 @@ GraphQLType _objectTypeFromDartType(Type type, [List<Type> typeArguments]) {
|
|||
type, typeArguments?.isNotEmpty == true ? typeArguments : null);
|
||||
|
||||
if (mirror is! ClassMirror) {
|
||||
throw new StateError(
|
||||
throw StateError(
|
||||
'$type is not a class, and therefore cannot be converted into a GraphQL object type.');
|
||||
}
|
||||
|
||||
|
@ -69,7 +70,7 @@ GraphQLType _objectTypeFromDartType(Type type, [List<Type> typeArguments]) {
|
|||
return listOf(inner.nonNullable());
|
||||
}
|
||||
|
||||
throw new ArgumentError(
|
||||
throw ArgumentError(
|
||||
'Cannot convert ${clazz.reflectedType}, an iterable WITHOUT a type argument, into a GraphQL type.');
|
||||
}
|
||||
|
||||
|
@ -213,7 +214,7 @@ GraphQLEnumType enumTypeFromClassMirror(ClassMirror mirror) {
|
|||
if (name != #values) {
|
||||
var methodMirror = mirror.staticMembers[name];
|
||||
values.add(
|
||||
new GraphQLEnumValue(
|
||||
GraphQLEnumValue(
|
||||
MirrorSystem.getName(name),
|
||||
mirror.getField(name).reflectee,
|
||||
description: _getDescription(methodMirror.metadata),
|
||||
|
@ -223,7 +224,7 @@ GraphQLEnumType enumTypeFromClassMirror(ClassMirror mirror) {
|
|||
}
|
||||
}
|
||||
|
||||
return new GraphQLEnumType(
|
||||
return GraphQLEnumType(
|
||||
MirrorSystem.getName(mirror.simpleName),
|
||||
values,
|
||||
description: _getDescription(mirror.metadata),
|
||||
|
@ -294,7 +295,7 @@ String _getSerializedName(Symbol name, MethodMirror mirror, ClassMirror clazz) {
|
|||
var ann = obj.reflectee as Serializable;
|
||||
|
||||
if (ann.autoSnakeCaseNames != false) {
|
||||
return new ReCase(MirrorSystem.getName(name)).snakeCase;
|
||||
return ReCase(MirrorSystem.getName(name)).snakeCase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,11 +18,12 @@ abstract class Server {
|
|||
if ((msg.type == OperationMessage.gqlConnectionInit) && !_init) {
|
||||
try {
|
||||
Map connectionParams;
|
||||
if (msg.payload is Map)
|
||||
if (msg.payload is Map) {
|
||||
connectionParams = msg.payload as Map;
|
||||
else if (msg.payload != null)
|
||||
} else if (msg.payload != null) {
|
||||
throw FormatException(
|
||||
'${msg.type} payload must be a map (object).');
|
||||
}
|
||||
|
||||
var connect = await onConnect(client, connectionParams);
|
||||
if (!connect) throw false;
|
||||
|
@ -39,33 +40,39 @@ abstract class Server {
|
|||
});
|
||||
}
|
||||
} catch (e) {
|
||||
if (e == false)
|
||||
if (e == false) {
|
||||
_reportError('The connection was rejected.');
|
||||
else
|
||||
} else {
|
||||
_reportError(e.toString());
|
||||
}
|
||||
}
|
||||
} else if (_init) {
|
||||
if (msg.type == OperationMessage.gqlStart) {
|
||||
if (msg.id == null)
|
||||
if (msg.id == null) {
|
||||
throw FormatException('${msg.type} id is required.');
|
||||
if (msg.payload == null)
|
||||
}
|
||||
if (msg.payload == null) {
|
||||
throw FormatException('${msg.type} payload is required.');
|
||||
else if (msg.payload is! Map)
|
||||
} else if (msg.payload is! Map) {
|
||||
throw FormatException(
|
||||
'${msg.type} payload must be a map (object).');
|
||||
}
|
||||
var payload = msg.payload as Map;
|
||||
var query = payload['query'];
|
||||
var variables = payload['variables'];
|
||||
var operationName = payload['operationName'];
|
||||
if (query == null || query is! String)
|
||||
if (query == null || query is! String) {
|
||||
throw FormatException(
|
||||
'${msg.type} payload must contain a string named "query".');
|
||||
if (variables != null && variables is! Map)
|
||||
}
|
||||
if (variables != null && variables is! Map) {
|
||||
throw FormatException(
|
||||
'${msg.type} payload\'s "variables" field must be a map (object).');
|
||||
if (operationName != null && operationName is! String)
|
||||
}
|
||||
if (operationName != null && operationName is! String) {
|
||||
throw FormatException(
|
||||
'${msg.type} payload\'s "operationName" field must be a string.');
|
||||
}
|
||||
var result = await onOperation(
|
||||
msg.id,
|
||||
query as String,
|
||||
|
|
|
@ -44,14 +44,15 @@ class OperationMessage {
|
|||
var payload = map['payload'];
|
||||
var id = map['id'];
|
||||
|
||||
if (type == null)
|
||||
if (type == null) {
|
||||
throw ArgumentError.notNull('type');
|
||||
else if (type is! String)
|
||||
} else if (type is! String) {
|
||||
throw ArgumentError.value(type, 'type', 'must be a string');
|
||||
else if (id is num)
|
||||
} else if (id is num) {
|
||||
id = id.toString();
|
||||
else if (id != null && id is! String)
|
||||
} else if (id != null && id is! String) {
|
||||
throw ArgumentError.value(id, 'id', 'must be a string or number');
|
||||
}
|
||||
|
||||
// TODO: This is technically a violation of the spec.
|
||||
// https://github.com/apollographql/subscriptions-transport-ws/issues/551
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: graphql_server
|
||||
version: 1.0.0
|
||||
version: 1.0.1
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
description: Base package for implementing GraphQL servers. You might prefer `package:angel_graphql`, the fastest way to implement GraphQL backends in Dart.
|
||||
homepage: https://github.com/angel-dart/graphql
|
||||
|
|
|
@ -23,16 +23,16 @@ void main() {
|
|||
'todos',
|
||||
listOf(todoType),
|
||||
resolve: (_, __) => [
|
||||
new Todo(
|
||||
text: 'Clean your room!',
|
||||
completed: false,
|
||||
)
|
||||
],
|
||||
Todo(
|
||||
text: 'Clean your room!',
|
||||
completed: false,
|
||||
)
|
||||
],
|
||||
),
|
||||
]),
|
||||
);
|
||||
|
||||
var graphql = new GraphQL(schema);
|
||||
var graphql = GraphQL(schema);
|
||||
var result = await graphql.parseAndExecute('{ todos { text } }');
|
||||
|
||||
print(result);
|
||||
|
|
Loading…
Reference in a new issue