TypeORM已过时?Drizzle ORM + Nest.js:下一代ORM的入门指南

2,448 阅读14分钟

为啥使用 Drizzle Orm 而不是 TypeOrm

  1. 类型安全性更强
    • Drizzle ORM 提供了完全类型安全的查询构建器
    • 所有的查询都在编译时进行类型检查,减少运行时错误
  2. 性能更优
    • Drizzle ORM 是一个轻量级的 ORM,没有太多额外的抽象层
    • 查询性能比 TypeORM 更好,因为它更接近原生 SQL
    • 内存占用更小,启动时间更快
  3. 更好的开发体验
    • 不需要装饰器,减少了代码的复杂性
    • 更好的 IDE 支持和自动补全
    • 迁移工具更简单易用
  4. 同时支持类似 SQL 和关系型的查询语法。

npm 下载量对比,可以看出来 drizzle-orm 相对较新,而且包体积差不多是 TypeOrm 的 1/3。

image.png

最戳我的是它的学习曲线较低,因为支持类似SQL的语法。

image.png

而且它的官网首页 [Developers love Drizzle ORM] 部分特别幽默,恨也是一种爱是吧。

image.png

ok,开始搭配 nest.js 学习 drizzle-orm。为了简便起见,使用 postgres,因为太多公司提供 postgres free tier,直接远程连接就不用本地运行数据库服务了。

接下来会创建一个类似博客的数据库项目,有用户表 (users),用户个人主页表 (profileInfo),博客表 (posts),评论表 (comments),用户分组表 (groups),用户和用户分组关联表 (usersToGroups)。

学习表与表之间的关联关系,如何造模拟数据,最后使用 nest.js 进行 crud。

初始化

初始化 nestjs 项目:

nest new learn-drizzle

安装依赖:

npm i drizzle-orm pg
npm i -D drizzle-kit @types/pg # 迁移的时候要使用 drizzle-kit

为drizzle orm新增一个module,用于配置数据库的连接。

nest g module /database/drizzle

image.png

使用 Neon 的免费 postgres 数据库。

将neon的连接串存放在 .env 文件中:

# 连接串示例
POSTGRES_URL = 'postgresql://neondb_owner:npg_O5N@ep-silent-hazer.ap-southeast-1.aws.neon.tech/neondb?sslmode=require'

安装 npm i @nestjs/config 读取 .env 文件,然后在 app.module.ts 中引入 ConfigModule

// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [ConfigModule.forRoot({ isGlobal: true })],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

drizzle.module.ts文件中配置和初始化Drizzle ORM的数据库连接:

import { Module } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { drizzle, NodePgDatabase } from 'drizzle-orm/node-postgres';
import { Pool } from 'pg';

export const Drizzle = Symbol('drizzle-connection');

@Module({
  providers: [
    {
      provide: Drizzle,
      inject: [ConfigService],
      useFactory: async (configService: ConfigService) => {
        const databaseUrl = configService.get<string>('POSTGRES_URL');
        const pool = new Pool({
          connectionString: databaseUrl,
        });
        return drizzle(pool);
      },
    },
  ],
  exports: [Drizzle],
})
export class DrizzleModule {}


注意这里的 drizzle 函数来自 drizzle-orm/node-postgres

创建表

新建 database/drizzle/schema/users.schema.ts 文件,里面新增一个 users 表:

image.png

// schema/user.schema.ts
import { pgTable, serial, text } from "drizzle-orm/pg-core";

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

schema 文件夹中新建 index.ts 文件,用于导出全部的 xxx.schema.ts 文件:

// schema/index.ts
export * from './users.schema'

// ... 后续添加的schema文件通过这里统一导出

然后在 drizzle.module.ts 中引入:

image.png

import { Module } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { drizzle, NodePgDatabase } from 'drizzle-orm/node-postgres';
import { Pool } from 'pg';
import * as schema from './schemas';

