zmdbzero-maintenance data layer
Docs Benchmarks Anti-patterns OpenAPI
Docs / Schema and ORM

Projections (partial select)Supported

Projections let you narrow the result set to specific columns, reducing payload size and improving query performance. zmdb provides compile-time type narrowing and a runtime helper for applying projections to fetched rows.

Narrowing Select Results#

The repository's read methods accept a select option that narrows the returned row type. This is type-safe — only valid column keys from the schema are allowed.

import { type Entity } from '@zmdb/schema';

// Given `interface User` with columns: id, email, role, createdAt
type UserRow = Entity<User>;
// UserRow = { id: number; email: string; role: string; createdAt: Date }

// Select only email and role — type narrows automatically
const minimal = await users.findById(1, { select: ['email', 'role'] as const });
// Type: { email: string; role: string } | undefined

Runtime Projection Helper#

The project() function applies a column selection to a fetched row, returning a new object with only the specified keys.

import { project } from '@zmdb/schema/dto';

const row = { id: 1, email: 'a@b.com', role: 'admin', createdAt: new Date() };

const narrow = project(row, ['email', 'role'] as const);
// narrow = { email: 'a@b.com', role: 'admin' }

// Passing undefined returns the row unchanged
const full = project(row, undefined);
// full = { id: 1, email: 'a@b.com', role: 'admin', createdAt: ... }

SQL Emitted#

When you specify select in a repository call, the compiler emits only those columns in the SELECT clause.

import { trustedTable } from '@zmdb/sql';

const q = qb.selectFrom(trustedTable('users')).select(['email', 'role']).where('id', '=', 1).compile();

console.log(q.text);
// SELECT "email", "role" FROM "users" WHERE "id" = $1
❗ Important

Repository projections and compiler projections bound to a declared schema are compile-time checked. The explicit trustedTable boundary above accepts physical column names without a schema-derived column check.

Use Cases#

// Expose only public-safe user data
const publicUser = await users.findById(id, {
  select: ['id', 'email', 'role'] as const,
});
// Never leaks internal fields like password_hash
💡 Tip

Combine projections with pagination to minimize data transfer. Fetch only what you display.