Drizzle 查询

Drizzle ORM 旨在在 SQL 之上提供一个薄型的类型化层。我们真诚地相信我们设计了一种在 TypeScript 中操作 SQL 数据库的最佳方式,现在是时候让它变得更好了。

关系查询旨在为您提供优秀的开发人员体验,用于从 SQL 数据库中查询嵌套关系数据,避免多个连接和复杂的数据映射。

它是现有模式定义和查询构建器的扩展。您可以根据自己的需求选择使用它。我们确保您既有一流的开发人员体验又有高性能。

index.ts
schema.ts
import * as schema from './schema';
import { drizzle } from 'drizzle-orm/...';

const db = drizzle(client, { schema });

const result = await db.query.users.findMany({
  with: {
    posts: true      
  },
});
[{
  id: 10,
  name: "Dan",
  posts: [
    {
      id: 1,
      content: "SQL is awesome",
      authorId: 10,
    },
    {
      id: 2,
      content: "But check relational queries",
      authorId: 10,
    }
  ]
}]
import { integer, serial, text, pgTable } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
});

export const usersRelations = relations(users, ({ many }) => ({
  posts: many(posts),
}));

export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  content: text('content').notNull(),
  authorId: integer('author_id').notNull(),
});

export const postsRelations = relations(posts, ({ one }) => ({
  author: one(users, { fields: [posts.authorId], references: [users.id] }),
}));

⚠️ If you have SQL schema declared in multiple files you can do it like that

index.ts
schema1.ts
schema2.ts
import * as schema1 from './schema1';
import * as schema2 from './schema2';
import { drizzle } from 'drizzle-orm/...';

const db = drizzle(client, { schema: { ...schema1, ...schema2 } });

const result = await db.query.users.findMany({
  with: {
    posts: true      
  },
});
// schema declaration in the first file
// schema declaration in the second file

模式

Drizzle 关系查询始终生成一个要在数据库上运行的 SQL 语句,并且有一定的注意事项。 为了对每个数据库提供最佳支持,我们引入了 modes

Drizzle 关系查询在内部使用子查询的侧向连接,但目前 PlanetScale 不支持它们。

当使用 mysql2 驱动程序和常规 MySQL 数据库时,应该指定 mode: "default" 当使用 mysql2 驱动程序和 PlanetScale 时,需要指定 mode: "planetscale"

import * as schema from './schema';
import { drizzle } from "drizzle-orm/mysql2";
import mysql from "mysql2/promise";

const connection = await mysql.createConnection({
  uri: process.env.PLANETSCALE_DATABASE_URL,
});

const db = drizzle(connection, { schema, mode: 'planetscale' });

声明关系

一对一

Drizzle ORM 提供了一种 API 来定义表之间的 一对一 关系,使用 relations 运算符。

下面是 users 和 users 之间的 一对一 关系的示例,其中一个用户可以邀请另一个用户(此示例使用了自我引用):

import { pgTable, serial, text, integer, boolean } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name'),
  invitedBy: integer('invited_by'),
});

export const usersRelations = relations(users, ({ one }) => ({
  invitee: one(users, {
    fields: [users.invitedBy],
    references: [users.id],
  }),
}));

另一个示例是用户在单独的表中存储个人资料信息。在这种情况下,由于外键存储在 “profile_info” 表中,用户关系既没有字段也没有引用。它告诉 Typescript user.profileInfo 是可空的:

import { pgTable, serial, text, integer, jsonb } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name'),
});

export const usersRelations = relations(users, ({ one }) => ({
  profileInfo: one(profileInfo),
}));

export const profileInfo = pgTable('profile_info', {
  id: serial('id').primaryKey(),
  userId: integer('user_id').references(() => users.id),
  metadata: jsonb('metadata'),
});

export const profileInfoRelations = relations(profileInfo, ({ one }) => ({
  user: one(users, { fields: [profileInfo.userId], references: [users.id] }),
}));

const user = await queryUserWithProfileInfo();
//____^? type { id: number, profileInfo: { ... } | null  }

一对多

Drizzle ORM 提供了一种 API 来定义表之间的 一对多 关系,使用 relations 运算符。

users 和他们编写的 posts 之间的 一对多 关系示例:

import { pgTable, serial, text, integer } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name'),
});

