Created
October 29, 2020 20:53
-
-
Save UberMouse/62631a290a7fbbb6759ffa0344d68039 to your computer and use it in GitHub Desktop.
GraphQL + Apollo + XState dump
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type QueryResult<TTransformedData> = | |
| { type: "success"; data: TTransformedData } | |
| { type: "error"; errors: readonly GraphQLError[] }; | |
type ParentEvents<TData, TId extends string = "dataLoader"> = | |
| { type: "dataStream.NEW_DATA"; data: TData; id: TId } | |
| { type: "dataStream.ERROR"; id: TId }; | |
export function createDataStream< | |
TObservableFactory extends (...args: $YesReallyAny[]) => Observable<QueryResult<$YesReallyAny>>, | |
TData = ReturnType<TObservableFactory> extends Observable<QueryResult<infer TResult>> | |
? TResult | |
: never, | |
TParameters = Parameters<TObservableFactory>[0] | |
>(observableFactory: TObservableFactory, dataStreamId = "dataStream") { | |
return (params: TParameters) => | |
observableFactory(params).pipe( | |
map( | |
(result): ParentEvents<TData, typeof dataStreamId> => { | |
if (result.type === "error") { | |
return { type: "dataStream.ERROR", id: dataStreamId }; | |
} | |
return { type: "dataStream.NEW_DATA", data: result.data, id: dataStreamId }; | |
} | |
) | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
gql` | |
mutation commit($repoId: String!, $message: String!, $datasets: [String!]!) { | |
commit(id: $repoId, message: $message, datasets: $datasets) | |
} | |
`; | |
async function basePerformCommit(variables: CommitMutationVariables): Promise<boolean> { | |
const mutation = gqlClient.mutate<CommitMutation, CommitMutationVariables>({ | |
mutation: CommitDocument, | |
variables, | |
refetchQueries: [{ query: GetUncommitedChangesDocument }, { query: GetTimelineDataDocument }], | |
}); | |
return newHandleMutationResult(mutation, (res) => res.commit); | |
} | |
export const performCommit = attachRepoId(basePerformCommit); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
gql` | |
query haveCommitDetails($repoId: String!) { | |
currentReposheetId @client @export(as: "repoId") | |
repository2(id: $repoId) { | |
... on ReadyRepository { | |
userDetailsSet | |
} | |
} | |
} | |
`; | |
export function haveCommitDetails(): GqlQuery<boolean> { | |
const query = gqlClient.watchQuery<HaveCommitDetailsQuery>({ | |
query: HaveCommitDetailsDocument, | |
fetchPolicy: "network-only", | |
}); | |
return newHandleQueryResult(query, (q) => { | |
assert(q.repository2.__typename === "ReadyRepository"); | |
return q.repository2.userDetailsSet; | |
}); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export type QueryResultContainer<TGqlData, TVariables, TTransformedData> = { | |
query: QueryWrapper<TGqlData, TVariables>; | |
results: Observable<QueryResult<TTransformedData>>; | |
}; | |
export function handleQueryResult<TQueryType, TVariables, TResultType>( | |
query: ObservableQuery<TQueryType, TVariables>, | |
mapper: (queryResult: TQueryType) => TResultType | |
): QueryResultContainer<TQueryType, TVariables, TResultType> { | |
const rxjsResults = new Observable<QueryResult<TResultType>>((observer) => { | |
const subscription = query.subscribe((result) => { | |
if (result.errors) { | |
console.debug("GraphQL error: ", result.errors); | |
observer.next({ type: "error", errors: result.errors }); | |
} else if (!result.loading) { | |
observer.next({ type: "success", data: mapper(result.data) }); | |
} | |
}); | |
return () => subscription.unsubscribe(); | |
}); | |
return { query, results: rxjsResults }; | |
} | |
export function newHandleQueryResult<TQueryType, TVariables, TResultType>( | |
query: ObservableQuery<TQueryType, TVariables>, | |
mapper: (queryResult: TQueryType) => TResultType | |
): Observable<QueryResult<TResultType>> { | |
return handleQueryResult(query, mapper).results; | |
} | |
function MutationError( | |
this: { message: string; graphqlErrors: GraphQLError[]; name: string }, | |
message: string, | |
graphqlErrors: GraphQLError[] | |
) { | |
this.name = "MutationError"; | |
this.message = message; | |
this.graphqlErrors = graphqlErrors; | |
} | |
MutationError.prototype = Error.prototype; | |
export function newHandleMutationResult<TQueryType, TResultType>( | |
mutation: Promise<FetchResult<TQueryType>>, | |
mapper: (mutationResult: TQueryType) => TResultType | |
): Promise<TResultType> { | |
return mutation.then((result) => { | |
if (result.errors) { | |
// @ts-ignore what are you even on about TypeScript? | |
throw new MutationError("GraphQL mutation failed", result.errors); | |
} | |
return mapper(result.data!); | |
}); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const haveCommitDetailsStream = createDataStream(haveCommitDetails, "commitDetails"); | |
export const machine = createMachine<Context, Events, States>( | |
{ | |
type: "parallel", | |
context: { | |
}, | |
states: { | |
ui: { | |
initial: "loading", | |
states: { | |
loading: { | |
on: { | |
"dataStream.ERROR": "error", | |
"dataStream.NEW_DATA": [ | |
{ | |
target: "loaded.uncommittedChanges", | |
cond: Guards.hasUncommitedChanges, | |
}, | |
{ target: "loaded.noChanges" }, | |
], | |
}, | |
}, | |
error: {}, | |
loaded: {} | |
}, | |
}, | |
data: { | |
invoke: { | |
src: Services.changes, | |
}, | |
initial: "loading", | |
states: { | |
loading: { | |
on: { | |
"dataStream.ERROR": "error", | |
"dataStream.NEW_DATA": { | |
target: "loaded", | |
actions: Actions.storeChanges, | |
}, | |
}, | |
}, | |
error: {}, | |
loaded: { | |
invoke: { | |
src: Services.commitDetails, | |
}, | |
on: { | |
"dataStream.NEW_DATA": [ | |
{ | |
actions: Actions.storeChanges, | |
cond: Guards.isChangesStream, | |
}, | |
{ actions: Actions.storeUserCommitDetails }, | |
], | |
}, | |
}, | |
}, | |
}, | |
}, | |
}, | |
{ | |
actions: { | |
}, | |
guards: { | |
}, | |
services: { | |
[Services.commitDetails]: () => haveCommitDetailsStream(undefined), | |
}, | |
} | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
HI, Can you please elaborate on
createDataStream.ts
file? I'm gettingobservableFactory(...).pipe is not a function