预准备查询
基本用法
使用预准备查询的基本示例如下:
import { surql, Surreal, Thing } from "@tai-kun/surrealdb";
const CreateUserQuery = surql`CREATE ONLY user:foo CONTENT { age: 42 };` .returns<[{ id: Thing<"user">, age: number }]>();
const db = new Surreal();await db.connect(`ws://localhost:8000`);await db.signin({ user: "root", pass: "root" });await db.use("example", "example");
const results = await db.query(CreateUserQuery);// ^? const results: [{ id: Thing<"user">, age: number }]
await db.disconnect();
预准备查询可以启用类型推断。但是,推断的类型需要手动设置。
验证查询结果
通过向.returns
方法传入查询结果验证器,可以使查询更安全。以下示例使用zod来验证查询结果是否为预期值:
import { surql, Surreal, Thing } from "@tai-kun/surrealdb";import { z } from "zod";
const isUserTable = (id: Thing): id is Thing<"user"> => id.tb === "user";
const CreatedUserSchema = z.tuple([ z.object({ id: z.instanceof(Thing).refine(isUserTable), age: z.number(), }),]);
const CreateUserQuery = surql`CREATE ONLY user:bar CONTENT { age: 42 };` .returns(CreatedUserSchema.parse.bind(CreatedUserSchema));
const db = new Surreal();await db.connect(`ws://localhost:8000`);await db.signin({ user: "root", pass: "root" });await db.use("example", "example");
const results = await db.query(CreateUserQuery);// ^? const results: [{ id: Thing<"user">, age: number }]
await db.disconnect();
本例并非依赖于zod,您可以使用valibot或通用函数来验证响应。
将变量嵌入查询
surql
允许使用模板字符串编写查询,因此可以直观地嵌入值:
import { surql, Surreal, Thing } from "@tai-kun/surrealdb";
const USERNAME = "baz";const USER_AGE = 42;
const CreateUserQuery = surql` CREATE ONLY type::thing('user', ${USERNAME}) CONTENT { age: ${USER_AGE} };` .returns<[{ id: Thing<"user">; age: number }]>();
const db = new Surreal();await db.connect(`ws://localhost:8000`);await db.signin({ user: "root", pass: "root" });await db.use("example", "example");
const results = await db.query(CreateUserQuery);// ^? const results: [{ id: Thing<"user">, age: number }]
await db.disconnect();
上述示例发送的RPC请求参数如下:
CREATE ONLY type::thing('user', $_jst_0) CONTENT { age: $_jst_1 };
{ _jst_0: "baz", _jst_1: 42}
定义查询参数
要为预准备查询定义参数,请使用surql.slot
:
import { surql, Surreal, Thing } from "@tai-kun/surrealdb";import { z } from "zod";
const isUserTable = (id: Thing): id is Thing<"user"> => id.tb === "user";
const UserIdSchema = z.instanceof(Thing).refine(isUserTable);
const UserIdSlot = surql.slot("id") .type(UserIdSchema.parse.bind(UserIdSchema));
const UserAgeSlot = surql.slot("age", 42);
const CreateUserQuery = surql` CREATE ONLY ${UserIdSlot} CONTENT { age: ${UserAgeSlot} };` .returns<[{ id: Thing<"user">; age: number }]>();
const db = new Surreal();await db.connect(`ws://localhost:8000`);await db.signin({ user: "root", pass: "root" });await db.use("example", "example");
const results = await db.query(CreateUserQuery, { id: new Thing("user", "tai-kun"),});
await db.disconnect();
槽必须有变量名。可以使用.type()
方法在类型级别上限制变量。与.returns()
类似,可以将验证值的函数作为.type()
的参数传入。在上述示例中,变量名为id
的槽必须是表名为"user"
的记录ID。
槽的参数可以跟随变量名设置默认值。如果在运行时省略槽的变量名,则使用此默认值。在上述示例中,变量名为age
的槽设置了默认值42
。
除了.type()
之外,槽还可以使用.rename()
、.default()
、.optional()
和.required()
。
如果预准备查询包含在运行时必须指定变量的槽,并且未指定该变量,则查询将在运行时被SurrealTypeError
拒绝。如果TypeScript类型推断正确,则无需运行即可在类型级别显示错误。例如,如果省略必需的变量并使用tsc
进行类型检查,则会发生错误:
import { surql, Surreal, Thing } from "@tai-kun/surrealdb";
const UserIdSlot = surql.slot("id") .type<Thing<"user">>();
const UserAgeSlot = surql.slot("age", 42);
const CreateUserQuery = surql` CREATE ONLY ${UserIdSlot} CONTENT { age: ${UserAgeSlot} };` .returns<[{ id: Thing<"user">, age: number }]>()
const db = new Surreal();await db.connect("ws://localhost:8000");
const results = await db.query(CreateUserQuery, { // id: new Thing("user", "tai-kun"),});
await db.disconnect();
npx tsc --noEmit
: