跳到主要内容

Tabnine

Tabnine 是一个 AI 软件开发平台,以 扩展程序 的形式提供给您的 IDE(例如 VS Code、WebStorm、IntelliJ 等)。

概述

它通过以下方式帮助开发者更快地编写代码:

  • 为编辑器中小的、重复的编码任务提供上下文感知的 代码补全 建议
  • 为更高级别的任务和详细的指令提供集成的 聊天 功能

为什么将 Prisma ORM 与 Tabnine 一起使用?

像 Tabnine 这样的 AI 编辑器是强大的工具,可以极大地提高开发人员的生产力。 它在以下工作流程中尤其有效

  • 数据建模和数据库 schema 设计
  • 构建和优化数据库查询
  • 生成 CRUD 功能和其他样板代码
  • 生成可与 TypedSQL 一起使用的纯 SQL 查询
  • 生成单元测试和集成测试的代码
  • 指导进行重大重构
  • 生成 seeding 脚本

利用 Prisma schema

由于 Prisma 有自己的 schema,Tabnine 可以理解您的数据的基本结构,并帮助您为技术栈的其他部分编写代码。

因此,我们建议您首先定义您的 Prisma schema,然后使用 Tabnine 在其周围构建应用程序层(包括 API 调用、DTO、业务逻辑、第三方集成等)。

数据建模和数据库 schema 设计

Tabnine 如何提供帮助

从头开始设计数据库 schema 涉及大量样板代码,并且可能非常耗时。

Tabnine 可以通过以下方式加速此过程:

  • 为模型、索引、约束和关系生成样板代码。
  • 通过坚持命名和其他约定来保持 schema 的一致性。
  • 根据常见的数据库模式自动完成模型和字段定义。
  • 根据命名约定建议关系和字段类型。

示例:定义 Prisma schema

提示

为一个 SaaS 应用程序定义一个 Prisma schema,其中包含 User、Organization 和 Subscription 模型。 确保正确设置关系。

生成的代码

generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

model User {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
email String @unique
name String
organization Organization @relation(fields: [organizationId], references: [id])
organizationId Int
}

model Organization {
id Int @id @default(autoincrement())
name String
slug String @unique
subscription Subscription?
users User[]
}

model Subscription {
id Int @id @default(autoincrement())
organization Organization @relation(fields: [organizationId], references: [id])
organizationId Int @unique
plan String
status Status
}

enum Status {
Active
Paused
Expired
}

构建和优化数据库查询

Tabnine 如何提供帮助

Prisma ORM 提供了一个方便的高级 API,用于直观地编写数据库查询。 但是,涉及过滤器、分页和高级模式的查询仍然可能变得难以构建。

Tabnine 可以通过以下方式提供帮助:

  • 根据 schema 自动完成 Prisma 查询。
  • 为过滤器建议 where 子句,为分页逻辑建议 skip / take 选项。
  • 帮助提高效率和性能优化。

示例:获取具有关系的数据

提示

生成一个 Prisma 查询,以获取具有有效订阅的组织中的所有活跃用户。 在查询结果中包含有关用户组织的数据。

生成的代码

const activeUsers = await prisma.user.findMany({
where: {
organization: {
subscription: {
status: "ACTIVE"
}
}
},
include: {
organization: true
}
});

生成 CRUD 功能和其他样板代码

Tabnine 如何提供帮助

大多数应用程序都需要基本的 CRUD 操作或其他样板代码,这些代码通常源自数据库 schema 的结构。 例如,API 层可能会公开一组 HTTP 端点,这些端点允许创建、读取、更新或删除特定模型的记录。 同样,前端将具有数据获取和状态管理逻辑,以与这些 API 端点交互并相应地更新 UI。

Tabnine 可以通过以下方式加速此过程,而无需手动编写此代码:

  • 为后端生成 Prisma createreadupdatedelete 操作,为前端生成 UI 组件。
  • 自动完成函数名称和参数类型。
  • 在编写样板代码时,遵循使用 DTO、错误处理、一致的 API 设计等方面的最佳实践。

