From 3de4b6db168abceae2df66413a585d58418faa62 Mon Sep 17 00:00:00 2001 From: Paul Paterson Date: Wed, 13 Nov 2024 13:39:21 -0500 Subject: [PATCH] Better support for interfaces as query responses (#305) --- README.md | 20 +++++++++++++ __tests__/integration/query-typings.test.ts | 33 ++++++++++++++++++++- src/wire-protocol.ts | 4 +-- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f86c1594..b96f4a4a 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ See the [Fauna Documentation](https://docs.fauna.com/fauna/current/) for additio - [Usage](#usage) - [Write FQL queries](#write-fql-queries) - [Typescript support](#typescript-support) + - [Interfaces as `QueryValue` responses](#interfaces-as-queryvalue-responses) - [Query options](#query-options) - [Query statistics](#query-statistics) - [Pagination](#pagination) @@ -239,6 +240,25 @@ console.assert(userDoc.email === "alice@site.example"); client.close(); ``` +#### Interfaces as `QueryValue` responses + +To use a custom interface as a query response, extend the `QueryValueObject` +interface. + +```typescript +interface User extends QueryValueObject { + name: string; + email: string; +} + +const query = fql`{ + name: "Alice", + email: "alice@site.example", +}`; + +const response: QuerySuccess = await client.query(query); +``` + ### Query options Options are available to configure queries on each request. These override any diff --git a/__tests__/integration/query-typings.test.ts b/__tests__/integration/query-typings.test.ts index b847b6ff..4a09db53 100644 --- a/__tests__/integration/query-typings.test.ts +++ b/__tests__/integration/query-typings.test.ts @@ -1,9 +1,14 @@ -import { fql, Page, QueryCheckError } from "../../src"; +import { fql, Page, QueryCheckError, QueryValueObject } from "../../src"; import { getClient } from "../client"; // added in a junk property that is not part of QueryValue type MyType = { x: number; t: QueryCheckError }; +interface IMyTYpe extends QueryValueObject { + x: number; + t: QueryCheckError; +} + const client = getClient(); afterAll(() => { @@ -41,6 +46,32 @@ describe.each` } }); + it("allows customers to use their own interfaces in queries", async () => { + const query = fql`{ "x": 123 }`; + const paginatedQuery = fql`[{ "x": 123}].toSet()`; + + if ("query" === method) { + const result = (await client.query(query)).data; + expect(result).toEqual({ x: 123 }); + } else { + expect.assertions(2); + for await (const page of client.paginate(paginatedQuery)) { + for (const result of page) { + expect(result).toEqual({ x: 123 }); + } + } + + // It is also allowed to provide a query that does not return a page. + // When this happenes, the driver treats the result as if a page with + // exactly one item is returned. + for await (const page of client.paginate(query)) { + for (const result of page) { + expect(result).toEqual({ x: 123 }); + } + } + } + }); + it("allows customers to infer their own types in queries from fql statements", async () => { const query = fql`{ "x": 123 }`; const paginatedQuery = fql>`[{ "x": 123}].toSet()`; diff --git a/src/wire-protocol.ts b/src/wire-protocol.ts index 325f672c..96a49204 100644 --- a/src/wire-protocol.ts +++ b/src/wire-protocol.ts @@ -353,9 +353,9 @@ export interface Span { * QueryValue. * These objects can be returned in {@link QuerySuccess}. */ -export type QueryValueObject = { +export interface QueryValueObject { [key: string]: QueryValue; -}; +} /** * A QueryValue represents the possible return values in a {@link QuerySuccess}.