export const Drizzle = Symbol('drizzle-connection');
export type DrizzleDB = NodePgDatabase<typeof schema>;

@Module({
  providers: [
    {
      provide: Drizzle,
      inject: [ConfigService],
      useFactory: async (configService: ConfigService) => {
        const databaseUrl = configService.get<string>('POSTGRES_URL');
        const pool = new Pool({
          connectionString: databaseUrl,
        });
        return drizzle(pool, { schema }) as DrizzleDB;
      },
    },
  ],
  exports: [Drizzle],
})
export class DrizzleModule {}

useFactory的最后一行 drizzle(pool, { schema }) as DrizzleDB 将普通的 PostgreSQL 连接池包装成 Drizzle ORM 实例。

迁移

使用 Drizzle ORM 时,修改数据库表结构需要进行迁移操作。

在根目录下创建 drizzle.config.ts 文件,运行 Drizzle 迁移命令等。

  • drizzle-kit generate: 根据 schema 变化生成迁移文件。
  • drizzle-kit migrate: 执行生成的迁移文件,将数据库更新到最新的 schema 状态。

在 drizzle.config.ts 中,不能使用 NestJS 的依赖注入系统,所以需要直接使用 dotenv 包来读取环境变量文件。

import { config } from 'dotenv';
import { defineConfig } from 'drizzle-kit';

// 指定 .env 文件路径
config({ path: './.env' });
export default defineConfig({
  schema: './src/database/drizzle/schema/**.schema.ts', // 指定schema路径
  dialect: 'postgresql',
  dbCredentials: {
    url: process.env.POSTGRES_URL,
  },
});

生成数据库表迁移文件:

npx drizzle-kit generate

image.png

推送到数据库中:

npx drizzle-kit migrate

一对一关系

users 当成主表,再创建 profileInfo 作为从表。 profileInfo 的 userId 是外键,关联到 users 表的 id 字段。

// 新增 schema/profileInfo.schema.ts
import { integer, jsonb, pgTable, serial, text } from 'drizzle-orm/pg-core';
import { users } from './users.schema';


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

// schema/index.ts 导出profileInfo
export * from './users.schema'
export * from './profileInfo.schema'

从 drizzle-orm/pg-core 导入的几个 postgres 类型:

  • integer : 用于定义整数类型的列
  • jsonb : 用于定义 PostgreSQL 的 JSONB 类型列
  • serial : 用于定义自增的序列类型
  • text : 用于定义文本类型的列

默认的外键约束 是 No action。PostgreSQL 提供了以下几种外键约束行为,可以在定义外键时使用 ON DELETEON UPDATE 子句来指定:

  1. NO ACTION: 这是 默认 的外键约束行为。如果父表中被引用的行有任何子表中的行引用它,那么删除或更新父表中的该行将导致错误。事务会被回滚。NO ACTIONRESTRICT 非常相似,主要区别在于 NO ACTION 会在检查约束时才执行检查(如果约束是可延迟的),而 RESTRICT 会立即检查。但在不可延迟的约束下,它们的行为实际上是一样的。
  2. RESTRICT: 与 NO ACTION 类似,如果父表中被引用的行有任何子表中的行引用它,那么删除或更新父表中的该行将导致错误,并且事务会被回滚。RESTRICT 会立即执行检查。
  3. CASCADE: 当父表中被引用的行被删除时,子表中所有引用该行的行也会被自动删除。当父表中被引用的主键或唯一键被更新时,子表中所有引用该键的外键列的值也会自动更新为新的值。
  4. SET NULL: 当父表中被引用的行被删除或更新时,子表中引用该行的外键列的值会被设置为 NULL。前提是外键列允许存储 NULL 值。
  5. SET DEFAULT: 当父表中被引用的行被删除或更新时,子表中引用该行的外键列的值会被设置为该列的默认值。前提是外键列定义了默认值。

在 drizzle 中也可以自定义外键约束行为:

