Client API
Query and mutate data with full type safety — all operations inferred from your schema, no code generation required
Creating a Client
import { createClient } from "viborm/pg";
import { user, post } from "./schema";
const client = createClient({
schema: { user, post },
databaseUrl: process.env.DATABASE_URL,
});
Operations
Every operation works identically on every database. Prisma-inspired, not a drop-in replacement — see Compatibility for the differences.
Queries
| Operation | Description | Returns |
|---|---|---|
findMany |
Find multiple records | T[] |
findFirst |
Find first matching record | T | null |
findUnique |
Find by unique identifier | T | null |
exist |
Check if any record matches | boolean |
count |
Count records | number |
aggregate |
Compute min/max/sum/avg/count | { _count, _avg, ... } |
groupBy |
Group records and aggregate per group | grouped rows |
findFirstOrThrow and findUniqueOrThrow throw NotFoundError instead of returning null — documented on their base operation’s page.
Mutations
| Operation | Description | Returns |
|---|---|---|
create |
Create a record, with relations | T |
createMany |
Create multiple records | { count }, or T[] with select |
update |
Update a record | T |
updateMany |
Update every match | { count }, or T[] with select |
upsert |
Create or update | T |
delete |
Delete a record | T |
deleteMany |
Delete every match | { count }, or T[] with select |
| Nested writes | Write related records in one call | — |
createMany, updateMany, and deleteMany return the affected rows instead of a count when the call carries a select — there are no separate createManyAndReturn / updateManyAndReturn methods, and deleteMany gains a returning form Prisma does not have. See each operation’s page.
Quick Examples
// Find many with filters
const users = await client.user.findMany({
where: { role: "ADMIN" },
orderBy: { createdAt: "desc" },
take: 10,
});
// Find unique by ID
const user = await client.user.findUnique({
where: { id: "user_123" },
});
// Create a record
const newUser = await client.user.create({
data: {
email: "alice@example.com",
name: "Alice",
},
});
// Update with relations
const updated = await client.user.update({
where: { id: "user_123" },
data: {
name: "Alice Smith",
posts: {
create: { title: "New Post" },
},
},
include: { posts: true },
});
// Count with filters
const count = await client.user.count({
where: { role: "ADMIN" },
});
Type Safety
Every operation is fully typed:
// ✅ TypeScript knows the exact return type
const user = await client.user.findUnique({
where: { id: "user_123" },
select: { id: true, email: true },
});
// Type: { id: string; email: string } | null
// ❌ TypeScript catches invalid fields
await client.user.create({
data: {
email: "bob@example.com",
invalidField: "value", // Error!
},
});
// ❌ TypeScript catches missing required fields
await client.user.create({
data: {
name: "Bob",
// Error: 'email' is required
},
});