Last active
February 24, 2021 15:09
-
-
Save alloy/19b8fe4dd3dac6ab509e6c54f15844c4 to your computer and use it in GitHub Desktop.
Rewrite GraphQL Live Query to subscription.
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 is a Live Query polyfill, as graphql-js does not strictly have support for that. Instead, we leave it up to the | |
* client to recognize a Live Query is requested with the `@live` directive on a `query` operation and here we | |
* transform it into a `live` subscription instead. | |
* | |
* Consider a schema like the following: | |
* | |
* ```graphql | |
type Badge { | |
id: ID! | |
} | |
type Query { | |
current: Badge! | |
} | |
type Subscription { | |
live: Query! | |
} | |
* ``` | |
* | |
* …and an incoming query like the following: | |
* | |
* ```graphql | |
query BadgeQuery @live { | |
current { | |
id | |
} | |
} | |
* ``` | |
* | |
* This polyfill will then rewrite it to be: | |
* | |
* ```graphql | |
subscription BadgeQuery { | |
live { | |
current { | |
id | |
} | |
} | |
} | |
* ``` | |
*/ | |
function rewriteLiveQuery(ast: DocumentNode): { document: DocumentNode, live: boolean } { | |
let live = false; | |
const document = visit(ast, { | |
OperationDefinition: { | |
leave(operationNode) { | |
if (operationNode.operation === "query" && live) { | |
return { | |
...operationNode, | |
// Change the operation to be a subscription | |
operation: "subscription", | |
// Insert a `live` field selection in place of the existing selection set… | |
selectionSet: { | |
kind: "SelectionSet", | |
selections: [{ | |
kind: "Field", | |
name: { | |
kind: "Name", | |
value: "live", | |
}, | |
// …and add the existing selection set to the new `live` field selection. | |
selectionSet: operationNode.selectionSet, | |
}], | |
}, | |
}; | |
} | |
}, | |
}, | |
Directive(directiveNode) { | |
if (directiveNode.name.value === "live") { | |
live = true; | |
// Delete the `live` directive | |
// eslint-disable-next-line no-null/no-null | |
return null; | |
} | |
}, | |
SelectionSet() { | |
// Ensure we don't find directives anywhere else in the query | |
return false; | |
}, | |
}); | |
return { | |
document, | |
live, | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment