Coder Social home page Coder Social logo

micimize / graphql-to-dart Goto Github PK

View Code? Open in Web Editor NEW
43.0 3.0 8.0 1.33 MB

generate dart classes and respective JsonSerializable transcoders

Shell 1.00% TypeScript 44.07% JavaScript 1.48% Java 0.53% Ruby 4.31% Objective-C 1.09% Dart 14.78% Handlebars 32.75%

graphql-to-dart's Introduction

⚠️ Deprecated ⚠️

This project has been superseded by major_graphql which uses build_runner and generates built_value types, and is no longer maintained

graphql-to-dart

Custom templates for graphql-code-generator for generating dart PODOs and json_serializable classes

Beta

npm install [email protected] includes a number of updates, such as:

  • per-operation file generation (probably non-optional)
  • gql_code_gen support via integrateGqlCodeGenAst
  • transformCharacters support for handling _underscore_prefixed fields defaults to { "^_+": "" }, resulting in "__typename" -> "typename"
  • Models graphql-style "inheritance" by defining a protected _$[Type}Fields type along with every object type, which is then exposed by fragment mixins and selection sets.
  • Fragments are modeled generated as mixins, as well as standalone FragmentNameSelectionSet classes

usage

yarn add -D graphql-code-generator graphql [email protected]

write codegen.yaml to customize your build as needed. This is the full working config I'm using in the wild:

schema: schema/__generated__/schema.json
documents:
  # fragments are _private and collected first
  # so we can hack their fields
  - '../app/lib/**/_*.graphql'
  - '../app/lib/**/!(_)*.graphql'
overwrite: true
generates:
  ../app/lib/graphql/schema.dart:
    - graphql-to-dart/schema-types
  ../app/lib/:
    # generate operation types next to their source files
    # NOTE there's actually a coupling between the preset and plugin
    # with respect to `integrateGqlCodeGenAst` atm
    preset: graphql-to-dart
    presetConfig:
      # all required
      extension: .graphql.dart
      packageName: savvy_app
      schemaTypesPath: ../app/lib/graphql/schema.dart
    plugins:
      - graphql-to-dart/documents
config:
  # re-export built gql_code_gen ast files
  integrateGqlCodeGenAst: true
  schema:
    imports:
      # import 'package:foo/bar.dart' show biz; works as well here
      - package:savvy_app/graphql/scalars/scalars.dart
      - package:savvy_app/graphql/base.dart
    exports:
      - package:savvy_app/graphql/scalars/scalars.dart
      - package:savvy_app/graphql/base.dart
  mixins:
    # add `with Entity` when a generated class has these fields
    - when:
        fields:
        - entityId
        - validFrom
        - validUntil
      name: Entity
  scalars:
    Date: DateTime
    # requires a PGDateTimeProvider in the schema lib
    Datetime: PGDateTime
    FiniteDatetime: DateTime
    UUID: String
    Rrule: RecurrenceRule
    Cursor: String
    JSON: Object
  replaceTypes:
    TemporalIdInput: TemporalId
    # Replace with a reference, if I remember correctly
    TemporalId: TemporalId
    GoogleSignInInput: GoogleSignIn
  irreducibleTypes:
   # I have a common in-fragment type
   # that is always inherited the same way,
   # so I just repace it's inputs and make my own irreducible.
   - TemporalId

Then generate with yarn gql-gen (or gql-gen if you have it globally installed), And theeeen generate the actual json serializers (json_serializable is a peer dependency, but on the flutter side, also gql_code_gen if you're using the ast integration). So:

yarn gql-gen
flutter packages pub run build_runner build
flutter format lib/**/*graphql.dart # you're gunna want this
# or npm install globstar && globstar -- flutter format "lib/**/*.graphql.dart"

Make sure you have a build.yaml like in the example, and the deps in the pubspec.yaml:

# ...
dev_dependencies:
  build_runner: ^0.9.0
  json_serializable: ^0.5.4
  # ...

dependencies:
  json_annotation: ^0.2.3
  # ...
# ...

...Obviously this is not the most user friendly process yet.

Take a look at the example output to see how it generates code, as well as src/build-plugin.ts for the configuration object, which has some docs just aching to be properly generated.

NOTES

  • Base types do not currently have json helpers, but it should probably be configurable in case of the configuration replaceTypes: { "BaseTypeInput": "BaseType" }
  • I probably won't touch this for a while once again.
  • Really what we want is for @klavs's gql_code_gen to become more mature, but I keep sinking energy into this because I can go fast here
  • #import "./fragment.graphql bolton support has been merged into gql_code_gen
  • (possibly outdated): You can have multiple inline fragments on the same document, but they will be named with leading underscores, like Query_TypeInlineFragment, which is ugly

graphql-to-dart's People

Contributors

dependabot[bot] avatar micimize avatar ryankauk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

graphql-to-dart's Issues

Document using fragment causing issues when expanding fields that already exist in fragment

On the document that's using the fragment, the generated dart creates the get/set methods howeveer they throw an error. For example...

'SendMomentMessageCreateMomentMessage.readReceipts=' ('void Function(List)') isn't a valid override of 'MessageModel.readReceipts=' ('void Function(List)').

Maybe the selection set classes that are generated from fragments template should all be mixins that are implemented on the documents that use them.
Example scenario:
_fragment.gql

fragment MyFragment on Model {
    myField {
        id
    }
}

GetModel.gql

query GetModel {
    models {
        ...MyFragment
        myField {
            createdAt
        }
    }
}

Use latest codegen API :)

Hi @micimize !

This template looks awesome!
We recently released a new version of the codegen, with a new API and a better plugins support.
I think it will be much easier for you to implement this template now :)

fragment merging

I've handled regular field merging

{
      f: friends {
        name
      }
      f: friends {
        id
      }
}
#=>
{
      f: friends {
        name
        id
      }
}

But nested field fragment merging is a nightmare. I'm not going to do it anytime soon.

Basically, figuring out that ...info generates Relationships which contains the field friends which gets merged into friends in the top level query is just a horrible thing to deal with in the current design.

fragment home on Human {
  home: homePlanet
  planet: homePlanet
}

fragment dimensions on Human {
  height
  mass
}

fragment relationships on Human {
  friends {
    name
  }
  starships {
    name
    length
  }
}

fragment info on Human {
  ...dimensions
  ...home
}

query HeroForEpisode($ep: Episode!) {
  hero(episode: $ep) {
    # without typename we can't really tell which fragments to parse
    __typename
    name
    ... on Droid {
      primaryFunction
    }
    ... on Human {
      friends {
        name
        id
      }
      appearsIn
      ...info
      ...relationships
    }
  }
}

Problem with aliases (on master)

Hi,

There's a problem with aliases. Query like this:

    route: geoRoute(locations: $locations) {
        ...RouteFragment
    }

    targetRoute: geoRoute(locations: $locationsAll) {
        ...RouteFragment
    }

... is generated to this code:

SimulatorRoutesQuery({
          @required SimulatorRouteFragmentRoute route,
          @required SimulatorRouteFragmentTargetRoute targetRoute,
      
  }): super(
      geoRoute: route,
      geoRoute: targetRoute,
  )

(2 geoRoute passed to super)

Inline fragments are broken, unions won't be deserialized

  • Unions need to implement a discriminated union deserializer. Here's what looks like a relevant block in json_serializable.
  • (Harder) inline fragments aren't generated properly -
query HeroForEpisode($ep: Episode!) {
  hero(episode: $ep) {
    # without typename we can't really tell which fragments to parse
    __typename
    name
    ... on Droid {
      primaryFunction
    }
    ... on Human {
      appearsIn
      ...info
      ...relationships
    }
  }
}

generates the HeroForEpisode{ Human, Droid }InlineFragment models,
but the top level model is just

class HeroForEpisodeHero extends Character with HelloMixin {
  static final String typeName = "Character";

  @JsonKey(name: r'name', required: true, disallowNullValue: true)
  String get name => fields.name;
  set name(String name) => fields.name = name;
  HeroForEpisodeHero({
    @required String name,
  }) : super(
          name: name,
        );
//...

Error compiling generated Dart File

I get an error when compiling the Dart file with command:
flutter packages pub run build_runner build

Error:

[WARNING] json_serializable on lib/serializers/graphql.dart:
This element has an undefined type. It may causes issues when generated code.
package:myplace/serializers/graphql.dart:15554:10
      ╷
15554 │     I18n i18n;
      │          ^^^^
      ╵

Error seems due to the following Schema information with Scalar type

scalar I18n

generating example file from schema

Hi. thank you for the work on this project. I am new to Dart/Flutter, and evaluating for my graphql heavy project. For web, I use apollo and typescript. Hope your package will help me to with similar experience on marshaling the API response.

I am mainly trying to see how the generator uses documents. Along with type serializer, are there any helpers for query/mutations? Not sure it needed as I am yet to look at graphql_flutter.

When I try to generate the code with example:gql-gen, I get his error

yarn run v1.15.2
$ cd example/ && gql-gen
  ✔ Parse configuration
  ❯ Generate outputs
    ❯ Generate lib/starwars_graphql_serializers
.dart
      ✔ Load GraphQL schemas
      ✔ Load GraphQL documents
      ✖ Generate
        → Cannot read property 'includes' of un
…


  Found 1 error

   ✖ lib/starwars_graphql_serializers.dart
    TypeError: Cannot read property 'includes' 
of undefined

Only change I made was

plugins:
    'graphql-to-dart'

instead of the local file path.

when I remove

documents:
  - './lib/gql/HeroForEpisode.gql'

it generates the file.

versions:
"graphql-code-generator": "^0.18.2",
"graphql-to-dart": "^0.3.2",

because of helpers like .empty(), having invalid types is easy. We should validate not null somehow

Use an Option type.
It's a good substitute for non nullable types.
I recommend using Dartz's one, this is a good library.

Code looks like

// full api: https://www.crossdart.info/p/dartz/0.6.1/src/option.dart.html
// Declare a maybe-null type
Option<int> count = option(data["count"] != null, data["count"]);

// use it
var text = count.fold(
  () => "no count yet",
  (_count) => "$_count counted ",
);

var timesTwo = totalCount.getOrElse(()=>0) * 2;

if (count.isNone()) {
  print("it's null");
} else {
  // safely "unwrap"
  int _count = count.getOrElse(()=>null);
}

// deeper into functional programming
item.lat.flatMap(
  (lat) => item.lng.map(
    (lng) => Coords(latitude: lat, longitude: lng),
  ),
).forEach((coords) {
  // will run if isSome()
  print(coords);
});

Demo

I assume this is meant to be used with graphql-flutter package ?
It would be awesome to see an example hooked up with flutter if you have time.

Union Type Does Not Convert

Hey I'm having issues with a union type, the operation class is using addAll that does not exist in the schema type's class which does not appear in the union template. Was this intentional? If you could explain some direction I can do the fix if needed. As well there's a syntax error when not constructor inputs exists you get

UnionItem({
}): super(
);

Looking at the example it seems to work with the union since there's an interface they're both implementing, maybe it doesn't work when the union doesn't have an interface.

You can reproduce the error with the example with gql:

query Search($text: String) {
  search(text:$text){
    ...on Starship{
      id
    }
  }
}

Include documents in output

Hello,

It works nice already, but would be better if output will also contain document, so there's no need to load file.

const HeroForEpisodeDoc = """query HeroForEpisode($ep: Episode!) {
  hero(episode: $ep) {
    __typename
    name
    ... on Droid {
      primaryFunction
    }
    ... on Human {
      height
      homePlanet
    }
  }
}""";

Override schema types of specific fields with custom scalars

By example, the Schema I'm using is not managing date field properly and those date field are managed as String.
I would like to overload type of some fields with configuration.

By Exemple:
From Schema:
creationDate String

I would like to transform to
creationDate DateTime

toJson() should not include items which were not set

final testInput = CreateTestInput(fkID: '123', color: 'red');

print('${createTestInput.toJson()}');
// This prints { fkID: 123, color: red, otherAttr: null, id: null, ...}

This becomes a problem when trying to use this library with https://github.com/zino-app/graphql-flutter because in most cases you don't want to explicitly null things out.

Workaround:

final newItemResult = await client.mutate(MutationOptions(
  documentNode: gql(mutationString),
  variables: { 'input': createTestInput.toJson()
    ..removeWhere((_, dynamic val) => val == null) // remove the null items
}));

merge should map only to base types, base type methods should be respected

If we model the schema types completely, and treat selection sets only as projections, we can avoid the trade off created with mergedLeftWith / << covariance (rejection of the Liskov substitution principle)

MyFragment(baseField: 'bar', alias: 'bar') as MyBaseType << MyBaseType(baseField: 'biz');
# compiles, valid conceptually, not type safe

Merging using base types would exclude aliases and methods right now, but if we assume idempotent getters and methods within the same query on the server (a and b in { a, b: a } and { a: foo(), b: foo() } should always return the same thing) and implement the methods as getters against an internal map on object types:

/// ```graphql
/// type Task {
///   method(arg: Int): String!
/// }
/// ```
class _TaskFields {
  /// https://pub.dev/packages/tuple
  Map<Tuple<int>, String> methodResults;
  _TaskFields({ this.methodResults });

  method(int arg) => methodResults[Tuple(arg)];

}

// ...

/// ```graphql
/// task {
///   method(1)
/// }
/// ```
class TaskSelectionSet {
  get method => fields.method(1);
}

Cannot install

Hey, I updated flutter and in turn updated this package but it couldn't be installed.


> @graphql-codegen/[email protected] prepack 
> bob-update-version

sh: bob-update-version: command not found
npm ERR! premature close

npm ERR! A complete log of this run can be found in:

Non nullable fields in graphql vs required fields in models

Hi,

we again run into problems with the required fields. Lets consider the following minimal example:

type Query {
  getBooks(): [Book!]
}

type Book {
 name: String!
 category : Category!
}

type Category{
  name: String!
  books: [Book!]!
}

If i want to query now for books -> category -> ... -> books and some point the category or the books array has to be null which breaks the parsing.

In my opinion the root cause if the problem is that two different concepts are mixed up

  • non nullable fields in graphql
  • required fields in the data model

This also leads to problems if non nullable fields are not selected, the parsing fails which should also not be the case. As far as I understand it's the idea of graphql to select only the fields you need, which does not mean that the fields you are not selecting can't be not nullable.

A possible solution would be to make the required: true, disallowNullValue: true configurable or to remove it completely. I would go the for the later.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.