Build dart types from GraphQL schemas and queries

Overview

Artemis

Build dart types from GraphQL schemas and queries

View at pub.dev Test PRs Welcome Star on GitHub Fork on GitHub Discord

Check the beta branch for the bleeding edge (and breaking) stuff.

Artemis is a code generator that looks for schema.graphql (GraphQL SDL - Schema Definition Language) and *.graphql files and builds .graphql.dart files typing that query, based on the schema. That's similar to what Apollo does (Artemis is his sister anyway).


Installation

Add the following to your pubspec.yaml file to be able to do code generation:

dev_dependencies:
  artemis: '>=6.0.0 <7.0.0'
  build_runner: ^1.10.4
  json_serializable: ^3.5.0

The generated code uses the following packages in run-time:

dependencies:
  artemis: '>=6.0.0 <7.0.0' # only if you're using ArtemisClient!
  json_annotation: ^3.1.0
  equatable: ^1.2.5
  meta: '>=1.0.0 <2.0.0' # only if you have non nullable fields
  gql: '>=0.12.3 <1.0.0'

Then run:

pub packages get

or

flutter packages get

Now Artemis will generate the API files for you by running:

pub run build_runner build

or

flutter pub run build_runner build

Configuration

Artemis offers some configuration options to generate code. All options should be included on build.yaml file on the root of the project:

targets:
  $default:
    builders:
      artemis:
        options:
          # custom configuration options!

⚠️ 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.
schema_mapping [] Mapping of queries and which schemas they will use for code generation. See 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 will follow Dart's package layout conventions, 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:

