-
Notifications
You must be signed in to change notification settings - Fork 7
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
Add backwards compatible generics support for fql statements #277
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
a1592f2
WIP of generic support in fql statements
ecooper 1707dfb
Temp eslint ignore on query typing
ecooper 6889f27
Update doc strings about generic usage with fql
ecooper 5a37964
Merge branch 'main' into FE-5389-fql-generics
ecooper 97f7b12
Update typing for Client.paginate()
ptpaterson 1d1ac81
fix argument type for stream()
ptpaterson 8facc3b
default to Query<any>
ptpaterson 045b479
test for type errors where we want, too
ptpaterson c63e370
simplify .paginate() signature
ptpaterson 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,7 +41,6 @@ See the [Fauna Documentation](https://docs.fauna.com/fauna/current/) for additio | |
|
||
</details> | ||
|
||
|
||
## Supported runtimes | ||
|
||
**Server-side** | ||
|
@@ -67,10 +66,9 @@ Stable versions of: | |
- Safari 12.1+ | ||
- Edge 79+ | ||
|
||
|
||
## Install | ||
|
||
The driver is available on [npm](https://www.npmjs.com/package/fauna). You | ||
The driver is available on [npm](https://www.npmjs.com/package/fauna). You | ||
can install it using your preferred package manager. For example: | ||
|
||
```shell | ||
|
@@ -85,7 +83,6 @@ Browsers can import the driver using a CDN link: | |
</script> | ||
``` | ||
|
||
|
||
## Usage | ||
|
||
By default, the driver's `Client` instance authenticates with Fauna using an | ||
|
@@ -134,7 +131,6 @@ try { | |
} | ||
``` | ||
|
||
|
||
### Write FQL queries | ||
|
||
The `fql` function is your gateway to building safe, reuseable Fauna queries. | ||
|
@@ -175,8 +171,7 @@ This has several advantages: | |
|
||
- You can use `fql` to build a library of subqueries applicable to your domain - and combinable in whatever way you need | ||
- Injection attacks are not possible if you pass input variables into the interpolated (`` `${interpoloated_argument}` ``) parts of the query. | ||
- The driver speaks "pure" FQL - you can try out some FQL queries on the dashboard's terminal and paste it directly into your app like `` fql`copied from terminal...` `` and the query will work as is. | ||
|
||
- The driver speaks "pure" FQL - you can try out some FQL queries on the dashboard's terminal and paste it directly into your app like ``fql`copied from terminal...` `` and the query will work as is. | ||
|
||
### Typescript support | ||
|
||
|
@@ -198,14 +193,37 @@ const query = fql`{ | |
}`; | ||
|
||
const response: QuerySuccess<User> = await client.query<User>(query); | ||
const user_doc: User = response.data; | ||
const userDoc: User = response.data; | ||
|
||
console.assert(user_doc.name === "Alice"); | ||
console.assert(user_doc.email === "[email protected]"); | ||
console.assert(userDoc.name === "Alice"); | ||
console.assert(userDoc.email === "[email protected]"); | ||
|
||
client.close(); | ||
``` | ||
|
||
Alternatively, you can apply a type parameter directly to your | ||
fql statements and `Client` methods will infer your return types. | ||
Due to backwards compatibility, if a type parameter is provided to | ||
`Client` methods, it will override the inferred type from your | ||
query. | ||
|
||
```typescript | ||
const query = fql<User>`{ | ||
name: "Alice", | ||
email: "[email protected]", | ||
}`; | ||
|
||
// response will be typed as QuerySuccess<User> | ||
const response = await client.query(query); | ||
|
||
// userDoc will be automatically inferred as User | ||
const userDoc = response.data; | ||
|
||
console.assert(userDoc.name === "Alice"); | ||
console.assert(userDoc.email === "[email protected]"); | ||
|
||
client.close(); | ||
``` | ||
|
||
### Query options | ||
|
||
|
@@ -230,12 +248,11 @@ const options: QueryOptions = { | |
}; | ||
|
||
const response = await client.query(fql`"Hello, #{name}!"`, options); | ||
console.log(response.data) | ||
console.log(response.data); | ||
|
||
client.close(); | ||
``` | ||
|
||
|
||
### Query statistics | ||
|
||
Query statistics are returned with successful query responses and errors of | ||
|
@@ -255,7 +272,7 @@ const client = new Client(); | |
|
||
try { | ||
const response: QuerySuccess<string> = await client.query<string>( | ||
fql`"Hello world"` | ||
fql`"Hello world"`, | ||
); | ||
const stats: QueryStats | undefined = response.stats; | ||
console.log(stats); | ||
|
@@ -307,7 +324,7 @@ const pages: SetIterator<QueryValue> = client.paginate(query, options); | |
|
||
for await (const products of pages) { | ||
for (const product of products) { | ||
console.log(product) | ||
console.log(product); | ||
} | ||
} | ||
|
||
|
@@ -320,7 +337,7 @@ Use `flatten()` to get paginated results as a single, flat array: | |
const pages: SetIterator<QueryValue> = client.paginate(query, options); | ||
|
||
for await (const product of pages.flatten()) { | ||
console.log(product) | ||
console.log(product); | ||
} | ||
``` | ||
|
||
|
@@ -360,7 +377,6 @@ const config: ClientConfiguration = { | |
const client = new Client(config); | ||
``` | ||
|
||
|
||
### Environment variables | ||
|
||
The driver will default to configuring your client with the values of the `FAUNA_SECRET` and `FAUNA_ENDPOINT` environment variable. | ||
|
@@ -378,27 +394,22 @@ You can initalize the client with a default configuration: | |
const client = new Client(); | ||
``` | ||
|
||
|
||
### Retry | ||
|
||
|
||
#### Max attempts | ||
|
||
The maximum number of times a query will be attempted if a retryable exception is thrown (ThrottlingError). Default 3, inclusive of the initial call. The retry strategy implemented is a simple exponential backoff. | ||
|
||
To disable retries, pass max_attempts less than or equal to 1. | ||
|
||
|
||
#### Max backoff | ||
|
||
The maximum backoff in seconds to be observed between each retry. Default 20 seconds. | ||
|
||
|
||
### Timeouts | ||
|
||
There are a few different timeout settings that can be configured; each comes with a default setting. We recommend that most applications simply stick to the defaults. | ||
|
||
|
||
#### Query timeout | ||
|
||
The query timeout is the time, in milliseconds, that Fauna will spend executing your query before aborting with a 503 Timeout error. If a query timeout occurs, the driver will throw an instance of `QueryTimeoutError`. | ||
|
@@ -417,7 +428,6 @@ when performing this query. | |
const response = await client.query(myQuery, { query_timeout_ms: 20_000 }); | ||
``` | ||
|
||
|
||
#### Client timeout | ||
|
||
The client timeout is the time, in milliseconds, that the client will wait for a network response before canceling the request. If a client timeout occurs, the driver will throw an instance of `NetworkError`. | ||
|
@@ -428,7 +438,6 @@ The client timeout is always the query timeout plus an additional buffer. This e | |
const client = new Client({ client_timeout_buffer_ms: 6000 }); | ||
``` | ||
|
||
|
||
#### HTTP/2 session idle timeout | ||
|
||
The HTTP/2 session idle timeout is the time, in milliseconds, that an HTTP/2 session will remain open after there is no more pending communication. Once the session idle time has elapsed the session is considered idle and the session is closed. Subsequent requests will create a new session; the session idle timeout does not result in an error. | ||
|
@@ -473,15 +482,15 @@ const response = await client.query(fql` | |
`); | ||
const { initialPage, streamToken } = response.data; | ||
|
||
client.stream(streamToken) | ||
client.stream(streamToken); | ||
``` | ||
|
||
You can also pass a query that produces a stream token directly to `stream()`: | ||
|
||
```javascript | ||
const query = fql`Product.all().changesOn(.price, .quantity)` | ||
const query = fql`Product.all().changesOn(.price, .quantity)`; | ||
|
||
client.stream(query) | ||
client.stream(query); | ||
``` | ||
|
||
### Iterate on a stream | ||
|
@@ -504,7 +513,6 @@ try { | |
// An error will be handled here if Fauna returns a terminal, "error" event, or | ||
// if Fauna returns a non-200 response when trying to connect, or | ||
// if the max number of retries on network errors is reached. | ||
|
||
// ... handle fatal error | ||
} | ||
``` | ||
|
@@ -527,9 +535,8 @@ stream.start( | |
// An error will be handled here if Fauna returns a terminal, "error" event, or | ||
// if Fauna returns a non-200 response when trying to connect, or | ||
// if the max number of retries on network errors is reached. | ||
|
||
// ... handle fatal error | ||
} | ||
}, | ||
); | ||
``` | ||
|
||
|
@@ -538,7 +545,7 @@ stream.start( | |
Use `close()` to close a stream: | ||
|
||
```javascript | ||
const stream = await client.stream(fql`Product.all().toStream()`) | ||
const stream = await client.stream(fql`Product.all().toStream()`); | ||
|
||
let count = 0; | ||
for await (const event of stream) { | ||
|
@@ -548,7 +555,7 @@ for await (const event of stream) { | |
|
||
// Close the stream after 2 events | ||
if (count === 2) { | ||
stream.close() | ||
stream.close(); | ||
break; | ||
} | ||
} | ||
|
@@ -570,14 +577,13 @@ const options = { | |
status_events: true, | ||
}; | ||
|
||
client.stream(fql`Product.all().toStream()`, options) | ||
client.stream(fql`Product.all().toStream()`, options); | ||
``` | ||
|
||
For supported properties, see [Stream | ||
options](https://docs.fauna.com/fauna/current/drivers/js-client#stream-options) | ||
in the Fauna docs. | ||
|
||
|
||
## Contributing | ||
|
||
Any contributions are from the community are greatly appreciated! | ||
|
@@ -586,26 +592,22 @@ If you have a suggestion that would make this better, please fork the repo and c | |
|
||
Don't forget to give the project a star! Thanks again! | ||
|
||
|
||
### Set up the repo | ||
|
||
1. Clone the repository; e.g. `gh repo clone fauna/fauna-js` if you use the GitHub CLI | ||
2. Install dependencies via `yarn install` | ||
|
||
|
||
### Run tests | ||
|
||
1. Start a docker desktop or other docker platform. | ||
2. Run `yarn test`. This will start local fauna containers, verify they're up and run all tests. | ||
|
||
|
||
### Lint your code | ||
|
||
Linting runs automatically on each commit. | ||
|
||
If you wish to run on-demand run `yarn lint`. | ||
|
||
|
||
## License | ||
|
||
Distributed under the MPL 2.0 License. See [LICENSE](./LICENSE) for more information. |
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
Oops, something went wrong.
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.
wow cool assertion here.
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.
Would you mind adding how to use this to the development section of the README?
As we tweak type arguments in future work capturing that we can sanity check our types using this and proper linter settings will help out future devs.
For example, we got some work we'd like to do to make less boilerplate for users when definining their own types and when using
.query
calls that return pages (as opposed to using the clients pagination utils - there's cases you might do that in an API for example). We have some of these type improvements documented internally here: https://faunadb.atlassian.net/wiki/spaces/DX/pages/3852697604/Developer+Tooling+Pain#API-PaginationSo this test pattern is something we will likely need aagain.
Just linking here: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-9.html with some text about the linter settings needed would suffice.