export const usersRelations = relations(users, ({ many }) => ({
  posts: many(posts),
}));

export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  content: text('content'),
  authorId: integer('author_id'),
});

export const postsRelations = relations(posts, ({ one }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
  }),
}));

现在让我们给帖子添加评论:

...

export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  content: text('content'),
  authorId: integer('author_id'),
});

export const postsRelations = relations(posts, ({ one, many }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
  }),
  comments: many(comments)
}));

export const comments = pgTable('comments', {
  id: serial('id').primaryKey(),
  text: text('text'),
  authorId: integer('author_id'),
  postId: integer('post_id'),
});

export const commentsRelations = relations(comments, ({ one }) => ({
  post: one(posts, {
    fields: [comments.postId],
    references: [posts.id],
  }),
}));

多对多

Drizzle ORM 提供了一种 API 来定义表之间的 多对多 关系,通过所谓的 junctionjoin 表进行关联,它们必须明确定义并存储相关表之间的关联。

users 和 groups 之间的 多对多 关系示例:

import { relations } from 'drizzle-orm';
import { integer, pgTable, primaryKey, serial, text } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name'),
});

export const usersRelations = relations(users, ({ many }) => ({
  usersToGroups: many(usersToGroups),
}));

export const groups = pgTable('groups', {
  id: serial('id').primaryKey(),
  name: text('name'),
});

export const groupsRelations = relations(groups, ({ many }) => ({
  usersToGroups: many(usersToGroups),
}));

export const usersToGroups = pgTable(
  'users_to_groups',
  {
    userId: integer('user_id')
      .notNull()
      .references(() => users.id),
    groupId: integer('group_id')
      .notNull()
      .references(() => groups.id),
  },
  (t) => ({
    pk: primaryKey({ columns: [t.userId, t.groupId] }),
  }),
);

export const usersToGroupsRelations = relations(usersToGroups, ({ one }) => ({
  group: one(groups, {
    fields: [usersToGroups.groupId],
    references: [groups.id],
  }),
  user: one(users, {
    fields: [usersToGroups.userId],
    references: [users.id],
  }),
}));

外键

您可能已经注意到 relations 看起来类似于外键 —— 甚至具有 references 属性。那么它们的区别是什么?

虽然外键是用于在表之间定义关系的相似目的,但它们与 relations 在不同的层面上工作。

外键是数据库级别的约束,它们在每次 插入/更新/删除 操作时进行检查,并在违反约束时抛出错误。 另一方面,relations 是一个更高级别的抽象,它们仅用于在应用程序级别定义表之间的关系。 它们不会以任何方式影响数据库架构,也不会隐式地创建外键。

这意味着 relations 和外键可以一起使用,但它们彼此之间不依赖。 您可以定义 relations 而不使用外键(反之亦然),这使它们能够与不支持外键的数据库一起使用。

以下两个示例在使用 Drizzle 关系查询查询数据方面的效果完全相同。

schema1.ts
schema2.ts
export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name'),
});

export const usersRelations = relations(users, ({ one, many }) => ({
  profileInfo: one(users, {
    fields: [profileInfo.userId],
    references: [users.id],
  }),
}));

export const profileInfo = pgTable('profile_info', {
  id: serial('id').primaryKey(),
  userId: integer("user_id"),
  metadata: jsonb("metadata"),
});
export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name'),
});

export const usersRelations = relations(users, ({ one, many }) => ({
  profileInfo: one(users, {
    fields: [profileInfo.userId],
    references: [users.id],
  }),
}));

export const profileInfo = pgTable('profile_info', {
  id: serial('id').primaryKey(),
  userId: integer("user_id").references(() => users.id),
  metadata: jsonb("metadata"),
});

外键操作

有关更多信息,请参阅 postgres 外键文档

您可以指定在修改父表中的引用数据时应执行的操作。这些操作称为 “外键操作”。PostgreSQL 提供了几个选项用于这些操作。

删除/更新操作

  • CASCADE:当删除父表中的行时,子表中的所有相关行也将被删除。这样可以确保子表中不存在孤立的行。

  • NO ACTION:这是默认操作。如果子表中存在相关行,则会阻止删除父表中的行。父表中的 DELETE 操作将失败。

  • RESTRICT:与 NO ACTION 类似,它防止删除父行,如果子表中有依赖行的话。本质上它与 NO ACTION 相同,并包含兼容性的原因。

  • SET DEFAULT:如果删除父表中的行,则如果它有默认值,则子表中的外键列将设置为其默认值。如果它没有默认值,则删除操作将失败。

  • SET NULL:当删除父表中的行时,子表中的外键列将设置为空。此操作假设子表中的外键列允许空值。

类似于 ON DELETE,还有 ON UPDATE,它在引用列更改(更新)时调用。可能的操作和 ON DELETE 相同,只是不能为 SET NULL 和 SET DEFAULT 指定列列表。在这种情况下,CASCADE 表示应将更新后的引用列的值复制到引用行中。 在 Drizzle 中,您可以使用 references() 的第二个参数添加外键操作。

操作的类型

export type UpdateDeleteAction = 'cascade' | 'restrict' | 'no action' | 'set null' | 'set default';

// second argument of references interface
actions?: {
    onUpdate?: UpdateDeleteAction;
    onDelete?: UpdateDeleteAction;
  } | undefined

In the following example, adding onDelete: 'cascade' to the author field on the posts schema means that deleting the user will also delete all related Post records.

import { pgTable, serial, text, integer } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name'),
});

export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  name: text('name'),
  author: integer('author').references(() => users.id, {onDelete: 'cascade'}).notNull(),
});

对于使用 foreignKey 操作符指定的约束,外键操作的语法格式如下:

import { foreignKey, pgTable, serial, text, integer } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name'),
});

export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  name: text('name'),
  author: integer('author').notNull(),
}, (table) => ({
    fk: foreignKey({
      name: "author_fk",
      columns: [table.author],
      foreignColumns: [users.id],
    })
      .onDelete('cascade')
      .onUpdate('cascade')
  }),
);

消除模糊关系

Drizzle 还提供了 relationName 选项来消除在相同的两个表之间定义多个关系时的模糊关系。 例如,如果定义了具有 authorreviewer 关系的 posts 表。

import { pgTable, serial, text, integer } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
 
export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name'),
});
 
export const usersRelations = relations(users, ({ many }) => ({
  author: many(posts, { relationName: 'author' }),
  reviewer: many(posts, { relationName: 'reviewer' }),
}));
 
export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  content: text('content'),
  authorId: integer('author_id'),
  reviewerId: integer('reviewer_id'),
});
 
export const postsRelations = relations(posts, ({ one }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
    relationName: 'author',
  }),
  reviewer: one(users, {
    fields: [posts.reviewerId],
    references: [users.id],
    relationName: 'reviewer',
  }),
}));

查询

关系查询是 Drizzle 原始 查询构建器 的扩展。 在 drizzle() 初始化时,您需要提供来自模式文件/文件的所有 tablesrelations,然后只需使用 db.query API。

ℹ️

drizzle 的导入路径取决于您使用的 数据库驱动程序

index.ts
schema.ts
import * as schema from './schema';
import { drizzle } from 'drizzle-orm/...';

const db = drizzle(client, { schema });

await db.query.users.findMany(...);
// if you have schema in multiple files
import * as schema1 from './schema1';
import * as schema2 from './schema2';
import { drizzle } from 'drizzle-orm/...';

const db = drizzle(client, { schema: { ...schema1, ...schema2 } });

