comigor / artemis Goto Github PK
View Code? Open in Web Editor NEWBuild dart types from GraphQL schemas and queries
License: MIT License
Build dart types from GraphQL schemas and queries
License: MIT License
It seems like queries with Object inputs can't be processed. I'm getting the following error for the following query:
query SomeQuery($filter: ModelEventFilterInput) {
viewer {
__typename
id
}
}
[INFO] Generating build script...
[INFO] Generating build script completed, took 307ms
[INFO] BuildDefinition:Initializing inputs
[INFO] BuildDefinition:Reading cached asset graph...
[INFO] BuildDefinition:Reading cached asset graph completed, took 101ms
[INFO] BuildDefinition:Checking for updates since last build...
[INFO] BuildDefinition:Checking for updates since last build completed, took 738ms
[INFO] Build:Running build...
[INFO] Build:Running build completed, took 29ms
[INFO] Build:Caching finalized dependency graph...
[INFO] Build:Caching finalized dependency graph completed, took 55ms
[SEVERE] artemis:artemis on lib/$lib$ (cached):
Stack Overflow
dart:core Iterable.firstWhere
package:artemis/generator/graphql_helpers.dart 53:10 getSingleScalarMap
package:artemis/generator/graphql_helpers.dart 33:22 buildTypeString
package:artemis/generator.dart 173:23 _createClassProperty
package:artemis/generator.dart 279:14 _extractClasses.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 303:8 _extractClasses
package:artemis/generator.dart 289:13 _extractClasses.<fn>.<fn>
package:artemis/generator.dart 179:20 _createClassProperty
package:artemis/generator.dart 279:14 _extractClasses.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 303:8 _extractClasses
package:artemis/generator.dart 289:13 _extractClasses.<fn>.<fn>
package:artemis/generator.dart 179:20 _createClassProperty
package:artemis/generator.dart 279:14 _extractClasses.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 303:8 _extractClasses
package:artemis/generator.dart 289:13 _extractClasses.<fn>.<fn>
package:artemis/generator.dart 179:20 _createClassProperty
package:artemis/generator.dart 279:14 _extractClasses.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 303:8 _extractClasses
package:artemis/generator.dart 289:13 _extractClasses.<fn>.<fn>
package:artemis/generator.dart 179:20 _createClassProperty
package:artemis/generator.dart 279:14 _extractClasses.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 303:8 _extractClasses
package:artemis/generator.dart 289:13 _extractClasses.<fn>.<fn>
package:artemis/generator.dart 179:20 _createClassProperty
package:artemis/generator.dart 279:14 _extractClasses.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 303:8 _extractClasses
package:artemis/generator.dart 289:13 _extractClasses.<fn>.<fn>
package:artemis/generator.dart 179:20 _createClassProperty
package:artemis/generator.dart 279:14 _extractClasses.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 303:8 _extractClasses
package:artemis/generator.dart 289:13 _extractClasses.<fn>.<fn>
package:artemis/generator.dart 179:20 _createClassProperty
package:artemis/generator.dart 279:14 _extractClasses.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 303:8 _extractClasses
package:artemis/generator.dart 289:13 _extractClasses.<fn>.<fn>
package:artemis/generator.dart 179:20 _createClassProperty
. ...
. ...
package:artemis/generator.dart 179:20 _createClassProperty
package:artemis/generator.dart 279:14 _extractClasses.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 303:8 _extractClasses
package:artemis/generator.dart 289:13 _extractClasses.<fn>.<fn>
package:artemis/generator.dart 179:20 _createClassProperty
package:artemis/generator.dart 279:14 _extractClasses.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 303:8 _extractClasses
package:artemis/generator.dart 106:30 generateQuery.<fn>
dart:core List.forEach
package:artemis/generator.dart 100:35 generateQuery
package:artemis/generator.dart 21:21 generateLibrary.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 23:8 generateLibrary
package:artemis/builder.dart 93:29 GraphQLQueryBuilder.build
[SEVERE] Build:
Failed after 131ms
Is there something that would need to be set explicitly for this to work?
I create by file graphql with content:
query AllUsers($filter: FilterInput, $limit: Int, $nextToken: String) {
allUsers(filter: $filter, limit: $limit, nextToken: $nextToken) {
items {
Attributes {
Name
Value
}
Username
}
nextToken
}
}
with file schema.json create from appsync aws. Everything worked fine and created .dart files but it didn't include enum type.
Has it been supported since the beginning or is this a bug?
From here, you can find that builder can be added in the builders
section of pubspec.yaml
, so it will run as a step for build, or flutter run.
That could let the code generation as build step of the code.
I have this on my build.yaml
schema_mapping:
- schema: rygapp.schema.json
queries_glob: graphql/**.query.graphql
output: lib/graphql/consultas.dart
When I run I received this error :
Exception: Two classes were generated with the same name Usuario
!
You may want to do either:
Enable add_query_prefix on this schema_map
Make queries_glob stricter, to gather less .graphql files on a single output
Use alias on one of the places a Usuario
field is requested
Ok. I understand what causes the issue.
What about create one file per query :
schema_mapping:
- schema: rygapp.schema.json
queries_glob: graphql/**.query.graphql
output: lib/graphql/**
So it will create many files without the need to declare each query on build.yaml
Hey there, tried searching but couldn't find any mention of subscription query types for gql. Wondering if they are currently supported and if not if there is any plan to support them?
thanks!
I have the following mutation
written in a file that is built by artemis
:
mutation ExternalAuthenticate(
$provider: AuthProvider!
$email: String!
$username: String!
) {
externalAuthenticate(
provider: $provider
email: $email
username: $username
)
}
AuthProvider is an enum, and works perfectly in, say, the GraphQL Playground. However, the artemis generated output does not contain this enum type. I get an error in the output, for the variable arguments of the mutation that tells me the class is undefined.
@JsonSerializable(explicitToJson: true)
class ExternalAuthenticateArguments extends JsonSerializable with EquatableMixin {
ExternalAuthenticateArguments({this.provider, this.email, this.username});
factory ExternalAuthenticateArguments.fromJson(Map<String, dynamic> json) =>
_$ExternalAuthenticateArgumentsFromJson(json);
final AuthProvider provider; // Undefined class 'AuthProvider'.
final String email;
final String username;
@override
List<Object> get props => [provider, email, username];
Map<String, dynamic> toJson() => _$ExternalAuthenticateArgumentsToJson(this);
}
Here is my build.yaml
:
targets:
$default:
sources:
- lib/**
- lib/graphql/**
- my.schema.json
builders:
artemis:
options:
schema_mapping:
- schema: my.schema.json
queries_glob: lib/graphql/**.graphql
output: lib/graphql_api.dart
If I create the common.graphql
for fragments and refer from two different files to the fragments from common.graphql
i'll get the next error - https://tppr.me/X9tyQ
I'll try to fix this this and cover with tests)
I'm using this lib with GitHub GraphQL API. Seems it does not support operation name and returns an error:
{"errors":[{"message":"No operation named \"test\""}]}
Hi. Thanks for you work.
I'd like to suggest an improvement.
I have a query
query SearchDestinationsData($pagination: PaginationInput!, $startsWith: Boolean!, $term: String!, $types: [DestinationType!]) {
searchDestinations(pagination: $pagination, startsWith: $startsWith, term: $term, types: $types) {
destinations {
id
name
type
}
totalCount
}
}
After generation I have corresponding class
class SearchDestinationsDataArguments extends JsonSerializable
with EquatableMixin {
SearchDestinationsDataArguments(
{this.pagination, this.startsWith, this.term, this.types});
...
}
The arguments in constructor are not marked with @required
annotation but they are definitely required according(marked with exclamation mark PaginationInput!
) to the schema definition.
Expected result
SearchDestinationsDataArguments(
{@required this.pagination, @required this.startsWith, @required this.term, this.types})
This will help to avoid unexpected errors.
Thanks
As far as dart passes objects by reference it would be great to have a 'copyWith' extension for the data classes with something like this
https://github.com/numen31337/copy_with_extension
docs
https://www.oleksandrkirichenko.com/blog/dart-extensions/
Hey there! I'm exploring this library a bit, working good so far, but I got a custom scalar for BigDecimal
that uses decimal on the dart side, as you can see in my custom parser:
import 'package:decimal/decimal.dart';
Decimal fromGraphQLBigDecimalToDartDecimal(String value) => Decimal.parse(value);
String fromDartDecimalToGraphQLBigDecimal(Decimal value) => value.toString();
But the generated code does not build because it is missing a import for package:decimal/decimal.dart
, so the compiler cannot figure out where Decimal
is defined.
I'm editing the generated file and adding the import manually in order to be able to run my app.
Maybe we should have a imports
array in the ScalarMap and inject the imports from there in the resulting file?
The build config would look like this:
scalar_mapping:
- graphql_type: BigDecimal
dart_type: Decimal
use_custom_parser: true
imports: ['package:decimal/decimal.dart']
Another alternative I can think of is using a map, but that could make the logic a bit more complicated (to handle string or map):
scalar_mapping:
- graphql_type: BigDecimal
dart_type:
name: Decimal
import: 'package:decimal/decimal.dart'
use_custom_parser: true
WDYT? I can work on a PR to implement this on my spare time.
Is there a way to generate classes from the base types of a schema? Is this planned?
We'll want to do this for graphql-flutter, and maintain fragment inheritance somehow
// base type
class Foo {
String _foo;
int _bar;
}
//fragment exposing foo
class FooFragment extends Foo {
String get foo => _foo;
set foo(String value) => _foo = value;
FooFragment({String foo}) {
this.foo = foo;
}
}
Relatedly, we'll need to be able to customize the generated models if we continue with the moor cache route
Hi,
Generated files are not following some analyzer rules (ex: public_member_api_docs), would it be possible to add an //ignore_for_file: ..
with rules ?
Or even better, as possible with json_serializable (coming from source_gen: https://pub.dev/packages/source_gen#configuring-combining_builder-ignore_for_file) a way to specify in bulid.yaml; some rules to ignore in generated files.
source_gen|combining_builder:
options:
ignore_for_file:
- public_member_api_docs
Thanks :)
When using graphql codegen and the introspection
plugin, the JSON output has a root key of schema
, but the artemis parser expects this object to be nested inside a root data
object (I believe this is the result if you request the introspection schema from the server).
The error you see in my case is:
[SEVERE] artemis:artemis on lib/$lib$:
NoSuchMethodError: The method '[]' was called on null.
Receiver: null
Tried calling: []("__schema")
It shouldn't be too hard to support both formats in the parser.
An alternative solution might be to support fetching the schema from a server directly (similar to what is supported by graphql codegen). I am already using graphql codegen for another corner of this project, so it was convenient to use it for providing the introspection json for artemis to consume as well, but it would be much cleaner to configure artemis to fetch the schema from the server directly.
Hi,
I would like to output my .g.dart
and .dart
files into generated/
folder.
Is it possible to do so? How can I do it?
I'm getting this error.
Not sure what could cause that
NoSuchMethodError: The getter 'value' was called on null.
Receiver: null
Tried calling: value
dart:core Object.noSuchMethod
package:artemis/generator.dart 71:43 generateQuery
package:artemis/generator.dart 33:19 generateLibrary.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 34:8 generateLibrary
package:artemis/builder.dart 66:29 GraphQLQueryBuilder.build
package:build runBuilder
package:build_runner_core/src/generate/build_impl.dart 472:19 _SingleBuild._runForInput.<fn>.<fn>.<fn>
package:build_runner_core/src/generate/performance_tracker.dart 300:15 _NoOpBuilderActionTracker.trackStage
package:build_runner_core/src/generate/build_impl.dart 470:23 _SingleBuild._runForInput.<fn>.<fn>
package:timing/src/timing.dart 222:44 NoOpTimeTracker.track
package:build_runner_core/src/generate/build_impl.dart 429:22 _SingleBuild._runForInput.<fn>
package:pool/pool.dart 127:28 Pool.withResource
package:build_runner_core/src/generate/build_impl.dart 425:17 _SingleBuild._runForInput
package:build_runner_core/src/generate/build_impl.dart 373:38 _SingleBuild._runBuilder.<fn>
dart:async Future.wait
package:build_runner_core/src/generate/build_impl.dart 372:36 _SingleBuild._runBuilder
package:build_runner_core/src/generate/build_impl.dart 319:20 _SingleBuild._runPhases.<fn>.<fn>
package:build_runner_core/src/generate/performance_tracker.dart 184:15 _NoOpBuildPerformanceTracker.trackBuildPhase
package:build_runner_core/src/generate/build_impl.dart 315:47 _SingleBuild._runPhases.<fn>
package:timing/src/timing.dart 222:44 NoOpTimeTracker.track
package:build_runner_core/src/generate/build_impl.dart 309:32 _SingleBuild._runPhases
package:build_runner_core/src/logging/logging.dart 25:30 logTimedAsync
package:build_runner_core/src/generate/build_impl.dart 266:26 _SingleBuild._safeBuild.<fn>
dart:async runZoned
package:build_runner_core/src/generate/build_impl.dart 261:5 _SingleBuild._safeBuild
package:build_runner_core/src/generate/build_impl.dart 208:24 _SingleBuild.run
package:build_runner_core/src/generate/build_impl.dart 96:42 BuildImpl.run
package:build_runner_core/src/generate/build_runner.dart 25:14 BuildRunner.run
package:build_runner BuildCommand.run
package:args/command_runner.dart 197:27 CommandRunner.runCommand
package:args/command_runner.dart 112:25 CommandRunner.run.<fn>
dart:async new Future.sync
package:args/command_runner.dart 112:14 CommandRunner.run
package:build_runner run
.dart_tool/build/entrypoint/build.dart 27:22 main
I also notice that it printed a lot of this warnnings
[INFO] Build:Running build...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "id" of class "Repo". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "role" of class "Repo". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "last_updated_by_card" of class "Repo". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "opened_cards_count" of class "Repo". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "anyone_can_create_card" of class "Repo". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "users_count" of class "Repo". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "id" of class "Repo". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "role" of class "Repo". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "last_updated_by_card" of class "Repo". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "opened_cards_count" of class "Repo". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "anyone_can_create_card" of class "Repo". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "users_count" of class "Repo". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "id" of class "PublicPipeInterface". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "name" of class "PublicPipeInterface". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "icon" of class "PublicPipeInterface". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "role" of class "PublicPipeInterface". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "opened_cards_count" of class "PublicPipeInterface". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "id" of class "PublicPipeInterface". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "name" of class "PublicPipeInterface". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "icon" of class "PublicPipeInterface". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "role" of class "PublicPipeInterface". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "opened_cards_count" of class "PublicPipeInterface". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "name" of class "PipeSharedProperties". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "icon" of class "PipeSharedProperties". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "last_updated_by_card" of class "PipeSharedProperties". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "anyone_can_create_card" of class "PipeSharedProperties". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "users_count" of class "PipeSharedProperties". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "name" of class "PipeSharedProperties". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "icon" of class "PipeSharedProperties". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "last_updated_by_card" of class "PipeSharedProperties". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "anyone_can_create_card" of class "PipeSharedProperties". Moving on...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "users_count" of class "PipeSharedProperties". Moving on...
[SEVERE] artemis:artemis on lib/$lib$:
A query like this :
query RygappGeral {
versao
}
generates a file with :
final String operationName = 'rygapp_geral';
As the names are not equals it gives a runtime erro of :
Unknown operation named "rygapp_geral"
If I named my query rygapp_geral it works fine.
I'm not sure what has broken here.
It might have something to do with _defaultScalarMapping
, or some sort of variable that should be specified in the ScalarMap
, but the error is not clear, so I couldn't know what I'm doing wrong or if it is a new bug.
artemis/lib/generator/graphql_helpers.dart
Lines 47 to 54 in fca47fd
Stack Overflow
dart:collection ListMixin.followedBy
package:artemis/generator/graphql_helpers.dart 49:10 getSingleScalarMap
package:artemis/generator/graphql_helpers.dart 30:22 buildTypeString
package:artemis/generator/graphql_helpers.dart 27:14 buildTypeString
package:artemis/generator.dart 155:23 _createClassProperty
package:artemis/generator.dart 238:14 _extractClasses.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 264:8 _extractClasses
package:artemis/generator.dart 249:15 _extractClasses.<fn>.<fn>
package:artemis/generator.dart 160:20 _createClassProperty
package:artemis/generator.dart 238:14 _extractClasses.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 264:8 _extractClasses
package:artemis/generator.dart 249:15 _extractClasses.<fn>.<fn>
package:artemis/generator.dart 160:20 _createClassProperty
package:artemis/generator.dart 238:14 _extractClasses.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 264:8 _extractClasses
package:artemis/generator.dart 249:15 _extractClasses.<fn>.<fn>
package:artemis/generator.dart 160:20 _createClassProperty
package:artemis/generator.dart 238:14 _extractClasses.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 264:8 _extractClasses
package:artemis/generator.dart 249:15 _extractClasses.<fn>.<fn>
package:artemis/generator.dart 160:20 _createClassProperty
package:artemis/generator.dart 238:14 _extractClasses.<fn>
dart:_internal ListIterable.toList
. ...
. ...
package:artemis/generator.dart 264:8 _extractClasses
package:artemis/generator.dart 249:15 _extractClasses.<fn>.<fn>
package:artemis/generator.dart 160:20 _createClassProperty
package:artemis/generator.dart 238:14 _extractClasses.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 264:8 _extractClasses
package:artemis/generator.dart 88:30 generateQuery.<fn>
dart:core List.forEach
package:artemis/generator.dart 82:35 generateQuery
package:artemis/generator.dart 21:19 generateLibrary.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 22:8 generateLibrary
package:artemis/builder.dart 66:29 GraphQLQueryBuilder.build
[SEVERE] Build:
Failed after 8.4s
pub finished with exit code 1
#0 throwToolExit (package:flutter_tools/src/base/common.dart:28:3)
#1 pubInteractively (package:flutter_tools/src/dart/pub.dart:213:5)
<asynchronous suspension>
#2 PackagesForwardCommand.runCommand (package:flutter_tools/src/commands/packages.dart:241:11)
<asynchronous suspension>
#3 FlutterCommand.verifyThenRunCommand (package:flutter_tools/src/runner/flutter_command.dart:527:18)
#4 _asyncThenWrapperHelper.<anonymous closure> (dart:async-patch/async_patch.dart:71:64)
#5 _rootRunUnary (dart:async/zone.dart:1132:38)
#6 _CustomZone.runUnary (dart:async/zone.dart:1029:19)
#7 _FutureListener.handleValue (dart:async/future_impl.dart:137:18)
#8 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:678:45)
#9 Future._propagateToListeners (dart:async/future_impl.dart:707:32)
#10 Future._completeWithValue (dart:async/future_impl.dart:522:5)
#11 Future._asyncComplete.<anonymous closure> (dart:async/future_impl.dart:552:7)
#12 _rootRun (dart:async/zone.dart:1124:13)
#13 _CustomZone.run (dart:async/zone.dart:1021:19)
#14 _CustomZone.runGuarded (dart:async/zone.dart:923:7)
#15 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:963:23)
#16 _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
#17 _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)
#18 _runPendingImmediateCallback (dart:isolate-patch/isolate_patch.dart:116:13)
#19 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:173:5)
Artemis needs the value of __typename
field of union types and interfaces to be able to differentiate the object type when resolving those types. This means the user must add the type name field (tipically __typename
) to the union type/interfaces they're querying.
Ideally, Artemis could automatically add this field to the query, avoiding this hassle.
I'm working with a graphql endpoint that has both class names and property names come back in snake_case. This causes issues with Dart linter/compiler since it is expecting class names to be in PascalCase and properties to be in camelCase
Currently functionality generates as
@JsonSerializable(explicitToJson: true)
class group_mutation_response with EquatableMixin {
group_mutation_response({this.returning_groups});
factory group_mutation_response.fromJson(Map<String, dynamic> json) =>
_$group_mutation_responseFromJson(json);
List<group> returning_groups;
@override
List<Object> get props => [returning_groups];
Map<String, dynamic> toJson() => _$group_mutation_responseToJson(this);
}
Ideally it would generate as
@JsonSerializable(explicitToJson: true)
class GroupMutationResponse with EquatableMixin { // <----- PascalCase
GroupMutationResponse({this.returningGroups});
factory GroupMutationResponse.fromJson(Map<String, dynamic> json) =>
_$GroupMutationResponse(json);
@JsonKey(name: 'returning_groups') // <---- Handle mapping to/from graphql json
List<Group> returningGroups; // <---- camelCase
@override
List<Object> get props => [returningGroups];
Map<String, dynamic> toJson() => _$GroupMutationResponseToJson(this); // <---- PascalCase
}
Is there anything I can do to force the casing to generate using dart compatible casing?
#52 Issue with shared fragments is partially resolved in this PR: #65
But there is still a problem, new fragment mixin is generated for every query.
So you must use different output files for queries which use the same fragment.
This leading to the next problem: you can't use these mixins as base class for your fields in generated classes.
I hope the most appropriate solution would be to add fragmets_output
field in build.yaml
options and import this in queries output. (maybe also export(?))
I have tried to generate the error using the pokemon example from the this repo.
the schema:
https://github.com/agent3bood/artemis/blob/master/example/pokemon/pokemon.schema.graphql#L96
the query:
https://github.com/agent3bood/artemis/blob/master/example/pokemon/graphql/complex_query.query.graphql
the generated input type is wrong:
https://github.com/agent3bood/artemis/blob/master/example/pokemon/lib/graphql/complex_query.graphql.dart#L59
it is
final List<ComplexQuery$Query> input;
which should be
final List<ComplexQuery$complexObjects> input;
Hey there! First of all thanks for this package, it really helps us to improve our development process! I have some troubles building unions and connections with unions.
I have the following gql queries:
query Search($searchTerm, $filters, $first, $last, and more...) {
edges {
node {
.. on Product {
id
}
.. on User {
id
}
}
}
}
or
query CurrentViewer($id, $favorites_first, and more..) {
node(id: $id) {
id
favorites(first: $favorites_first) {
edges {
node {
.. on Location {
id
}
.. on Category {
id
}
}
}
}
}
}
In both cases the type Node
has no props
e.g.:
--- SNIP ---
@JsonSerializable(explicitToJson: true)
class Searchables with EquatableMixin {
Searchables();
factory Searchables.fromJson(Map<String, dynamic> json) =>
_$SearchablesFromJson(json);
@override
List<Object> get props => []; # empty props
Map<String, dynamic> toJson() => _$SearchablesToJson(this);
}
--- SNIP ---
Expectation is:
--- SNIP ---
@JsonSerializable(explicitToJson: true)
class Node with EquatableMixin {
Node();
factory Node.fromJson(Map<String, dynamic> json) {
switch (json['__typename']) {
case 'Category':
return Category.fromJson(json);
case 'Location':
return Location.fromJson(json);
default:
}
return _$NodeFromJson(json);
}
}
--- SNIP ---
Including the file name in the stack trace output would greatly improve usability
flutter pub run build_runner build -vvv
[INFO] Generating build script...
[INFO] Generating build script completed, took 267ms
[INFO] BuildDefinition:Initializing inputs
[INFO] BuildDefinition:Reading cached asset graph...
[INFO] BuildDefinition:Reading cached asset graph completed, took 94ms
[INFO] BuildDefinition:Checking for updates since last build...
[INFO] BuildDefinition:Checking for updates since last build completed, took 837ms
[INFO] Build:Running build...
[INFO] Build:Running build completed, took 27ms
[INFO] Build:Caching finalized dependency graph...
[INFO] Build:Caching finalized dependency graph completed, took 53ms
[SEVERE] artemis:artemis on lib/$lib$ (cached):
NoSuchMethodError: The getter 'selections' was called on null.
Receiver: null
Tried calling: selections
dart:core Object.noSuchMethod
package:artemis/generator.dart 435:28 _extractClasses.<fn>
dart:collection SetMixin.forEach
package:artemis/generator.dart 423:23 _extractClasses
package:artemis/generator.dart 99:19 generateQuery
package:artemis/generator.dart 21:21 generateLibrary.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 22:8 generateLibrary
package:artemis/builder.dart 75:29 GraphQLQueryBuilder.build
package:build runBuilder
package:build_runner_core/src/generate/build_impl.dart 478:19 _SingleBuild._runForInput.<fn>.<fn>.<fn>
package:build_runner_core/src/generate/performance_tracker.dart 300:15 _NoOpBuilderActionTracker.trackStage
package:build_runner_core/src/generate/build_impl.dart 476:23 _SingleBuild._runForInput.<fn>.<fn>
package:timing/src/timing.dart 222:44 NoOpTimeTracker.track
package:build_runner_core/src/generate/build_impl.dart 434:22 _SingleBuild._runForInput.<fn>
package:pool/pool.dart 127:28 Pool.withResource
package:build_runner_core/src/generate/build_impl.dart 430:17 _SingleBuild._runForInput
package:build_runner_core/src/generate/build_impl.dart 378:38 _SingleBuild._runBuilder.<fn>
dart:async Future.wait
package:build_runner_core/src/generate/build_impl.dart 377:36 _SingleBuild._runBuilder
package:build_runner_core/src/generate/build_impl.dart 323:20 _SingleBuild._runPhases.<fn>.<fn>
package:build_runner_core/src/generate/performance_tracker.dart 184:15 _NoOpBuildPerformanceTracker.trackBuildPhase
package:build_runner_core/src/generate/build_impl.dart 319:47 _SingleBuild._runPhases.<fn>
package:timing/src/timing.dart 222:44 NoOpTimeTracker.track
package:build_runner_core/src/generate/build_impl.dart 313:32 _SingleBuild._runPhases
package:build_runner_core/src/logging/logging.dart 25:30 logTimedAsync
package:build_runner_core/src/generate/build_impl.dart 270:26 _SingleBuild._safeBuild.<fn>
dart:async runZoned
package:build_runner_core/src/generate/build_impl.dart 265:5 _SingleBuild._safeBuild
package:build_runner_core/src/generate/build_impl.dart 212:24 _SingleBuild.run
package:build_runner_core/src/generate/build_impl.dart 97:56 BuildImpl.run
package:build_runner_core/src/generate/build_runner.dart 25:14 BuildRunner.run
package:build_runner BuildCommand.run
package:args/command_runner.dart 197:27 CommandRunner.runCommand
package:args/command_runner.dart 112:25 CommandRunner.run.<fn>
dart:async new Future.sync
package:args/command_runner.dart 112:14 CommandRunner.run
package:build_runner run
.dart_tool/build/entrypoint/build.dart 31:22 main
[SEVERE] Build:
Failed after 145ms
pub finished with exit code 1
It might be related to
Lines 80 to 88 in ce09046
type 'ListTypeNode' is not a subtype of type 'NamedTypeNode'
package:artemis/generator.dart 84:21 generateQuery.<fn>
dart:core List.forEach
package:artemis/generator.dart 83:35 generateQuery
package:artemis/generator.dart 33:19 generateLibrary.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 34:8 generateLibrary
package:artemis/builder.dart 66:29 GraphQLQueryBuilder.build
package:build runBuilder
package:build_runner_core/src/generate/build_impl.dart 477:19 _SingleBuild._runForInput.<fn>.<fn>.<fn>
package:build_runner_core/src/generate/performance_tracker.dart 300:15 _NoOpBuilderActionTracker.trackStage
package:build_runner_core/src/generate/build_impl.dart 475:23 _SingleBuild._runForInput.<fn>.<fn>
package:timing/src/timing.dart 222:44 NoOpTimeTracker.track
package:build_runner_core/src/generate/build_impl.dart 434:22 _SingleBuild._runForInput.<fn>
package:pool/pool.dart 127:28 Pool.withResource
package:build_runner_core/src/generate/build_impl.dart 430:17 _SingleBuild._runForInput
package:build_runner_core/src/generate/build_impl.dart 378:38 _SingleBuild._runBuilder.<fn>
dart:async Future.wait
package:build_runner_core/src/generate/build_impl.dart 377:36 _SingleBuild._runBuilder
package:build_runner_core/src/generate/build_impl.dart 323:20 _SingleBuild._runPhases.<fn>.<fn>
package:build_runner_core/src/generate/performance_tracker.dart 184:15 _NoOpBuildPerformanceTracker.trackBuildPhase
package:build_runner_core/src/generate/build_impl.dart 319:47 _SingleBuild._runPhases.<fn>
package:timing/src/timing.dart 222:44 NoOpTimeTracker.track
package:build_runner_core/src/generate/build_impl.dart 313:32 _SingleBuild._runPhases
package:build_runner_core/src/logging/logging.dart 25:30 logTimedAsync
package:build_runner_core/src/generate/build_impl.dart 270:26 _SingleBuild._safeBuild.<fn>
dart:async runZoned
package:build_runner_core/src/generate/build_impl.dart 265:5 _SingleBuild._safeBuild
package:build_runner_core/src/generate/build_impl.dart 212:24 _SingleBuild.run
package:build_runner_core/src/generate/build_impl.dart 97:56 BuildImpl.run
package:build_runner_core/src/generate/build_runner.dart 25:14 BuildRunner.run
package:build_runner BuildCommand.run
package:args/command_runner.dart 197:27 CommandRunner.runCommand
package:args/command_runner.dart 112:25 CommandRunner.run.<fn>
dart:async new Future.sync
package:args/command_runner.dart 112:14 CommandRunner.run
package:build_runner run
.dart_tool/build/entrypoint/build.dart 27:22 main
Is it possible to share fragments between queries?
For example if I have a fragment and two queries that use it...
fragment Category on JobCategory {
id
name
}
query fetchInformationToCreateJobs($divisionId: Int!) {
jobCategories(divisionId: $divisionId) {
...JobCategory
}
}
query prefetcher($divisionId: Int!) {
jobCategories(divisionId: $divisionId) {
...JobCategory
}
division(id: $divisionId) {
id
name
}
}
If I place the fragment one of the queries or the other I get the following error message:
[SEVERE] artemis:artemis on lib/$lib$:
Bad state: No element
dart:collection ListMixin.firstWhere
package:artemis/generator.dart 290:16 _extractClasses.<fn>
dart:core Iterable.forEach
package:artemis/generator.dart 306:10 _extractClasses
package:artemis/generator.dart 320:15 _extractClasses.<fn>.<fn>
package:artemis/generator.dart 159:20 _createClassProperty
package:artemis/generator.dart 206:10 _selectionToClassProperty
package:artemis/generator.dart 308:20 _extractClasses.<fn>
dart:core Iterable.forEach
package:artemis/generator.dart 306:10 _extractClasses
package:artemis/generator.dart 98:19 generateQuery
package:artemis/generator.dart 21:21 generateLibrary.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 22:8 generateLibrary
package:artemis/builder.dart 75:29 GraphQLQueryBuilder.build
package:build runBuilder
package:build_runner_core/src/generate/build_impl.dart 478:19 _SingleBuild._runForInput.<fn>.<fn>.<fn>
package:build_runner_core/src/generate/performance_tracker.dart 300:15 _NoOpBuilderActionTracker.trackStage
package:build_runner_core/src/generate/build_impl.dart 476:23 _SingleBuild._runForInput.<fn>.<fn>
package:timing/src/timing.dart 222:44 NoOpTimeTracker.track
package:build_runner_core/src/generate/build_impl.dart 434:22 _SingleBuild._runForInput.<fn>
package:pool/pool.dart 127:28 Pool.withResource
package:build_runner_core/src/generate/build_impl.dart 430:17 _SingleBuild._runForInput
package:build_runner_core/src/generate/build_impl.dart 378:38 _SingleBuild._runBuilder.<fn>
dart:async Future.wait
package:build_runner_core/src/generate/build_impl.dart 377:36 _SingleBuild._runBuilder
package:build_runner_core/src/generate/build_impl.dart 323:20 _SingleBuild._runPhases.<fn>.<fn>
package:build_runner_core/src/generate/performance_tracker.dart 184:15 _NoOpBuildPerformanceTracker.trackBuildPhase
package:build_runner_core/src/generate/build_impl.dart 319:47 _SingleBuild._runPhases.<fn>
package:timing/src/timing.dart 222:44 NoOpTimeTracker.track
package:build_runner_core/src/generate/build_impl.dart 313:32 _SingleBuild._runPhases
package:build_runner_core/src/logging/logging.dart 25:30 logTimedAsync
package:build_runner_core/src/generate/build_impl.dart 270:26 _SingleBuild._safeBuild.<fn>
dart:async runZoned
package:build_runner_core/src/generate/build_impl.dart 265:5 _SingleBuild._safeBuild
package:build_runner_core/src/generate/build_impl.dart 212:24 _SingleBuild.run
package:build_runner_core/src/generate/build_impl.dart 97:56 BuildImpl.run
package:build_runner_core/src/generate/build_runner.dart 25:14 BuildRunner.run
package:build_runner BuildCommand.run
package:args/command_runner.dart 197:27 CommandRunner.runCommand
package:args/command_runner.dart 112:25 CommandRunner.run.<fn>
dart:async new Future.sync
package:args/command_runner.dart 112:14 CommandRunner.run
package:build_runner run
.dart_tool/build/entrypoint/build.dart 31:22 main
If I place the fragment in both of the queries I get:
Exception: Two classes were generated with the same name `JobCategory`!
You may want to do either:
- Enable add_query_prefix on this schema_map
- Make queries_glob stricter, to gather less .graphql files on a single output
- Use alias on one of the places a `JobCategory` field is requested
I understand that it is possible to define two different schema mappings and have these generate to two different files. However, I would like the resultant fragment class to be independent of the queries like apollo does
For javascript there is a module called gqless: https://gqless.dev/
It basically generates all your queries etc. based on how you use them in your code. So you don't need any .query.graqhql files anymore and you also don't need to update them because you need a new property in your request somewhere within your app.
But you still get auto completion because gqless uses the schema.graphl file to generate the types for that.
So I think that this approach is pretty cool as you will automatically fetch the most minimal amount of data from your server as possible, because your code defines, what you need and you don't fetch to much just because you put to much fields into your local .query.graphql file..
Also the general usage is much faster as you don't need to write those files anymore at all.
So I think it would be amazing to have such a feature in Artemis.
What do you think?
Today, it's always a breaking change to add a new option on a Enum on Artemis: the generated code will create an Enum based on the schema of on that code was generated, and if the server returns a new value on that enum, it will break with "ArgumentError".
To make enums retro-compatible, I suggest to (optionally) add an UNKNOWN
value to every enum, and fallback to it on (well) unknown values.
Originally posted by @michael-golfi in #31
I use __typename/id
as a key for client side caching.
It's currently, on purpose, filtering any field that starts with __
.
First thanks for such a great project. I'm trying to add an call an Amplify graphql server that requires Cognito authorization as follows:
https://github.com/jonsaw/amazon-cognito-identity-dart/#for-appsyncs-graphql
final body = {
'operationName': 'CreateItem',
'query': '''mutation CreateItem {
createItem(name: "Some Name") {
name
}
}''',
};
http.Response response;
try {
response = await http.post(
'$_endpoint/graphql',
headers: {
'Authorization': _session.getAccessToken().getJwtToken(),
'Content-Type': 'application/json',
},
body: json.encode(body),
);
} catch (e) {
print(e);
}
print(response.body);
Is it possible to pass custom headers to through ArtemisClient so that I can include the appropriate Authorization
header?
Hello,
I did not find any example with the artemis package on how to use the type_name_field argument in the build.yaml to resolve interface.
Does anyone have an idea on how to do it?
Thanks in advance.
The way graphql_flutter implements NormalizedCache would require denormalizing data on every build call, making allocations for everything under that type for fields that may not be even relevant.
Like a list of friends and respective chat history that would require denormalizing the chat history and allocate it event if I just asked for the friends names.
I would suggest using lazy getters that use their public Map<String,dynamic> interface to interact with data.
That means type generation becomes "cost free" as the compiler would remove most of the indirection it generates and wouldn't require any allocation, dereferencing, etc.
The way I'm currently dealing with it is like this:
# addressAutosuggest: [AddressAutosuggestResponse!]!
addressAutosuggest {
locationName # String!
latitude # Float!
longitude # Float!
}
// generated
class AddressAutosuggestAddressAutosuggestResponse {
AddressAutosuggestAddressAutosuggestResponse(this._d);
final Map<String, dynamic> _d;
String get locationName => this._d["locationName"];
double get latitude => this._d["latitude"].toDouble();
double get longitude => this._d["longitude"].toDouble();
}
class AddressAutosuggest {
AddressAutosuggest(this._d);
final Map<String, dynamic> _d;
List<AddressAutosuggestAddressAutosuggestResponse> get addressAutosuggest =>
(this._d["addressAutosuggest"] as List)
.map<AddressAutosuggestAddressAutosuggestResponse>(
(dynamic addressAutosuggestResponse) =>
AddressAutosuggestAddressAutosuggestResponse(
addressAutosuggestResponse))
.toList();
}
Thanks for this lib, really amazing!
I'm planning to replace all the GraphQL queries with artemis
in my app, and have some problems with GitHub search API:
{
search(first: 10, type: REPOSITORY, query: "flutter") {
nodes {
__typename
... on Repository {
name
}
}
}
}
Seems the generated dart file has several analyzer errors. The schema file could be found here.
I tried to keep my.schema.json
file in the root directory of the flutter app (one directory before /lib
). But, the files couldn't be generated.
targets:
$default:
sources:
- lib/**
builders:
artemis:
options:
schema_mapping:
- schema: my.schema.json
queries_glob: lib/**.query.graphql
resolve_type_field: __typename
Then, I try to use schema: ./my.schema.json
, but didn't work as well.
And then, I tried to use schema: lib/my.schema.json
and also moved the file to inside /lib
folder, so it managed to work well and generate the files.
In relay, one of the strength points is that queries and fragments can be written along side the widgets using them.
We had a discussion regarding this here.
For example:
@gql(r"""
query MyHomePage_query {
...AllFilmsList_allFilms
}
""")
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return QueryBuilder(
query: MyHomePage_query(),
builder: (context, QueryResponse<$MyHomePage_query> response) {
// The QueryBuilder implicitly exposese through context the AllFilmsList_allFilms fragment
return AllFilmsList();
}
);
}
}
@gql(r"""
fragment AllFilmsList_allFilms {
allFilms {
title
}
}
""")
class AllFilmsList extends StatelessWidget {
const AllFilmsList({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return FragmentBuilder<$AllFilmsList_allFilms>(
builder: (context, allFilms) {
}
);
}
}
I also have been able to make vscode to auto-complete me inside the annotation's query.
What do you think?
It would be nice if the plugin could automatically generate a dart file for each query.graphql file.
Also it should generate a types.dart which contains all shared types like enums.
This would make it more easy for me to work with the "simple" naming_scheme configuration.
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.
Error:
Two classes were generated with the same name `EntryTimeEntityMixin`!
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 `EntryTimeEntityMixin` is requested
- Change naming_scheme to `pathedWithFields` to avoid duplication
fragments_glob.fragment.qraphql:
fragment EntryTimeEntity on EntryTimeEntity {
lesson
length
}
query_1.query.graphql:
query moduleDataExams($moduleId: String!) {
moduleDataExams(moduleId: $moduleId) {
id
date
sClass
time {
...EntryTimeEntity
}
subject
teacher
comment
}
}
query_2.query.graphql:
query moduleDataSubst($moduleId: String!) {
moduleDataSubst(moduleId: $moduleId) {
entries {
time {
...EntryTimeEntity
}
additionalData {
insteadOf {
date
time {
...EntryTimeEntity
}
}
postponed {
date
time {
...EntryTimeEntity
}
}
customType
}
}
}
}
build.yaml:
targets:
$default:
sources:
- lib/**
- graphql/**
builders:
artemis:
options:
fragments_glob: graphql/**.fragment.graphql
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
I'm using the fragment EntryTimeEntity
on 2 different queries. Why is this a problem?
type BaseSchoolEntity {
id: String!
name: String!
city: String!
theme: SchoolTheme!
authRequired: Boolean!
}
type DocumentDataEntity {
type: DocumentDataType!
data: String!
}
# Document data type
enum DocumentDataType {
PDF
IMAGE
}
type DocumentEntity implements ModuleData {
_type: String!
title: String!
description: String!
date: String!
type: DocumentDataType!
id: String!
feedback: DocumentFeedbackEntity!
}
type DocumentFeedbackEntity {
required: Boolean!
sent: Boolean!
fields: [String!]!
}
type EntryTimeEntity {
lesson: String!
length: Int!
}
type ExamEntryEntity implements ModuleData {
_type: String!
id: String!
date: String!
sClass: String!
time: EntryTimeEntity!
subject: String!
teacher: String!
comment: String!
}
interface ModuleData {
_type: String!
}
type ModuleDataEntity implements ModuleData {
_type: String!
}
type Mutation {
sickReport(body: sickReport!): SickReportEntity!
}
type PdfDataEntity {
pdf: String!
}
type Query {
school: SchoolEntity
schools: [BaseSchoolEntity!]
moduleDataSubst(moduleId: String!): [SubstitutionPlanEntity!]
moduleDataExams(moduleId: String!): [ExamEntryEntity!]
moduleDataDocuments(moduleId: String!): [DocumentEntity!]
moduleDataDocumentsData(id: String!, moduleId: String!): DocumentDataEntity!
pdfData(moduleId: String!): PdfDataEntity!
}
type SchoolEntity {
id: String!
name: String!
city: String!
theme: SchoolTheme!
authRequired: Boolean!
website: String!
image: String!
hidden: Boolean!
codeOfConduct: [String!]!
features: [SchoolFeatureEntity!]!
modules: [SchoolModuleEntity!]!
substData: [[SubstitutionPlanEntity!]!]!
}
type SchoolFeatureEntity {
type: SchoolInformationFeatureType!
}
# School information feature type
enum SchoolInformationFeatureType {
SICK_REPORT
}
# School module category
enum SchoolModuleCategory {
SUBST
EXAMS
CAFETERIA
NEWS
DOCUMENTS
OTHER
}
type SchoolModuleEntity {
dataType: SchoolModuleType!
id: String!
category: SchoolModuleCategory!
suffix: String!
}
# School module type
enum SchoolModuleType {
SUBST
EXAMS
NEWS
CAFETERIA
PDF
DOCUMENTS
}
# School theme
enum SchoolTheme {
RED
PINK
PURPLE
DEEP_PURPLE
INDIGO
BLUE
LIGHT_BLUE
CYAN
TEAL
GREEN
LIGHT_GREEN
AMBER
ORANGE
DEEP_ORANGE
BROWN
GREY
BLUE_GREY
}
input sickReport {
name: String!
sClass: String!
message: String!
attested: Boolean!
duration: sickReportDuration!
specialEvent: String!
}
input sickReportDuration {
start: String!
end: String!
}
type SickReportDurationEntity {
start: String!
end: String!
}
type SickReportEntity {
name: String!
sClass: String!
message: String!
attested: Boolean!
duration: SickReportDurationEntity!
specialEvent: String!
}
# Subst entry type
enum SubstEntryType {
EVA
SUBST
CANCELLED
EXAM
NORMAL
SHIFTED_TO
INSTEAD_OF
SPECIAL
BREAK_SUPERVISORY
CUSTOM
}
type SubstitutionEntryAdditionalDataEntity {
taskBy: [String!]!
postponed: [SubstitutionEntryAdditionalDataTimeEntity!]!
insteadOf: [SubstitutionEntryAdditionalDataTimeEntity!]!
customType: String!
}
type SubstitutionEntryAdditionalDataTimeEntity {
date: String!
time: EntryTimeEntity!
}
type SubstitutionEntryEntity {
date: String!
sClass: String!
room: String!
comment: String!
subject: String!
newSubject: String!
missingTeacher: String!
teacher: String!
time: EntryTimeEntity!
type: SubstEntryType!
additionalData: SubstitutionEntryAdditionalDataEntity!
}
type SubstitutionPlanEntity implements ModuleData {
_type: String!
date: String!
entries: [SubstitutionEntryEntity!]!
messages: [String!]!
}
Prefixes are probably not being considered in Enums.
First of all, thank you for building this useful tool! I'm looking forward to have this implemented on this tool, my project would benefit a lot from this functionality. In the meantime I planned to use add_query_prefix to generate diferent prefixes and avoid the class name collision but I wasn't able to use it with all my queries whenever more than one query returned a graphql enum of the same type, however this setting worked fine with other queries that didn't return an enum of the same type.
Originally posted by @edwjusti in #27 (comment)
When we have a Query that contains the same Object in different paths with different fields selected the generations does not work as supposed. This is a problem, especially in heavy recursive schemas. For eg:
Schema.graphql
type MyObject {
id: ID!
name: String!
number: Int!
connections: [MyObject]
}
query MyQuery {
myObject {
id
connections {
name
number
}
}
}
Given that the Classes are generated based on the Object name, here we would have two conflicting classes of MyObject
, with a different set of fields each.
class MyObject {
final String id;
final List<MyObject> connections;
}
and
class MyObject {
final String name;
final int number;
}
We may have some options to solve this problem, being one of they the same strategy used by Apollo, that is creating classes taking into account the path in the query like: MyQuery_myObject
and MyQuery_myObject_connections
. However, this ends up creating very unreadable and long-named classes, so if possible would be great to have an alternative.
I'm creating a GraphQL client that persists mutations when offline and runs them when the client comes back online.
I'd like to request that we make the GraphQLQuery class JsonSerializable so that we can easily persist queries for later use.
I get the following Exception when trying to use an input type
from my downloaded schema... what am I missing? Thanks!
Exception: Two classes were generated with the same name `Tools$ToolOrderByInput$OrderByArg`!
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 `Tools$ToolOrderByInput$OrderByArg` is requested
- File a bug on artemis (https://is.gd/YLSfC2)
lib/graphql/queries.graphql
# Add [__typename] and [id] to every model you want cached
query tools($orderBy: ToolOrderByInput) {
tools(orderBy: $orderBy) {
__typename
id
name
state
updatedAt
}
}
lib/graphql/schema.g.graphql (partial):
type Query {
me: User!
tool(where: ToolWhereUniqueInput!): Tool
tools(orderBy: ToolOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Tool!]!
}
type Tool {
id: String!
name: String!
isConnected: Boolean!
state: String
telemetryUpdatedAt: DateTime!
createdAt: DateTime!
updatedAt: DateTime!
}
input ToolOrderByInput {
id: OrderByArg
createdAt: OrderByArg
updatedAt: OrderByArg
name: OrderByArg
isConnected: OrderByArg
state: OrderByArg
telemetryUpdatedAt: OrderByArg
}
enum OrderByArg {
asc
desc
}
build.yaml
targets:
$default:
builders:
artemis:
options:
schema_mapping:
- schema: lib/graphql/schema.g.graphql
queries_glob: lib/graphql/**[^.g].graphql
output: lib/graphql/graphql.g.dart
# resolve_type_field: __typename
In my schema, I have something like:
type MyType implements Blah & PublicBlahInterface & BlahSharedProperties { ... }
And the generated code got something like
class MyQuery extends MyTypes
with EquatableMixin
implements Blah, PublicBlahInterface, BlahSharedProperties {
However Blah, PublicBlahInterface, BlahSharedProperties
never got created by the builder.
As far as I could tell Artemis isn't doing something to address Dart's lack of non nullable types.
I couldn't see a way to deal with it using custom scalars as nullable types wouldn't be addressed.
The way I work around this right now is by using Dartz Option, meaning having to wrap all nullable types with a runtime check to "cast" them.
Is something like this possible?
Here is a snippet of my current generator result and how the generated code deals with it:
query authToken {
# authToken: String
authToken
}
// generated
import 'package:dartz/dartz.dart';
class AuthToken {
AuthToken(this._d);
final Map<String, dynamic> _d;
Option<String> get authToken =>
option<String>(this._d["authToken"] != null, this._d["authToken"]);
}
I'd like to use gql
's ast.transform
to implement an inline imports handler similar to graphql-import
or graphql-import-loader
, but would need a parser middleware hook to use it with artemis.
artemis
nativelyIf you use the javascript graphql "Apollo", then you don't have do put any schema.json or schema.graphql in your project at all. Apollo automatically gets the current schema just by the url you specify like this:
schema: https://example.myapi.com/gql/graphql
I think it would be cool to have this in artemis as well.
If you use the graphql Playground, it is very easy do download the graphql schema as a .graphql file in the SDL format. This format is very clean an nice to use compared to the introspection schema which is annoying to query and so on..
So it would be very nice to support this.
#8 already mentioned something like this
My code was working in Artemis 3 but since version 4 I get this error:
Exception: Two classes were generated with the same name `ModuleDataSubst$Query$SubstitutionPlanEntity$SubstitutionEntryEntity$SubstitutionEntryAdditionalDataEntity$SubstitutionEntryAdditionalDataTimeEntity$EntryTimeEntity`!
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 `ModuleDataSubst$Query$SubstitutionPlanEntity$SubstitutionEntryEntity$SubstitutionEntryAdditionalDataEntity$SubstitutionEntryAdditionalDataTimeEntity$EntryTimeEntity` is requested
- File a bug on artemis (https://is.gd/YLSfC2)
targets:
$default:
sources:
- lib/**
- graphql/**
builders:
artemis:
options:
schema_mapping:
- schema: graphql/schema.graphql
queries_glob: graphql/moduleDataSubst.query.graphql
output: lib/graphql/moduleDataSubst.dart
interface ModuleData {
_type: String!
}
type Query {
moduleDataSubst(moduleId: String!): [SubstitutionPlanEntity!]
}
# Subst entry type
enum SubstEntryType {
EVA
SUBST
CANCELLED
EXAM
NORMAL
SHIFTED_TO
INSTEAD_OF
SPECIAL
BREAK_SUPERVISORY
CUSTOM
}
type SubstitutionEntryAdditionalDataEntity {
taskBy: [String!]!
postponed: [SubstitutionEntryAdditionalDataTimeEntity!]!
insteadOf: [SubstitutionEntryAdditionalDataTimeEntity!]!
customType: String!
}
type EntryTimeEntity {
lesson: String!
length: Int!
}
type SubstitutionEntryAdditionalDataTimeEntity {
date: String!
time: EntryTimeEntity!
}
type SubstitutionEntryEntity {
date: String!
sClass: String!
room: String!
comment: String!
subject: String!
newSubject: String!
missingTeacher: String!
teacher: String!
time: EntryTimeEntity!
type: SubstEntryType!
additionalData: SubstitutionEntryAdditionalDataEntity!
}
type SubstitutionPlanEntity implements ModuleData {
_type: String!
date: String!
entries: [SubstitutionEntryEntity!]!
messages: [String!]!
}
query moduleDataSubst($moduleId: String!) {
moduleDataSubst(moduleId: $moduleId) {
date
messages
entries {
type
date
time {
lesson
length
}
sClass
comment
missingTeacher
teacher
subject
newSubject
room
additionalData {
taskBy
insteadOf {
date
time {
lesson
length
}
}
postponed {
date
time {
lesson
length
}
}
customType
}
}
}
}
Why isn't it working? There are 3 places where I use the EntryTimeEntity
but its always the same entity so the generator should just generate it once and use it everywhere. There shouldn't be any conflicts ...
When the root Query
implements Node
, artemis
fails:
Could not find property "eventByEntityIdAndValidUntil" of class "Node". Moving on...
[SEVERE] artemis:artemis on lib/$lib$:
NoSuchMethodError: The getter 'selections' was called on null.
[INFO] Generating build script...
[INFO] Generating build script completed, took 261ms
[INFO] BuildDefinition:Initializing inputs
[INFO] BuildDefinition:Reading cached asset graph...
[INFO] BuildDefinition:Reading cached asset graph completed, took 94ms
[INFO] BuildDefinition:Checking for updates since last build...
[INFO] BuildDefinition:Checking for updates since last build completed, took 828ms
[INFO] Build:Running build...
[WARNING] artemis:artemis on lib/$lib$:
Could not find property "eventByEntityIdAndValidUntil" of class "Node". Moving on...
[SEVERE] artemis:artemis on lib/$lib$:
NoSuchMethodError: The getter 'selections' was called on null.
Receiver: null
Tried calling: selections
dart:core Object.noSuchMethod
package:artemis/generator.dart 435:28 _extractClasses.<fn>
dart:collection SetMixin.forEach
package:artemis/generator.dart 423:23 _extractClasses
package:artemis/generator.dart 99:19 generateQuery
package:artemis/generator.dart 21:21 generateLibrary.<fn>
dart:_internal ListIterable.toList
package:artemis/generator.dart 22:8 generateLibrary
package:artemis/builder.dart 75:29 GraphQLQueryBuilder.build
package:build runBuilder
package:build_runner_core/src/generate/build_impl.dart 478:19 _SingleBuild._runForInput.<fn>.<fn>.<fn>
package:build_runner_core/src/generate/performance_tracker.dart 300:15 _NoOpBuilderActionTracker.trackStage
package:build_runner_core/src/generate/build_impl.dart 476:23 _SingleBuild._runForInput.<fn>.<fn>
package:timing/src/timing.dart 222:44 NoOpTimeTracker.track
package:build_runner_core/src/generate/build_impl.dart 434:22 _SingleBuild._runForInput.<fn>
package:pool/pool.dart 127:28 Pool.withResource
package:build_runner_core/src/generate/build_impl.dart 430:17 _SingleBuild._runForInput
package:build_runner_core/src/generate/build_impl.dart 378:38 _SingleBuild._runBuilder.<fn>
dart:async Future.wait
package:build_runner_core/src/generate/build_impl.dart 377:36 _SingleBuild._runBuilder
package:build_runner_core/src/generate/build_impl.dart 323:20 _SingleBuild._runPhases.<fn>.<fn>
package:build_runner_core/src/generate/performance_tracker.dart 184:15 _NoOpBuildPerformanceTracker.trackBuildPhase
package:build_runner_core/src/generate/build_impl.dart 319:47 _SingleBuild._runPhases.<fn>
package:timing/src/timing.dart 222:44 NoOpTimeTracker.track
package:build_runner_core/src/generate/build_impl.dart 313:32 _SingleBuild._runPhases
package:build_runner_core/src/logging/logging.dart 25:30 logTimedAsync
package:build_runner_core/src/generate/build_impl.dart 270:26 _SingleBuild._safeBuild.<fn>
dart:async runZoned
package:build_runner_core/src/generate/build_impl.dart 265:5 _SingleBuild._safeBuild
package:build_runner_core/src/generate/build_impl.dart 212:24 _SingleBuild.run
package:build_runner_core/src/generate/build_impl.dart 97:56 BuildImpl.run
package:build_runner_core/src/generate/build_runner.dart 25:14 BuildRunner.run
package:build_runner BuildCommand.run
package:args/command_runner.dart 197:27 CommandRunner.runCommand
package:args/command_runner.dart 112:25 CommandRunner.run.<fn>
dart:async new Future.sync
package:args/command_runner.dart 112:14 CommandRunner.run
package:build_runner run
.dart_tool/build/entrypoint/build.dart 31:22 main
[INFO] Build:Running build completed, took 169ms
[INFO] Build:Caching finalized dependency graph...
[INFO] Build:Caching finalized dependency graph completed, took 43ms
[SEVERE] Build:
Failed after 220ms
pub finished with exit code 1
When I delete the interface it works fine
- "interfaces": [
- {
- "kind": "INTERFACE",
- "name": "Node",
- "ofType": null
- }
- ],
Query:
query GetEvent($eventId: UUID!) {
event: eventByEntityIdAndValidUntil(entityId: $eventId, validUntil: "infinity") {
title
}
}
Config:
schema_mapping:
- output: 'lib/serializers/artemis.dart'
schema: 'schema.json'
queries_glob: 'lib/gql/raw/GetEvent.gql'
resolve_type_field: __typename
#add_query_prefix: true
Simplified schema:
type Query implements Node {
nodeId: ID!
event(nodeId: ID!): Event
eventByEntityIdAndValidUntil(entityId: UUID!, validUntil: Datetime!): Event
}
type Event implements Node {
nodeId: ID!
entityId: UUID!
validFrom: Datetime!
validUntil: Datetime!
title: String
}
interface Node {
nodeId: ID!
}
The following mutation fails with due to an {}
input literal with
Error on line 2, column 43 of lib/gql/raw/SignIn.gql: Expected an object field name
. Generation succeeds if the literal is converted into an input $variable
mutation SignIn {
authenticated: currentAppUser(input: {}) {
user: appUser {
__typename
entityId
}
}
}
dependencies:
artemis: ^2.0.4
equatable: ^0.6.1
gql: ^0.10.0
flutter pub run build_runner build --verbose
output
[INFO] Generating build script...
[INFO] Generating build script completed, took 318ms
[INFO] BuildDefinition:Initializing inputs
[INFO] BuildDefinition:Reading cached asset graph...
[INFO] BuildDefinition:Reading cached asset graph completed, took 120ms
[INFO] BuildDefinition:Checking for updates since last build...
[INFO] BuildDefinition:Checking for updates since last build completed, took 1.0s
[INFO] Build:Running build...
[SEVERE] artemis:artemis on lib/$lib$:
Error on line 2, column 43 of lib/gql/raw/SignIn.gql: Expected an object field name
╷
2 │ authenticated: currentAppUser(input: {}) {
│ ^
╵
package:gql/src/language/parser.dart 61:5 _Parser._expectToken
package:gql/src/language/parser.dart 553:19 _Parser._parseName
package:gql/src/language/parser.dart 324:18 _Parser._parseObjectField
package:gql/src/language/parser.dart 321:7 _Parser._parseNonConstObjectField
package:gql/src/language/parser.dart 152:22 _Parser._parseAny
package:gql/src/language/parser.dart 409:17 _Parser._parseObject
package:gql/src/language/parser.dart 341:16 _Parser._parseValue
package:gql/src/language/parser.dart 451:14 _Parser._parseArgument
package:gql/src/language/parser.dart 442:44 _Parser._parseNonConstArgument
package:gql/src/language/parser.dart 117:22 _Parser._parseMany
package:gql/src/language/parser.dart 130:14 _Parser._maybeParseMany
package:gql/src/language/parser.dart 434:57 _Parser._parseArguments
package:gql/src/language/parser.dart 535:23 _Parser._parseField
package:gql/src/language/parser.dart 487:12 _Parser._parseSelection
package:gql/src/language/parser.dart 117:22 _Parser._parseMany
package:gql/src/language/parser.dart 474:21 _Parser._parseSelectionSet
package:gql/src/language/parser.dart 252:21 _Parser._parseOperationDefinition
package:gql/src/language/parser.dart 204:18 _Parser._parseExecutableDefinition
package:gql/src/language/parser.dart 173:18 _Parser._parseDefinition
package:gql/src/language/parser.dart 117:22 _Parser._parseMany
package:gql/src/language/parser.dart 159:22 _Parser._parseDocument
package:gql/src/language/parser.dart 41:27 _Parser.parse
package:gql/src/language/parser.dart 17:17 parse
package:gql/src/language/parser.dart 27:5 parseString
package:artemis/builder.dart 68:30 GraphQLQueryBuilder.build.<fn>
[INFO] Build:Running build completed, took 162ms
[INFO] Build:Caching finalized dependency graph...
[INFO] Build:Caching finalized dependency graph completed, took 74ms
[SEVERE] Build:
Failed after 246ms
pub finished with exit code 1
#0 throwToolExit (package:flutter_tools/src/base/common.dart:28:3)
#1 pubInteractively (package:flutter_tools/src/dart/pub.dart:244:5)
<asynchronous suspension>
#2 PackagesForwardCommand.runCommand (package:flutter_tools/src/commands/packages.dart:239:11)
<asynchronous suspension>
#3 FlutterCommand.verifyThenRunCommand
(package:flutter_tools/src/runner/flutter_command.dart:557:18)
#4 _asyncThenWrapperHelper.<anonymous closure> (dart:async-patch/async_patch.dart:71:64)
#5 _rootRunUnary (dart:async/zone.dart:1132:38)
#6 _CustomZone.runUnary (dart:async/zone.dart:1029:19)
#7 _FutureListener.handleValue (dart:async/future_impl.dart:137:18)
#8 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:678:45)
#9 Future._propagateToListeners (dart:async/future_impl.dart:707:32)
#10 Future._completeWithValue (dart:async/future_impl.dart:522:5)
#11 Future._asyncComplete.<anonymous closure> (dart:async/future_impl.dart:552:7)
#12 _rootRun (dart:async/zone.dart:1124:13)
#13 _CustomZone.run (dart:async/zone.dart:1021:19)
#14 _CustomZone.runGuarded (dart:async/zone.dart:923:7)
#15 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:963:23)
#16 _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
#17 _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)
#18 _runPendingImmediateCallback (dart:isolate-patch/isolate_patch.dart:116:13)
#19 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:173:5)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.