userId: integer('userId').references(() => users.id, { 
  onDelete: 'cascade',  // 当删除用户时级联删除相关的 profileInfo
  onUpdate: 'cascade'   // 当更新用户 id 时级联更新相关的 profileInfo
}),

现在生成数据库表,然后推送到远程服务器:

npx drizzle-kit generate
npx drizzle-kit migrate

多对一/一对多关系

user 可以发布多个 post,一个 user 对于多个 post。

每个 post 可以对应多个评论,但每条评论只能属于属于某一个特定的用户。

新增 posts 表:

// schema/posts.schema.ts
import { integer, pgTable, serial, text } from "drizzle-orm/pg-core";
import { users } from "./users.schema";

export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  title: text('title').notNull(),
  content: text('content').notNull(),
  authorId: integer('authorId').references(()=>users.id) // 外键!
})

新增 comments 表:

// schema/comments.schema.ts
import { integer, pgTable, serial, text } from "drizzle-orm/pg-core";
import { users } from "./users.schema";
import { posts } from "./posts.schema";

export const comments = pgTable('comments', {
  id: serial('id').primaryKey(),
  text: text('title').notNull(),
  authorId: integer('authorId').references(() => users.id), // 外键!
  postId:integer('postId').references(()=> posts.id) // 外键!
})
// schema/index.ts
export * from './users.schema'
export * from './profileInfo.schema'
export * from './posts.schema'
export * from './comments.schema'

然后同样进行生成 sql 代码后进行迁移:

npx drizzle-kit generate
npx drizzle-kit migrate

运行 npx drizzle-kit studio 可启动本地的 drizzle studio 服务器,在 https://local.drizzle.studio 网页会自动请求本地的 drizzle studio 服务器。关于 drizzle studio 的介绍,点击查看

image.png

image.png

多对多关系

每个小组可以包含多个 user,而每个 user 可以加入多个 小组。group 和 user 之间就是多对多关系。在关系型数据库中,可以通过建立第 3 张表来关联 user 和group,实现多对多关系。

新增 groups 表和关联表 usersToGroups

// schema/groups.schema.ts
import { integer, serial, text } from 'drizzle-orm/pg-core';
import { pgTable } from 'drizzle-orm/pg-core';
import { users } from './users.schema';

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

// 关联表
export const usersToGroups = pgTable('usersToGroups', {
  userId: integer('userId').references(() => users.id),
  groupId: integer('groupId').references(() => groups.id),
});

usersToGroups 是一个关联表,用于建立用户和群组之间的多对多关系:

  • usersId : 外键,关联到users表的id
  • groupId : 外键,关联到groups表的id

usersToGroups 表中应该怎样设置主键?常见的作法是设置复合主键(composite primary key),将 usersId 和 groupId 一起作为主键,原因如下:

  • 在多对多关系中,一个用户可以属于多个组,一个组可以包含多个用户,使用复合主键可以确保同一个用户不会重复加入同一个组
  • 复合主键可以自动创建索引,提高查询性能
import { integer, primaryKey, serial, text } from 'drizzle-orm/pg-core';
import { pgTable } from 'drizzle-orm/pg-core';
import { users } from './users.schema';

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

// 关联表
export const usersToGroups = pgTable(
  'usersToGroups',
  {
    userId: integer('userId').references(() => users.id),
    groupId: integer('groupId').references(() => groups.id),
  },
  (table) => [primaryKey({ columns: [table.userId, table.groupId] })],
);

最后在 index.ts 文件中导出:

// schema/index.ts
export * from './users.schema'
export * from './profileInfo.schema'
export * from './posts.schema'
export * from './comments.schema'
export * from  './groups.schema'

image.png

造数据

现在数据库表中没有任何数据,我们可以造一下假数据。

新增 seed.ts 文件,由于这个文件和 nestjs 服务器无关,无法使用 nestjs 中的 drizzle 实例,所以手动创建 drizzleDB 实例:

