Skip to content

Commit

Permalink
Merge pull request gql-dart#86 from micimize/feat-gql-types
Browse files Browse the repository at this point in the history
gql/schema.dart and gql/operation.dart
  • Loading branch information
klavs authored Apr 28, 2020
2 parents 84ca217 + 81c6ff9 commit 0fcecd8
Show file tree
Hide file tree
Showing 23 changed files with 2,576 additions and 4 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,16 +110,19 @@ Ideas for future work:
| [graphql_flutter][graphql_flutter] | A GraphQL client for Flutter, bringing all the features from a modern GraphQL client to one easy to use package. |
| [normalize][normalize] | Normalization and denormalization of GraphQL responses in Dart |
| [ferry][ferry] | GraphQL Client for Dart |
| [graphql-to-dart][graphql-to-dart]| generate dart classes and respective JsonSerializable transcoders |
| [graphql_server][graphql_server]| Base package for implementing GraphQL servers. |
| [graphql-to-dart][graphql-to-dart]| generate dart classes and respective JsonSerializable transcoders ([npm package][graphql-to-dart-npm]) |
| [major_graphql][major_graphql]| generate `built_value` classes and serializers with `pub build` (successor of [graphql-to-dart][graphql-to-dart]) |
| Your project? | Open a PR to add it to this readme! |

[artemis]: https://github.com/comigor/artemis
[graphql_flutter]: https://github.com/zino-app/graphql-flutter
[normalize]: https://github.com/smkhalsa/normalize
[ferry]: https://github.com/gql-dart/ferry
[graphql-to-dart]: https://github.com/micimize/graphql-to-dart
[graphql_server]: https://pub.dev/packages/graphql_server/versions/2.0.0-beta
[graphql-to-dart]: https://github.com/micimize/graphql-to-dart
[graphql-to-dart-npm]: https://www.npmjs.com/package/graphql-to-dart
[major_graphql]: https://github.com/micimize/major

## Contributing

Expand Down
101 changes: 100 additions & 1 deletion gql/README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
A package for working with GraphQL documents.

This package exports several libraries:

- `package:gql/language.dart` provides ability to parse GraphQL string into AST and print AST as a string;
- `package:gql/ast.dart` defines the AST and provides visitors and transformers;

## ⚠ Call for contributions ⚠

`package:gql/document.dart` implements some of the validation rules defined in GraphQL spec.

PRs are welcome to finish the validation support. Rules which are concerned with Schema validation should take preference over rules concerned with Document validation.


## `package:gql/language.dart`

