Fixed case of recursive types in mirrors
This commit is contained in:
parent
a2454be927
commit
cf9d94d123
20 changed files with 429 additions and 23 deletions
|
@ -3,6 +3,7 @@
|
|||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/angel_graphql/angel_graphql.iml" filepath="$PROJECT_DIR$/angel_graphql/angel_graphql.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/example_star_wars/example_star_wars.iml" filepath="$PROJECT_DIR$/example_star_wars/example_star_wars.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/graphql.iml" filepath="$PROJECT_DIR$/graphql.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/graphql_parser/graphql_parser.iml" filepath="$PROJECT_DIR$/graphql_parser/graphql_parser.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/graphql_schema/graphql_schema.iml" filepath="$PROJECT_DIR$/graphql_schema/graphql_schema.iml" />
|
||||
|
|
7
.idea/runConfigurations/server_dart.xml
Normal file
7
.idea/runConfigurations/server_dart.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="server.dart" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application" singleton="true" nameIsGenerated="true">
|
||||
<option name="filePath" value="$PROJECT_DIR$/example_star_wars/bin/server.dart" />
|
||||
<option name="workingDirectory" value="$PROJECT_DIR$/example_star_wars" />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
|
@ -56,7 +56,7 @@ main() async {
|
|||
);
|
||||
|
||||
app.all('/graphql', graphQLHttp(new GraphQL(schema)));
|
||||
app.get('/graphiql', graphiql());
|
||||
app.get('/graphiql', graphiQL());
|
||||
|
||||
await todoService
|
||||
.create({'text': 'Clean your room!', 'completion_status': 'COMPLETE'});
|
||||
|
|
|
@ -2,11 +2,15 @@ import 'dart:io';
|
|||
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
|
||||
RequestHandler graphiql({String graphqlEndpoint: '/graphql'}) {
|
||||
/// Returns a simple [RequestHandler] that renders the GraphiQL visual interface for GraphQL.
|
||||
///
|
||||
/// By default, the interface expects your backend to be mounted at `/graphql`; this is configurable
|
||||
/// via [graphQLEndpoint].
|
||||
RequestHandler graphiQL({String graphQLEndpoint: '/graphql'}) {
|
||||
return (req, res) {
|
||||
res
|
||||
..contentType = new ContentType('text', 'html')
|
||||
..write(renderGraphiql(graphqlEndpoint: graphqlEndpoint))
|
||||
..write(renderGraphiql(graphqlEndpoint: graphQLEndpoint))
|
||||
..end();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -15,7 +15,11 @@ final Validator graphQlPostBody = new Validator({
|
|||
'variables': predicate((v) => v == null || v is String || v is Map),
|
||||
});
|
||||
|
||||
RequestHandler graphQLHttp(GraphQL graphQl) {
|
||||
/// A [RequestHandler] that serves a spec-compliant GraphQL backend.
|
||||
///
|
||||
/// Follows the guidelines listed here:
|
||||
/// https://graphql.org/learn/serving-over-http/
|
||||
RequestHandler graphQLHttp(GraphQL graphQL) {
|
||||
return (req, res) async {
|
||||
executeMap(Map map) async {
|
||||
var text = req.body['query'] as String;
|
||||
|
@ -27,7 +31,7 @@ RequestHandler graphQLHttp(GraphQL graphQl) {
|
|||
}
|
||||
|
||||
return {
|
||||
'data': await graphQl.parseAndExecute(
|
||||
'data': await graphQL.parseAndExecute(
|
||||
text,
|
||||
sourceUrl: 'input',
|
||||
operationName: operationName,
|
||||
|
@ -45,7 +49,7 @@ RequestHandler graphQLHttp(GraphQL graphQl) {
|
|||
if (req.headers.contentType?.mimeType == graphQlContentType.mimeType) {
|
||||
var text = utf8.decode(await req.lazyOriginalBuffer());
|
||||
return {
|
||||
'data': await graphQl.parseAndExecute(text, sourceUrl: 'input')
|
||||
'data': await graphQL.parseAndExecute(text, sourceUrl: 'input')
|
||||
};
|
||||
} else if (req.headers.contentType?.mimeType == 'application/json') {
|
||||
if (await validate(graphQlPostBody)(req, res)) {
|
||||
|
|
93
example_star_wars/.gitignore
vendored
Normal file
93
example_star_wars/.gitignore
vendored
Normal file
|
@ -0,0 +1,93 @@
|
|||
# See https://www.dartlang.org/tools/private-files.html
|
||||
|
||||
# Files and directories created by pub
|
||||
.buildlog
|
||||
.packages
|
||||
.project
|
||||
.pub/
|
||||
.scripts-bin/
|
||||
build/
|
||||
**/packages/
|
||||
|
||||
# Files created by dart2js
|
||||
# (Most Dart developers will use pub build to compile Dart, use/modify these
|
||||
# rules if you intend to use dart2js directly
|
||||
# Convention is to use extension '.dart.js' for Dart compiled to Javascript to
|
||||
# differentiate from explicit Javascript files)
|
||||
*.dart.js
|
||||
*.part.js
|
||||
*.js.deps
|
||||
*.js.map
|
||||
*.info.json
|
||||
|
||||
# Directory created by dartdoc
|
||||
doc/api/
|
||||
|
||||
# Don't commit pubspec lock file
|
||||
# (Library packages only! Remove pattern if developing an application package)
|
||||
pubspec.lock
|
||||
### Dart template
|
||||
# See https://www.dartlang.org/tools/private-files.html
|
||||
|
||||
# Files and directories created by pub
|
||||
|
||||
# SDK 1.20 and later (no longer creates packages directories)
|
||||
|
||||
# Older SDK versions
|
||||
# (Include if the minimum SDK version specified in pubsepc.yaml is earlier than 1.20)
|
||||
|
||||
|
||||
# Files created by dart2js
|
||||
# (Most Dart developers will use pub build to compile Dart, use/modify these
|
||||
# rules if you intend to use dart2js directly
|
||||
# Convention is to use extension '.dart.js' for Dart compiled to Javascript to
|
||||
# differentiate from explicit Javascript files)
|
||||
|
||||
# Directory created by dartdoc
|
||||
|
||||
# Don't commit pubspec lock file
|
||||
# (Library packages only! Remove pattern if developing an application package)
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff:
|
||||
../.idea/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/dictionaries
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.xml
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
21
example_star_wars/LICENSE
Normal file
21
example_star_wars/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017 The Angel Framework
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
3
example_star_wars/analysis_options.yaml
Normal file
3
example_star_wars/analysis_options.yaml
Normal file
|
@ -0,0 +1,3 @@
|
|||
analyzer:
|
||||
strong-mode:
|
||||
implicit-casts: false
|
30
example_star_wars/bin/server.dart
Normal file
30
example_star_wars/bin/server.dart
Normal file
|
@ -0,0 +1,30 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_hot/angel_hot.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:star_wars/src/pretty_logging.dart' as star_wars;
|
||||
import 'package:star_wars/star_wars.dart' as star_wars;
|
||||
|
||||
main() async {
|
||||
Future<Angel> createServer() async {
|
||||
var app = new Angel()
|
||||
..lazyParseBodies = true
|
||||
..storeOriginalBuffer = true;
|
||||
app.logger = new Logger('star_wars')..onRecord.listen(star_wars.prettyLog);
|
||||
await app.configure(star_wars.configureServer);
|
||||
return app;
|
||||
}
|
||||
|
||||
hierarchicalLoggingEnabled = true;
|
||||
|
||||
var hot = new HotReloader(createServer, [new Directory('lib')]);
|
||||
|
||||
var server = await hot.startServer('127.0.0.1', 3000);
|
||||
var serverUrl =
|
||||
new Uri(scheme: 'http', host: server.address.address, port: server.port);
|
||||
var graphiQLUrl = serverUrl.replace(path: '/graphiql');
|
||||
print('Listening at $serverUrl');
|
||||
print('GraphiQL endpoint: $graphiQLUrl');
|
||||
}
|
14
example_star_wars/example_star_wars.iml
Normal file
14
example_star_wars/example_star_wars.iml
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
</content>
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Dart SDK" level="project" />
|
||||
<orderEntry type="library" name="Dart Packages" level="project" />
|
||||
</component>
|
||||
</module>
|
11
example_star_wars/lib/src/models/character.dart
Normal file
11
example_star_wars/lib/src/models/character.dart
Normal file
|
@ -0,0 +1,11 @@
|
|||
import 'episode.dart';
|
||||
|
||||
abstract class Character {
|
||||
String get id;
|
||||
|
||||
String get name;
|
||||
|
||||
List<Episode> get appearsIn;
|
||||
|
||||
List<Character> get friends;
|
||||
}
|
13
example_star_wars/lib/src/models/droid.dart
Normal file
13
example_star_wars/lib/src/models/droid.dart
Normal file
|
@ -0,0 +1,13 @@
|
|||
import 'package:angel_model/angel_model.dart';
|
||||
|
||||
import 'character.dart';
|
||||
import 'episode.dart';
|
||||
|
||||
class Droid extends Model implements Character {
|
||||
String name;
|
||||
List<Character> friends;
|
||||
List<Episode> appearsIn;
|
||||
String primaryFunction;
|
||||
|
||||
Droid({this.name, this.friends, this.appearsIn, this.primaryFunction});
|
||||
}
|
5
example_star_wars/lib/src/models/episode.dart
Normal file
5
example_star_wars/lib/src/models/episode.dart
Normal file
|
@ -0,0 +1,5 @@
|
|||
enum Episode {
|
||||
NEWHOPE,
|
||||
EMPIRE,
|
||||
JEDI,
|
||||
}
|
20
example_star_wars/lib/src/models/human.dart
Normal file
20
example_star_wars/lib/src/models/human.dart
Normal file
|
@ -0,0 +1,20 @@
|
|||
import 'package:angel_model/angel_model.dart';
|
||||
|
||||
import 'character.dart';
|
||||
import 'episode.dart';
|
||||
import 'starship.dart';
|
||||
|
||||
class Human extends Model implements Character {
|
||||
String name;
|
||||
List<Character> friends;
|
||||
List<Episode> appearsIn;
|
||||
List<Starship> starships;
|
||||
int totalCredits;
|
||||
|
||||
Human(
|
||||
{this.name,
|
||||
this.friends,
|
||||
this.appearsIn,
|
||||
this.starships,
|
||||
this.totalCredits});
|
||||
}
|
5
example_star_wars/lib/src/models/models.dart
Normal file
5
example_star_wars/lib/src/models/models.dart
Normal file
|
@ -0,0 +1,5 @@
|
|||
export 'character.dart';
|
||||
export 'droid.dart';
|
||||
export 'episode.dart';
|
||||
export 'human.dart';
|
||||
export 'starship.dart';
|
8
example_star_wars/lib/src/models/starship.dart
Normal file
8
example_star_wars/lib/src/models/starship.dart
Normal file
|
@ -0,0 +1,8 @@
|
|||
import 'package:angel_model/angel_model.dart';
|
||||
|
||||
class Starship extends Model {
|
||||
String name;
|
||||
int length;
|
||||
|
||||
Starship({this.name, this.length});
|
||||
}
|
35
example_star_wars/lib/src/pretty_logging.dart
Normal file
35
example_star_wars/lib/src/pretty_logging.dart
Normal file
|
@ -0,0 +1,35 @@
|
|||
import 'package:angel_http_exception/angel_http_exception.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:io/ansi.dart';
|
||||
|
||||
/// Prints the contents of a [LogRecord] with pretty colors.
|
||||
void prettyLog(LogRecord record) {
|
||||
var code = chooseLogColor(record.level);
|
||||
|
||||
if (record.error == null) print(code.wrap(record.toString()));
|
||||
|
||||
if (record.error != null) {
|
||||
var err = record.error;
|
||||
if (err is AngelHttpException && err.statusCode != 500) return;
|
||||
print(code.wrap(record.toString() + '\n'));
|
||||
print(code.wrap(err.toString()));
|
||||
|
||||
if (record.stackTrace != null) {
|
||||
print(code.wrap(record.stackTrace.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Chooses a color based on the logger [level].
|
||||
AnsiCode chooseLogColor(Level level) {
|
||||
if (level == Level.SHOUT)
|
||||
return backgroundRed;
|
||||
else if (level == Level.SEVERE)
|
||||
return red;
|
||||
else if (level == Level.WARNING)
|
||||
return yellow;
|
||||
else if (level == Level.INFO)
|
||||
return cyan;
|
||||
else if (level == Level.FINER || level == Level.FINEST) return lightGray;
|
||||
return resetAll;
|
||||
}
|
55
example_star_wars/lib/star_wars.dart
Normal file
55
example_star_wars/lib/star_wars.dart
Normal file
|
@ -0,0 +1,55 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_graphql/angel_graphql.dart';
|
||||
import 'package:graphql_schema/graphql_schema.dart';
|
||||
import 'package:graphql_server/graphql_server.dart';
|
||||
import 'package:graphql_server/mirrors.dart';
|
||||
|
||||
import 'src/models/models.dart';
|
||||
|
||||
Future configureServer(Angel app) async {
|
||||
// Create standard Angel services. Note that these will also *automatically* be
|
||||
// exposed via a REST API as well.
|
||||
var droidService = mountService<Droid>(app, '/api/droids');
|
||||
var humansService = mountService<Human>(app, '/api/humans');
|
||||
var starshipService = mountService<Starship>(app, '/api/starships');
|
||||
|
||||
// Create the GraphQL schema.
|
||||
// This code uses dart:mirrors to easily create GraphQL types from Dart PODO's.
|
||||
//var droidType = convertDartType(Droid);
|
||||
//var episodeType = convertDartType(Episode);
|
||||
var humanType = convertDartType(Human);
|
||||
|
||||
// Create the query type.
|
||||
//
|
||||
// Use the `resolveViaServiceIndex` helper to load data directly from an
|
||||
// Angel service.
|
||||
var queryType = objectType('StarWarsQuery', fields: [
|
||||
field(
|
||||
'humans',
|
||||
type: listType(humanType.nonNullable()),
|
||||
resolve: resolveViaServiceIndex(humansService),
|
||||
),
|
||||
]);
|
||||
|
||||
// Finally, create the schema.
|
||||
var schema = graphQLSchema(query: queryType);
|
||||
|
||||
// Next, create a GraphQL object, which will be passed to `graphQLHttp`, and
|
||||
// used to mount a spec-compliant GraphQL endpoint on the server.
|
||||
var graphQL = new GraphQL(schema);
|
||||
|
||||
// Mount the GraphQL endpoint.
|
||||
app.all('/graphql', graphQLHttp(graphQL));
|
||||
|
||||
// In development, we'll want to mount GraphiQL, for easy management of the database.
|
||||
if (!app.isProduction) {
|
||||
app.get('/graphiql', graphiQL());
|
||||
}
|
||||
}
|
||||
|
||||
Service mountService<T extends Model>(Angel app, String path) => app.use(
|
||||
path,
|
||||
new TypedService(new MapService(
|
||||
autoIdAndDateFields: false, autoSnakeCaseNames: false))) as Service;
|
8
example_star_wars/pubspec.yaml
Normal file
8
example_star_wars/pubspec.yaml
Normal file
|
@ -0,0 +1,8 @@
|
|||
name: star_wars
|
||||
publish_to: none
|
||||
dependencies:
|
||||
#angel_file_service: ^1.0.0
|
||||
angel_graphql:
|
||||
path: ../angel_graphql
|
||||
angel_hot: ^1.0.0
|
||||
io: ^0.3.2
|
|
@ -3,20 +3,21 @@ import 'dart:mirrors';
|
|||
import 'package:angel_serialize/angel_serialize.dart';
|
||||
import 'package:graphql_schema/graphql_schema.dart';
|
||||
import 'package:recase/recase.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
/// Reflects upon a given [type] and dynamically generates a [GraphQLType] that corresponds to it.
|
||||
///
|
||||
/// This function is aware of the annotations from `package:angel_serialize`, and works seamlessly
|
||||
/// with them.
|
||||
GraphQLType convertDartType(Type type, [List<Type> typeArguments]) {
|
||||
var tuple = new Tuple2(type, typeArguments);
|
||||
return _cache.putIfAbsent(
|
||||
tuple, () => _objectTypeFromDartType(type, typeArguments));
|
||||
if (_cache[type] != null) {
|
||||
return _cache[type];
|
||||
} else {
|
||||
return _objectTypeFromDartType(type, typeArguments);
|
||||
}
|
||||
}
|
||||
|
||||
final Map<Tuple2<Type, List<Type>>, GraphQLType> _cache =
|
||||
<Tuple2<Type, List<Type>>, GraphQLType>{};
|
||||
final Map<Type, GraphQLType> _cache =
|
||||
<Type, GraphQLType>{};
|
||||
|
||||
GraphQLType _objectTypeFromDartType(Type type, [List<Type> typeArguments]) {
|
||||
if (type == bool) {
|
||||
|
@ -46,6 +47,17 @@ GraphQLType _objectTypeFromDartType(Type type, [List<Type> typeArguments]) {
|
|||
|
||||
var clazz = mirror as ClassMirror;
|
||||
|
||||
if (clazz.isAssignableTo(reflectType(Iterable))) {
|
||||
if (clazz.typeArguments.isNotEmpty) {
|
||||
var inner = convertDartType(clazz.typeArguments[0].reflectedType);
|
||||
//if (inner == null) return null;
|
||||
return listType(inner.nonNullable());
|
||||
}
|
||||
|
||||
throw new ArgumentError(
|
||||
'Cannot convert ${clazz.reflectedType}, an iterable WITHOUT a type argument, into a GraphQL type.');
|
||||
}
|
||||
|
||||
if (clazz.isEnum) {
|
||||
return enumTypeFromClassMirror(clazz);
|
||||
}
|
||||
|
@ -54,7 +66,14 @@ GraphQLType _objectTypeFromDartType(Type type, [List<Type> typeArguments]) {
|
|||
}
|
||||
|
||||
GraphQLObjectType objectTypeFromClassMirror(ClassMirror mirror) {
|
||||
if (_cache[mirror.reflectedType] != null) {
|
||||
return _cache[mirror.reflectedType] as GraphQLObjectType;
|
||||
} else {
|
||||
}
|
||||
|
||||
var fields = <GraphQLField>[];
|
||||
var ready = <Symbol, MethodMirror>{};
|
||||
var forward = <Symbol, MethodMirror>{};
|
||||
|
||||
void walkMap(Map<Symbol, MethodMirror> map) {
|
||||
for (var name in map.keys) {
|
||||
|
@ -64,13 +83,47 @@ GraphQLObjectType objectTypeFromClassMirror(ClassMirror mirror) {
|
|||
name != #runtimeType &&
|
||||
!methodMirror.isPrivate &&
|
||||
exclude?.canSerialize != true;
|
||||
|
||||
if (methodMirror.isGetter && canAdd) {
|
||||
fields.add(fieldFromGetter(name, methodMirror, exclude, mirror));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
walkMap(mirror.instanceMembers);
|
||||
bool isReady(TypeMirror returnType) {
|
||||
var canContinue = returnType.reflectedType != mirror.reflectedType;
|
||||
|
||||
if (canContinue &&
|
||||
returnType.isAssignableTo(reflectType(Iterable)) &&
|
||||
returnType.typeArguments.isNotEmpty &&
|
||||
!isReady(returnType.typeArguments[0])) {
|
||||
canContinue = false;
|
||||
}
|
||||
|
||||
return canContinue;
|
||||
}
|
||||
|
||||
void prepReadyForward(Map<Symbol, MethodMirror> map) {
|
||||
map.forEach((name, methodMirror) {
|
||||
if (methodMirror.isGetter &&
|
||||
name != #_identityHashCode &&
|
||||
name != #runtimeType &&
|
||||
name != #hashCode &&
|
||||
MirrorSystem.getName(name) != '_identityHashCode') {
|
||||
var returnType = methodMirror.returnType;
|
||||
|
||||
if (isReady(returnType)) {
|
||||
ready[name] = methodMirror;
|
||||
} else {
|
||||
forward[name] = methodMirror;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
prepReadyForward(mirror.instanceMembers);
|
||||
|
||||
walkMap(ready);
|
||||
|
||||
if (mirror.isAbstract) {
|
||||
var decls = <Symbol, MethodMirror>{};
|
||||
|
@ -81,7 +134,11 @@ GraphQLObjectType objectTypeFromClassMirror(ClassMirror mirror) {
|
|||
}
|
||||
});
|
||||
|
||||
walkMap(decls);
|
||||
ready.clear();
|
||||
forward.clear();
|
||||
prepReadyForward(decls);
|
||||
walkMap(ready);
|
||||
//walkMap(decls);
|
||||
}
|
||||
|
||||
var inheritsFrom = <GraphQLObjectType>[];
|
||||
|
@ -116,13 +173,21 @@ GraphQLObjectType objectTypeFromClassMirror(ClassMirror mirror) {
|
|||
walk(mirror.superclass);
|
||||
mirror.superinterfaces.forEach(walk);
|
||||
|
||||
return objectType(
|
||||
MirrorSystem.getName(mirror.simpleName),
|
||||
fields: fields,
|
||||
isInterface: mirror.isAbstract,
|
||||
interfaces: inheritsFrom,
|
||||
description: _getDescription(mirror.metadata),
|
||||
);
|
||||
var result = _cache[mirror.reflectedType];
|
||||
|
||||
if (result == null) {
|
||||
result = objectType(
|
||||
MirrorSystem.getName(mirror.simpleName),
|
||||
fields: fields,
|
||||
isInterface: mirror.isAbstract,
|
||||
interfaces: inheritsFrom,
|
||||
description: _getDescription(mirror.metadata),
|
||||
);
|
||||
_cache[mirror.reflectedType] = result;
|
||||
walkMap(forward);
|
||||
}
|
||||
|
||||
return result as GraphQLObjectType;
|
||||
}
|
||||
|
||||
GraphQLEnumType enumTypeFromClassMirror(ClassMirror mirror) {
|
||||
|
@ -155,8 +220,12 @@ GraphQLField fieldFromGetter(
|
|||
var wasProvided = type != null;
|
||||
|
||||
if (!wasProvided) {
|
||||
type = convertDartType(mirror.returnType.reflectedType,
|
||||
mirror.returnType.typeArguments.map((t) => t.reflectedType).toList());
|
||||
var returnType = mirror.returnType;
|
||||
|
||||
if (!clazz.isAssignableTo(returnType)) {
|
||||
type = convertDartType(returnType.reflectedType,
|
||||
mirror.returnType.typeArguments.map((t) => t.reflectedType).toList());
|
||||
}
|
||||
}
|
||||
|
||||
var nameString = _getSerializedName(name, mirror, clazz);
|
||||
|
|
Loading…
Reference in a new issue