// drizzle/seed.ts
import { drizzle, NodePgDatabase } from "drizzle-orm/node-postgres";
import { Pool } from "pg";
import { config } from 'dotenv';
import * as schema from './schema';

config({ path: './.env' });

const pool = new Pool({
  connectionString: process.env.POSTGRES_URL,
});
const drizzleDB =  drizzle(pool, { schema }) as NodePgDatabase<typeof schema>;

使用 npm install drizzle-seed 库来造看起来真实的假数据,比如创建 50 个假用户。

import { drizzle, NodePgDatabase } from 'drizzle-orm/node-postgres';
import { Pool } from 'pg';
import { config } from 'dotenv';
import * as schema from './schema';
import { reset, seed } from 'drizzle-seed';

config({ path: './.env.development' });

const pool = new Pool({
  connectionString: process.env.POSTGRES_URL,
});
const drizzleDB = drizzle(pool, { schema }) as NodePgDatabase<typeof schema>;

async function main() {
  await seed(
    drizzleDB,
    { users: schema.users},
    { seed: 12345 },
  ).refine((funcs) => ({
    users: {
      count: 50,
      columns: {
        email: funcs.email(),
        name: funcs.fullName(),
        password: funcs.default({ defaultValue: '' }),
      },
    },
  }));
}

main()
  .then(() => {
    console.log('数据填充完成');
    process.exit(0);
  })
  .catch((e) => {
    console.error('数据填充失败:', e);
    process.exit(1);
  });

然后在 package.json 增加一条运行 seed.ts 的命令。

{
	"scripts":{
		"db:seed": "ts-node ./src/database/drizzle/seed.ts "
	}
}

通过利用伪随机数生成器(pseudorandom number generator , pRNG),可以确保每次生成的数据一致的。这里我传了 {seed: 12345},如果下次也传入12345后生成的用户和本次是一致的。

执行 npm run db:seed,再刷新数据库就能看到已经填充了50条数据。

image.png

接下来创建 50 个用户和 50 个 posts,并且将 post 的外键指向 user。只需要在父表(即 users 表)中使用 with: { posts: 1},代表每生成一条 user 记录也生成一条 post。注意这里不是 with: { posts: 50},如果这样配置将生成 2500 条 posts。

import { reset, seed } from 'drizzle-seed';
async function main() {
  await reset(drizzleDB, schema);
  await seed(
    drizzleDB,
    { users: schema.users, posts: schema.posts },
    { seed: 12345 },
  ).refine((funcs) => ({
    users: {
      count: 50,
      columns: {
        email: funcs.email(),
        name: funcs.fullName(),
        password: funcs.default({ defaultValue: '' }),
      },
      with: {
        posts: 1, // 每生成一条 user 记录也生成一条 post
      },
      posts: {
        columns: {
          title: funcs.loremIpsum({
            sentencesCount: 1,
          }),
          content: funcs.loremIpsum({
            sentencesCount: 10,
          }),
        },
      },

    },
  }));
}

注意 seed 函数的参数:第一个参数是数据库连接对象,第二个参数指参与填充的数据库表。这里 users表和 posts 表都需要参与填充,所以把它们两个都放入第二个参数对象中。

在这里先运行了 reset 函数,因为我前面已经插入了50个假用户,需要先 TRUNCATE 清空。重新运行后,会发现 users 生成的数据和先前一致,而且 posts 表的外键字段指向了 users 表!

image.png

接下来再生成评论,创建小组,生成用户的 profileInfo,以及分配用户加入小组:

import { drizzle, NodePgDatabase } from 'drizzle-orm/node-postgres';
import { Pool } from 'pg';
import { config } from 'dotenv';
import * as schema from './schema';
import { reset, seed } from 'drizzle-seed';

config({ path: './.env.development' });

const pool = new Pool({
  connectionString: process.env.POSTGRES_URL,
});
const drizzleDB = drizzle(pool, { schema }) as NodePgDatabase<typeof schema>;

async function main() {
  await reset(drizzleDB, schema);

  await seed(
    drizzleDB,
    {
      users: schema.users,
      posts: schema.posts,
      profileInfo: schema.profileInfo,
      groups: schema.groups,
      comments: schema.comments,
      usersToGroups: schema.usersToGroups,
    },
    { seed: 12345 },
  ).refine((funcs) => ({
    users: {
      count: 50,
      columns: {
        email: funcs.email(),
        name: funcs.fullName(),
        password: funcs.default({ defaultValue: '' }),
      },
      with: {
        posts: 1,
        profileInfo: 1,
        comments: 1,
        usersToGroups: 1,
      },
    },
    posts: {
      columns: {
        title: funcs.loremIpsum({
          sentencesCount: 1,
        }),
        content: funcs.loremIpsum({
          sentencesCount: 10,
        }),
      },
      with: {
        comments: 1,
      },
    },
    groups: {
      count: 2,
      columns: {
        name: funcs.valuesFromArray({
          values: ['前端', '后端'],
        }),
      },
      usersToGroups: 1,
    },
    comments: {
      count: 1,
      columns: {
        text: funcs.loremIpsum({
          sentencesCount: 10,
        }),
      },
    },
  }));
}

main()
  .then(() => {
    console.log('数据填充完成');
    process.exit(0);
  })
  .catch((e) => {
    console.error('数据填充失败:', e);
    process.exit(1);
  });

此时,可以把 seed 的第二个参数用 schema 直接代替,因为现在已经将所有表的填充都配置好了。

最后的生成结果:

image.png

image.png

image.png

image.png

image.png

image.png

CRUD

现在终于有数据了,可以开始进行增删改查了。

新建一个 crud 模块 nest g res modules/post

注入DrizzleDB

如何注入 DrizzleDB 呢? 通过 @Inject(Drizzle) 来注入数据库连接。

image.png

// post.service.ts
import { Inject, Injectable } from '@nestjs/common';
import { CreatePostDto } from './dto/create-post.dto';
import { UpdatePostDto } from './dto/update-post.dto';
import { Drizzle, type DrizzleDB } from 'src/database/drizzle/drizzle.module';

@Injectable()
export class PostService {
  constructor(@Inject(Drizzle) private readonly db: DrizzleDB) {}
}    

如果没有把 DrizzleModule 设置为全局模块,则还需要在 post.module.ts 导入它:

image.png

对于数据库服务一般需要在多个模块中都需要使用,建议使用全局模块方式。

查询

现在给 get 请求返回数据:

// post.service.ts
import { posts } from './../../database/drizzle/schema/posts.schema';
import { Inject, Injectable } from '@nestjs/common';
import { CreatePostDto } from './dto/create-post.dto';
import { UpdatePostDto } from './dto/update-post.dto';
import { Drizzle, type DrizzleDB } from 'src/database/drizzle/drizzle.module';

@Injectable()
export class PostService {

  constructor(@Inject(Drizzle) private readonly db: DrizzleDB) {}
  
  findAll() {
    return this.db.select().from(posts);
  }
}

image.png

除了 select api 还可以使用 query api 查询数据,这种方法更加类似于 ORM(Object-Relational Mapping) 的方法。ORM(对象关系映射)让你可以使用面向对象的方式来操作数据库,而不是直接写 SQL 查询语句。

findAll() {
    return this.db.query.posts.findMany();
}

联表查询

如果想要查询 post 的时候,同时能够返回发布 post 的 user 信息呢?

首先,用 select 语法:

findAll() {
  return this.db
    .select({
      id: posts.id,
      title: posts.title,
      content: posts.content,
      author: {
        id: users.id,
        name: users.name,
        email: users.email,
      },
    })
    .from(posts)
    .leftJoin(users, eq(posts.authorId,users.id));
}

