Constructing Query Constraints
Relevant source files
The following files were used as context for generating this wiki page:
Query constraints provide a declarative mechanism to secure Prisma model access by automatically injecting filters into database queries. The system transforms high-level role definitions found in Prisma model comments into complex Prisma where clauses, ensuring that users only access records permitted by their assigned roles.
This module primarily serves findMany operations and nested relation queries. It integrates with the GraphQL execution flow through middleware, allowing developers to define authorization logic once in the schema and apply it universally across all resolvers using a standardized withAuth utility.
Logic Flow for Constraint Generation
The system generates constraints by evaluating the @Auth annotations against the current user context and the configured role matchers.
Constraint Resolution Process
- Parse Annotations: The system extracts role names and arguments from the
@Authstring using a generated Peggy parser. - Lookup Matchers: For every role identified, the system searches for a corresponding
queryConstraintfunction in the global or type-specific configuration. - Execute Constraints: The system executes these functions with the current
contextandroleArgs. - Aggregrate Logic: Individual constraints are combined into a single Prisma-compatible object.
Core Components and Data Structures
Role Configuration
Developers define authorization logic within a Configuration object. Each role must provide a queryConstraint that returns either a Prisma where object or a boolean.
| Property | Type | Description |
|---|---|---|
matcher | Function | Validates a single record; returns boolean. |
queryConstraint | Function | Returns a Prisma where clause or boolean. |
matcherDependenciesSelect | Object | Function | Defines fields required for the matcher to function. |
Sources: src/index.ts:8-16, src/index.ts:18-29
Predicate Conditions
When a queryConstraint returns a boolean, the system converts it into a specific Prisma condition to ensure query integrity.
- alwaysTrueCondition: Used when a role is granted unrestricted access (e.g., an Admin). It filters by ensuring the
iddoes not equal a non-existent placeholder string. - alwaysFalseCondition: Used to short-circuit queries when no authorization roles match. It filters by searching for a non-existent placeholder string, effectively returning an empty set.
Sources: src/getListWhereConstrains.ts:7-23
Middleware Integration
The makeListConstraintMiddleware injects the withAuth function into the GraphQL context. This utility allows resolvers to wrap Prisma queries, automatically merging user-provided where clauses with the system-generated authorization constraints.
Recursive Selection and Filtering
The PrismaSelect class manages the recursive construction of constraints for nested relations. When a GraphQL query requests related models (e.g., User.posts), the system performs the following actions:
- Identify Kind: Checks if the field is a relation (kind is
object). - List Check: If the field is a list, it calls
getListWhereConstrainsfor the related type. - Dependency Injection: Automatically adds fields defined in
matcherDependenciesSelectto the Prismaselectblock to ensurematcherfunctions have necessary data for post-query validation. - Deep Merge: Uses
PrismaSelect.mergeDeepto combine constraints safely, protecting against prototype pollution.
Sources: src/select.ts:121-160, src/select.ts:223-245
Usage Example
// src/getListWhereConstrains.ts logic output example
// For @Auth(read:[Admin, Owner]) where current user ID is '123'
{
AND: [
{
OR: [
{ id: { not: { equals: 'ffffffffffffffffffffffff' } } }, // Admin (True)
{ userId: '123' } // Owner constraint
]
}
]
}
Sources: src/getListWhereConstrains.ts:60-70, src/getListWhereConstrains.test.ts:72-82
Query constraints ensure that security rules are enforced at the database level rather than the application level. By wrapping role logic in AND and OR blocks, the system prevents user-supplied queries from bypassing authorization filters.