Transform Prisma into a powerful Active Record ORM with advanced querying, batch operations, and graph utilities
A complete TypeScript framework that extends Prisma Client with the Active Record pattern, a declarative query builder, relation graph traversal, and high-performance batch operations.
Prisma is a fantastic query builder, but it's not a traditional ORM. This framework brings the ergonomic benefits of an Active Record pattern to your Prisma workflow, without sacrificing the type safety and performance you love. Get the best of both worlds: a powerful, intuitive entity system on top of Prisma's rock-solid foundation.
| Feature | Prisma Client | Prisma Entity Framework |
|---|---|---|
| Active Record | β No | β
user.create(), user.update() |
| Instance Methods | β No | β Full lifecycle methods |
| Query DSL | Basic where | β Composable AND/OR/NOT tree, LIKE, ranges, lists |
| Case-insensitive search | Provider-dependent | β Consistent on every provider |
| Batch Optimization | Basic | β Database-specific, SQL-optimized |
| Upsert | Manual | β Automatic with change detection |
| Graph Traversal | Manual | β Automatic path finding |
| Performance Tools | β No | β Metrics, retry, memory estimation |
| Pagination | Manual | β Built-in formatted responses |
| Type Safety | β Full | β Full (maintains Prisma types) |
npm install @didactika/prisma-entity
# or
yarn add @didactika/prisma-entity
# or
pnpm add @didactika/prisma-entityRequirements:
- Node.js >= 16
- Prisma Client >= 4.0.0
-
Configure Prisma Client (one-time setup)
import { PrismaClient } from '@prisma/client'; import { configurePrisma } from '@didactika/prisma-entity'; const prisma = new PrismaClient(); configurePrisma(prisma);
-
Define an Entity
import { BaseEntity, Property } from '@didactika/prisma-entity'; import { User as PrismaUser } from '@prisma/client'; import { prisma } from './prisma-client'; export class User extends BaseEntity<PrismaUser> { static readonly model = prisma.user; @Property() declare id: number; @Property() declare name: string; @Property() declare email: string; }
-
Use It!
import { anyOf } from '@didactika/prisma-entity'; // Create a new user with the Active Record pattern const user = new User({ name: "John Doe", email: "john.doe@example.com" }); await user.create(); // Find users with the declarative query builder const results = await User.findByFilter({ isActive: true }, { onlyOne: true, //get only first match or all records, false by default search: anyOf(['name', 'email'], { like: 'john' }), pagination: { page: 1, pageSize: 10, take: 10, skip: 0 } }); console.log(results.data); // Paginated array of User instances
- ποΈ Active Record Pattern: Manage your data with intuitive instance methods like
user.create().const user = new User({ name: "John" }); await user.create();
- π Declarative Query Tree: Compose
and,orandnotaround plain conditions to any depth. Searches are plain data, so they can be typed, stored in a variable, or sent as JSON from a client.// Simple range const users = await User.findByFilter({ name: "John" }, { search: { field: 'age', gte: 18 } }); // (name LIKE john OR email LIKE john) AND (createdAt <= now OR createdAt IS NULL) const users = await User.findByFilter({ isActive: true }, { search: { and: [ anyOf(['name', 'email'], { like: 'john' }), { field: 'createdAt', lte: new Date(), orNull: true } ] }, orderBy: [{ createdAt: 'asc' }, { name: 'asc' }] });
- π€ Case-insensitive text search everywhere:
like,startsWithandendsWithignore letter case on every provider by default, instead of leaking each database's own collation rules into your results.// matches "John", "JOHN" and "john" on PostgreSQL, MySQL, SQLite and MongoDB alike await User.findByFilter({}, { search: { field: 'name', like: 'john' } }); // opt out globally, or per condition configurePrisma(prisma, { caseInsensitiveSearch: false }); await User.findByFilter({}, { search: { field: 'code', like: 'X9', insensitive: false } });
- β‘ Optimized Batch Operations: High-performance, database-aware batching for
createMany,updateMany, andupsertMany.await User.createMany([{ name: "User1" }, { name: "User2" }]);
- π Parallel Execution: Run batch operations concurrently for a 2-6x speed boost with zero configuration required.
// This feature is automatic, no code change needed! const manyUsers = [{ email: 'user1@example.com' }, { email: 'user2@example.com' }]; await User.upsertMany(manyUsers); // Runs in parallel
- πΈοΈ Graph Traversal: Analyze and navigate your data model with utilities for dependency sorting and pathfinding.
import { ModelUtils } from '@didactika/prisma-entity'; const path = ModelUtils.findPathToParentModel('Comment', 'User'); // -> "post.author"
- π Automatic Pagination: Get formatted, paginated responses from your queries out of the box.
const paginated = await User.findByFilter({}, { pagination: { page: 1, pageSize: 10 } });
Dive deeper into the framework's capabilities:
- Complete API Reference: A detailed breakdown of all classes, methods, and types.
- Advanced Examples: See complex queries in action.
- Advanced configuration guide: Learn about advanced configuration.
- Property Behavior Guide: Understand how the
@Propertydecorator works. - Testing Guide: Best practices for testing your entities.
# Run all tests (SQLite)
npm test
# Test a specific database
npm run test:mysql
# Run tests on all databases
npm run test:all-databasesContributions are welcome! Please feel free to submit a Pull Request. Check out our development setup guide.
MIT Β© 2025 Eduardo Estrada & Hector Arrechea