await db.query.users.findMany(...);
  import { type AnyPgColumn, boolean, integer, pgTable, primaryKey, serial, text, timestamp } from 'drizzle-orm/pg-core';

  import { relations } from 'drizzle-orm';

  export const users = pgTable('users', {
    id: serial('id').primaryKey(),
    name: text('name').notNull(),
    invitedBy: integer('invited_by').references((): AnyPgColumn => users.id),
  });

  export const usersRelations = relations(users, ({ one, many }) => ({
    invitee: one(users, { fields: [users.invitedBy], references: [users.id] }),
    usersToGroups: many(usersToGroups),
    posts: many(posts),
  }));

  export const groups = pgTable('groups', {
    id: serial('id').primaryKey(),
    name: text('name').notNull(),
    description: text('description'),
  });

  export const groupsRelations = relations(groups, ({ many }) => ({
    usersToGroups: many(usersToGroups),
  }));

  export const usersToGroups = pgTable('users_to_groups', {
    id: serial('id').primaryKey(),
    userId: integer('user_id').notNull().references(() => users.id),
    groupId: integer('group_id').notNull().references(() => groups.id),
  }, (t) => ({
    pk: primaryKey(t.userId, t.groupId),
  }));

  export const usersToGroupsRelations = relations(usersToGroups, ({ one }) => ({
    group: one(groups, { fields: [usersToGroups.groupId], references: [groups.id] }),
    user: one(users, { fields: [usersToGroups.userId], references: [users.id] }),
  }));

  export const posts = pgTable('posts', {
    id: serial('id').primaryKey(),
    content: text('content').notNull(),
    authorId: integer('author_id').references(() => users.id),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  });

  export const postsRelations = relations(posts, ({ one, many }) => ({
    author: one(users, { fields: [posts.authorId], references: [users.id] }),
    comments: many(comments),
  }));

  export const comments = pgTable('comments', {
    id: serial('id').primaryKey(),
    content: text('content').notNull(),
    creator: integer('creator').references(() => users.id),
    postId: integer('post_id').references(() => posts.id),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  });

  export const commentsRelations = relations(comments, ({ one, many }) => ({
    post: one(posts, { fields: [comments.postId], references: [posts.id] }),
    author: one(users, { fields: [comments.creator], references: [users.id] }),
    likes: many(commentLikes),
  }));

  export const commentLikes = pgTable('comment_likes', {
    id: serial('id').primaryKey(),
    creator: integer('creator').references(() => users.id),
    commentId: integer('comment_id').references(() => comments.id),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  });

  export const commentLikesRelations = relations(commentLikes, ({ one }) => ({
    comment: one(comments, { fields: [commentLikes.commentId], references: [comments.id] }),
    author: one(users, { fields: [commentLikes.creator], references: [users.id] }),
  }));

Drizzle 提供了 .findMany().findFirst() API。

查询多个

const users = await db.query.users.findMany();
// result type
const result: {
  id: number;
  name: string;
  verified: boolean;
  invitedBy: number | null;
}[];

Find first

💡

.findFirst() will add limit 1 to the query.

const user = await db.query.users.findFirst();
// result type
const result: {
  id: number;
  name: string;
  verified: boolean;
  invitedBy: number | null;
};

查询第一个

包含关系

With 运算符允许您将多个相关表的数据组合在一起,并正确聚合结果。

获取所有带有评论的帖子:

const posts = await db.query.posts.findMany({
  with: {
    comments: true,
  },
});

获取带有评论的第一篇帖子:

const post = await db.query.posts.findFirst({
  with: {
    comments: true,
  },
});

您可以将嵌套的 with 语句链接起来,需要多少链接就可以。对于任何嵌套的 with 查询,Drizzle 将使用 核心类型 API 推断类型。

获取所有用户和他们的帖子。每个帖子都应包含一条评论列表:

const users = await db.query.users.findMany({
  with: {
    posts: {
      with: {
        comments: true,
      },
    },
  },
});

部分字段选择

columns 参数允许您包含或省略要从数据库获取的列。

ℹ️

Drizzle 在查询级别执行部分选择,不会从数据库传输额外的数据。

请注意,Drizzle 只输出一个 SQL 语句。

仅获取带有 idcontent 的所有帖子,并包含 comments

const posts = await db.query.posts.findMany({
  columns: {
    id: true,
    content: true,
  },
  with: {
    comments: true,
  }
});

Get all posts without content:

const posts = await db.query.posts.findMany({
  columns: {
    content: false,
  },
});
ℹ️

当同时存在 truefalse 选择选项时,所有 false 选项将被忽略。

如果将 name 字段包含进来并排除 id 字段,id 的排除将是多余的,因为除了 name 之外的所有字段都将被排除。

在同一个查询中排除和包含字段:

const users = await db.query.users.findMany({
  columns: {
    name: true,
    id: false //ignored
  },
});
// result type
const users: {
  name: string;
};

仅包括嵌套关联的列:

const res = await db.query.users.findMany({
  columns: {},
  with: {
    posts: true
  }
});
// result type
const res: {
  posts: {
    id: number,
    text: string
  }
}[];

嵌套部分字段选择

与**部分选择**一样,您可以包含或排除嵌套关系的列:

