artemis icon indicating copy to clipboard operation
artemis copied to clipboard

Add an option to create classes that include a superset of fields from all fragments

Open euriasb opened this issue 5 years ago • 4 comments

This is better explained with an example, let's say you have the following GraphQL class:

User
- id
- name
- email
- facebook_account
- instagram_account
- ...some other fields

And you have these fragments and queries

fragment BasicUserData {
  id
  name  
  email
}

fragment SocialUserData {
  ...BasicUserData
  facebook_account
  instagram_account
}

query BasicQuery {
  basicUser(id: ID) {
    ...BasicUserData
  }
}

query AdvancedUserQuery1 {
  advancedUser1(id: ID) {
    ...SocialUserData
    *some other fields*
  }
}

query AdvancedUserQuery2 {
  advancedUser2(id: ID) {
    ...SocialUserData
   *some other fields*
  }
}

This would generate a BasicUserDataMixin and a SocialUserDataMixin. BasicQuery would return an object of type BasicQuery$RootQuery$User which implements BasicUserDataMixin. AdvancedUserQuery1 would return and object of type AdvancedUserQuery1$RootQuery$User which implements both Mixins, and AdvancedUserQuery2 would return and object of type AdvancedUserQuery2$RootQuery$User which also implements both Mixins.

Now, let's say I have a shared widget which renders basic and social media data for a user and it can be used from parent widgets which perform AdvancedUserQuery 1 and 2, since I need both basic and social data my widget needs both Mixins, but since dart doesn't have union types there is no way to specify that, and since it is used from different parents I also cannot specify the concrete type.

My proposal is to generate classes containing the properties from fields that are included in all fragments, and use those as the return types for all queries, with the fields not queried set to null, so in this case you would generate

class User {
  String id;
  String name;
  String email;
  String facebook_account;
  String instagram_account;
  *all other queried fields*
}

And all three queries would return a User object.

Note that this was the approach that Facebook used at least in the internal GraphQL sdks, not sure what they released publicly.

euriasb avatar Feb 26 '21 19:02 euriasb

@comigor technically this could be solved by flattening nested fragments from the same object

vasilich6107 avatar Feb 28 '21 19:02 vasilich6107

As far as I understand, that's similar to my proposal of canonical types generation. The User class you're proposing is basically the canonical (1:1 match with schema's class with all nullable fields). However, this is not as easy as it seems, specially when you try to deal with interfaces and union types.

comigor avatar Feb 28 '21 20:02 comigor

Yes, it sounds like it's the same thing. Could be possible to add some version of this, even if it doesn't support all cases like interfaces and unions as you mention?

euriasb avatar Mar 01 '21 17:03 euriasb

My issue with shipping a version without considering some cases is to create a huge breaking change. Yesterday I did work on that proposal again and it already changed a lot. Even in beta, it's not that good to create a lot of breakingn changes.

comigor avatar Mar 01 '21 17:03 comigor