Skip to main content

Overview

Refinement methods control how query results are shaped and formatted. Some operate at the SQL level (.select(), .exclude(), .with()), while others transform results programmatically (.omit(), .raw(), .safe()).

SQL-Level Refinement

select

Specify which columns to include in the SQL SELECT clause (whitelist).

Syntax

query.select(fields) => ModelQueryResult

Parameters

fields
Record<string, boolean | SelectObject>
required
Object mapping field names to true (include) or nested select objects for relations.

Examples

const users = await userModel
  .findMany()
  .select({ id: true, name: true });
// SELECT id, name FROM user
// Type: { id: number, name: string }[]

exclude

Specify which columns to exclude from the SQL SELECT clause (blacklist).

Syntax

query.exclude(fields) => ModelQueryResult

Parameters

fields
Record<string, boolean | ExcludeObject>
required
Object mapping field names to true (exclude) or nested exclude objects for relations.

Examples

const users = await userModel
  .findMany()
  .exclude({ password: true, secretField: true });
// SELECT * EXCEPT password, secretField FROM user

with

Load related entities via JOINs (eager loading).

Syntax

query.with(relations) => ModelQueryResult

Parameters

relations
Record<string, boolean | Model | WithObject>
required
Object mapping relation names to:
  • true - Load all fields from the relation
  • Model instance - Load with filters via .where()
  • Nested object - Load nested relations

Examples

const users = await userModel
  .findMany()
  .with({ posts: true });
// Each user includes posts array

include

Specify nested relations when using a model instance in .with().

Syntax

model.include(relations) => Model

Parameters

relations
Record<string, boolean | Model | WithObject>
required
Same format as .with() - specifies which nested relations to load.

Why It Exists

When you use .where() on a model and pass it to .with(), you need a way to also load nested relations. .include() enables this:
// ❌ Without .include() - can only filter, not load nested relations
const users = await userModel.findMany().with({
  posts: postModel.where({ published: esc(true) })
  // Can't specify comments here
});

// ✅ With .include() - filter AND load nested relations
const users = await userModel.findMany().with({
  posts: postModel
    .where({ published: esc(true) })
    .include({ comments: true })
});

Examples

const users = await userModel.findMany().with({
  posts: postModel
    .where({ published: esc(true) })
    .include({ comments: true })
});

Programmatic Refinement

These methods transform results AFTER the query executes (not in SQL).

omit

Remove fields from the result object programmatically.

Syntax

result.omit(fields) => ModelMutateResult

Parameters

fields
Record<string, boolean>
required
Object mapping field names to true (remove).

When to Use

  • .exclude() - SQL-level (doesn’t fetch the data)
  • .omit() - Programmatic (fetches data, then removes it)
Use .omit() when:
  • You need the data for processing but want to hide it from the final result
  • Working with mutations (.returnFirst().omit(...))

Examples

const user = await userModel
  .where({ id: esc(1) })
  .update({ secretField: "new-value" })
  .returnFirst()
  .omit({ secretField: true, password: true });
// secretField and password are excluded from result

raw

Skip the model’s format function and return raw database results.

Syntax

query.raw() => ModelQueryResult

When to Use

  • Performance-critical paths where formatting overhead matters
  • When you need original database types (e.g., before date parsing)
  • Debugging to see raw database output

Examples

const postModel = model("post", {
  format(row) {
    return {
      ...row,
      createdAt: new Date(row.createdAt), // Parse dates
    };
  },
});

const post = await postModel.findFirst().raw();
// post.createdAt is string (raw DB value), not Date

safe

Wrap the result in { data, error } instead of throwing errors.

Syntax

query.safe() => Promise<SafeResult<T>>

Return Type

type SafeResult<T> = 
  | { data: T; error: undefined }
  | { data: undefined; error: unknown };

When to Use

  • You prefer error-as-value patterns over try-catch
  • Building APIs that need consistent error responses
  • Functional programming style

Examples

const result = await userModel.findMany().safe();

if (result.error) {
  console.error("Failed to fetch users:", result.error);
  return;
}

console.log(result.data); // User[]

Chaining Refinements

All refinement methods can be chained together:
const users = await userModel
  .where({ isVerified: esc(true) })
  .findMany()
  .with({ posts: true })
  .select({ id: true, name: true, posts: { title: true } })
  .exclude({ email: true })
  .raw()
  .safe();

Performance Considerations

SQL-Level (Efficient)

// ✅ Only fetches needed columns
const users = await userModel
  .findMany()
  .select({ id: true, name: true });
// SQL: SELECT id, name FROM user

Programmatic (Less Efficient)

// ⚠️ Fetches all columns, then removes them
const users = await userModel
  .findMany()
  .omit({ email: true, password: true });
// SQL: SELECT * FROM user (then omit in JavaScript)

Relation Loading

// ✅ Single query with JOIN
const users = await userModel
  .findMany()
  .with({ posts: true });
// Uses efficient JOIN strategy, not N+1 queries

Type Safety

All refinement methods update the result type:
const user = await userModel
  .findFirst()
  .select({ id: true, name: true });
// Type: { id: number, name: string } | undefined

const users = await userModel
  .findMany()
  .with({ posts: true });
// Type: { ...User, posts: Post[] }[]

const result = await userModel.findMany().safe();
// Type: { data: User[], error: undefined } | { data: undefined, error: unknown }

Notes

SQL vs Programmatic: Use .select() and .exclude() to reduce data transfer. Use .omit() only when you need the data for processing but want to hide it from the final result.
Relation Loading: .with() uses efficient JOIN-based loading, not N+1 queries.
Deep relation nesting can generate large queries. Use .select() to reduce payload size:
const users = await userModel
  .findMany()
  .with({ posts: { comments: { author: true } } })
  .select({ 
    id: true, 
    posts: { 
      id: true, 
      comments: { id: true } 
    } 
  });

Build docs developers (and LLMs) love