const posts = await db.query.posts.findMany({
  columns: {
    id: true,
    content: true,
  },
  with: {
    comments: {
      columns: {
        authorId: false
      }
    }
  }
});

选择过滤器

就像在我们的 SQL-类似的查询构建器中一样, 关系查询 API 允许您使用我们的**operators**列表定义过滤器和条件。

您可以从 drizzle-orm 中导入它们,也可以使用回调语法中的操作符:

import { eq } from 'drizzle-orm';

const users = await db.query.users.findMany({
  where: eq(users.id, 1)
})
const users = await db.query.users.findMany({
  where: (users, { eq }) => eq(users.id, 1),
})

查找帖子 id=1 和早于特定日期创建的评论:

await db.query.posts.findMany({
  where: (posts, { eq }) => (eq(posts.id, 1)),
  with: {
    comments: {
      where: (comments, { lt }) => lt(comments.createdAt, new Date()),
    },
  },
});

限制和偏移量

Drizzle ORM 为查询和嵌套实体提供了 limitoffset API。

查找 5 条帖子:

await db.query.posts.findMany({
  limit: 5,
});

查找帖子并在最多的 3 条评论:

await db.query.posts.findMany({
  with: {
    comments: {
      limit: 3,
    },
  },
});
⚠️

offset 只适用于顶级查询。

await db.query.posts.findMany({
  limit: 5,
  offset: 2, // correct ✅
  with: {
    comments: {
      offset: 3, // incorrect ❌
      limit: 3,
    },
  },
});

查找带有评论的帖子,并从第 5 条到第 10 条帖子:

await db.query.posts.findMany({
  limit: 5,
  offset: 5,
  with: {
    comments: true,
  },
});

排序

Drizzle 在关系查询构建器中提供排序的 API。

您可以使用相同的排序 核心 API 或使用回调中的 order by 运算符,无需导入。

import { desc, asc } from 'drizzle-orm';

await db.query.posts.findMany({
  orderBy: [asc(posts.id)],
});
await db.query.posts.findMany({
  orderBy: (posts, { asc }) => [asc(posts.id)],
});

asc + desc 排序:

await db.query.posts.findMany({
  orderBy: (posts, { asc }) => [asc(posts.id)],
  with: {
    comments: {
      orderBy: (comments, { desc }) => [desc(comments.id)],
    },
  },
});

包含自定义字段

关系查询 API 允许您添加自定义的附加字段。在需要检索数据并对其应用其他函数时非常有用。

⚠️

目前不支持在 extras 中进行聚合,请使用 核心查询

import { sql } from 'drizzle-orm';

await db.query.users.findMany({
  extras: {
    loweredName: sql`lower(${users.name})`.as('lowered_name'),
  },
})
await db.query.users.findMany({
  extras: {
    loweredName: (users, { sql }) => sql`lower(${users.name})`.as('lowered_name'),
  },
})

lowerName 为键将包含在返回对象的所有字段中。

⚠️

您必须明确指定 .as("<name_for_column>")

要检索包含组的所有用户,但包含全名字段(它是 firstName 和 lastName 的串联),您可以使用以下查询中的 Drizzle 关系查询构建器。

const res = await db.query.users.findMany({
  extras: {
    fullName: sql<string>`concat(${users.name}, " ", ${users.name})`.as('full_name'),
  },
  with: {
    usersToGroups: {
      with: {
        group: true,
      },
    },
  },
});
// result type
const res: {
  id: number;
  name: string;
  verified: boolean;
  invitedBy: number | null;
  fullName: string;
  usersToGroups: {
      group: {
          id: number;
          name: string;
          description: string | null;
      };
  }[];
}[];

要检索所有帖子及其评论,并添加一个额外的字段来计算帖子内容的大小和每个评论内容的大小:

const res = await db.query.posts.findMany({
  extras: (table, { sql }) => ({
    contentLength: (sql<number>`length(${table.content})`).as('content_length'),
  }),
  with: {
    comments: {
      extras: {
        commentSize: sql<number>`length(${comments.content})`.as('comment_size'),
      },
    },
  },
});
// result type
const res: {
  id: number;
  createdAt: Date;
  content: string;
  authorId: number | null;
  contentLength: number;
  comments: {
      id: number;
      createdAt: Date;
      content: string;
      creator: number | null;
      postId: number | null;
      commentSize: number;
  }[];
};

