install
source · Clone the upstream repo
git clone https://github.com/Intense-Visions/harness-engineering
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/codex/prisma-filtering-sorting" ~/.claude/skills/intense-visions-harness-engineering-prisma-filtering-sorting-7908bc && rm -rf "$T"
manifest:
agents/skills/codex/prisma-filtering-sorting/SKILL.mdsource content
Prisma Filtering and Sorting
Filter and sort Prisma queries with where, AND/OR/NOT, orderBy, and cursor/offset pagination
When to Use
- Building dynamic search or filter queries against Prisma models
- Combining multiple filter conditions with boolean logic
- Sorting results by one or more fields
- Implementing pagination with cursor-based or offset strategies
Instructions
- Basic equality filter — pass field values directly in
:where
const users = await prisma.user.findMany({ where: { role: 'ADMIN', isActive: true }, });
Multiple top-level fields are implicitly AND-ed.
- Comparison operators — use
,equals
,not
,gt
,gte
,lt
,lte
,in
:notIn
const recentPosts = await prisma.post.findMany({ where: { createdAt: { gte: new Date('2024-01-01') }, viewCount: { gt: 100 }, }, });
- String filters — use
,contains
,startsWith
. AddendsWith
for case-insensitive matching (PostgreSQL only):mode: 'insensitive'
const results = await prisma.user.findMany({ where: { name: { contains: 'john', mode: 'insensitive' } }, });
- Boolean combinators — use
,AND
,OR
for complex logic:NOT
const filtered = await prisma.post.findMany({ where: { OR: [{ title: { contains: search } }, { content: { contains: search } }], AND: { published: true }, NOT: { authorId: blockedUserId }, }, });
- Filter on relations — use
,some
,every
for to-many relations andnone
,is
for to-one:isNot
const usersWithPublishedPosts = await prisma.user.findMany({ where: { posts: { some: { published: true } } }, });
- Sort with
— pass one or multiple sort fields:orderBy
const sorted = await prisma.post.findMany({ orderBy: [{ pinned: 'desc' }, { createdAt: 'desc' }], });
- Sort on relations — order by a related field count or value:
const byPostCount = await prisma.user.findMany({ orderBy: { posts: { _count: 'desc' } }, });
- Offset pagination — use
andskip
:take
const page = await prisma.post.findMany({ skip: (pageNumber - 1) * pageSize, take: pageSize, orderBy: { createdAt: 'desc' }, });
- Cursor pagination — use
withcursor
to exclude the cursor record:skip: 1
const nextPage = await prisma.post.findMany({ cursor: { id: lastPostId }, skip: 1, take: 20, orderBy: { createdAt: 'desc' }, });
- Aggregations — use
,aggregate
, andgroupBy
:count
const stats = await prisma.post.aggregate({ _avg: { viewCount: true }, _max: { viewCount: true }, where: { published: true }, });
Details
Prisma's filtering and sorting are fully type-safe. The available filter operators depend on the field type —
contains only appears on String fields, gt/lt only on numeric and DateTime fields.
Offset vs cursor pagination: Offset (
skip/take) is simpler to implement but degrades at high offsets because the database still scans skipped rows. Cursor pagination (cursor/take) uses an indexed value (usually id or createdAt) and performs consistently regardless of position. Use cursor pagination for infinite scroll or large datasets.
Dynamic filters: Build
where objects conditionally to avoid unnecessary filters:
const where: Prisma.PostWhereInput = { published: true }; if (search) where.title = { contains: search, mode: 'insensitive' }; if (authorId) where.authorId = authorId; const posts = await prisma.post.findMany({ where });
filtering: Use null
equals: null to find null values and not: null to exclude them. With strictNullChecks, Prisma distinguishes between "field is null" and "field is not provided in the filter."
Aggregation limitations:
requires all non-aggregated fields in thegroupBy
arrayby- You cannot aggregate on relations — use raw queries for complex aggregations like joining and grouping across tables
returnscount
, notnumber
, even on tables withBigInt
IDsBigInt
Performance notes:
- Filtering on non-indexed fields triggers full table scans. Always check that filtered fields have database indexes
on PostgreSQL usesmode: 'insensitive'
which cannot use standard B-tree indexes — create a GIN/GiST trigram index or a functional index withILIKE
for production workloadslower()
Source
https://prisma.io/docs/orm/prisma-client/queries/filtering-and-sorting
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.