### Parsing GraphQL documents
Expand Down Expand Up @@ -117,6 +118,7 @@ void main() {
```

### Transforming GraphQL documents

```dart
import "package:gql/ast.dart" as ast;
import "package:gql/language.dart" as lang;
Expand Down Expand Up @@ -189,6 +191,103 @@ void main() {
}
```

## `gql/schema.dart` and `gql/operation.dart` <sub>(experimental)</sub>

`gql/schema.dart` and `gql/operation.dart` provide higher-level
type definitions derived from `gql/ast.dart` asts for
GraphQL Schemas and Operations respectively.

**NOTE**: does not currently have runtime features, such as field resolution.
It was initially developed as a more friendly way to work with schema ASTs.

```dart
import "package:gql/language.dart" as lang;
import "package:gql/schema.dart" as gql_schema;
import "package:gql/operation.dart" as gql_operation;
final schemaDefinition = lang.parseString(r"""
schema {
query: StarWarsQuery
}
interface Character {
id: String
name: String
}
type Droid implements Character {
id: String
name: String
primaryFunction: String
}
type StarWarsQuery {
droids: [Droid!]
}
""");
void inspectSchema() {
final schema = gql_schema.GraphQLSchema.fromNode(schemaDefinition);
final character =
schema.getType("Character") as gql_schema.InterfaceTypeDefinition;
final droid = schema.getType("Droid") as gql_schema.ObjectTypeDefinition;
print(character.isImplementedBy(droid));
// prints "true"
print(schema.query.getField("droids").type.toString());
// prints "[Droid!]"
}
final fragmentDefinitions = [
lang.parseString(r"""
fragment droidName on Droid {
name
}
"""),
];
final queryDefinition = lang.parseString(r"""
query AllDroids {
droids {
...droidName
primaryFunction
}
}
""");
void inspectQuery() {
final schema = gql_schema.GraphQLSchema.fromNode(schemaDefinition);
final document = gql_operation.ExecutableDocument(
queryDefinition,
schema.getType,
// necessary for dereferencing schema definitions
fragmentDefinitions,
);
final importedFragment = document.getFragment("droidName");
print(importedFragment);
// prints the fagment above
final query = document.operations.first;
final droids = query.selectionSet.fields.first;
final spreadDroidName = droids.selectionSet.fragmentSpreads.first;
print(
// dereference fragment spread into fragment definition
spreadDroidName.fragment == importedFragment,
);
}
void main() {
inspectSchema();
inspectQuery();
}
```

## Features and bugs

Please file feature requests and bugs at the [GitHub][tracker].
Expand Down
84 changes: 84 additions & 0 deletions gql/example/inspect.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import "package:gql/language.dart" as lang;
import "package:gql/schema.dart" as gql_schema;
import "package:gql/operation.dart" as gql_operation;

final schemaDefinition = lang.parseString(r"""
schema {
query: StarWarsQuery
}
interface Character {
id: String
name: String
}
type Droid implements Character {
id: String
name: String
primaryFunction: String
}
type StarWarsQuery {
droids: [Droid!]
}
""");

void inspectSchema() {
final schema = gql_schema.GraphQLSchema.fromNode(schemaDefinition);

final character =
schema.getType("Character") as gql_schema.InterfaceTypeDefinition;
final droid = schema.getType("Droid") as gql_schema.ObjectTypeDefinition;

print(character.isImplementedBy(droid));
// prints "true"

print(schema.query.getField("droids").type.toString());
// prints "[Droid!]"
}

final fragmentDefinitions = [
lang.parseString(r"""
fragment droidName on Droid {
name
}
"""),
];

final queryDefinition = lang.parseString(r"""
query AllDroids {
droids {
...droidName
primaryFunction
}
}
""");

void inspectQuery() {
final schema = gql_schema.GraphQLSchema.fromNode(schemaDefinition);

final document = gql_operation.ExecutableDocument(
queryDefinition,
schema.getType,
// necessary for dereferencing schema definitions
fragmentDefinitions,
);

final importedFragment = document.getFragment("droidName");
print(importedFragment);
// prints the fagment above

final query = document.operations.first;
final droids = query.selectionSet.fields.first;
final spreadDroidName = droids.selectionSet.fragmentSpreads.first;

print(
// dereference fragment spread into fragment definition
spreadDroidName.fragment == importedFragment,
);
}

void main() {
inspectSchema();
inspectQuery();
}
15 changes: 15 additions & 0 deletions gql/lib/operation.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/// AST-based GraphQL Executable Definitions (operations).
///
/// Adds type resolution and useful helper methods for working with executable graphql documents,
/// such as is useful for code generation.
///
/// The primary entrypoint is usually [ExecutableDocument]
/// which accepts an [gql.ast.DocumentNode],
/// a tearoff of [gql.schema.GraphQLSchema.getType()],
/// and an optional list of imported ASTs.
///
/// **NOTE**: This library is currently only for working with executable _definitions_.
library operation;

export "package:gql/src/operation/definitions.dart";
export "package:gql/src/operation/executable.dart";
13 changes: 13 additions & 0 deletions gql/lib/schema.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/// AST-based GraphQL Schema Type Definitions.
///
/// Adds type resolution and useful helper methods for working with graphql schema definitions,
/// such as is useful for code generation.
///
/// The primary entrypoint is usually [GraphQLSchema.fromNode()], which accepts an [gql.ast.DocumentNode]
///
/// **NOTE**: This library is currently only for working with schema _definitions_,
/// and is not a package for implementing servers like [`graphql_server`](https://pub.dev/packages/graphql_server).
library schema;

export "package:gql/src/schema/definitions.dart";
export "package:gql/src/schema/schema.dart";
4 changes: 4 additions & 0 deletions gql/lib/src/operation/definitions.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export "package:gql/src/operation/definitions/type_resolver.dart";
export "package:gql/src/operation/definitions/base_types.dart";
export "package:gql/src/operation/definitions/selections.dart";
export "package:gql/src/operation/definitions/definitions.dart";
38 changes: 38 additions & 0 deletions gql/lib/src/operation/definitions/base_types.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import "package:meta/meta.dart";
import "package:collection/collection.dart";
import "package:gql/src/schema/definitions.dart";

import "package:gql/src/operation/definitions/type_resolver.dart";

@immutable
abstract class ExecutableGraphQLEntity extends GraphQLEntity {
const ExecutableGraphQLEntity();
}

@immutable
abstract class ExecutableWithResolver extends ExecutableGraphQLEntity
implements ExecutableTypeResolver {
const ExecutableWithResolver([GetExecutableType getType])
: getType = getType ?? GetExecutableType.withoutContext,
super();

@override
final GetExecutableType getType;

@override
bool operator ==(Object o) {
if (identical(this, o)) return true;

if (o.runtimeType == runtimeType) {
final _o = o as ExecutableWithResolver;
return astNode == _o.astNode && getType == _o.getType;
}

return false;
}

@override
int get hashCode => const ListEquality<Object>(
DeepCollectionEquality(),
).hash([astNode, getType]);
}
Loading

0 comments on commit 0fcecd8

Please sign in to comment.