Conditional fragment spreading in a fragment
So i have a feed which can have 2 types of videos, a position and an update.
Here are how they defined using an interface VideoInterface. An update only has these fields. A position has all of these fields plus an extra field position
interface VideoInterface {
id: ID!
thumbnail: String!
video: String!
likeCount: Int!
company: CompanyType!
}
type PositionVideoViewType implements VideoInterface {
id: ID!
thumbnail: String!
video: String!
likeCount: Int!
company: CompanyType!
position: PositionType!
}
Since these are used in more than one place in the app and I do not actually need all the fields from the company, I put them in a fragment.
fragment VideoViewFields on VideoInterface {
id
thumbnail
video
likeCount
company {
id
name
username
}
}
I then query the videos from the server
query GetExploreVideos {
getExploreVideos{
...VideoViewFields
... on PositionVideoViewType {
position {
title
}
}
}
}
Everything works
However, as I said these videos are queried very often, so I get decide to put it in a fragment.
fragment VideoViewFragment on VideoInterface {
...VideoViewFields
... on PositionVideoViewType {
position {
title
...PositionDescriptionFragment
}
}
}
And therefore the request becomes
query GetExploreVideos {
getExploreVideos{
...VideoViewFragment
}
}
However, his is where things break. The graphiQl still processes everything correct, but ferry has some trouble. Specifically it only queries the fields in ...VideoViewFields and completely ignores ...on PositionVideoViewType, even if G__typenname is PositionVideoViewType.
Using .when() also doesn't work, even though it correctly identifies that it is a PositionVideoViewType, it fails at casting it, because the data for these fields is simply not saved.
So for now I cannot use VideoViewFragment, which is very sad, because not only do I have to do a lot of repetitions in the .graphql queries, but the code-gened types are not compatible.
Would be great if you could produce a minimal reproductible example so I can take a look.
schema.graphql
schema {
query: Queries
}
interface VideoInterface {
id: ID!
thumbnail: String!
video: String!
likeCount: Int!
company: ComanyType!
}
type CompanyType {
id: String
name: String
username: String
other: String
}
type PositionType {
id: ID!
title: String
startDate: String
duration: Int
}
type PositionVideoViewType implements VideoInterface {
id: ID!
thumbnail: String!
video: String!
likeCount: Int!
company: CompanyType!
position: PositionType!
}
type Queries {
getExploreVideos: [VideoInterface!]!
}
fragments.graphql
fragment VideoViewFields on VideoInterface {
id
thumbnail
video
likeCount
company {
id
name
username
}
}
fragment VideoViewFragment on VideoInterface {
...VideoViewFields
... on PositionVideoViewType {
position {
title
}
}
}
get_explore_videos.graphql
# import "fragments.graphql"
query GetExploreVideos {
getExploreVideos{
...VideoViewFragment
}
}
Test
typedef VideoView = GVideoViewFragment;
Future<List<VideoView>> fetchExploreVideos() async {
final response = await client
.request(GGetExploreVideosReq(
(b) => b..fetchPolicy = FetchPolicy.NetworkOnly))
.first;
return response.data!.getExploreVideos.toList();
final videos = await fetchExploreVideos();
for (var video in response.data!.getExploreVideos.toList()) {
if (video.G__typename == 'PositionVideoViewType') {
final castedPosition = video as PositionVideoView;
**// Unhandled Exception: type '_$GGetExploreVideosData_getExploreVideos' is not a subtype of type 'GVideoViewFragment__asPositionVideoViewType' in type cast**
}
}
I think these 2 screenshots from the debugger communicate the issue well: This is what happens if you fragment the request, i.e you do
query GetExploreVideos {
getExploreVideos{
...VideoViewFragment
}
}
And here is what happens if you do not fragment it and do
query GetExploreVideos {
getExploreVideos{
...VideoViewFields
... on PositionVideoViewType {
position {
title
}
}
}
}
Thanks, I can reproduce the issue.
I have the same issue.
Any news on this ?
I've got exactly the same problem. @Masadow @rexmihaela @Pylyr - did you ever figure out how to solve it?
is still still reproducible with the latest version of ferry_generator?
@knaeckeKami - here's the version from my pubspec.lock
ferry_generator:
dependency: "direct dev"
description:
name: ferry_generator
sha256: "6637ea751297f56c8971691f63b1191d14bf649dacfdcaa08a594915eba47bda"
url: "https://pub.dev"
source: hosted
version: "0.12.0"
so, does it happen on 0.14.0?
Hi @knaeckeKami , no it doesn't happen on 0.14.0 👏👏 But I run into a different error with the same setup.
fragment validationError on ValidationError {
... on ValidationError {
__typename
message
}
}
query getUserProfile($userId: ExternalRefInput!) {
PolicyApplication {
getUserProfile(userId: $userId) {
...validationError
... on PolicyApplicationQueryGetUserProfileSuccess {
data {
...person
}
}
}
}
}
ValidationError is in separate fragment because I use it in many places.
The generated file contains this:
abstract class GgetUserProfileData_PolicyApplication_getUserProfile__asPolicyApplicationQueryGetUserProfileSuccess
implements
Built<
GgetUserProfileData_PolicyApplication_getUserProfile__asPolicyApplicationQueryGetUserProfileSuccess,
GgetUserProfileData_PolicyApplication_getUserProfile__asPolicyApplicationQueryGetUserProfileSuccessBuilder>,
_i3.GvalidationError,
_i3.GvalidationError__asPolicyApplicationQueryGetUserProfileSuccess,
GgetUserProfileData_PolicyApplication_getUserProfile {
GgetUserProfileData_PolicyApplication_getUserProfile__asPolicyApplicationQueryGetUserProfileSuccess._();
_i3.GvalidationError__asPolicyApplicationQueryGetUserProfileSuccess, makes no sense and the linter shows this error: