askill
zodipus-query-engine

zodipus-query-engineSafety 92Repository

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.

1 stars
1.2k downloads
Updated 1/31/2026

Package Files

Loading files...
SKILL.md

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.

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

96/100Analyzed 2/10/2026

An exceptionally well-documented skill for the zodipus-query-engine. It provides comprehensive coverage from basic setup to advanced patterns, including common mistakes and a clear API reference.

92
98
90
98
95

Metadata

Licenseunknown
Version-
Updated1/31/2026
Publisherbratsos

Tags

apici-cd