示例:使用 Next.js 生成 CRUD 功能

提示

基于上面 schema 中的 User 模型,为一个 Next.js 应用程序生成 CRUD 功能。

生成的代码

API 端点
filename=app/api/users/routes.ts
import { NextResponse } from 'next/server';
import prisma from '../../../lib/prisma';

export async function GET() {
const users = await prisma.user.findMany({
include: { organization: true },
});
return NextResponse.json(users);
}

export async function POST(request: Request) {
const body = await request.json();
const user = await prisma.user.create({
data: {
email: body.email,
name: body.name,
organization: {
connect: { id: body.organizationId },
},
},
include: { organization: true },
});
return NextResponse.json(user);
}

export async function PUT(request: Request) {
const body = await request.json();
const user = await prisma.user.update({
where: { id: body.id },
data: {
email: body.email,
name: body.name,
organizationId: body.organizationId,
},
include: { organization: true },
});
return NextResponse.json(user);
}

export async function DELETE(request: Request) {
const { searchParams } = new URL(request.url);
const id = searchParams.get('id');
const user = await prisma.user.delete({
where: { id: Number(id) },
});
return NextResponse.json(user);
}
React 组件
filename=app/components/User.tsx
import React, { useState, useEffect } from 'react';

interface User {
id: number;
email: string;
name: string;
organizationId: number;
}

const User: React.FC = () => {
const [users, setUsers] = useState<User[]>([]);
const [newUser, setNewUser] = useState({ email: '', name: '', organizationId: 0 });

useEffect(() => {
fetchUsers();
}, []);

const fetchUsers = async () => {
const response = await fetch('/api/users');
const data = await response.json();
setUsers(data);
};

const createUser = async () => {
await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newUser),
});
fetchUsers();
setNewUser({ email: '', name: '', organizationId: 0 });
};

const deleteUser = async (id: number) => {
await fetch(`/api/users?id=${id}`, { method: 'DELETE' });
fetchUsers();
};

return (
<div>
<h2>Users</h2>
<ul>
{users.map((user) => (
<li key={user.id}>
{user.name} ({user.email}) - Org ID: {user.organizationId}
<button onClick={() => deleteUser(user.id)}>Delete</button>
</li>
))}
</ul>
<h3>Create New User</h3>
<input
type="text"
placeholder="Name"
value={newUser.name}
onChange={(e) => setNewUser({ ...newUser, name: e.target.value })}
/>
<input
type="email"
placeholder="Email"
value={newUser.email}
onChange={(e) => setNewUser({ ...newUser, email: e.target.value })}
/>
<input
type="number"
placeholder="Organization ID"
value={newUser.organizationId}
onChange={(e) => setNewUser({ ...newUser, organizationId: Number(e.target.value) })}
/>
<button onClick={createUser}>Create User</button>
</div>
);
};

export default User;

生成用于 TypedSQL 的纯 SQL 查询

Tabnine 如何提供帮助

虽然 Prisma 提供了用于查询的高级 API,但有时开发人员可能需要使用原始 SQL 来更低级别地控制查询。 在这些情况下,他们可以使用 TypedSQL,它为 Prisma ORM 中的原始 SQL 查询提供完整的类型安全。

一个常见的用例是聚合查询,例如计算上面 schema 示例中不同订阅状态的百分比。

Tabnine 可以通过以下方式提供帮助:

  • 根据您的 Prisma schema 生成 SQL 查询。
  • 无需手动试错即可构建复杂的聚合。
  • 将查询集成到您的应用程序代码中。

示例:计算活跃、过期和暂停订阅的百分比

提示

生成一个 SQL 查询,该查询返回 Active、Paused 和 Expired 订阅的百分比。

生成的 SQL 查询

prisma/sql/subscriptionsReport.sql
SELECT 
status,
COUNT(*) * 100.0 / (SELECT COUNT(*) FROM "Subscription") AS percentage
FROM "Subscription"
GROUP BY status;

应用程序代码

import { PrismaClient } from '@prisma/client'
import { subscriptionsReport } from '@prisma/client/sql'

const prisma = new PrismaClient();

const usersWithPostCounts = await prisma.$queryRawTyped(subscriptionsReport())
console.log(usersWithPostCounts)

生成单元测试和集成测试的代码

Tabnine 如何提供帮助

编写测试可确保基于 Prisma 的应用程序正常运行并按照要求和期望运行。 但是,编写测试是一项耗时的活动,通常遵循可预测和重复的模式。

Tabnine 可以通过以下方式极大地加速编写测试:

  • 为单元测试和集成测试生成测试样板代码。
  • 为 Prisma 数据库交互建议 mocks 和 fixtures。
  • 帮助构建测试用例以遵循最佳实践。
  • 为使用真实数据库或内存数据库测试 Prisma 提供集成测试脚手架。

示例:为 Prisma 服务编写单元测试

提示

为一个 Prisma 服务函数生成一个 Jest 单元测试,该函数获取所有活跃用户。

生成的代码

filename=__tests__/userService.test.ts
import { prismaMock } from '../prisma/singleton';
import { getActiveUsers } from '../services/userService';

test('should return only active users', async () => {
prismaMock.user.findMany.mockResolvedValue([
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' }
]);

const users = await getActiveUsers();
expect(users).toHaveLength(2);
expect(users[0].email).toBe('alice@example.com');
});

指导进行重大重构

Tabnine 如何提供帮助

由于 Prisma ORM 的类型安全查询,重构比其他 ORM 更安全和可预测:在进行 schema 更改后,生成的 Prisma Client 代码将更新,并且 TypeScript 编译器将突出显示所有需要更改的地方。

但是,在重构期间可能仍然存在更困难的情况,例如,当需要调整业务逻辑或复杂查询时。

Tabnine 可以在重构期间通过以下方式提供帮助:

  • 在保持一致性的同时,识别代码中的模式并建议重构。
  • 帮助在 schema 更改后更新数据库查询,并减少手动工作量。
  • 提供函数重写以简化和优化逻辑。
  • 建议需要在整个代码库中处理的破坏性更改。

示例:在 schema 更改后重构 Prisma 查询

提示

重构此 Prisma 查询,以支持在 User 模型中使用 deletedAt 时间戳字段进行软删除。

初始代码

const users = await prisma.user.findMany();

重构后的代码

const users = await prisma.user.findMany({
where: { deletedAt: null }
});

生成 seeding 脚本

Tabnine 如何提供帮助

使用真实的测试数据 seeding 数据库可能很麻烦。 真实的 seeding 数据在开发期间很有帮助,因为它使开发人员对应用程序在实际使用时的印象更好。 Tabnine 可以通过以下方式帮助进行数据库 seeding:

  • 根据 schema 和特定要求生成具有结构化 seeding 数据的脚本。
  • 创建看起来真实的占位符数据,可用于测试应用程序。
  • 生成特定数据以覆盖边缘情况。

示例:创建 seeding 脚本

提示

生成一个 Prisma seeding 脚本,用于填充 User、Organization 和 Subscription 模型。

生成的代码

import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

async function main() {
await prisma.organization.create({
data: {
name: "Prisma Corp",
slug: "prisma-corp",
subscription: {
create: {
plan: "PRO",
status: "ACTIVE"
}
},
users: {
create: [
{ name: "Alice Doe", email: "alice@prisma.io" },
{ name: "Bob Smith", email: "bob@prisma.io" }
]
}
}
});

console.log("Seed data created successfully");
}

main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});

与 Prisma 保持联系

通过与以下平台联系,继续您的 Prisma 之旅 我们活跃的社区。 随时了解最新信息,参与其中,并与其他开发人员协作

我们真诚地重视您的参与,并期待您成为我们社区的一份子!