-
Notifications
You must be signed in to change notification settings - Fork 722
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AnyGraphQLQuery? #65
Comments
I also tried type erasure to create an |
I'd love to help, but I'd like to better understand your use case to see if there might be a better way to achieve what you want. What would you want use a I've run into the same issue myself in working on upcoming support for dynamic operations and a more flexible network layer. One solution I've been thinking about is to create a The default implementation of the protocol on |
Thank for the comment. I'll try to explain my use case. Middleware<MainState>()
.sideEffect { _, dispatch, action in
switch action {
case let action as FetchAction<VerticalTvGuideQuery>:
GraphQLMiddleWare.fetch(mediaProvider: mediaProvider, dispatch: dispatch, query: action.query, disposeBag: action.disposeBag)
default:
break
}
}
}
private static func fetch<Q: GraphQLQuery>(mediaProvider: MediaProvider, dispatch: @escaping Middleware<MainState>.DispatchFunction, query: Q, disposeBag: DisposeBag) {
mediaProvider.fetch(query).subscribe(
onNext: { data in
let finishAction = FetchFinishAction<Q>(disposeBag:disposeBag, data: data)
dispatch(finishAction)
},
onError: { error in
let failureAction = FetchFailureAction(disposeBag:disposeBag, error: error)
dispatch(failureAction)
}) // onComplete or onDisposed
.addDisposableTo(disposeBag)
} In the View layer something like this happens. let fetchAction = FetchAction(disposeBag: self.disposeBag, query: VerticalTvGuideQuery())
store.dispatch(fetchAction) The success and failure actions will be handles in the Reducer that is responsible for the screen that fired the FetchAction. |
I don't think This is similar to how other type erased wrappers like If you want access to the typed data, the query-specific type information will have to come from somewhere. You may be able to define your own non-generic wrapper, but then you'll have to force cast the result somewhere else in your code in order to use it: struct FetchQueryAction {
let fetch: (ApolloClient, @escaping (Any?, Error?) -> Void) -> Void
init<Query: GraphQLQuery>(query: Query) {
fetch = { client, completionHandler in
client.fetch(query: query) { result, error in
completionHandler(result, error)
}
}
}
}
let action = FetchQueryAction(query: HeroNameQuery())
action.fetch(client) { result, error in
(result as! GraphQLResult<HeroNameQuery.Data>).data?.hero?.name
} |
You are correct as far as I understand it. To come back to the original reason why I wanted switch action {
case let action as FetchAction<Query1>:
GraphQLMiddleWare.fetch(mediaProvider: mediaProvider, dispatch: dispatch, query: action.query, disposeBag: action.disposeBag)
case let action as FetchAction<Query2>:
GraphQLMiddleWare.fetch(mediaProvider: mediaProvider, dispatch: dispatch, query: action.query, disposeBag: action.disposeBag)
case let action as FetchAction<Query3>:
GraphQLMiddleWare.fetch(mediaProvider: mediaProvider, dispatch: dispatch, query: action.query, disposeBag: action.disposeBag)
default:
break
} Also that the results needs to be cast somewhere else is what I'm currently doing with static func createViewModelReducer(mediaProvider: MediaProvider) -> Reducer<VerticalTVGuideState> {
return { action, state in
switch action {
case let action as FetchFinishAction<VerticalTvGuideQuery>:
var state = state
state.queryData = Box(action.data)
state.error = nil
return state
case let action as FetchFailureAction:
var state = state
state.queryData = nil
state.error = Box(action.error)
return state
default:
return state
}
}
} |
This ends up feeling like a bit of a hack, but I think I got something working... let fetch: (ApolloClient, @escaping (Any?, Error?) -> Void) -> Void
let resultType: Any.Type
init<Query: GraphQLQuery>(query: Query) {
fetch = { client, completionHandler in
client.fetch(query: query) { result, error in
completionHandler(result, error)
}
}
resultType = GraphQLResult<Query.Data>.self
}
}
let action = FetchQueryAction(query: HeroNameQuery())
action.fetch(client) { result, error in
switch action.resultType {
case is GraphQLResult<HeroNameQuery.Data>.Type:
let hero = (result as! GraphQLResult<HeroNameQuery.Data>).data?.hero
hero?.name
default:
fatalError("Unknown result type")
}
} |
Then again, if you have to hard code your queries anyway, a cleaner solution might be to use an enum: enum FetchQueryAction {
case heroName(HeroNameQuery)
case heroAndFriendsNames(HeroAndFriendsNamesQuery)
} |
@Nuke- is this still an issue you need help with? I'm trying to clean up old issues and if there's a particular solution you used here, it'd probably be helpful to share with the community before I close this out. Thanks! |
@designatednerd no longer an issue. I settled on using a giant switch for all my queries and mutation. |
|
Is it possible to create an AnyGraphQLQuery class?
I'm having some troubles/difficulties that you cannot assign a
GraphQLQuery
to a variable without knowing its concrete type.So I tried building a type erasure but that doesn't work because the protocol contains a static var
static var operationDefinition
Is it possible to not make it a
static var
and just a regularvar
?Because it seems to be only used in
HTTPNetworkTransport
And there is doesn't seem to be really necessary for it to be a static variable.
The text was updated successfully, but these errors were encountered: