Skip to content

Commit 3a79084

Browse files
elithrarOxyjun
andauthored
durable objects: examples for using type args with SQL API (#18516)
* durable objects: examples for using type args with SQL API cc @geelen to keep me honest * Update src/content/docs/durable-objects/api/sql-storage.mdx * Update src/content/docs/durable-objects/api/sql-storage.mdx --------- Co-authored-by: Jun Lee <[email protected]>
1 parent b98914c commit 3a79084

File tree

1 file changed

+54
-0
lines changed

1 file changed

+54
-0
lines changed

src/content/docs/durable-objects/api/sql-storage.mdx

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,57 @@ let now = new Date();
148148
let bookmark = ctx.storage.getBookmarkForTime(now - 2);
149149
ctx.storage.onNextSessionRestoreBookmark(bookmark);
150150
```
151+
152+
## TypeScript and query results
153+
154+
You can use TypeScript [type parameters](https://www.typescriptlang.org/docs/handbook/2/generics.html#working-with-generic-type-variables) to provide a type for your results, allowing you to benefit from type hints and checks when iterating over the results of a query.
155+
156+
:::caution
157+
158+
Providing a type parameter does _not_ validate that the query result matches your type definition. In TypeScript, properties (fields) that do not exist in your result type will be silently dropped.
159+
160+
:::
161+
162+
Your type must conform to the shape of a TypeScript [Record](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type) type representing the name (`string`) of the column and the type of the column. The column type must be a valid `SqlStorageValue`: one of `ArrayBuffer | string | number | null`.
163+
164+
For example,
165+
166+
```ts
167+
type User = {
168+
id: string;
169+
name: string;
170+
email_address: string;
171+
version: number;
172+
}
173+
```
174+
175+
This type can then be passed as the type parameter to a `sql.exec` call:
176+
177+
```ts
178+
// The type parameter is passed between the "pointy brackets" before the function argument:
179+
const result = this.ctx.storage.sql.exec<User>("SELECT id, name, email_address, version FROM users WHERE id = ?", [user_id]).one()
180+
// result will now have a type of "User"
181+
182+
// Alternatively, if you are iterating over results using a cursor
183+
let cursor = this.sql.exec<User>("SELECT id, name, email_address, version FROM users WHERE id = ?", [user_id])
184+
for (let row of cursor) {
185+
// Each row object will be of type User
186+
}
187+
188+
// Or, if you are using raw() to convert results into an array, define an array type:
189+
type UserRow = [
190+
id: string,
191+
name: string,
192+
email_address: string,
193+
version: number,
194+
];
195+
196+
// ... and then pass it as the type argument to the raw() method:
197+
let cursor = sql.exec("SELECT id, name, email_address, version FROM users WHERE id = ?", [user_id]).raw<UserRow>();
198+
199+
for (let row of cursor) {
200+
// row is of type User
201+
}
202+
```
203+
204+
You can represent the shape of any result type you wish, including more complex types. If you are performing a JOIN across multiple tables, you can compose a type that reflects the results of your queries.

0 commit comments

Comments
 (0)