diff --git a/CHANGELOG.md b/CHANGELOG.md index 10664362..b3b65de5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ - operation name constant +## 7.6.2-beta + +- generate_queries flag to signify if query documents and operation names should be generated + +## 7.6.1-beta + +- operation name constant + ## 7.6.0-beta - package updates diff --git a/README.md b/README.md index e57dbeef..e147d724 100644 --- a/README.md +++ b/README.md @@ -85,15 +85,20 @@ targets: > ⚠️ Make sure your configuration file is called `build.yaml` (with `.yaml` extension, not `.yml`)! -| Option | Default value | Description | -| - | - | - | -| `generate_helpers` | `true` | If Artemis should generate query/mutation helper GraphQLQuery subclasses. | -| `scalar_mapping` | `[]` | Mapping of GraphQL and Dart types. See [Custom scalars](#custom-scalars). | -| `schema_mapping` | `[]` | Mapping of queries and which schemas they will use for code generation. See [Schema mapping](#schema-mapping). | -| `fragments_glob` | `null` | Import path to the file implementing fragments for all queries mapped in schema_mapping. If it's assigned, fragments defined in schema_mapping will be ignored. | -| `ignore_for_file` | `[]` | The linter rules to ignore for artemis generated files. | - -It's important to remember that, by default, [build](https://github.com/dart-lang/build) will follow [Dart's package layout conventions](https://dart.dev/tools/pub/package-layout), meaning that only some folders will be considered to parse the input files. So, if you want to reference files from a folder other than `lib/`, make sure you've included it on `sources`: +| Option | Default value | Description | | - | - | - | | `generate_helpers` | `true` | If Artemis should generate +query/mutation helper GraphQLQuery subclasses. | | `generate_queries` | `true` | If Artemis should generate query +documents and operation names. If you are using Artemis with `graphql` library it is useful to have those queries and +operation names generated but without Atremis specific classes to exclude Artemis from dependancies | | `scalar_mapping` +| `[]` | Mapping of GraphQL and Dart types. See [Custom scalars](#custom-scalars). | | `schema_mapping` | `[]` | Mapping +of queries and which schemas they will use for code generation. See [Schema mapping](#schema-mapping). | +| `fragments_glob` | `null` | Import path to the file implementing fragments for all queries mapped in schema_mapping. +If it's assigned, fragments defined in schema_mapping will be ignored. | | `ignore_for_file` | `[]` | The linter rules +to ignore for artemis generated files. | + +It's important to remember that, by default, [build](https://github.com/dart-lang/build) will +follow [Dart's package layout conventions](https://dart.dev/tools/pub/package-layout), meaning that only some folders +will be considered to parse the input files. So, if you want to reference files from a folder other than `lib/`, make +sure you've included it on `sources`: ```yaml targets: $default: diff --git a/lib/generator.dart b/lib/generator.dart index 13854e55..d80ff96e 100644 --- a/lib/generator.dart +++ b/lib/generator.dart @@ -259,6 +259,7 @@ Iterable generateDefinitions({ ], inputs: visitor.context.inputsClasses, generateHelpers: options.generateHelpers, + generateQueries: options.generateQueries, suffix: suffix, ); }); diff --git a/lib/generator/data/query_definition.dart b/lib/generator/data/query_definition.dart index d478974a..12ff8086 100644 --- a/lib/generator/data/query_definition.dart +++ b/lib/generator/data/query_definition.dart @@ -23,6 +23,9 @@ class QueryDefinition extends Definition with DataPrinter { /// If instances of [GraphQLQuery] should be generated. final bool generateHelpers; + /// If query documents and operation names should be generated + final bool generateQueries; + /// The suffix of generated [GraphQLQuery] classes. final String suffix; @@ -34,6 +37,7 @@ class QueryDefinition extends Definition with DataPrinter { this.classes = const [], this.inputs = const [], this.generateHelpers = false, + this.generateQueries = false, this.suffix = 'Query', }) : assert(hasValue(operationName)), super(name: name); @@ -41,6 +45,13 @@ class QueryDefinition extends Definition with DataPrinter { /// class name for helper classes String? get className => ClassName(name: operationName).namePrintable; + /// name for document constant + String get documentName => '$className${suffix}Document'; + + /// name for document operation name constant + String get documentOperationName => + '$className${suffix}DocumentOperationName'; + @override Map get namedProps => { 'name': name, diff --git a/lib/generator/print_helpers.dart b/lib/generator/print_helpers.dart index add9f560..168d06ea 100644 --- a/lib/generator/print_helpers.dart +++ b/lib/generator/print_helpers.dart @@ -275,16 +275,24 @@ Spec generateArgumentClassSpec(QueryDefinition definition) { ); } +Spec generateQuerySpec(QueryDefinition definition) { + return Block((b) => b + ..statements.addAll([ + Code( + "final ${definition.documentOperationName.constantCase} = '${definition.operationName}';"), + Code('final ${definition.documentName.constantCase} = '), + dart.fromNode(definition.document).code, + Code(';'), + ])); +} + /// Generates a [Spec] of a query/mutation class. -List generateQueryClassSpec(QueryDefinition definition) { +Spec generateQueryClassSpec(QueryDefinition definition) { final typeDeclaration = definition.inputs.isEmpty ? '${definition.name.namePrintable}, JsonSerializable' : '${definition.name.namePrintable}, ${definition.className}Arguments'; final name = '${definition.className}${definition.suffix}'; - final documentName = ReCase('${name}Document').constantCase; - final documentOperationName = - ReCase('${name}DocumentOperationName').constantCase; final constructor = definition.inputs.isEmpty ? Constructor() @@ -304,7 +312,7 @@ List generateQueryClassSpec(QueryDefinition definition) { ..modifier = FieldModifier.final$ ..type = refer('DocumentNode', 'package:gql/ast.dart') ..name = 'document' - ..assignment = Code(documentName), + ..assignment = Code(definition.documentName.constantCase), ), Field( (f) => f @@ -312,7 +320,7 @@ List generateQueryClassSpec(QueryDefinition definition) { ..modifier = FieldModifier.final$ ..type = refer('String') ..name = 'operationName' - ..assignment = Code(documentOperationName), + ..assignment = Code(definition.documentOperationName.constantCase), ), ]; @@ -326,39 +334,30 @@ List generateQueryClassSpec(QueryDefinition definition) { )); } - return [ - Block((b) => b - ..statements.addAll([ - Code("final $documentOperationName = '${definition.operationName}';"), - Code('final $documentName = '), - dart.fromNode(definition.document).code, - Code(';'), - ])), - Class( - (b) => b - ..name = name - ..extend = refer('GraphQLQuery<$typeDeclaration>') - ..constructors.add(constructor) - ..fields.addAll(fields) - ..methods.add(_propsMethod([ - 'document', - 'operationName${definition.inputs.isNotEmpty ? ', variables' : ''}' - ])) - ..methods.add(Method( - (m) => m - ..annotations.add(CodeExpression(Code('override'))) - ..returns = refer(definition.name.namePrintable) - ..name = 'parse' - ..requiredParameters.add(Parameter( - (p) => p - ..type = refer('Map') - ..name = 'json', - )) - ..lambda = true - ..body = Code('${definition.name.namePrintable}.fromJson(json)'), - )), - ) - ]; + return Class( + (b) => b + ..name = name + ..extend = refer('GraphQLQuery<$typeDeclaration>') + ..constructors.add(constructor) + ..fields.addAll(fields) + ..methods.add(_propsMethod([ + 'document', + 'operationName${definition.inputs.isNotEmpty ? ', variables' : ''}' + ])) + ..methods.add(Method( + (m) => m + ..annotations.add(CodeExpression(Code('override'))) + ..returns = refer(definition.name.namePrintable) + ..name = 'parse' + ..requiredParameters.add(Parameter( + (p) => p + ..type = refer('Map') + ..name = 'json', + )) + ..lambda = true + ..body = Code('${definition.name.namePrintable}.fromJson(json)'), + )), + ); } /// Gathers and generates a [Spec] of a whole query/mutation and its @@ -405,11 +404,17 @@ Spec generateLibrarySpec(LibraryDefinition definition) { bodyDirectives.addAll(enums.map(enumDefinitionToSpec)); for (final queryDef in definition.queries) { - if (queryDef.inputs.isNotEmpty && queryDef.generateHelpers) { + if (queryDef.inputs.isNotEmpty && + (queryDef.generateHelpers || queryDef.generateQueries)) { bodyDirectives.add(generateArgumentClassSpec(queryDef)); } + + if (queryDef.generateHelpers || queryDef.generateQueries) { + bodyDirectives.add(generateQuerySpec(queryDef)); + } + if (queryDef.generateHelpers) { - bodyDirectives.addAll(generateQueryClassSpec(queryDef)); + bodyDirectives.add(generateQueryClassSpec(queryDef)); } } diff --git a/lib/schema/options.dart b/lib/schema/options.dart index d0756df3..fe85273d 100644 --- a/lib/schema/options.dart +++ b/lib/schema/options.dart @@ -12,6 +12,10 @@ class GeneratorOptions { @JsonKey(defaultValue: true) final bool generateHelpers; + /// If query documents and operation names should be generated + @JsonKey(defaultValue: true) + final bool generateQueries; + /// A list of scalar mappings. @JsonKey(defaultValue: []) final List scalarMapping; @@ -31,6 +35,7 @@ class GeneratorOptions { /// Instantiate generator options. GeneratorOptions({ this.generateHelpers = true, + this.generateQueries = true, this.scalarMapping = const [], this.fragmentsGlob, this.schemaMapping = const [], diff --git a/lib/schema/options.g2.dart b/lib/schema/options.g2.dart index 4feec2d9..4b03cbe3 100644 --- a/lib/schema/options.g2.dart +++ b/lib/schema/options.g2.dart @@ -9,6 +9,7 @@ part of 'options.dart'; GeneratorOptions _$GeneratorOptionsFromJson(Map json) { return GeneratorOptions( generateHelpers: json['generate_helpers'] as bool? ?? true, + generateQueries: json['generate_queries'] as bool? ?? true, scalarMapping: (json['scalar_mapping'] as List?) ?.map((e) => e == null ? null @@ -31,6 +32,7 @@ GeneratorOptions _$GeneratorOptionsFromJson(Map json) { Map _$GeneratorOptionsToJson(GeneratorOptions instance) => { 'generate_helpers': instance.generateHelpers, + 'generate_queries': instance.generateQueries, 'scalar_mapping': instance.scalarMapping, 'fragments_glob': instance.fragmentsGlob, 'schema_mapping': instance.schemaMapping, diff --git a/pubspec.yaml b/pubspec.yaml index 98f2db4d..4ad7a55b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: artemis -version: 7.6.1-beta +version: 7.6.2-beta description: Build dart types from GraphQL schemas and queries (using Introspection Query). homepage: https://github.com/comigor/artemis diff --git a/test/generator/print_helpers_test.dart b/test/generator/print_helpers_test.dart index fc8d7595..dcf8c09e 100644 --- a/test/generator/print_helpers_test.dart +++ b/test/generator/print_helpers_test.dart @@ -501,6 +501,46 @@ class TestQueryQuery extends GraphQLQuery { '''); }); + test( + 'When generateHelpers is false and generateQueries is true, an execute fn is generated.', + () { + final buffer = StringBuffer(); + final definition = LibraryDefinition( + basename: r'test_query.graphql', + queries: [ + QueryDefinition( + name: QueryName(name: 'test_query'), + operationName: 'test_query', + document: parseString('query test_query {}'), + generateHelpers: false, + generateQueries: true, + ) + ], + ); + final ignoreForFile = []; + + writeLibraryDefinitionToBuffer(buffer, ignoreForFile, definition); + + expect(buffer.toString(), '''// GENERATED CODE - DO NOT MODIFY BY HAND +// @dart = 2.12 + +import 'package:json_annotation/json_annotation.dart'; +import 'package:equatable/equatable.dart'; +import 'package:gql/ast.dart'; +part 'test_query.graphql.g.dart'; + +final TEST_QUERY_QUERY_DOCUMENT_OPERATION_NAME = 'test_query'; +final TEST_QUERY_QUERY_DOCUMENT = DocumentNode(definitions: [ + OperationDefinitionNode( + type: OperationType.query, + name: NameNode(value: 'test_query'), + variableDefinitions: [], + directives: [], + selectionSet: SelectionSetNode(selections: [])) +]); +'''); + }); + test('The generated execute fn could have input.', () { final buffer = StringBuffer(); final definition = @@ -621,8 +661,8 @@ class TestQueryArguments extends JsonSerializable with EquatableMixin { suffix: 'Query', ); - final str = - generateQueryClassSpec(definition).map((e) => specToString(e)).join(); + final str = specToString(generateQuerySpec(definition)) + + specToString(generateQueryClassSpec(definition)); expect(str, r'''final TEST_QUERY_QUERY_DOCUMENT_OPERATION_NAME = 'test_query'; diff --git a/test/helpers.dart b/test/helpers.dart index e2265e7a..f929be09 100644 --- a/test/helpers.dart +++ b/test/helpers.dart @@ -17,6 +17,7 @@ Future testGenerator({ String namingScheme = 'pathedWithTypes', bool appendTypeName = false, bool generateHelpers = false, + bool generateQueries = false, Map builderOptionsMap = const {}, Map sourceAssetsMap = const {}, Map outputsMap = const {}, @@ -25,6 +26,7 @@ Future testGenerator({ final anotherBuilder = graphQLQueryBuilder(BuilderOptions({ if (!generateHelpers) 'generate_helpers': false, + if (!generateQueries) 'generate_queries': false, 'schema_mapping': [ { 'schema': 'api.schema.graphql', @@ -66,6 +68,7 @@ Future testNaming({ }) { final anotherBuilder = graphQLQueryBuilder(BuilderOptions({ 'generate_helpers': false, + 'generate_queries': false, 'schema_mapping': [ { 'schema': 'api.schema.graphql',