Skip to content
This repository has been archived by the owner on Oct 2, 2024. It is now read-only.

Commit

Permalink
Merge pull request #158 from comigor/feature/multiple-operations-per-…
Browse files Browse the repository at this point in the history
…file

allow multiple operations per file
  • Loading branch information
comigor authored Jul 27, 2020
2 parents 65a833d + 06cfa6f commit d490277
Show file tree
Hide file tree
Showing 4 changed files with 619 additions and 101 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# CHANGELOG

## 6.6.1-beta.1
- allow multiple operations per file

## 6.5.2-beta.1
- performance improvements - scan schema for canonical types only once

Expand Down
210 changes: 110 additions & 100 deletions lib/generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,21 @@ LibraryDefinition generateLibrary(
List<FragmentDefinitionNode> fragmentsCommon,
DocumentNode schema,
) {
final queriesDefinitions = gqlDocs
.map((doc) => generateQuery(
final queryDefinitions = gqlDocs
.map((doc) => generateDefinitions(
schema,
path,
doc,
options,
schemaMap,
fragmentsCommon,
))
.expand((e) => e)
.toList();

final allClassesNames = queriesDefinitions
// final queryDefinitions = definitions.expand((e) => e).toList();

final allClassesNames = queryDefinitions
.map((def) => def.classes.map((c) => c))
.expand((e) => e)
.toList();
Expand All @@ -63,7 +66,7 @@ LibraryDefinition generateLibrary(
final customImports = _extractCustomImports(schema, options);
return LibraryDefinition(
basename: basename,
queries: queriesDefinitions,
queries: queryDefinitions,
customImports: customImports,
);
}
Expand Down Expand Up @@ -100,17 +103,14 @@ _CanonicalVisitor _canonicalVisitor;

/// Generate a query definition from a GraphQL schema and a query, given
/// Artemis options and schema mappings.
QueryDefinition generateQuery(
Iterable<QueryDefinition> generateDefinitions(
DocumentNode schema,
String path,
DocumentNode document,
GeneratorOptions options,
SchemaMap schemaMap,
List<FragmentDefinitionNode> fragmentsCommon,
) {
final operation =
document.definitions.whereType<OperationDefinitionNode>().first;

final fragments = <FragmentDefinitionNode>[];

final documentFragments =
Expand All @@ -120,107 +120,117 @@ QueryDefinition generateQuery(
throw FragmentIgnoreException();
}

if (fragmentsCommon.isEmpty) {
fragments.addAll(documentFragments);
} else {
final fragmentsOperation =
_extractFragments(operation.selectionSet, fragmentsCommon);
document.definitions.addAll(fragmentsOperation);
fragments.addAll(fragmentsOperation);
}

final basename = p.basenameWithoutExtension(path).split('.').first;
final operationName = operation.name?.value ?? basename;

final schemaVisitor = SchemaDefinitionVisitor();
final objectVisitor = ObjectTypeDefinitionVisitor();

schema.accept(schemaVisitor);
schema.accept(objectVisitor);

String suffix;
switch (operation.type) {
case OperationType.subscription:
suffix = 'Subscription';
break;
case OperationType.mutation:
suffix = 'Mutation';
break;
case OperationType.query:
default:
suffix = 'Query';
break;
}
final operations =
document.definitions.whereType<OperationDefinitionNode>().toList();

final rootTypeName = (schemaVisitor.schemaDefinitionNode?.operationTypes ??
[])
.firstWhere((e) => e.operation == operation.type, orElse: () => null)
?.type
?.name
?.value ??
suffix;
return operations.map((operation) {
if (fragmentsCommon.isEmpty) {
fragments.addAll(documentFragments);
} else {
final fragmentsOperation =
_extractFragments(operation.selectionSet, fragmentsCommon);
document.definitions.addAll(fragmentsOperation);
fragments.addAll(fragmentsOperation);
}

if (rootTypeName == null) {
throw Exception(
'''No root type was found for ${operation.type} $operationName.''');
}
final basename = p.basenameWithoutExtension(path).split('.').first;
final operationName = operation.name?.value ?? basename;

final schemaVisitor = SchemaDefinitionVisitor();
final objectVisitor = ObjectTypeDefinitionVisitor();

schema.accept(schemaVisitor);
schema.accept(objectVisitor);

String suffix;
switch (operation.type) {
case OperationType.subscription:
suffix = 'Subscription';
break;
case OperationType.mutation:
suffix = 'Mutation';
break;
case OperationType.query:
default:
suffix = 'Query';
break;
}

final TypeDefinitionNode parentType = objectVisitor.getByName(rootTypeName);

final name = QueryName.fromPath(
path: createPathName([
ClassName(name: operationName),
ClassName(name: parentType.name.value)
], schemaMap.namingScheme));

final context = Context(
schema: schema,
options: options,
schemaMap: schemaMap,
path: [
TypeName(name: operationName),
TypeName(name: parentType.name.value)
],
currentType: parentType,
currentFieldName: null,
currentClassName: null,
generatedClasses: [],
inputsClasses: [],
fragments: fragments,
usedEnums: {},
usedInputObjects: {},
);
final rootTypeName =
(schemaVisitor.schemaDefinitionNode?.operationTypes ?? [])
.firstWhere((e) => e.operation == operation.type,
orElse: () => null)
?.type
?.name
?.value ??
suffix;

if (rootTypeName == null) {
throw Exception(
'''No root type was found for ${operation.type} $operationName.''');
}

final visitor = _GeneratorVisitor(
context: context,
);
final TypeDefinitionNode parentType = objectVisitor.getByName(rootTypeName);

final name = QueryName.fromPath(
path: createPathName([
ClassName(name: operationName),
ClassName(name: parentType.name.value)
], schemaMap.namingScheme));

final context = Context(
schema: schema,
options: options,
schemaMap: schemaMap,
path: [
TypeName(name: operationName),
TypeName(name: parentType.name.value)
],
currentType: parentType,
currentFieldName: null,
currentClassName: null,
generatedClasses: [],
inputsClasses: [],
fragments: fragments,
usedEnums: {},
usedInputObjects: {},
);

// scans schema for canonical types only once
if (_canonicalVisitor == null) {
_canonicalVisitor = _CanonicalVisitor(
context: context.sameTypeWithNoPath(),
final visitor = _GeneratorVisitor(
context: context,
);
// scans schema for canonical types only once
if (_canonicalVisitor == null) {
_canonicalVisitor = _CanonicalVisitor(
context: context.sameTypeWithNoPath(),
);

schema.accept(_canonicalVisitor);
}
schema.accept(_canonicalVisitor);
}

document.accept(visitor);
DocumentNode(
definitions: document.definitions
// filtering unused operations
.where((e) => e is! OperationDefinitionNode || e == operation)
.toList(),
).accept(visitor);

return QueryDefinition(
name: name,
operationName: operationName,
document: document,
classes: [
..._canonicalVisitor.enums
.where((e) => context.usedEnums.contains(e.name)),
...visitor.context.generatedClasses,
..._canonicalVisitor.inputObjects
.where((i) => context.usedInputObjects.contains(i.name)),
],
inputs: visitor.context.inputsClasses,
generateHelpers: options.generateHelpers,
suffix: suffix,
);
return QueryDefinition(
name: name,
operationName: operationName,
document: document,
classes: [
..._canonicalVisitor.enums
.where((e) => context.usedEnums.contains(e.name)),
...visitor.context.generatedClasses,
..._canonicalVisitor.inputObjects
.where((i) => context.usedInputObjects.contains(i.name)),
],
inputs: visitor.context.inputsClasses,
generateHelpers: options.generateHelpers,
suffix: suffix,
);
});
}

List<String> _extractCustomImports(
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: artemis
version: 6.5.2-beta.1
version: 6.6.1-beta.1

authors:
- Igor Borges <[email protected]>
Expand Down
Loading

0 comments on commit d490277

Please sign in to comment.