zodipus-query-engine

Build type-safe, composable Prisma queries with automatic Zod validation. Use when working with createRegistry, query builders, select/include patterns, validated database queries, findMany validation, or type-safe Prisma results.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "zodipus-query-engine" with this command: npx skills add bratsos/zodipus/bratsos-zodipus-zodipus-query-engine

Query Engine

Build validated, type-safe Prisma queries with automatic result validation.

When to Apply

  • User mentions "query engine" or "createRegistry"
  • User wants type-safe Prisma queries
  • User asks about select/include with validation
  • User needs to validate Prisma query results
  • User mentions "composable queries"
  • User asks about relation queries with Zod

Core Concept

The Query Engine creates composable query builders that:

  1. Generate Prisma query objects (select, include)
  2. Provide matching Zod schemas for validation
  3. Infer TypeScript types automatically
User Request → Query Builder → Prisma Query + Zod Schema → Validated Result

Setup

import { createRegistry } from 'zodipus/queryEngine';
import { models, modelRelations } from './generated/generated-index';

// Create registry with all models
const registry = createRegistry({
  models,
  relations: modelRelations,
});

// Create query builders for each model you need
const userQuery = registry.createQuery('user');
const postQuery = registry.createQuery('post');
const commentQuery = registry.createQuery('comment');

Basic Patterns

Pattern 1: Select Specific Fields

Select only the fields you need. Validation matches your selection.

const query = userQuery({
  select: { id: true, email: true, name: true }
});

// query.query = { select: { id: true, email: true, name: true } }
const user = await prisma.user.findFirst(query.query);

// Validates and types only selected fields
const validated = query.parse(user);
// Type: { id: string; email: string; name: string | null }

Pattern 2: Include Relations

Include related records with their own field selection.

const query = userQuery({
  select: { id: true, email: true },
  posts: {
    select: { id: true, title: true, published: true }
  }
});

const users = await prisma.user.findMany(query.query);
const validated = query.array().parse(users);
// Type: {
//   id: string;
//   email: string;
//   posts: { id: string; title: string; published: boolean }[]
// }[]

Pattern 3: Nested Relations

Chain relations as deeply as your relationDepth allows.

const query = userQuery({
  select: { id: true, name: true },
  posts: {
    select: { title: true },
    comments: {
      select: { content: true, createdAt: true },
      author: {
        select: { name: true, email: true }
      }
    }
  }
});

// 4 levels deep: User → posts → comments → author

Pattern 4: Array Results (findMany)

Use .array() for validating arrays of results.

const query = userQuery({
  select: { id: true, email: true }
});

const users = await prisma.user.findMany(query.query);

// Validate array
const validated = query.array().parse(users);
// Type: { id: string; email: string }[]

Pattern 5: Safe Parsing

Handle validation errors without throwing.

const result = query.safeParse(data);

if (result.success) {
  // result.data is fully typed
  console.log(result.data.email);
} else {
  // result.error is ZodError
  console.error(result.error.issues);
  console.error(result.error.format()); // Formatted errors
}

Pattern 6: Partial Validation

For PATCH endpoints or partial updates.

const query = userQuery({
  select: { id: true, email: true, name: true }
});

// Make all fields optional
const partialQuery = query.partial();

const updates = partialQuery.parse({ name: 'New Name' });
// Type: { id?: string; email?: string; name?: string | null }

Advanced Patterns

Combining with Prisma Where/OrderBy

The Query Engine generates select/include objects. Combine with your own conditions:

const query = userQuery({
  select: { id: true, email: true, name: true },
  posts: { select: { title: true } }
});

// Add where, orderBy, pagination
const users = await prisma.user.findMany({
  ...query.query,
  where: { role: 'ADMIN' },
  orderBy: { createdAt: 'desc' },
  take: 10,
  skip: 0,
});

const validated = query.array().parse(users);

Reusable Query Fragments

Create reusable query configurations:

// Define reusable configs
const minimalUser = { select: { id: true, email: true } } as const;
const fullUser = {
  select: { id: true, email: true, name: true, role: true },
  posts: { select: { id: true, title: true } }
} as const;

// Use them
const minimalQuery = userQuery(minimalUser);
const fullQuery = userQuery(fullUser);

Conditional Relations

Include relations conditionally:

function getUserQuery(includePosts: boolean) {
  const base = { select: { id: true, email: true, name: true } };

  if (includePosts) {
    return userQuery({
      ...base,
      posts: { select: { id: true, title: true } }
    });
  }

  return userQuery(base);
}

Type Extraction

Extract types from queries:

import { z } from 'zod';

const query = userQuery({
  select: { id: true, email: true },
  posts: { select: { title: true } }
});

// Extract the validated type
type UserWithPosts = z.infer<ReturnType<typeof query.parse>>;
// or
type UserWithPosts = z.output<typeof query>;

API Reference

createRegistry(config)

Creates a registry for building queries.

const registry = createRegistry({
  models,           // From generated-index.ts
  relations: modelRelations,  // From generated-index.ts
});

registry.createQuery(modelName)

Returns a query builder function for the specified model.

const userQuery = registry.createQuery('user');
const postQuery = registry.createQuery('post');

Query Builder Return Object

const query = userQuery({ select: { id: true } });

query.query       // Prisma query object: { select: { id: true } }
query.parse()     // Validates single result (throws on error)
query.safeParse() // Validates single result (returns result object)
query.array()     // Returns schema for validating arrays
query.partial()   // Returns schema with all fields optional

Priority Patterns

PriorityPatternWhen to Use
Criticalquery.parse(result)Validate findFirst/findUnique results
Criticalquery.array().parse(results)Validate findMany results
Highquery.safeParse(result)When you need error handling
HighNested relationsQuerying with related data
Mediumquery.partial()PATCH endpoints, partial updates
MediumCombining with where/orderByFiltered queries
LowType extractionAdvanced TypeScript usage

Common Mistakes

Mistake 1: Forgetting .array() for findMany

// Wrong - will fail validation
const users = await prisma.user.findMany(query.query);
const validated = query.parse(users); // Error: expected object, got array

// Correct
const validated = query.array().parse(users);

Mistake 2: Using query.query as the whole argument

// Wrong - overwrites your conditions
const user = await prisma.user.findFirst(query.query); // OK
const user = await prisma.user.findFirst({
  query.query, // Syntax error!
  where: { id: '123' }
});

// Correct - spread the query
const user = await prisma.user.findFirst({
  ...query.query,
  where: { id: '123' }
});

Mistake 3: Accessing unselected fields

const query = userQuery({ select: { id: true } });
const user = query.parse(result);

// Wrong - 'email' wasn't selected
console.log(user.email); // TypeScript error

// Correct - add 'email' to select
const query = userQuery({ select: { id: true, email: true } });

For more patterns, see references/QUERY-PATTERNS.md.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

zodipus-setup

No summary provided by upstream source.

Repository SourceNeeds Review
General

zodipus-custom-schemas

No summary provided by upstream source.

Repository SourceNeeds Review
General

zodipus-troubleshooting

No summary provided by upstream source.

Repository SourceNeeds Review
General

zodipus

No summary provided by upstream source.

Repository SourceNeeds Review