-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
GraphQL websocket subscription integration #540
Merged
Merged
Changes from all commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
183cb54
GraphQL subscriptions code
amandajliu 4c320dd
Merge remote-tracking branch 'origin' into subscription-integration
amandajliu 2bcf7a8
Making dummy npm package
amandajliu b30c7f5
changed package name
amandajliu f2d3efe
Added graphQLSubscriptions boolean to watchQuery
amandajliu 3f06f82
Updated package.json
amandajliu 3160f80
Merge remote-tracking branch 'origin' into subscription-integration
amandajliu a9fd7bc
Updated version
amandajliu e6afd0f
Added wsClient option to apollo client constructor
amandajliu be1629c
Non-incremental query subscriptions under dummy package name
amandajliu d503c1d
Incremental queries and gql subscriptions under dummy package name
amandajliu 4e1b08a
debuggin
amandajliu 8cc5d1f
0.0.26
amandajliu fc21291
Removed dummy package name, fixed linter errors, updated changelog
amandajliu 1d80d52
Removed websocket client from code except addGraphQLSubscriptions, ad…
amandajliu e65ec0e
Merge remote-tracking branch 'origin' into subscription-integration
amandajliu c633675
Basic error handling for subscription handler
amandajliu 48dd670
move subscription options to subscribe function
helfer 513d3a4
shorten tests a bit
helfer 8408cca
remove addSubscriptions from network interface
helfer 2dee8b1
Merge branch 'master' into subscription-integration
helfer 9b5bceb
Pass variables and fragments to subscription options (+minor changes)
helfer c33748c
move subscriptionOptions definition
helfer 5b25fe3
update CHANGELOG.md
helfer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,3 +17,13 @@ export interface FetchMoreQueryOptions { | |
query?: Document; | ||
variables?: { [key: string]: any }; | ||
} | ||
|
||
export interface GraphQLSubscriptionOptions { | ||
subscription: Document; | ||
variables?: { [key: string]: any }; | ||
fragments?: FragmentDefinition[]; | ||
updateFunction: (previousQueryResult: Object, options: { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't there a type for a graphql result? Or is this not a graphql result (which has data and errors)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not a graphql result |
||
subscriptionResult: Object, | ||
queryVariables: Object, | ||
}) => Object; | ||
}; |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,233 @@ | ||
import { | ||
mockSubscriptionNetworkInterface, | ||
} from './mocks/mockNetworkInterface'; | ||
|
||
import { | ||
assert, | ||
} from 'chai'; | ||
|
||
import clonedeep = require('lodash.clonedeep'); | ||
|
||
import ApolloClient from '../src'; | ||
|
||
import gql from 'graphql-tag'; | ||
|
||
import { | ||
QueryManager, | ||
} from '../src/QueryManager'; | ||
|
||
import { | ||
createApolloStore, | ||
} from '../src/store'; | ||
|
||
describe('GraphQL Subscriptions', () => { | ||
const results = ['Dahivat Pandya', 'Vyacheslav Kim', 'Changping Chen', 'Amanda Liu'].map( | ||
name => ({ result: { user: { name: name } }, delay: 10 }) | ||
); | ||
|
||
let sub1; | ||
let options; | ||
let watchQueryOptions; | ||
let sub2; | ||
let commentsQuery; | ||
let commentsVariables; | ||
let commentsSub; | ||
let commentsResult; | ||
let commentsResultMore; | ||
let commentsWatchQueryOptions; | ||
beforeEach(() => { | ||
|
||
sub1 = { | ||
request: { | ||
query: gql` | ||
subscription UserInfo($name: String) { | ||
user(name: $name) { | ||
name | ||
} | ||
} | ||
`, | ||
variables: { | ||
name: 'Changping Chen', | ||
}, | ||
}, | ||
id: 0, | ||
results: [...results], | ||
}; | ||
|
||
options = { | ||
query: gql` | ||
subscription UserInfo($name: String) { | ||
user(name: $name) { | ||
name | ||
} | ||
} | ||
`, | ||
variables: { | ||
name: 'Changping Chen', | ||
}, | ||
handler: (error, result) => { | ||
// do nothing | ||
}, | ||
}; | ||
|
||
watchQueryOptions = { | ||
query: gql` | ||
query UserInfo($name: String) { | ||
user(name: $name) { | ||
name | ||
} | ||
} | ||
`, | ||
variables: { | ||
name: 'Changping Chen', | ||
}, | ||
}; | ||
|
||
commentsQuery = gql` | ||
query Comment($repoName: String!) { | ||
entry(repoFullName: $repoName) { | ||
comments { | ||
text | ||
} | ||
} | ||
} | ||
`; | ||
|
||
commentsSub = gql` | ||
subscription getNewestComment($repoName: String!) { | ||
getNewestComment(repoName: $repoName) { | ||
text | ||
} | ||
}`; | ||
|
||
commentsVariables = { | ||
repoName: 'org/repo', | ||
}; | ||
|
||
commentsWatchQueryOptions = { | ||
query: commentsQuery, | ||
variables: commentsVariables, | ||
}; | ||
|
||
commentsResult = { | ||
data: { | ||
entry: { | ||
comments: [], | ||
}, | ||
}, | ||
}; | ||
|
||
commentsResultMore = { | ||
result: { | ||
entry: { | ||
comments: [], | ||
}, | ||
}, | ||
}; | ||
|
||
for (let i = 1; i <= 10; i++) { | ||
commentsResult.data.entry.comments.push({ text: `comment ${i}` }); | ||
} | ||
|
||
for (let i = 11; i < 12; i++) { | ||
commentsResultMore.result.entry.comments.push({ text: `comment ${i}` }); | ||
} | ||
|
||
sub2 = { | ||
request: { | ||
query: commentsSub, | ||
variables: commentsVariables, | ||
}, | ||
id: 0, | ||
results: [commentsResultMore], | ||
}; | ||
|
||
}); | ||
|
||
|
||
|
||
|
||
it('should start a subscription on network interface', (done) => { | ||
const network = mockSubscriptionNetworkInterface([sub1]); | ||
const queryManager = new QueryManager({ | ||
networkInterface: network, | ||
reduxRootKey: 'apollo', | ||
store: createApolloStore(), | ||
}); | ||
options.handler = (error, result) => { | ||
assert.deepEqual(result, results[0].result); | ||
done(); | ||
}; | ||
const id = queryManager.startSubscription(options); | ||
network.fireResult(id); | ||
}); | ||
|
||
it('should receive multiple results for a subscription', (done) => { | ||
const network = mockSubscriptionNetworkInterface([sub1]); | ||
let numResults = 0; | ||
const queryManager = new QueryManager({ | ||
networkInterface: network, | ||
reduxRootKey: 'apollo', | ||
store: createApolloStore(), | ||
}); | ||
options.handler = (error, result) => { | ||
assert.deepEqual(result, results[numResults].result); | ||
numResults++; | ||
if (numResults === 4) { | ||
done(); | ||
} | ||
}; | ||
const id = queryManager.startSubscription(options); | ||
for (let i = 0; i < 4; i++) { | ||
network.fireResult(id); | ||
} | ||
}); | ||
|
||
it('should work with an observable query', (done) => { | ||
const network = mockSubscriptionNetworkInterface([sub2], { | ||
request: { | ||
query: commentsQuery, | ||
variables: commentsVariables, | ||
}, | ||
result: commentsResult, // list of 10 comments | ||
}); | ||
const client = new ApolloClient({ | ||
networkInterface: network, | ||
}); | ||
client.query({ | ||
query: commentsQuery, | ||
variables: commentsVariables, | ||
}).then(() => { | ||
const graphQLSubscriptionOptions = { | ||
subscription: commentsSub, | ||
variables: commentsVariables, | ||
updateFunction: (prev, updateOptions) => { | ||
const state = clonedeep(prev) as any; | ||
// prev is that data field of the query result | ||
// updateOptions.subscriptionResult is the result entry from the subscription result | ||
state.entry.comments = [...state.entry.comments, ...(updateOptions.subscriptionResult as any).entry.comments]; | ||
return state; | ||
}, | ||
}; | ||
const obsHandle = client.watchQuery(commentsWatchQueryOptions); | ||
|
||
obsHandle.subscribe({ | ||
next(result) { | ||
let expectedComments = []; | ||
for (let i = 1; i <= 11; i++) { | ||
expectedComments.push({ text: `comment ${i}` }); | ||
} | ||
assert.equal(result.data.entry.comments.length, 11); | ||
assert.deepEqual(result.data.entry.comments, expectedComments); | ||
done(); | ||
}, | ||
}); | ||
|
||
const id = obsHandle.startGraphQLSubscription(graphQLSubscriptionOptions); | ||
network.fireResult(id); | ||
}); | ||
}); | ||
|
||
// TODO: test that we can make two subscriptions one one watchquery. | ||
|
||
}); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be
updateQuery
, just likefetchMore
. Sorry I didn't check on this.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I can change it for 0.4.13. Heads up @jbaxleyiii