apps/docs/content/docs.v6/orm/more/ai-tools/tabnine.mdx
Tabnine is a an AI software development platform that comes as an extension for your IDE (e.g. VS Code, WebStorm, IntelliJ, ...).
It helps developers write code faster by:
AI editors like Tabnine are powerful tools that can drastically improve developer productivity. It works especially well with the following workflows:
Because Prisma has its own schema, Tabnine can understand the basic shape of your data and help you write code for the other parts of your stack.
We therefore recommend that you start out by defining your Prisma schema and then use Tabnine to build the application layer around it (inluding API calls, DTOs, business logic, 3rd party integrations, ...).
Designing a database schema from scratch involves a lot of boilerplate and can be time-consuming.
Tabnine can accelerate this process by:
Define a Prisma schema for a SaaS application with User, Organization, and Subscription models. Ensure relationships are properly set up.
generator client {
provider = "prisma-client"
output = "./generated"
}
datasource db {
provider = "postgresql"
}
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
}
Prisma ORM provides a convenient high-level API for writing database queries intuitively. However, queries involving filters, pagination and advanced patterns can still become complex to construct.
Tabnine can help by:
where clauses for filters and skip / take options for pagination logic.Generate a Prisma query to fetch all active users from an organization with an active subscription. Include data about the users' organizations in the query result.
const activeUsers = await prisma.user.findMany({
where: {
organization: {
subscription: {
status: "ACTIVE",
},
},
},
include: {
organization: true,
},
});
Most applications require basic CRUD operations or other boilerplate code that's usually derived from the structure of the database schema. For example, an API layer may expose a set of HTTP endpoints that allow to create, read, update or delete records of a certain model. Similarly, a frontend will data fetching and state management logic to interact with these API endpoints and update the UI accordingly.
Instead of writing this code manually, Tabnine can speed up this process by:
create, read, update, and delete operations for the backend and UI components for the frontend.Generate CRUD functionality for a Next.js app based on the User model from the schema above.
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);
}
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;
While Prisma provides a high-level API for querying, sometimes a developer may need to drop down to raw SQL for more low-level control of a query. In these cases, they can use TypedSQL which provides full type safety for raq SQL queries in Prisma ORM.
One common use case are aggregation queries, such as calculating percentages of different subscription statuses in the schema example above.
Tabnine can assist by:
Generate a SQL query that returns the percentage of subscriptions that are Active, Paused, and Expired.
SELECT
status,
COUNT(*) * 100.0 / (SELECT COUNT(*) FROM "Subscription") AS percentage
FROM "Subscription"
GROUP BY status;
import { PrismaClient } from "../prisma/generated/client";
import { subscriptionsReport } from "../prisma/generated/client/sql";
const prisma = new PrismaClient();
const usersWithPostCounts = await prisma.$queryRawTyped(subscriptionsReport());
console.log(usersWithPostCounts);
Writing tests ensures that Prisma-based applications function correctly and behave according to requirements and expectations. However, writing tests is a time-consuming activity that often follows predictable and repetitive patterns.
Tabnine can drastically speed up writing tests by:
Generate a Jest unit test for a Prisma service function that fetches all active users.
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: "[email protected]" },
{ id: 2, name: "Bob", email: "[email protected]" },
]);
const users = await getActiveUsers();
expect(users).toHaveLength(2);
expect(users[0].email).toBe("[email protected]");
});
Thanks to Prisma ORM's type safe queries, refactoring are more safe and predictable than with other ORMs: After making schema changes, the generated Prisma Client code will be updated and the TypeScript compiler will highlight all places that need a change.
However, there may still be more difficult situations during a refactoring, e.g. when business logic or complex queries need to be adjusted.
Tabnine can assist during refactorings by:
Refactor this Prisma query to support soft deletion using a deletedAt timestamp field in the User model.
const users = await prisma.user.findMany();
const users = await prisma.user.findMany({
where: { deletedAt: null },
});
Seeding a database with realistic test data can be cumbersome. Realistic seed data is helpful during development because it gives the developer a better impression of the application when it's used in the real-world. Tabnine can help with database seeding by:
Generate a Prisma seed script for populating User, Organization, and Subscription models.
import { PrismaClient } from "../prisma/generated/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: "[email protected]" },
{ name: "Bob Smith", email: "[email protected]" },
],
},
},
});
console.log("Seed data created successfully");
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});
The Prisma VS Code extension is a powerful tool for building applications with Prisma Postgres. If you are using Tabnine in an editor that allows you to install the Prisma VS Code extension and you are using Prisma Postgres, you should use it. The extension provides a dedicated UI for managing Prisma Postgres instances, both local and remote, making it easy to view, create, and delete instances, push local databases to the cloud, and visualize your schema.
With its built-in database management interface, the Prisma VS Code extension lets you easily work with local and remote Prisma Postgres instances from inside your editor.
The UI enables the following workflows:
To manage Prisma Postgres instances via the UI in the Prisma VS Code extension:
Beyond managing your database instances, the Prisma VS Code extension embeds Prisma Studio directly in your editor, making it easy to perform create, update, and delete operations on your database right inside Windsurf. Follow these easy steps to get started.