准备语句

准备语句旨在大大提高查询性能 —— 请看这里。

在本节中,您可以了解如何定义占位符并使用 Drizzle 关系查询构建器执行准备语句。

where 中的占位符
PostgreSQL
MySQL
SQLite
const prepared = db.query.users.findMany({
  where: ((users, { eq }) => eq(users.id, placeholder('id'))),
  with: {
    posts: {
      where: ((users, { eq }) => eq(users.id, 1)),
    },
  },
}).prepare('query_name');

const usersWithPosts = await prepared.execute({ id: 1 });
const prepared = db.query.users.findMany({
  where: ((users, { eq }) => eq(users.id, placeholder('id'))),
  with: {
    posts: {
      where: ((users, { eq }) => eq(users.id, 1)),
    },
  },
}).prepare();

const usersWithPosts = await prepared.execute({ id: 1 });
const prepared = db.query.users.findMany({
  where: ((users, { eq }) => eq(users.id, placeholder('id'))),
  with: {
    posts: {
      where: ((users, { eq }) => eq(users.id, 1)),
    },
  },
}).prepare();

const usersWithPosts = await prepared.execute({ id: 1 });
limit 中的占位符
PostgreSQL
MySQL
SQLite
const prepared = db.query.users.findMany({
  with: {
    posts: {
      limit: placeholder('limit'),
    },
  },
}).prepare('query_name');

const usersWithPosts = await prepared.execute({ limit: 1 });
const prepared = db.query.users.findMany({
  with: {
    posts: {
      limit: placeholder('limit'),
    },
  },
}).prepare();

const usersWithPosts = await prepared.execute({ limit: 1 });
const prepared = db.query.users.findMany({
  with: {
    posts: {
      limit: placeholder('limit'),
    },
  },
}).prepare();

const usersWithPosts = await prepared.execute({ limit: 1 });
offset 中的占位符
PostgreSQL
MySQL
SQLite
const prepared = db.query.users.findMany({
  offset: placeholder('offset'),
  with: {
    posts: true,
  },
}).prepare('query_name');

const usersWithPosts = await prepared.execute({ offset: 1 });
const prepared = db.query.users.findMany({
  offset: placeholder('offset'),
  with: {
    posts: true,
  },
}).prepare();

const usersWithPosts = await prepared.execute({ offset: 1 });
const prepared = db.query.users.findMany({
  offset: placeholder('offset'),
  with: {
    posts: true,
  },
}).prepare();

const usersWithPosts = await prepared.execute({ offset: 1 });
多个占位符
PostgreSQL
MySQL
SQLite
const prepared = db.query.users.findMany({
  limit: placeholder('uLimit'),
  offset: placeholder('uOffset'),
  where: ((users, { eq, or }) => or(eq(users.id, placeholder('id')), eq(users.id, 3))),
  with: {
    posts: {
      where: ((users, { eq }) => eq(users.id, placeholder('pid'))),
      limit: placeholder('pLimit'),
    },
  },
}).prepare('query_name');

const usersWithPosts = await prepared.execute({ pLimit: 1, uLimit: 3, uOffset: 1, id: 2, pid: 6 });
const prepared = db.query.users.findMany({
  limit: placeholder('uLimit'),
  offset: placeholder('uOffset'),
  where: ((users, { eq, or }) => or(eq(users.id, placeholder('id')), eq(users.id, 3))),
  with: {
    posts: {
      where: ((users, { eq }) => eq(users.id, placeholder('pid'))),
      limit: placeholder('pLimit'),
    },
  },
}).prepare();

const usersWithPosts = await prepared.execute({ pLimit: 1, uLimit: 3, uOffset: 1, id: 2, pid: 6 });
const prepared = db.query.users.findMany({
  limit: placeholder('uLimit'),
  offset: placeholder('uOffset'),
  where: ((users, { eq, or }) => or(eq(users.id, placeholder('id')), eq(users.id, 3))),
  with: {
    posts: {
      where: ((users, { eq }) => eq(users.id, placeholder('pid'))),
      limit: placeholder('pLimit'),
    },
  },
}).prepare();

const usersWithPosts = await prepared.execute({ pLimit: 1, uLimit: 3, uOffset: 1, id: 2, pid: 6 });
Become a Gold Sponsor