非常类似于 sql 查询的语法!

也可以使用 query 的语法:

findAll() {
  return this.db.query.posts.findMany({
    with: {
      author: {
        columns: {
          id: true,
          name: true,
          email: true,
        },
      },
    },
  });
}

不过直接这样使用会报错 TypeError: Cannot read properties of undefined (reading 'referencedTable')

我们需要在 schema 中定义关联关系,使用 one 关系(因为一个帖子只能有一个作者),在关系定义中,通过 fields 字段指定 posts 表中的外键字段 (authorId),通过 references 字段指定 users 表中被引用的字段 (id)

// posts.schema.ts
import { integer, pgTable, serial, text } from 'drizzle-orm/pg-core';
import { users } from './users.schema';
import { relations } from 'drizzle-orm';

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


export const postsRelations = relations(posts, ({ one,many }) => ({
   // 定义与 users 表的关联关系
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
  }),
  // 与comments表的关联关系。
  // 外键在comments那里,所以这里不用使用fields和references指出关联关系
  comments: many(comments) 
  
}));

不管哪种方法,最终返回的结果都是一样的:

image.png

对于这种简单的查询,我觉得最好还是使用 query 的语法,因为需要明确用定义关系类型,IDE 能够保证类型安全。

再以 users 表为例,写出它和其它表的关系:

import { relations } from 'drizzle-orm';
import { pgTable, serial, text } from 'drizzle-orm/pg-core';
import { comments } from './comments.schema';
import { posts } from './posts.schema';
import { profileInfo } from './profileInfo.schema';
import { usersToGroups } from './groups.schema';

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

// 写出全部与 users 表的关联关系
export const usersRelations = relations(users, ({ one, many }) => ({
  comments: many(comments), 
  posts: many(posts),
  profile: one(profileInfo), // 一对一关联 但不需要指定关联字段,因为外键在 profileInfo 表中
  usersToGroups: many(usersToGroups),
}));

再写出 usersToGroups 与其它表的关系:

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

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

// 关联表
export const usersToGroups = pgTable(
  'usersToGroups',
  {
    userId: integer('userId').references(() => users.id),
    groupId: integer('groupId').references(() => groups.id),
  },
  (table) => [primaryKey({ columns: [table.userId, table.groupId] })],
);


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

现在就可以用 query 语法查询某个 post 对应的作者属于哪个 group:

findAll() {
  return this.db.query.posts.findMany({
    with: {
      author: {
        with: {
          usersToGroups: {
            with: {
              group: {
                columns: {
                  name: true,
                },
              },
            },
          },
        },
      },
    },
  });
}

image.png

最后,把剩下的几个表补齐关系配置:

// comments 表
export const comments = pgTable('comments', {
  id: serial('id').primaryKey(),
  text: text('title').notNull(),
  authorId: integer('authorId').references(() => users.id),
  postId: integer('postId').references(() => posts.id),
});

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

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


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

// 

条件查询

比如查询 id 为 1的用户发布的 post:

import { eq } from 'drizzle-orm';
findAll() {
  return this.db.query.posts.findMany({
    where: eq(posts.authorId, 1),
    with: {
      author: {},
    },
  });
}

改删

用 nestjs-cli 自动给 post.service.ts 生成的 update 方法来修改一下 post

image.png

update(id: number) {
  return this.db
    .update(posts)
    .set({
      title: 'hello',
      content: 'hi',
    })
    .where(eq(posts.id, id))
    .returning();
}

调用 update 的 controller 方法是一个 patch请求。

image.png

现在来调用试试,可以看到成功返回了修改后的结果

image.png

同样,也可以实现删除:

remove(id: number) {
  return this.db.delete(posts).where(eq(posts.id, id));
}

总结

简要介绍了如何在 nest.js 中使用 drizzle-orm,包括创建表,迁移,造数据和简单的 crud。