Chapter 08

高级特性

用 Client Extensions 扩展查询与结果,实现软删除、计算字段;掌握 JSON 字段查询、全文搜索与多 schema 组织。

8.1 核心概念

Client Extensions($extends)
新一代扩展机制,取代旧的 $use 中间件。可扩展四类组件,返回一个新的扩展后 Client(原 Client 不变,类型自动增强)。
result 组件
给查询结果加计算字段:声明依赖的真实字段,用 compute 派生出虚拟字段(如 fullName),查询时按需计算。
model 组件
给某个 model 加自定义方法,如 prisma.user.signup(...),把领域逻辑挂到模型上。
query 组件
拦截并改写查询:在操作执行前后插入逻辑(如自动加过滤条件、审计日志),实现软删除的关键。
软删除(soft delete)
不物理删除行,而是打 deletedAt 标记;查询默认过滤掉已删记录。可用 query 扩展统一实现。
JSON 字段查询
Json(Postgres jsonb)字段做路径过滤:path+equals/string_contains/array_contains 等。
全文搜索(full-text search)
PostgreSQL/MySQL 上的 search 过滤器,基于数据库原生全文索引做关键词检索(需开启 preview 或对应支持)。

8.2 计算字段:result 扩展

const xprisma = prisma.$extends({
  result: {
    user: {
      fullName: {
        needs: { firstName: true, lastName: true },
        compute(u) {
          return `${u.firstName} ${u.lastName}`;
        },
      },
    },
  },
});

const u = await xprisma.user.findFirst();
console.log(u?.fullName);   // 类型安全的虚拟字段

8.3 模型方法:model 扩展

const xprisma = prisma.$extends({
  model: {
    user: {
      async signup(email: string) {
        return prisma.user.create({ data: { email } });
      },
    },
  },
});

await xprisma.user.signup("new@x.com");

8.4 软删除:query 扩展

const xprisma = prisma.$extends({
  query: {
    user: {
      // 把 delete 改写为 update deletedAt
      async delete({ args, query }) {
        return prisma.user.update({ ...args, data: { deletedAt: new Date() } });
      },
      // 查询自动过滤已删
      async findMany({ args, query }) {
        args.where = { ...args.where, deletedAt: null };
        return query(args);
      },
    },
  },
});
$extends 不变异原 Client

$extends 返回 Client,类型自动带上扩展。可链式叠加多个扩展,也可抽成可复用的 Prisma.defineExtension(...) 包。

8.5 JSON 字段查询

// metadata Json? 字段
await prisma.product.findMany({
  where: {
    metadata: {
      path: ["specs", "color"],
      equals: "red",
    },
  },
});

// 数组包含
await prisma.product.findMany({
  where: { metadata: { path: ["tags"], array_contains: ["sale"] } },
});

8.6 全文搜索

// schema: previewFeatures = ["fullTextSearchPostgres"](视版本)
await prisma.post.findMany({
  where: { title: { search: "prisma & orm" } },
  orderBy: { _relevance: { fields: ["title"], search: "prisma", sort: "desc" } },
});
依数据库而异

全文搜索能力与语法随 provider 和 Prisma 版本变化,可能需在 generator 里开 previewFeatures,并在库中建对应全文索引。生产前请核对当前版本文档。

8.7 多 schema 组织

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
  schemas  = ["auth", "blog"]        // 多个 PG schema
}

model User {
  id Int @id @default(autoincrement())
  @@schema("auth")
}

model Post {
  id Int @id @default(autoincrement())
  @@schema("blog")
}

此外 schema.prisma 支持拆分为多文件(prisma/schema/*.prisma),便于大项目按领域组织模型。

8.8 小结与下一步