targets:
  $default:
    sources:
      - lib/**
      - graphql/**
      - data/**
      - schema.graphql

Schema mapping

By default, Artemis won't generate anything. That's because your queries/mutations should be linked to GraphQL schemas. To configure it, you need to point a schema_mapping to the path of those queries and schemas:

targets:
  $default:
    builders:
      artemis:
        options:
          schema_mapping:
            - output: lib/graphql_api.dart
              schema: lib/my_graphql_schema.graphql
              queries_glob: lib/**.graphql

Each SchemaMap is configured this way:

Option Default value Description
output Relative path to output the generated code. It should end with .graphql.dart or else the generator will need to generate one more file.
schema Relative path to the GraphQL schema.
queries_glob Glob that selects all query files to be used with this schema.
naming_scheme pathedWithTypes The naming scheme to be used on generated classes names. pathedWithTypes is the default for retrocompatibility, where the names of previous types are used as prefix of the next class. This can generate duplication on certain schemas. With pathedWithFields, the names of previous fields are used as prefix of the next class and with simple, only the actual GraphQL class name is considered.
type_name_field __typename The name of the field used to differentiatiate interfaces and union types (commonly __typename or __resolveType). Note that __typename field are not added automatically to the query. If you want interface/union type resolution, you need to manually add it there.

See examples for more information and configuration options.

Custom scalars

If your schema uses custom scalars, they must be defined on build.yaml. If it needs a custom parser (to decode from/to json), the custom_parser_import path must be set and the file must implement both fromGraphQL___ToDart___ and fromDart___toGraphQL___ constant functions.

targets:
  $default:
    builders:
      artemis:
        options:
          scalar_mapping:
            - custom_parser_import: 'package:graphbrainz_example/coercers.dart'
              graphql_type: Date
              dart_type: DateTime

If your custom scalar needs to import Dart libraries, you can provide it in the config as well:

targets:
  $default:
    builders:
      artemis:
        options:
          scalar_mapping:
            - custom_parser_import: 'package:graphbrainz_example/coercers.dart'
              graphql_type: BigDecimal
              dart_type:
                name: Decimal
                imports:
                  - 'package:decimal/decimal.dart'

Each ScalarMap is configured this way:

Option Default value Description
graphql_type The GraphQL custom scalar name on schema.
dart_type The Dart type this custom scalar should be converted from/to.
custom_parser_import null Import path to the file implementing coercer functions for custom scalars. See Custom scalars.

See examples for more information and configuration options.

Articles and videos

  1. Ultimate toolchain to work with GraphQL in Flutter
  2. Awesome GraphQL

ArtemisClient

If you have generate_helpers, Artemis will create a subclass of GraphQLQuery for you, this class can be used in conjunction with ArtemisClient.

final client = ArtemisClient('/graphql');
final gitHubReposQuery = MyGitHubReposQuery();
final response = await client.execute(gitHubReposQuery);

ArtemisClient adds type-awareness around Link from package:gql/link. You can create ArtemisClient from any Link using ArtemisClient.fromLink.

Check the examples to see how to use it in details.

Comments
  • Simple naming causes duplicate Query/Mutation classes

    Simple naming causes duplicate Query/Mutation classes

    Bug description When running artemis code generation, using the simple naming scheme with two queries in two separate files both returning different data. I get a duplicate class name error for the Query.

    [SEVERE] artemis:artemis on lib/$lib$:
    
    Two classes were generated with the same name `ClassName(name:r'Query')`
    but with different selection set.
    
    Class A
    ClassDefinition(name:ClassName(name:r'Query'), properties:[ClassProperty(type:TypeName(name:r'ClientPage'), name:ClassPropertyName(name:r'clients'), isNonNull:true, isResolveType:false)], factoryPoss
    ibilities:{}, typeNameField:TypeName(name:r'__typename'), isInput:false)
    
    Class B
    ClassDefinition(name:ClassName(name:r'Query'), properties:[ClassProperty(type:TypeName(name:r'String'), name:ClassPropertyName(name:r'__typename'), annotations:[r'override', r'''JsonKey(name: '__type
    name')'''], isNonNull:false, isResolveType:true), ClassProperty(type:TypeName(name:r'ClientEventPage'), name:ClassPropertyName(name:r'clientEvents'), isNonNull:true, isResolveType:false)], factoryPos
    sibilities:{}, typeNameField:TypeName(name:r'__typename'), isInput:false)
    

    From what I can see with only one query a class called Query is generated representing the single query I have. Once I have another though this causes a conflict. I understand that the simple naming doesn't do any name spacing and just uses the graphql class name but I would have thought in the case of a query or mutation the name I gave my query would be the class name.

    e.g.

    # file A
    query getUser {
    # ....
     }
    
    # file B
    query getActivity {
    # ...
    }
    

    In this case I would have expected the class name generated to be GetActivityQuery and GetUserQuery rather than attempting to create 2 Query classes.

    It could be that I've misunderstood how the simple strategy works and that it is only valid if you have one query and one mutation but I guessed not. Anyway thanks for your hard work it's made my development much easier in general πŸ™ŒπŸΏ . If you need any information please let me know, I've only added snippets of the output as it's a private work project πŸ˜“ . But I don't think the verbose output shows anything more as this happens regardless of what actual query is

    Specs Artemis version: 6.13.1-beta.1

    build.yaml:
    # Please paste your `build.yaml` file
          artemis:
            options:
              fragments_glob: lib/graphql/fragments/**.graphql
              schema_mapping:
                - output: lib/graphql/queries.dart
                  schema: graphql/schema.graphql
                  queries_glob: lib/graphql/queries/**.graphql
    
    Artemis output:
    # Please paste the output of
    $ flutter pub run build_runner build --verbose
    #or
    $ pub run build_runner build --verbose
    
    GraphQL schema:
    # If possible, please paste your GraphQL schema file,
    # or a minimum reproducible schema of the bug.
    
    GraphQL query:
    # If possible, please paste your GraphQL query file,
    # or a minimum reproducible query of the bug.
    
    bug 
    opened by akinsho 27
  • Couldn't generate 'fromJson' code for 'file'

    Couldn't generate 'fromJson' code for 'file'

    Before reporting a bug, please test the beta branch!

    Bug description

    I'm using MultipartFile for Upload type (in GraphQL). But when I run buid_runner, I'm getting error on FIle conversion (Upload scalar on GraphQL and MultipartFile on Dart). I have added custom parser in build.yaml file - graphql_serializer.dart below. I'm not sure what is wrong. Please could someone help me on this?

    Specs

    Artemis version: ^7.0.0-beta.10

    graphql_serializer.dart:
    export 'package:http/http.dart';
    
    MultipartFile fromGraphQLUploadToDartMultipartFile(MultipartFile file) => file;
    MultipartFile fromDartMultipartFileToGraphQLUpload(MultipartFile file) => file;
    List<MultipartFile> fromGraphQLListUploadToDartListMultipartFile(
        List<MultipartFile> files) =>
        files;
    List<MultipartFile> fromDartListMultipartFileToGraphQLListUpload(
        List<MultipartFile> files) =>
        files;
    
    build.yaml:
    targets:
      $default:
        sources:
          - lib/**
          - graphql/**
          - schema.graphql
        builders:
          artemis:
            options:
              schema_mapping:
                - schema: schema.graphql
                  queries_glob: graphql/*.graphql
                  output: lib/graphql/api.dart
              scalar_mapping:
                - graphql_type: Upload
                  custom_parser_import: lib/graphql/serializer/graphql_serializer.dart
                  dart_type:
                    name: MultipartFile
                    imports:
                      - 'package:http/http.dart'
                  use_custom_parser: true
    
    Artemis output:
    [  +86 ms] executing: sysctl hw.optional.arm64
    [  +15 ms] Exit code 1 from: sysctl hw.optional.arm64
    [        ] sysctl: unknown oid 'hw.optional.arm64'
    [   +7 ms] executing: [/Users/josh.buyandalai/android-projects/flutter/] git -c log.showSignature=false log -n 1 --pretty=format:%H
    [  +14 ms] Exit code 0 from: git -c log.showSignature=false log -n 1 --pretty=format:%H
    [        ] b22742018b3edf16c6cadd7b76d9db5e7f9064b5
    [        ] executing: [/Users/josh.buyandalai/android-projects/flutter/] git tag --points-at b22742018b3edf16c6cadd7b76d9db5e7f9064b5
    [  +25 ms] Exit code 0 from: git tag --points-at b22742018b3edf16c6cadd7b76d9db5e7f9064b5
    [        ] 2.2.0
    [   +7 ms] executing: [/Users/josh.buyandalai/android-projects/flutter/] git rev-parse --abbrev-ref --symbolic @{u}
    [  +14 ms] Exit code 0 from: git rev-parse --abbrev-ref --symbolic @{u}
    [        ] origin/stable
    [        ] executing: [/Users/josh.buyandalai/android-projects/flutter/] git ls-remote --get-url origin
    [  +13 ms] Exit code 0 from: git ls-remote --get-url origin
    [        ] https://github.com/flutter/flutter.git
    [ +115 ms] executing: [/Users/josh.buyandalai/android-projects/flutter/] git rev-parse --abbrev-ref HEAD
    [  +19 ms] Exit code 0 from: git rev-parse --abbrev-ref HEAD
    [        ] stable
    [   +8 ms] executing: sw_vers -productName
    [  +15 ms] Exit code 0 from: sw_vers -productName
    [        ] macOS
    [        ] executing: sw_vers -productVersion
    [  +17 ms] Exit code 0 from: sw_vers -productVersion
    [        ] 11.1
    [        ] executing: sw_vers -buildVersion
    [  +16 ms] Exit code 0 from: sw_vers -buildVersion
    [        ] 20C69
    [  +78 ms] Artifact Instance of 'AndroidGenSnapshotArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'AndroidInternalBuildArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'IOSEngineArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'FlutterWebSdk' is not required, skipping update.
    [   +4 ms] Artifact Instance of 'WindowsEngineArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'MacOSEngineArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'LinuxEngineArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'LinuxFuchsiaSDKArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'MacOSFuchsiaSDKArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'FlutterRunnerSDKArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'FlutterRunnerDebugSymbols' is not required, skipping update.
    [  +63 ms] Artifact Instance of 'MaterialFonts' is not required, skipping update.
    [        ] Artifact Instance of 'GradleWrapper' is not required, skipping update.
    [        ] Artifact Instance of 'AndroidGenSnapshotArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'AndroidInternalBuildArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'IOSEngineArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'FlutterWebSdk' is not required, skipping update.
    [        ] Artifact Instance of 'FlutterSdk' is not required, skipping update.
    [        ] Artifact Instance of 'WindowsEngineArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'MacOSEngineArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'LinuxEngineArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'LinuxFuchsiaSDKArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'MacOSFuchsiaSDKArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'FlutterRunnerSDKArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'FlutterRunnerDebugSymbols' is not required, skipping update.
    [        ] Artifact Instance of 'IosUsbArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'IosUsbArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'IosUsbArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'IosUsbArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'IosUsbArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'FontSubsetArtifacts' is not required, skipping update.
    [        ] Artifact Instance of 'PubDependencies' is not required, skipping update.
    [  +42 ms] Using /Users/josh.buyandalai/android-projects/flutter/.pub-cache for the pub cache.
    [        ] executing: /Users/josh.buyandalai/android-projects/flutter/bin/cache/dart-sdk/bin/pub run build_runner build --verbose
    [INFO] Entrypoint:Generating build script...
    [INFO] Entrypoint:Generating build script completed, took 402ms
    
    [WARNING] build.fallback:
    The package `uploader` does not include some required sources in any of its targets (see their build.yaml file).
    The missing sources are:
      - $package$
    [INFO] BuildDefinition:Initializing inputs
    [INFO] BuildDefinition:Reading cached asset graph...
    [INFO] BuildDefinition:Reading cached asset graph completed, took 65ms
    
    [INFO] BuildDefinition:Checking for updates since last build...
    [INFO] BuildDefinition:Checking for updates since last build completed, took 442ms
    
    [INFO] Build:Running build...
    [INFO] Build:Running build completed, took 14ms
    
    [INFO] Build:Caching finalized dependency graph...
    [INFO] Build:Caching finalized dependency graph completed, took 42ms
    
    [SEVERE] json_serializable:json_serializable on lib/graphql/api.graphql.dart (cached):
    
    Could not generate `fromJson` code for `file`.
    To support the type `MultipartFile` you can:
    * Use `JsonConverter`
      https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonConverter-class.html
    * Use `JsonKey` fields `fromJson` and `toJson`
      https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonKey/fromJson.html
      https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonKey/toJson.html
    package:uploader/graphql/api.graphql.dart:53:18
       β•·
    53 β”‚   MultipartFile? file;
       β”‚                  ^^^^
       β•΅
    package:json_serializable/src/decode_helper.dart 201:7     DecodeHelper._deserializeForField
    package:json_serializable/src/decode_helper.dart 53:9      DecodeHelper.createFactory.deserializeFun
    package:json_serializable/src/decode_helper.dart 303:32    _writeConstructorInvocation.<fn>
    dart:core                                                  StringBuffer.writeAll
    package:json_serializable/src/decode_helper.dart 301:9     _writeConstructorInvocation
    package:json_serializable/src/decode_helper.dart 56:18     DecodeHelper.createFactory
    package:json_serializable/src/generator_helper.dart 85:28  GeneratorHelper.generate
    
    [SEVERE] Build:
    Failed after 89ms
    [+3041 ms] "flutter run" took 3,184ms.
    [   +6 ms] pub finished with exit code 1
    [   +1 ms] 
               #0      throwToolExit (package:flutter_tools/src/base/common.dart:10:3)
               #1      _DefaultPub.interactively (package:flutter_tools/src/dart/pub.dart:366:7)
               <asynchronous suspension>
               #2      PackagesForwardCommand.runCommand (package:flutter_tools/src/commands/packages.dart:241:5)
               <asynchronous suspension>
               #3      FlutterCommand.run.<anonymous closure> (package:flutter_tools/src/runner/flutter_command.dart:1043:27)
               <asynchronous suspension>
               #4      AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
               <asynchronous suspension>
               #5      CommandRunner.runCommand (package:args/command_runner.dart:196:13)
               <asynchronous suspension>
               #6      FlutterCommandRunner.runCommand.<anonymous closure> (package:flutter_tools/src/runner/flutter_command_runner.dart:284:9)
               <asynchronous suspension>
               #7      AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
               <asynchronous suspension>
               #8      FlutterCommandRunner.runCommand (package:flutter_tools/src/runner/flutter_command_runner.dart:232:5)
               <asynchronous suspension>
               #9      run.<anonymous closure>.<anonymous closure> (package:flutter_tools/runner.dart:62:9)
               <asynchronous suspension>
               #10     AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
               <asynchronous suspension>
               #11     main (package:flutter_tools/executable.dart:91:3)
               <asynchronous suspension>
               
               
    [ +196 ms] ensureAnalyticsSent: 180ms
    [   +1 ms] Running shutdown hooks
    [        ] Shutdown hooks complete
    [        ] exiting with code 1
    
    
    GraphQL schema:
    type Mutation {
        uploadFile(upFileInput: FileCreateInput!): UploadResponse
    }
    
    input FileCreateInput {
        file: Upload
    }
    
    scalar Upload
    
    GraphQL query:
    mutation upload($fileCreateInput: FileCreateInput!) {
        uploadFile(upFileInput: $fileCreateInput) {
            returnMessage
            statusCode
        }
    }
    
    bug 
    opened by Khosbayar 22
  • [Artemis 6.0.0] Two classes were generated with the same name `DocumentDataType`!  -- which is an enum...

    [Artemis 6.0.0] Two classes were generated with the same name `DocumentDataType`! -- which is an enum...

    Error:

    Two classes were generated with the same name `DocumentDataType`!
    You may want to:
    - Make queries_glob stricter, to gather less .graphql files on a single output
    - Use alias on one of the places a field of type `DocumentDataType` is requested
    - Change naming_scheme to `pathedWithFields` to avoid duplication
    

    Queries:

    query moduleDataDocuments($moduleId: String!) {
      moduleDataDocuments(moduleId: $moduleId) {
        id
        type
        date
        title
        description
        feedback {
          required
          sent
        }
      }
    }
    
    query moduleDataDocumentsData($id: String! $moduleId: String!) {
      moduleDataDocumentsData(id: $id moduleId: $moduleId) {
        type
        data
      }
    }
    

    DocumentDataType gql schema:

    enum DocumentDataType {
      PDF
      IMAGE
    }
    

    build.yaml:

    targets:
      $default:
        sources:
          - lib/**
          - graphql/**
        builders:
          artemis:
            options:
              schema_mapping:
                - schema: graphql/schema.graphql
                  queries_glob: graphql/**.query.graphql
                  output: lib/graphql/graphql_api.dart
                  naming_scheme: pathedWithFields
    

    I use Artemis 6.0

    Why do I get this error? Shouldn't Enums always be the same? Meaning that you can just use the same enum class on both queries?

    Changing naming_scheme to pathedWithFields makes no difference.

    bug 
    opened by LasseRosenow 22
  • [Question] Custom types along with generated ones

    [Question] Custom types along with generated ones

    Hello, is there a way to tell Artemis to use specific already defined types instead of generating them? Basically, I want to define my main models myself but let Artemis to autogenerate other code like inputs, payloads, edges, etc. Is this possible? Thanks :)

    opened by fpabl0 21
  • Nullable scalar_mapping types

    Nullable scalar_mapping types

    Bug description

    I'm getting the following issue when attempting to generate my objects.

    Error with '@JsonKey' on 'occurrence'. The 'fromJson' function 'fromGraphQLDatetimeToDartDateTime' return type 'DateTime?' is not compatible with field type 'DateTime'.

    This seems to be occurring due to my parsing of datetime from postgres to dart:

    DateTime? fromGraphQLDatetimeToDartDateTime(String? date) => date == null ? null : DateTime.parse(date).toLocal();
    String? fromDartDateTimeToGraphQLDatetime(DateTime? date) => date?.toUtc().toIso8601String();
    

    I hope I'm just missing something obvious, but I want to be able to pass nullable date values back and forth from my database, any idea what I'm doing wrong?

    I tried adding the ? to the build.yaml and of course that doesn't work, but I had to try.

    Specs

    Artemis version: 7.0.0-beta.3

    build.yaml:
    targets:
      $default:
        sources:
          - lib/**
          - lib/graphql/**
          - schema.graphql
          - $package$
        builders:
          artemis:
            options:
              fragments_glob: lib/graphql/fragments/*.graphql
              schema_mapping:
                - output: lib/graphql/artemis/resolvers.dart
                  schema: schema.graphql
                  queries_glob: lib/graphql/resolvers/**/*.graphql
              scalar_mapping:
                - graphql_type: Datetime
                  dart_type: DateTime
                  custom_parser_import: "package:phyla/graphql/parsers.dart"
                - graphql_type: UUID
                  dart_type: String
                - graphql_type: JSON
                  dart_type: Json
                  custom_parser_import: "package:phyla/graphql/parsers.dart"
                - graphql_type: BigFloat
                  dart_type: double
                  custom_parser_import: "package:phyla/graphql/parsers.dart"
                - graphql_type: Cursor
                  dart_type: String
                - graphql_type: Date
                  dart_type: DateTime
                  custom_parser_import: "package:phyla/graphql/parsers.dart"
    
    
    Artemis output:
    
    [FINE] json_serializable:json_serializable on lib/graphql/artemis/resolvers.graphql.dart:Running JsonSerializableGenerator - 1 of 2
    [SEVERE] json_serializable:json_serializable on lib/graphql/artemis/resolvers.graphql.dart:
    
    Error with `@JsonKey` on `occurrence`. The `fromJson` function `fromGraphQLDatetimeToDartDateTime` return type `DateTime?` is not compatible with field type `DateTime`.
    package:phyla/graphql/artemis/resolvers.graphql.dart:462:17
        β•·
    462 β”‚   late DateTime occurrence;
        β”‚                 ^^^^^^^^^^
        β•΅
    package:json_serializable/src/utils.dart 56:5                         throwUnsupported
    package:json_serializable/src/type_helper_ctx.dart 138:7              _convertData
    package:json_serializable/src/type_helper_ctx.dart 99:26              new _ConvertPair
    package:json_serializable/src/type_helper_ctx.dart 41:40              TypeHelperCtx._pairFromContext
    package:json_serializable/src/type_helper_ctx.dart 39:46              TypeHelperCtx.deserializeConvertData
    package:json_serializable/src/type_helpers/convert_helper.dart 52:34  ConvertHelper.deserialize
    package:json_serializable/src/type_helper_ctx.dart 64:31              TypeHelperCtx.deserialize.<fn>
    dart:core                                                             Iterable.firstWhere
    package:json_serializable/src/type_helper_ctx.dart 77:46              TypeHelperCtx._run
    package:json_serializable/src/type_helper_ctx.dart 61:7               TypeHelperCtx.deserialize
    package:json_serializable/src/decode_helper.dart 192:14               DecodeHelper._deserializeForField
    package:json_serializable/src/decode_helper.dart 53:9                 DecodeHelper.createFactory.deserializeFun
    package:json_serializable/src/decode_helper.dart 120:33               DecodeHelper.createFactory
    package:json_serializable/src/generator_helper.dart 85:28             GeneratorHelper.generate.sync_op
    
    [INFO] Build:Running build completed, took 6.1s
    
    [INFO] Build:Caching finalized dependency graph...
    [INFO] Build:Caching finalized dependency graph completed, took 45ms
    
    [SEVERE] Build:
    Failed after 6.1s
    [+8980 ms] "flutter run" took 9,099ms.
    [   +6 ms] pub finished with exit code 1
    [   +2 ms] 
               #0      throwToolExit (package:flutter_tools/src/base/common.dart:10:3)
               #1      _DefaultPub.interactively (package:flutter_tools/src/dart/pub.dart:364:7)
               <asynchronous suspension>
               #2      PackagesForwardCommand.runCommand (package:flutter_tools/src/commands/packages.dart:238:5)
               <asynchronous suspension>
               #3      FlutterCommand.verifyThenRunCommand (package:flutter_tools/src/runner/flutter_command.dart:1157:12)
               <asynchronous suspension>
               #4      FlutterCommand.run.<anonymous closure> (package:flutter_tools/src/runner/flutter_command.dart:1009:27)
               <asynchronous suspension>
               #5      AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
               <asynchronous suspension>
               #6      AppContext.run (package:flutter_tools/src/base/context.dart:149:12)
               <asynchronous suspension>
               #7      CommandRunner.runCommand (package:args/command_runner.dart:197:13)
               <asynchronous suspension>
               #8      FlutterCommandRunner.runCommand.<anonymous closure> (package:flutter_tools/src/runner/flutter_command_runner.dart:278:9)
               <asynchronous suspension>
               #9      AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
               <asynchronous suspension>
               #10     AppContext.run (package:flutter_tools/src/base/context.dart:149:12)
               <asynchronous suspension>
               #11     FlutterCommandRunner.runCommand (package:flutter_tools/src/runner/flutter_command_runner.dart:234:5)
               <asynchronous suspension>
               #12     run.<anonymous closure>.<anonymous closure> (package:flutter_tools/runner.dart:64:9)
               <asynchronous suspension>
               #13     run.<anonymous closure> (package:flutter_tools/runner.dart:62:12)
               <asynchronous suspension>
               #14     AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
               <asynchronous suspension>
               #15     AppContext.run (package:flutter_tools/src/base/context.dart:149:12)
               <asynchronous suspension>
               #16     runInContext (package:flutter_tools/src/context_runner.dart:73:10)
               <asynchronous suspension>
               #17     main (package:flutter_tools/executable.dart:90:3)
               <asynchronous suspension>
    
    
    [ +180 ms] ensureAnalyticsSent: 172ms
    [   +4 ms] Running shutdown hooks
    [   +1 ms] Shutdown hooks complete
    [   +1 ms] exiting with code 1
    
    GraphQL schema:
    # If possible, please paste your GraphQL schema file,
    # or a minimum reproducible schema of the bug.
    
    GraphQL query:
    # If possible, please paste your GraphQL query file,
    # or a minimum reproducible query of the bug.
    
    bug 
    opened by michael-woolsey 21
  • Change variable name if it start with underscore.

    Change variable name if it start with underscore.

    Bug description Fields starting with underscore cause issues since dart can't have private named parameters.

    In the mutation/query I can alias field name to avoid the problem with fields starting with underscore. But in the input I can't do the same.

    I think this issue can be solved by checking for underscore in the field name and using @JsonKey(name:"noUnderScoreName") to mitigate the issue

    Specs Artemis version: '>=5.0.0 <6.0.0'

    mutation addStudent($input: StudentInput){
        addStudent(input:$input){
            id:_id,
        }
    }
    
    input StudentInput {
        _id: Int
        person: PersonInput
       ...
    }
    
    input PersonInput {
        ...
    }
    
    bug 
    opened by TarekkMA 19
  • Cannot define multiple queries (with fragments) in a single .graphql file

    Cannot define multiple queries (with fragments) in a single .graphql file

    Before reporting a bug, please test the beta branch! (Unfortunately I can't test it with the beta branch because it caused a lot of conflicting dependencies problems in my application).

    Bug description

    When multiple queries are defining in the same file using fragments, Artemis generate a Query with the Fragment declared twice. That causes this exception at runtime:

    Captura de Pantalla 2021-05-10 a la(s) 04 38 24

    Here it is defined twice:

    class GetAllPokemonsQuery
        extends GraphQLQuery<GetAllPokemons$Query, GetAllPokemonsArguments> {
      GetAllPokemonsQuery({this.variables});
    
      @override
      final DocumentNode document = DocumentNode(definitions: [
        ...
        FragmentDefinitionNode(
            name: NameNode(value: 'pokemonFragment'),
            ...
        ])),
        FragmentDefinitionNode(
            name: NameNode(value: 'pokemonFragment'),
            ...
        ])),
        ...
      ]);
      ...
    }
    

    Specs

    Artemis version: 6.18.4

    build.yaml:
    targets:
      $default:
        sources:
          - lib/**
          - graphql/**
          - schema.graphql
          - $package$
        builders:
          artemis:
            options:
              fragments_glob: graphql/fragments/fragments.graphql
              schema_mapping:
                - schema: schema.graphql
                  naming_scheme: pathedWithFields
                  queries_glob: graphql/*.{query,mutation}.graphql
                  output: lib/models/graphql/graphql_api.dart
    
    Artemis output:

    The error occurs at runtime.

    GraphQL schema:
    type Pokemon {
      number: String
      name: String
    }
    
    type Query {
      pokemons(first: Int!): [Pokemon]
      pokemon(name: String!): Pokemon!
    }
    
    GraphQL query:
    # graphql/fragments/fragments.graphql
    fragment pokemonFragment on Pokemon {
      number
      name
    }
    
    # graphql/pokemon.query.graphql
    query getPokemon($name: String!) {
      pokemon(name: $name) {
        ...pokemonFragment
      }
    }
    
    query getAllPokemons($first: Int!) {
      pokemons(first: $first) {
        ...pokemonFragment
      }
    }
    
    bug 
    opened by fpabl0 18
  • Refactor how Artemis processes code

    Refactor how Artemis processes code

    This version completely refactors how Artemis generate code (by finally using the implementation of visitor pattern provided by gql). On top of that, I've decided to do other major breaking changes to make code cleaner and more maintainable. Listed:

    • add_query_prefix doesn't exist anymore (it's now the default to generate classes with its "path" from the query), e.g., this query's city field will be typed as CityName$QueryRoot$User$Address$City:
      query city_name {
        user {
          address {
            city {
              name
            }
          }
        }
      }
      

      This change was also done to tip users to NOT use those generated queries directly on their code, to avoid coupling them to your business logic.

    • custom_parser_import was moved to inside a ScalarMap, and use_custom_parser was removed.
    • resolve_type_field option was renamed to type_name_field, as __typename is the correct field name (by GraphQL spec).
    • Classes generated for mutation will have a Mutation suffix, as queries already have Query suffix.
    • Change pre-generation data classes constructors to named parameters, so if you're using GraphQLQueryBuilder.onBuild, it will break.

    And also:

    • Add more logs and errors while generating code, to help debugging.
    • Add more/refactor tests.
    • Add a GitHub example.

    TODO:

    • [ ] clean options?
    • [ ] prefix every class with $ (?)
    • [ ] refactor class naming variables
    • [ ] review readme and changelog
    opened by comigor 18
  • Very long type names

    Very long type names

    Hi,

    I am trying out Artemis and I have some deeply nested queries that are generating very long type names, such as:

    For example, this query:

    query GetAggregatorCompanies(
      $aggregatorId: Int!
      $latitude: Float
      $longitude: Float
      $maximumDistanceKilometers: Float
      $filterBy: AggregatorFilterOption
      $first: Int
      $cursor: String
    ) {
      aggregator(
        aggregatorId: $aggregatorId
        latitude: $latitude
        longitude: $longitude
        maximumDistanceKilometers: $maximumDistanceKilometers
        filterBy: $filterBy
      ) {
        id
        __typename
        name
        numericalId
        images {
          __typename
          url
          context
        }
        companies(first: $first, after: $cursor) {
          edges {
            __typename
            cursor
            node {
              id
              __typename
              name
              numericalId
              onlineStatus
              hidden
              brand {
                id
                __typename
                numericalId
                images {
                  __typename
                  context
                  url
                }
              }
              images {
                __typename
                context
                url
              }
              highlight {
                __typename
                numericalId
                topLabel
                centerLabel
                bottomLabel
              }
            }
          }
        }
      }
    }
    

    Will generate these types:

    // GENERATED CODE - DO NOT MODIFY BY HAND
    
    import 'package:meta/meta.dart';
    import 'package:artemis/artemis.dart';
    import 'package:json_annotation/json_annotation.dart';
    import 'package:equatable/equatable.dart';
    import 'package:gql/ast.dart';
    part 'graphql_api.graphql.g.dart';
    
    @JsonSerializable(explicitToJson: true)
    class GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameter$OrderFieldParameter$OrderField
        with EquatableMixin {
      GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameter$OrderFieldParameter$OrderField();
    
      factory GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameter$OrderFieldParameter$OrderField.fromJson(
              Map<String, dynamic> json) =>
          _$GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameter$OrderFieldParameter$OrderFieldFromJson(
              json);
    
      String id;
    
      int numericalId;
    
      String title;
    
      String label;
    
      @JsonKey(
          unknownEnumValue:
              GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameter$OrderFieldParameter$OrderField$OrderFieldType
                  .ARTEMIS_UNKNOWN)
      GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameter$OrderFieldParameter$OrderField$OrderFieldType
          fieldType;
    
      int maxLength;
    
      int position;
    
      bool required;
    
      String requiredErrorMessage;
    
      String invalidErrorMessage;
    
      @override
      List<Object> get props => [
            id,
            numericalId,
            title,
            label,
            fieldType,
            maxLength,
            position,
            required,
            requiredErrorMessage,
            invalidErrorMessage
          ];
      Map<String, dynamic> toJson() =>
          _$GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameter$OrderFieldParameter$OrderFieldToJson(
              this);
    }
    
    @JsonSerializable(explicitToJson: true)
    class GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameter$OrderFieldParameter
        with EquatableMixin {
      GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameter$OrderFieldParameter();
    
      factory GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameter$OrderFieldParameter.fromJson(
              Map<String, dynamic> json) =>
          _$GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameter$OrderFieldParameterFromJson(
              json);
    
      String id;
    
      GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameter$OrderFieldParameter$OrderField
          field;
    
      @override
      List<Object> get props => [id, field];
      Map<String, dynamic> toJson() =>
          _$GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameter$OrderFieldParameterToJson(
              this);
    }
    
    @JsonSerializable(explicitToJson: true)
    class GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameter
        with EquatableMixin {
      GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameter();
    
      factory GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameter.fromJson(
              Map<String, dynamic> json) =>
          _$GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameterFromJson(
              json);
    
      String id;
    
      String title;
    
      int orderType;
    
      String description;
    
      List<GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameter$OrderFieldParameter>
          orderFields;
    
      @override
      List<Object> get props => [id, title, orderType, description, orderFields];
      Map<String, dynamic> toJson() =>
          _$GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameterToJson(
              this);
    }
    
    @JsonSerializable(explicitToJson: true)
    class GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter
        with EquatableMixin {
      GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter();
    
      factory GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter.fromJson(
              Map<String, dynamic> json) =>
          _$GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$ParameterFromJson(
              json);
    
      String id;
    
      List<GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameter>
          orderTypes;
    
      @override
      List<Object> get props => [id, orderTypes];
      Map<String, dynamic> toJson() =>
          _$GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$ParameterToJson(
              this);
    }
    
    @JsonSerializable(explicitToJson: true)
    class GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company
        with EquatableMixin {
      GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company();
    
      factory GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company.fromJson(
              Map<String, dynamic> json) =>
          _$GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$CompanyFromJson(
              json);
    
      String id;
    
      String name;
    
      int numericalId;
    
      @JsonKey(
          unknownEnumValue:
              GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$OnlineStatus
                  .ARTEMIS_UNKNOWN)
      GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$OnlineStatus
          onlineStatus;
    
      GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter
          parameter;
    
      @override
      List<Object> get props => [id, name, numericalId, onlineStatus, parameter];
      Map<String, dynamic> toJson() =>
          _$GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$CompanyToJson(
              this);
    }
    
    @JsonSerializable(explicitToJson: true)
    class GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge
        with EquatableMixin {
      GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge();
    
      factory GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge.fromJson(
              Map<String, dynamic> json) =>
          _$GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdgeFromJson(
              json);
    
      GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company
          node;
    
      @override
      List<Object> get props => [node];
      Map<String, dynamic> toJson() =>
          _$GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdgeToJson(
              this);
    }
    
    @JsonSerializable(explicitToJson: true)
    class GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection
        with EquatableMixin {
      GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection();
    
      factory GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection.fromJson(
              Map<String, dynamic> json) =>
          _$GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnectionFromJson(
              json);
    
      List<GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge>
          edges;
    
      @override
      List<Object> get props => [edges];
      Map<String, dynamic> toJson() =>
          _$GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnectionToJson(
              this);
    }
    
    @JsonSerializable(explicitToJson: true)
    class GetAggregatorCompanies$Query$CompanyGroup with EquatableMixin {
      GetAggregatorCompanies$Query$CompanyGroup();
    
      factory GetAggregatorCompanies$Query$CompanyGroup.fromJson(
              Map<String, dynamic> json) =>
          _$GetAggregatorCompanies$Query$CompanyGroupFromJson(json);
    
      String id;
    
      String name;
    
      int numericalId;
    
      GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection companies;
    
      @override
      List<Object> get props => [id, name, numericalId, companies];
      Map<String, dynamic> toJson() =>
          _$GetAggregatorCompanies$Query$CompanyGroupToJson(this);
    }
    
    @JsonSerializable(explicitToJson: true)
    class GetAggregatorCompanies$Query with EquatableMixin {
      GetAggregatorCompanies$Query();
    
      factory GetAggregatorCompanies$Query.fromJson(Map<String, dynamic> json) =>
          _$GetAggregatorCompanies$QueryFromJson(json);
    
      GetAggregatorCompanies$Query$CompanyGroup aggregator;
    
      @override
      List<Object> get props => [aggregator];
      Map<String, dynamic> toJson() => _$GetAggregatorCompanies$QueryToJson(this);
    }
    
    enum GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$OnlineStatus {
      ONLINE,
      OFFLINE,
      CLOSED,
      ARTEMIS_UNKNOWN,
    }
    enum GetAggregatorCompanies$Query$CompanyGroup$CompanySharedConnection$CompanySharedEdge$Company$Parameter$OrderTypeParameter$OrderFieldParameter$OrderField$OrderFieldType {
      TEXT,
      NUMERIC,
      TELEPHONE,
      CPF,
      OPTION_LIST,
      ARTEMIS_UNKNOWN,
    }
    
    @JsonSerializable(explicitToJson: true)
    class GetAggregatorCompaniesArguments extends JsonSerializable
        with EquatableMixin {
      GetAggregatorCompaniesArguments(
          {@required this.aggregatorId, this.latitude, this.longitude});
    
      factory GetAggregatorCompaniesArguments.fromJson(Map<String, dynamic> json) =>
          _$GetAggregatorCompaniesArgumentsFromJson(json);
    
      final int aggregatorId;
    
      final double latitude;
    
      final double longitude;
    
      @override
      List<Object> get props => [aggregatorId, latitude, longitude];
      Map<String, dynamic> toJson() =>
          _$GetAggregatorCompaniesArgumentsToJson(this);
    }
    
    class GetAggregatorCompaniesQuery extends GraphQLQuery<
        GetAggregatorCompanies$Query, GetAggregatorCompaniesArguments> {
      GetAggregatorCompaniesQuery({this.variables});
    
      @override
      final DocumentNode document = DocumentNode(definitions: [
        OperationDefinitionNode(
            type: OperationType.query,
            name: NameNode(value: 'GetAggregatorCompanies'),
            variableDefinitions: [
              VariableDefinitionNode(
                  variable: VariableNode(name: NameNode(value: 'aggregatorId')),
                  type:
                      NamedTypeNode(name: NameNode(value: 'Int'), isNonNull: true),
                  defaultValue: DefaultValueNode(value: null),
                  directives: []),
              VariableDefinitionNode(
                  variable: VariableNode(name: NameNode(value: 'latitude')),
                  type: NamedTypeNode(
                      name: NameNode(value: 'Float'), isNonNull: false),
                  defaultValue: DefaultValueNode(value: null),
                  directives: []),
              VariableDefinitionNode(
                  variable: VariableNode(name: NameNode(value: 'longitude')),
                  type: NamedTypeNode(
                      name: NameNode(value: 'Float'), isNonNull: false),
                  defaultValue: DefaultValueNode(value: null),
                  directives: [])
            ],
            directives: [],
            selectionSet: SelectionSetNode(selections: [
              FieldNode(
                  name: NameNode(value: 'aggregator'),
                  alias: null,
                  arguments: [
                    ArgumentNode(
                        name: NameNode(value: 'aggregatorId'),
                        value: VariableNode(name: NameNode(value: 'aggregatorId'))),
                    ArgumentNode(
                        name: NameNode(value: 'latitude'),
                        value: VariableNode(name: NameNode(value: 'latitude'))),
                    ArgumentNode(
                        name: NameNode(value: 'longitude'),
                        value: VariableNode(name: NameNode(value: 'longitude'))),
                    ArgumentNode(
                        name: NameNode(value: 'filterBy'),
                        value:
                            EnumValueNode(name: NameNode(value: 'DELIVERY_AREA')))
                  ],
                  directives: [],
                  selectionSet: SelectionSetNode(selections: [
                    FieldNode(
                        name: NameNode(value: 'id'),
                        alias: null,
                        arguments: [],
                        directives: [],
                        selectionSet: null),
                    FieldNode(
                        name: NameNode(value: '__typename'),
                        alias: null,
                        arguments: [],
                        directives: [],
                        selectionSet: null),
                    FieldNode(
                        name: NameNode(value: 'name'),
                        alias: null,
                        arguments: [],
                        directives: [],
                        selectionSet: null),
                    FieldNode(
                        name: NameNode(value: 'numericalId'),
                        alias: null,
                        arguments: [],
                        directives: [],
                        selectionSet: null),
                    FieldNode(
                        name: NameNode(value: 'companies'),
                        alias: null,
                        arguments: [],
                        directives: [],
                        selectionSet: SelectionSetNode(selections: [
                          FieldNode(
                              name: NameNode(value: 'edges'),
                              alias: null,
                              arguments: [],
                              directives: [],
                              selectionSet: SelectionSetNode(selections: [
                                FieldNode(
                                    name: NameNode(value: '__typename'),
                                    alias: null,
                                    arguments: [],
                                    directives: [],
                                    selectionSet: null),
                                FieldNode(
                                    name: NameNode(value: 'node'),
                                    alias: null,
                                    arguments: [],
                                    directives: [],
                                    selectionSet: SelectionSetNode(selections: [
                                      FieldNode(
                                          name: NameNode(value: 'id'),
                                          alias: null,
                                          arguments: [],
                                          directives: [],
                                          selectionSet: null),
                                      FieldNode(
                                          name: NameNode(value: '__typename'),
                                          alias: null,
                                          arguments: [],
                                          directives: [],
                                          selectionSet: null),
                                      FieldNode(
                                          name: NameNode(value: 'name'),
                                          alias: null,
                                          arguments: [],
                                          directives: [],
                                          selectionSet: null),
                                      FieldNode(
                                          name: NameNode(value: 'numericalId'),
                                          alias: null,
                                          arguments: [],
                                          directives: [],
                                          selectionSet: null),
                                      FieldNode(
                                          name: NameNode(value: 'onlineStatus'),
                                          alias: null,
                                          arguments: [],
                                          directives: [],
                                          selectionSet: null),
                                      FieldNode(
                                          name: NameNode(value: 'parameter'),
                                          alias: null,
                                          arguments: [],
                                          directives: [],
                                          selectionSet: SelectionSetNode(
                                              selections: [
                                                FieldNode(
                                                    name: NameNode(value: 'id'),
                                                    alias: null,
                                                    arguments: [],
                                                    directives: [],
                                                    selectionSet: null),
                                                FieldNode(
                                                    name: NameNode(
                                                        value: '__typename'),
                                                    alias: null,
                                                    arguments: [],
                                                    directives: [],
                                                    selectionSet: null),
                                                FieldNode(
                                                    name: NameNode(
                                                        value: 'orderTypes'),
                                                    alias: null,
                                                    arguments: [],
                                                    directives: [],
                                                    selectionSet: SelectionSetNode(
                                                        selections: [
                                                          FieldNode(
                                                              name: NameNode(
                                                                  value:
                                                                      '__typename'),
                                                              alias: null,
                                                              arguments: [],
                                                              directives: [],
                                                              selectionSet: null),
                                                          FieldNode(
                                                              name: NameNode(
                                                                  value: 'id'),
                                                              alias: null,
                                                              arguments: [],
                                                              directives: [],
                                                              selectionSet: null),
                                                          FieldNode(
                                                              name: NameNode(
                                                                  value: 'title'),
                                                              alias: null,
                                                              arguments: [],
                                                              directives: [],
                                                              selectionSet: null),
                                                          FieldNode(
                                                              name: NameNode(
                                                                  value:
                                                                      'orderType'),
                                                              alias: null,
                                                              arguments: [],
                                                              directives: [],
                                                              selectionSet: null),
                                                          FieldNode(
                                                              name: NameNode(
                                                                  value:
                                                                      'description'),
                                                              alias: null,
                                                              arguments: [],
                                                              directives: [],
                                                              selectionSet: null),
                                                          FieldNode(
                                                              name: NameNode(
                                                                  value:
                                                                      'orderFields'),
                                                              alias: null,
                                                              arguments: [],
                                                              directives: [],
                                                              selectionSet:
                                                                  SelectionSetNode(
                                                                      selections: [
                                                                    FieldNode(
                                                                        name: NameNode(
                                                                            value:
                                                                                'id'),
                                                                        alias: null,
                                                                        arguments: [],
                                                                        directives: [],
                                                                        selectionSet:
                                                                            null),
                                                                    FieldNode(
                                                                        name: NameNode(
                                                                            value:
                                                                                '__typename'),
                                                                        alias: null,
                                                                        arguments: [],
                                                                        directives: [],
                                                                        selectionSet:
                                                                            null),
                                                                    FieldNode(
                                                                        name: NameNode(
                                                                            value:
                                                                                'field'),
                                                                        alias: null,
                                                                        arguments: [],
                                                                        directives: [],
                                                                        selectionSet:
                                                                            SelectionSetNode(
                                                                                selections: [
                                                                              FieldNode(
                                                                                  name: NameNode(value: 'id'),
                                                                                  alias: null,
                                                                                  arguments: [],
                                                                                  directives: [],
                                                                                  selectionSet: null),
                                                                              FieldNode(
                                                                                  name: NameNode(value: '__typename'),
                                                                                  alias: null,
                                                                                  arguments: [],
                                                                                  directives: [],
                                                                                  selectionSet: null),
                                                                              FieldNode(
                                                                                  name: NameNode(value: 'numericalId'),
                                                                                  alias: null,
                                                                                  arguments: [],
                                                                                  directives: [],
                                                                                  selectionSet: null),
                                                                              FieldNode(
                                                                                  name: NameNode(value: 'title'),
                                                                                  alias: null,
                                                                                  arguments: [],
                                                                                  directives: [],
                                                                                  selectionSet: null),
                                                                              FieldNode(
                                                                                  name: NameNode(value: 'label'),
                                                                                  alias: null,
                                                                                  arguments: [],
                                                                                  directives: [],
                                                                                  selectionSet: null),
                                                                              FieldNode(
                                                                                  name: NameNode(value: 'fieldType'),
                                                                                  alias: null,
                                                                                  arguments: [],
                                                                                  directives: [],
                                                                                  selectionSet: null),
                                                                              FieldNode(
                                                                                  name: NameNode(value: 'maxLength'),
                                                                                  alias: null,
                                                                                  arguments: [],
                                                                                  directives: [],
                                                                                  selectionSet: null),
                                                                              FieldNode(
                                                                                  name: NameNode(value: 'position'),
                                                                                  alias: null,
                                                                                  arguments: [],
                                                                                  directives: [],
                                                                                  selectionSet: null),
                                                                              FieldNode(
                                                                                  name: NameNode(value: 'required'),
                                                                                  alias: null,
                                                                                  arguments: [],
                                                                                  directives: [],
                                                                                  selectionSet: null),
                                                                              FieldNode(
                                                                                  name: NameNode(value: 'requiredErrorMessage'),
                                                                                  alias: null,
                                                                                  arguments: [],
                                                                                  directives: [],
                                                                                  selectionSet: null),
                                                                              FieldNode(
                                                                                  name: NameNode(value: 'invalidErrorMessage'),
                                                                                  alias: null,
                                                                                  arguments: [],
                                                                                  directives: [],
                                                                                  selectionSet: null)
                                                                            ]))
                                                                  ]))
                                                        ]))
                                              ]))
                                    ]))
                              ]))
                        ]))
                  ]))
            ]))
      ]);
    
      @override
      final String operationName = 'GetAggregatorCompanies';
    
      @override
      final GetAggregatorCompaniesArguments variables;
    
      @override
      List<Object> get props => [document, operationName, variables];
      @override
      GetAggregatorCompanies$Query parse(Map<String, dynamic> json) =>
          GetAggregatorCompanies$Query.fromJson(json);
    }
    

    Am I doing something wrong? Is there a way for me to get shorter type names?

    opened by komyg 17
  • Unknown definition type 'createdAt' (timestamptz)

    Unknown definition type 'createdAt' (timestamptz)

    I am trying to generate classes from an hasura GQL endpoint, schema generated by graphqurl. I am getting an error:

    [SEVERE] artemis:artemis on lib/$lib$:
    
    Error on line 629, column 3 of lib/graphql/schema.graphql: Unknown definition type 'createdAt'
        β•·
    629 β”‚   createdAt: timestamptz
        β”‚   ^^^^^^^^^
        β•΅
    

    assuming I would need to do a custom mapping as timestamptz is a postgres thing, my build.yaml looks like this:

    targets:
      $default:
        sources:
          - lib/**
          - graphql/**
          - data/**
          - schema.graphql
        builders:
          artemis:
            options:
              schema_mapping:
                - output: lib/graphql_api.dart
                  schema: lib/my_graphql_schema.graphql
                  queries_glob: lib/**.graphql
              scalar_mapping:
                - graphql_type: timestamptz
                  dart_type: DateTime
    

    the schema in /lib/graphql/schema.graphql is https://paste.ubuntu.com/p/Mpw5wHMVWN/

    Any ideas how I can get timestamptz to map?

    bug 
    opened by FickleLife 15
  • Recursive inputs fail

    Recursive inputs fail

    Hi!

    Thanks again for all the great work! I was just trying to generate the query files and tried against a query with recursive input:

    <- Generated class Events$Query.
    [WARNING] artemis:artemis on lib/$lib$:
      Found new input filter (-> Events$ModelEventFilterInput).
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelIDFilterInput.
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelStringFilterInput.
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelStringFilterInput.
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelStringFilterInput.
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelStringFilterInput.
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelIDFilterInput.
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelEventFilterInput$ModelIDFilterInput.
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelEventFilterInput$ModelStringFilterInput.
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelEventFilterInput$ModelStringFilterInput.
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelEventFilterInput$ModelStringFilterInput.
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelEventFilterInput$ModelStringFilterInput.
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelEventFilterInput$ModelIDFilterInput.
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelEventFilterInput$ModelEventFilterInput$ModelIDFilterInput.
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelEventFilterInput$ModelEventFilterInput$ModelStringFilterInput.
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelEventFilterInput$ModelEventFilterInput$ModelStringFilterInput.
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelEventFilterInput$ModelEventFilterInput$ModelStringFilterInput.
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelEventFilterInput$ModelEventFilterInput$ModelStringFilterInput.
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelEventFilterInput$ModelEventFilterInput$ModelIDFilterInput.
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelEventFilterInput$ModelEventFilterInput$ModelEventFilterInput$ModelIDFilterInput.
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelEventFilterInput$ModelEventFilterInput$ModelEventFilterInput$ModelStringFilterInput.
    [WARNING] artemis:artemis on lib/$lib$:
    <- Generated input class Events$ModelEventFilterInput$ModelEventFilterInput$ModelEventFilterInput$ModelEventFilterInput$ModelStringFilterInput.
    

    It keeps going and fails at some point. My schema has recursive inputs:

    input ModelEventFilterInput {
      id: ModelIDFilterInput
      title: ModelStringFilterInput
      createdAt: ModelStringFilterInput
      updatedAt: ModelStringFilterInput
      occurrence: ModelStringFilterInput
      personEventsId: ModelIDFilterInput
      #and: [ModelEventFilterInput]
      #or: [ModelEventFilterInput]
      #not: ModelEventFilterInput
    }
    
    type Person {
        events(filter: ModelEventFilterInput): ResultConnection
    }
    
    query Events($filter: ModelEventFilterInput) {
      person {
        events(filter: $filter) {
            ....
        }
    }
    
    bug 
    opened by michael-golfi 13
  • Any way to prevent generated classes from extending JsonSerializable?

    Any way to prevent generated classes from extending JsonSerializable?

    Every class generated which extends JsonSerializable has all of the fields generated which you can see in the screenshot.

    Is there any way to disable this behaviour?

    Also curious if there is a good reason why I would want my class to extend JsonSerializable?

    Screenshot 2022-11-17 at 00 12 55
    opened by MarkOSullivan94 3
  • OperationName is passed for unnamed queries

    OperationName is passed for unnamed queries

    Bug description

    The problem I'm facing in 7.9.0-beta is that operationName property of my query class is always generating with the value that equals the output file name. So, when I'm using unnamed source query, the request fails with an error like "Unknown operation named ...". I tried to turn off the generate_queries option but nothing changed. The only way to solve this is to name raw queries explicitly. Is there any way to turn off the feature that generates operation names? Or is there any other approach you recommend.

    Specs

    Artemis version: 7.9.0-beta

    bug 
    opened by nikolay-popov-ideogram 1
  • How to pass nested fragments

    How to pass nested fragments

    If I have a query and fragments like below

    query Home {
      user {
        id
        ...fragment1_user
      }
    }
    
    fragment fragment1_user on User {
      __typename
      id
      firstName
      ...fragment2a_user
      ...fragment2b_user
    }
    
    fragment fragment2a_user on User {
       __typename
      id
      lastName
    }
    
    fragment fragment2b_user on User {
      __typename
      id
      email
    }
    

    When I try to pass the props to their child widgets inside the Fragment1 Widget:

    Fragment2aWidget(userFrag: widget.userFrag),
    Fragment2bWidget(userFrag: widget.userFrag),
    

    I get the following errors:

    The argument type 'Fragment1UserMixin' can't be assigned to the parameter type 'Fragment2aUserMixin'. The argument type 'Fragment1UserMixin' can't be assigned to the parameter type 'Fragment2bUserMixin'.

    From the Home to Fragment1 widgets I see I'm able to pass Home$Query$User to the Fragment1UserMixin type, but I can't pass the others. I could probably just cast to the child mixin types, but that prevents static analysis on the values I'm passing in.

    Am I missing something?

    opened by baconcheese113 2
  • Using fragments prevents using cache

    Using fragments prevents using cache

    I'm trying to create a sample app for others that want to use graphql-flutter and artemis, while learning how to use them myself. It appears that fragments can only be used with FetchPolicy.noCache (not even FetchPolicy.networkOnly. Removing the cache eliminates a huge part of what makes graphl-flutter appealing, so is there any way to use artemis with fragments and cache?

    In main.dart

      await initHiveForFlutter();
    

    In app.dart

    return GraphQLProvider(
          client: ValueNotifier(GraphQLClient(
            cache: GraphQLCache(store: HiveStore()),
            link: HttpLink("https://graphql-pokeapi.graphcdn.app"),
          )),
          child: MaterialApp(
            title: "Pokemon Demo",
            onGenerateRoute: (settings) {
              switch (settings.name) {
                case '/':
                default:
                  return MaterialPageRoute(builder: (_) => PokemonListScreen());
              }
            },
          ),
        );
    

    In pokemon_list.query.graphql

    query PokemonList {
        pokemons(limit: 50) {
            count
            results {
                id
                ...pokemonListCard_item
            }
        }
    }
    

    In pokemon_list_card.fragment.graphql

    fragment pokemonListCard_item on PokemonItem {
        url
        name
        image
        artwork
    }
    

    In pokemon_list.dart

    return Query(
            options: QueryOptions(
              document: POKEMON_LIST_QUERY_DOCUMENT,
              operationName: POKEMON_LIST_QUERY_DOCUMENT_OPERATION_NAME,
              fetchPolicy: FetchPolicy.noCache, // This prevents using the cache!!
            ),
            builder: (QueryResult result, {fetchMore, refetch}) {
              if (result.isLoading) return CircularProgressIndicator();
              if (result.hasException) return Center(child: Text(result.exception!.toString()));
    
              print("result is $result");
              // >>>>>result.data is missing all fragment data with a different fetch policy <<<<<
              final data = PokemonList$Query.fromJson(result.data!);
    
              final cardList = data.pokemons!.results!.map((pokemon) {
                print("Pokemon name: ${pokemon!.name}");
                return PokemonListCard(itemFrag: pokemon);
              }).toList();
    
              return RefreshIndicator(
                  child: ListView(children: cardList),
                  onRefresh: () async {
                    await refetch!();
                  });
            });
    
    opened by baconcheese113 7
  • Do queries have to be extracted?

    Do queries have to be extracted?

    I use graphql client side in Flutter very similar to how I use it with Apollo Client and Relay, where each Widget/Component houses the parts of the query that will be used in it's widget and child widgets have their own fragments. You can see an example of one of my main queries here and here.

    In Relay I would type each prop containing the fragment query response in that specific component with the type generated for the fragment, the types are then placed in the file's folder in a generated folder. Based on the example apps I've looked at it seems like the queries have to be extracted to their own files, is that right? Is there a way to get something similar to Relay/Apollo Client where the graphql fragments live in the same files as the component that uses them with Artemis?

    opened by baconcheese113 3
  • add `extensions` field to GraphQLResponse<T>

    add `extensions` field to GraphQLResponse

    Hi, thank you for this really great library.

    As described below, GraphQL response root may contain extensions field.

    https://spec.graphql.org/June2018/#sec-Response-Format

    The response map may also contain an entry with key extensions.

    But GraphQLResponse<T> seems to have only data and errors field. I think It's better that we can access to extensions field via GraphQLResponse<T> class.

    opened by ikenox 0
Releases(v7.11.0-beta.1)
Owner
Igor Borges
πŸ‡§πŸ‡·. 27. Staff Software Engineer. Bugless Developer.
Igor Borges
Libraries supporting GraphQL in Dart

gql-dart/gql This is an effort to advance the Dart GraphQL ecosystem. It consists of multiple packages and libraries centered around GraphQL AST. Core

GQL Dart 240 Dec 2, 2022
Stream Feed official Flutter SDK. Build your own feed experience using Dart and Flutter.

Official Flutter packages for Stream Activity Feeds The official Dart client for Stream Activity Feeds, a service for building activity feed applicati

Stream 67 Sep 26, 2022
Pensil Community official Flutter SDK. Build your own community experience using Dart and Flutter.

Official flutter package for Pensil The official Dart client for Pensil communities, a service for building communites applications. This library can

Pensil Inc 6 Oct 6, 2022
Build Win32 apps with Dart!

A package that wraps some of the most common Win32 API calls using FFI to make them accessible to Dart code without requiring a C compiler or the Wind

Tim Sneath 610 Jan 8, 2023
A Simple Todo app design in Flutter to keep track of your task on daily basis. Its build on BLoC Pattern. You can add a project, labels, and due-date to your task also you can sort your task on the basis of project, label, and dates

WhatTodo Life can feel overwhelming. But it doesn’t have to. A Simple To-do app design in flutter to keep track of your task on daily basis. You can a

Burhanuddin Rashid 1k Jan 6, 2023
Build a generative, customized admin for all platforms. Nice to use and nice to extend.

flutter admin kit Build a generative, customized admin for all platforms. Nice to use and nice to extend. Feature highlights: Declarative routing via

smartnuance 31 Nov 26, 2022
News Headline app is build in Flutter MVVM and REST Apis for News is used in this app.

About The Project Flutter MVVM project for News Headlines. REST Api for News is used in this project. App Demo Api for News Get free api from here : h

Aizaz ahmad 3 Aug 16, 2022
This is not an app. I made this architecture to build robust and easy-to-maintain products but in a faster way.

simple_architecture_flutter This is not an app. I made this architecture to build robust and easy-to-maintain products but in a faster way. Info I use

Batuhan Karababa 9 Oct 28, 2022
Learn to build apps that work on Android, iOS, Web, and Desktop

Cross-Platform Development with Flutter Course Learn to build apps that work on Android, iOS, Web, and Desktop Go To Course Flutter is Google’s UI too

Mohamed Ibrahim 11 Oct 24, 2022
build standings, matchs, players, news and all about premier league with flutter

premier_league A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started i

null 1 Feb 27, 2022
ChatMe is a messenger app build with Flutter and the power of Firebase

flutter_chatme A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started i

Aditya Rohman 11 Oct 24, 2022
let's build a mobile chat application using flutter and firebase

miichat A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if this

azzouz abdelhakim 2 Oct 7, 2022
Arisshopuiiesm - Build a clean and elegant Shop UI design for your Flutter app

Flutter Tutorial - 2/3 Shop UI - From Scratch We will build a clean and elegant

Behruz Hurramov 3 Oct 29, 2022
Chat-application - Build Chat Application using Flutter and Firebase

Build Chat Application using Flutter & Firebase Source Code - Enjoy ! Social Med

Muhammad Irvan 0 Jan 3, 2022
Showwcase is a professional network built for developers to connect, build community, and find new opportunities.

Showwcase Generated by the Very Good CLI ?? Showwcase is a professional network built for developers to connect, build community, and find new opportu

Luis Ciber 4 Jan 13, 2022
A Translator App Which is Build using Flutter, Speech To Text, Google ML Kit, Google Translator and Text To Speech.

AI Translator This is a Translator App Which is Build using Flutter, Speech To Text, Google ML Kit, Google Translator and Text To Speech. Download App

null 4 Jul 16, 2022
This is a mobile application that goals to build a quiz about programming subjects writter with Flutter.

❓ DevQuiz A mobile application being built with NLW5 (an event from Rockeatseat - https://app.rocketseat.com.br/). This application goals to build a q

Samilly Nunes 18 Dec 23, 2022
An expressive way to effortlessly build design systems in Flutter.

An expressive way to effortlessly build design systems in Flutter. Mix offers primitive building blocks to help developers and designers create beauti

Leo Farias 238 Jan 5, 2023
Hybrid App build on flutter SDK able to run on Android, IOS, web, desktop

Codeforces Visualizer APP Ready to use Flutter Application. Uses codeforces API. Useful for codeforces programmers. ScreenShots Single User Page Compa

vikas yadav 13 Dec 31, 2022