diff --git a/.idea/runConfigurations/tests_in_mirrors_test_dart.xml b/.idea/runConfigurations/tests_in_mirrors_test_dart.xml
new file mode 100644
index 00000000..c9450200
--- /dev/null
+++ b/.idea/runConfigurations/tests_in_mirrors_test_dart.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/angel_graphql/example/main.dart b/angel_graphql/example/main.dart
index 4ff9916f..99f57686 100644
--- a/angel_graphql/example/main.dart
+++ b/angel_graphql/example/main.dart
@@ -25,7 +25,7 @@ main() async {
fields: [
field(
'todo',
- type: listType(objectTypeFromDartType(Todo).nonNullable()),
+ type: listType(convertDartType(Todo).nonNullable()),
resolve: resolveFromService(todoService),
arguments: [
new GraphQLFieldArgument('id', graphQLId),
diff --git a/graphql_schema/lib/src/enum.dart b/graphql_schema/lib/src/enum.dart
index d85a7eca..3d68cc2c 100644
--- a/graphql_schema/lib/src/enum.dart
+++ b/graphql_schema/lib/src/enum.dart
@@ -1,39 +1,54 @@
part of graphql_schema.src.schema;
-GraphQLEnumType enumType(String name, List values,
+GraphQLEnumType enumType(String name, Map values,
{String description}) {
- return new GraphQLEnumType(
- name, values.map((s) => new GraphQLEnumValue(s)).toList(),
+ return new GraphQLEnumType(
+ name, values.keys.map((k) => new GraphQLEnumValue(k, values[k])).toList(),
description: description);
}
-class GraphQLEnumType extends _GraphQLStringType {
+GraphQLEnumType enumTypeFromStrings(String name, List values,
+ {String description}) {
+ return new GraphQLEnumType(
+ name, values.map((s) => new GraphQLEnumValue(s, s)).toList(),
+ description: description);
+}
+
+class GraphQLEnumType extends GraphQLScalarType
+ with _NonNullableMixin {
final String name;
- final List values;
+ final List> values;
final String description;
- GraphQLEnumType(this.name, this.values, {this.description}) : super._();
+ GraphQLEnumType(this.name, this.values, {this.description});
+
+ @override
+ String serialize(Value value) {
+ return values.firstWhere((v) => v.value == value).name;
+ }
+
+ @override
+ Value deserialize(String serialized) {
+ return values.firstWhere((v) => v.name == serialized).value;
+ }
@override
ValidationResult validate(String key, String input) {
- var result = super.validate(key, input);
-
- if (result.successful &&
- !values.map((v) => v.name).contains(result.value)) {
- return result._asFailure()
- ..errors.add(
- '"${result.value}" is not a valid value for the enum "$name".');
+ if (!values.any((v) => v.name == input)) {
+ return new ValidationResult._failure(
+ ['"$input" is not a valid value for the enum "$name".']);
}
- return result;
+ return new ValidationResult._ok(input);
}
}
-class GraphQLEnumValue {
+class GraphQLEnumValue {
final String name;
+ final Value value;
final String deprecationReason;
- GraphQLEnumValue(this.name, {this.deprecationReason});
+ GraphQLEnumValue(this.name, this.value, {this.deprecationReason});
bool get isDeprecated => deprecationReason != null;
diff --git a/graphql_schema/test/validation_test.dart b/graphql_schema/test/validation_test.dart
index bfe23bed..ce29838c 100644
--- a/graphql_schema/test/validation_test.dart
+++ b/graphql_schema/test/validation_test.dart
@@ -2,7 +2,7 @@ import 'package:graphql_schema/graphql_schema.dart';
import 'package:test/test.dart';
void main() {
- var typeType = enumType('Type', [
+ var typeType = enumTypeFromStrings('Type', [
'FIRE',
'WATER',
'GRASS',
diff --git a/graphql_server/lib/mirrors.dart b/graphql_server/lib/mirrors.dart
index 362eb221..36e8ef34 100644
--- a/graphql_server/lib/mirrors.dart
+++ b/graphql_server/lib/mirrors.dart
@@ -9,7 +9,7 @@ import 'package:tuple/tuple.dart';
///
/// This function is aware of the annotations from `package:angel_serialize`, and works seamlessly
/// with them.
-GraphQLType objectTypeFromDartType(Type type, [List typeArguments]) {
+GraphQLType convertDartType(Type type, [List typeArguments]) {
var tuple = new Tuple2(type, typeArguments);
return _cache.putIfAbsent(
tuple, () => _objectTypeFromDartType(type, typeArguments));
@@ -44,7 +44,13 @@ GraphQLType _objectTypeFromDartType(Type type, [List typeArguments]) {
'$type is not a class, and therefore cannot be converted into a GraphQL object type.');
}
- return objectTypeFromClassMirror(mirror as ClassMirror);
+ var clazz = mirror as ClassMirror;
+
+ if (clazz.isEnum) {
+ return enumTypeFromClassMirror(clazz);
+ }
+
+ return objectTypeFromClassMirror(clazz);
}
GraphQLObjectType objectTypeFromClassMirror(ClassMirror mirror) {
@@ -69,9 +75,30 @@ GraphQLObjectType objectTypeFromClassMirror(ClassMirror mirror) {
);
}
+GraphQLEnumType enumTypeFromClassMirror(ClassMirror mirror) {
+ var values = [];
+
+ for (var name in mirror.staticMembers.keys) {
+ var methodMirror = mirror.staticMembers[name];
+ values.add(
+ new GraphQLEnumValue(
+ MirrorSystem.getName(name),
+ mirror.getField(name).reflectee,
+ deprecationReason: _getDeprecationReason(methodMirror.metadata),
+ ),
+ );
+ }
+
+ return new GraphQLEnumType(
+ MirrorSystem.getName(mirror.simpleName),
+ values,
+ description: _getDescription(mirror.metadata),
+ );
+}
+
GraphQLField fieldFromGetter(
Symbol name, MethodMirror mirror, Exclude exclude, ClassMirror clazz) {
- var type = objectTypeFromDartType(mirror.returnType.reflectedType,
+ var type = convertDartType(mirror.returnType.reflectedType,
mirror.returnType.typeArguments.map((t) => t.reflectedType).toList());
var nameString = _getSerializedName(name, mirror, clazz);
diff --git a/graphql_server/test/mirrors_test.dart b/graphql_server/test/mirrors_test.dart
new file mode 100644
index 00000000..f6cfeee5
--- /dev/null
+++ b/graphql_server/test/mirrors_test.dart
@@ -0,0 +1,46 @@
+import 'package:graphql_schema/graphql_schema.dart';
+import 'package:graphql_server/mirrors.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('convertDartType', () {
+ group('on enum', () {
+ var type = convertDartType(RomanceLanguage);
+ var asEnumType = type as GraphQLEnumType;
+
+ test('produces enum type', () {
+ expect(type is GraphQLEnumType, true);
+ });
+
+ test('rejects invalid value', () {
+ expect(asEnumType.validate('@root', 'GERMAN').successful, false);
+ });
+
+ test('accepts valid value', () {
+ expect(asEnumType.validate('@root', 'SPANISH').successful, true);
+ });
+
+ test('deserializes to concrete value', () {
+ expect(asEnumType.deserialize('ITALIAN'), RomanceLanguage.ITALIAN);
+ });
+
+ test('serializes to concrete value', () {
+ expect(asEnumType.serialize(RomanceLanguage.FRANCE), 'FRANCE');
+ });
+
+ test('fails to serialize invalid value', () {
+ expect(() => asEnumType.serialize(34), throwsStateError);
+ });
+
+ test('fails to deserialize invalid value', () {
+ expect(() => asEnumType.deserialize('JAPANESE'), throwsStateError);
+ });
+ });
+ });
+}
+
+enum RomanceLanguage {
+ SPANISH,
+ FRANCE,
+ ITALIAN,
+}