ShipNowKit uses Prisma Client as the database client, providing type-safe database operation interfaces.
Import Database Client
The database client is exported from db/client.ts, and you can import it directly in server-side code:
import { prisma } from "@/db/client";Server-Side Usage: Prisma Client can only be used in server-side code (Server Components, Server Actions, API Routes). If you need to use the database in client components, you should access it through API Routes or Server Actions.
Recommended Organization
Although you can use the database client directly in any server-side part of your application, we strongly recommend encapsulating all database operations in service files under the db/services/ directory, then exporting specific query/mutation functions.
Advantages of this approach:
- Code Reusability: Avoid duplicate query logic
- Easy Maintenance: Centralized database operation management, easy to modify and optimize
- Type Safety: Unified type definitions and error handling
- Test-Friendly: Database operation logic can be tested independently
Basic Operations
Query Records
Use the findMany method to query multiple records:
import { prisma } from "@/db/client";
// Query all users, ordered by creation time descending
const users = await prisma.user.findMany({
orderBy: { createdAt: "desc" },
});Use the findUnique method to query a single record (based on unique fields):
// Query user by email
const user = await prisma.user.findUnique({
where: { email: "user@example.com" }
});Use the findFirst method to query the first matching record:
// Query first active subscription
const subscription = await prisma.subscription.findFirst({
where: {
userId: "user-id",
status: "active"
}
});Create Records
Use the create method to create new records:
import { prisma } from "@/db/client";
// Create new user
const user = await prisma.user.create({
data: {
email: "test@example.com",
name: "Test User",
emailVerified: false,
},
});Update Records
Use the update method to update existing records:
import { prisma } from "@/db/client";
// Update user information
const updatedUser = await prisma.user.update({
where: { id: "user-id" },
data: {
name: "Updated User Name",
emailVerified: true,
},
});Use the updateMany method to batch update records:
// Batch update subscription status
await prisma.subscription.updateMany({
where: {
status: "trialing",
trialEnd: { lt: new Date() }
},
data: {
status: "active"
}
});Delete Records
Use the delete method to delete a single record:
import { prisma } from "@/db/client";
// Delete user
const deletedUser = await prisma.user.delete({
where: { id: "user-id" }
});Use the deleteMany method to batch delete records:
// Delete all expired verification records
await prisma.verification.deleteMany({
where: {
expiresAt: { lt: new Date() }
}
});Advanced Queries
Relational Queries
Use include or select to include related data:
// Query user with subscription information
const userWithSubscriptions = await prisma.user.findUnique({
where: { id: "user-id" },
include: {
subscriptions: {
where: { status: "active" }
},
oneTimePayments: true
}
});Pagination
Combine skip and take to implement pagination:
const page = 1;
const limit = 10;
const skip = (page - 1) * limit;
const users = await prisma.user.findMany({
skip,
take: limit,
orderBy: { createdAt: "desc" }
});
// Get total count
const total = await prisma.user.count();Conditional Queries
Use where clause for conditional filtering:
// Query active subscriptions
const activeSubscriptions = await prisma.subscription.findMany({
where: {
status: {
in: ["active", "trialing"]
},
currentPeriodEnd: {
gte: new Date()
}
}
});Aggregate Queries
Use aggregate functions like count, sum, avg:
// Count total users
const userCount = await prisma.user.count();
// Count active subscriptions
const activeSubscriptionCount = await prisma.subscription.count({
where: { status: "active" }
});Practical Example
The following is a complete service file example (refer to db/services/user.ts), demonstrating how to encapsulate database operations:
"use server"
import { prisma } from "../client";
import { handleDatabaseError } from "../utils";
/**
* Find user by email
*/
export async function findUserByEmail(email: string) {
try {
return await prisma.user.findUnique({
where: { email }
});
} catch (error) {
throw handleDatabaseError(error);
}
}
/**
* Get user list (with pagination and search)
*/
export async function getUsersList(
page: number = 1,
limit: number = 10,
search?: string
) {
try {
const skip = (page - 1) * limit;
const searchConditions = search ? {
OR: [
{ email: { contains: search } },
{ name: { contains: search } }
]
} : {};
const users = await prisma.user.findMany({
where: searchConditions,
skip,
take: limit,
orderBy: { createdAt: 'desc' },
include: {
subscriptions: true,
oneTimePayments: true
}
});
const total = await prisma.user.count({
where: searchConditions
});
return {
users,
total,
page,
limit,
totalPages: Math.ceil(total / limit)
};
} catch (error) {
throw handleDatabaseError(error);
}
}Error Handling
ShipNowKit provides a unified error handling utility handleDatabaseError, recommended for use in all database operations:
import { handleDatabaseError } from "@/db/utils";
try {
const user = await prisma.user.findUnique({
where: { email }
});
} catch (error) {
throw handleDatabaseError(error);
}Database Overview
Learn how to use databases in ShipNowKit. ShipNowKit uses Prisma ORM to manage database models, supporting SQLite, PostgreSQL, MySQL, and MongoDB.
Using Database Studio
Learn how to use Prisma Studio to visually view and edit data in your database. Prisma Studio provides a graphical interface for browsing and managing database records.