Type-safe repository pattern abstraction for Prisma
npm install prisma-abstraction-alvamind





> Enterprise-ready Prisma ORM enhancement framework with advanced caching, repository pattern, performance optimizations, and robust transaction management.
PrismaStack is a beast of a framework that beefs up your Prisma ORM, made for enterprise apps that need to be fast, stable, and easy to manage. It throws in goodies like smart caching, repository patterns, solid transactions, and tons of tests.
prisma-orm typescript database orm caching repository-pattern enterprise nodejs typescript-orm database-framework prisma-extension orm-framework typescript-database prisma-tools database-caching prisma-wrapper prisma-enhancement database-performance prisma-utils acid-transactions- Enterprise-Ready: Built for big-time, heavy-traffic apps.
- Type-Safe: 100% TypeScript, so no weird type errors.
- Performance-Focused: Caching, query boosts, and fast batch ops.
- Battle-Tested: Rigorous tests for real-world problems.
- Developer-Friendly: Easy to use API with great docs.
- Production-Proven: Works like a charm in high-traffic spots.
- Extensible: Add your own stuff easily.
- Secure: Built with security in mind.
- Enterprise Apps
- High-Traffic Systems
- Microservices
- REST APIs
- GraphQL APIs
- E-commerce
- Real-time Apps
- SaaS Products
- Complex Data
- π Type-Safe Repos: No more type guessing.
- β‘ Blazing Fast Cache: Smart caching for speed.
- ποΈ Soft Delete: Easy peasy soft delete and restore.
- π± Transactions: Simple, strong transaction control.
- βοΈ Custom: Tweak it to your liking.
- π Raw SQL: Full SQL power when you need it.
- π¦ Bulk Ops: Quick create, update, delete many.
- π Pagination: Smooth pagination with metadata.
- β
Existence Checks: Fast checks for data.
- π€ Concurrency: Handles parallel stuff like a pro.
- π Runtime Config: Change settings on the fly.
- π§ͺ Tested: Enterprise-grade reliability.
- π Faster Dev: Less setup, more features.
- πͺ Maintainable Code: Clean and easy to read.
- π Better Perf: Faster queries, less load.
- π‘οΈ Fewer Bugs: Type safety and transactions fix common issues.
- π§ Easier to Learn: Simple, smooth API.
- β¨ Less Code: Do more with less code.
- π‘οΈ More Secure: Built-in protection.
- π Scalability: Designed for big growth.
- π REST APIs: Build solid APIs.
- GraphQL Resolvers: Clean, efficient resolvers.
- Microservices: Manage data smoothly.
- SaaS Apps: Handle multi-tenancy, data isolation.
- E-commerce: Products, orders, customers, all good.
- Real-time Systems: High-frequency updates handled well.
- π€ Prisma?: Basically everywhere you use Prisma.
``bash`
bun install prisma-abstraction-alvamind @prisma/clientor
npm install prisma-abstraction-alvamind @prisma/clientor
yarn add prisma-abstraction-alvamind @prisma/client
prisma/schema.prisma
`prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model User {
id String @id @default(uuid())
email String @unique
name String
status String @default("active")
metadata Json?
deletedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
`
`bash`
bunx prisma generate
src/user-repository.ts
`typescript
import { PrismaClient } from '@prisma/client';
import { BaseRepository, setPrismaClient } from 'prisma-abstraction-alvamind';
// Initialize Prisma client with prisma-abstraction
const prisma = setPrismaClient(new PrismaClient());
// Now you can chain prisma operations
prisma.$connect()
.then(() => console.log('Connected'))
.catch(console.error);
// Repository usage with proper types
export class UserRepository extends BaseRepository
`
`typescript
import { UserRepository } from './user-repository';
async function main() {
const userRepo = new UserRepository();
// Create
const newUser = await userRepo.create({
data: { email: 'test@example.com', name: 'Test User' },
});
// Find
const foundUser = await userRepo.findUnique({ where: { id: newUser.id } });
// Update
const updatedUser = await userRepo.update({
where: { id: newUser.id },
data: { name: 'Updated Name' },
});
// Delete
await userRepo.delete({ where: { id: newUser.id } });
}
main();
`
`typescript
import { PrismaClient } from '@prisma/client';
import { CachedRepository, setPrismaClient, Cache, setConfig } from 'prisma-abstraction-alvamind';
import Redis from 'ioredis';
// Redis cache implementation
class RedisCache implements Cache {
constructor(private redis: Redis) {}
async get
const value = await this.redis.get(key);
return value ? JSON.parse(value) : null;
}
async set
const serialized = JSON.stringify(value);
if (ttl) {
await this.redis.setex(key, ttl, serialized);
} else {
await this.redis.set(key, serialized);
}
}
async delete(key: string): Promise
await this.redis.del(key);
}
async clear(): Promise
await this.redis.flushdb();
}
async keys(): Promise
return this.redis.keys('*');
}
}
// Initialize
const prisma = new PrismaClient();
setPrismaClient(prisma);
setConfig({
cacheConfig: {
defaultCaching: true,
defaultTTL: 60
}
});
class CachedUserRepository extends CachedRepository
constructor(cache: Cache) {
super(cache);
}
}
async function main() {
const cache = new RedisCache(new Redis());
const userRepo = new CachedUserRepository(cache);
const newUser = await userRepo.create({
data: { email: 'cached@example.com', name: 'Cached User' },
});
// Cached
const user1 = await userRepo.cache({ cache: true }).findUnique({ where: { id: newUser.id } });
// From cache
const user2 = await userRepo.cache({ cache: true }).findUnique({ where: { id: newUser.id } });
}
main();
`
`typescript
import { UserRepository } from './user-repository';
import { setConfig } from 'prisma-abstraction-alvamind';
async function main() {
setConfig({ softDelete: true });
const userRepo = new UserRepository();
const newUser = await userRepo.create({
data: { email: 'softdelete@example.com', name: 'Soft Delete User' },
});
// Soft delete
await userRepo.delete({ where: { id: newUser.id } });
// Won't find
const deletedUser = await userRepo.findUnique({ where: { id: newUser.id } });
// Restore
const restoredUser = await userRepo.restoreById(newUser.id);
}
main();
`
`typescript
class UserRepository extends BaseRepository
// Find active users
async findActiveUsers() {
return this.findMany({ where: { status: 'active', deletedAt: null } });
}
// Update with history
async updateUserWithHistory(id: string, data: any) {
return this.$transaction(async (trx) => {
const currentUser = await this.trx(trx).findUnique({ where: { id } });
const updatedUser = await this.trx(trx).update({ where: { id }, data });
// Log to history model (not shown)
return updatedUser;
});
}
}
`
`typescript
class CachedUserRepository extends CachedRepository
// Custom cache settings
async findUsersByStatus(status: string) {
return this.cache({ cache: true, ttl: 300 }).findMany({ where: { status } });
}
// Conditional caching
async findUserWithPosts(userId: string, options: { cache?: boolean } = {}) {
return this.cache({ cache: options.cache, ttl: options.cache ? 60 : undefined })
.findUnique({ where: { id: userId }, include: { posts: true } });
}
}
`
`typescript
class UserService {
constructor(
private userRepo: UserRepository,
private postRepo: PostRepository,
private emailService: EmailService // Example service
) {}
async createUserWithPosts(userData: any, posts: any[]) {
return this.userRepo.$transaction(async (trx) => {
const user = await this.userRepo.trx(trx).create({ data: userData });
const createdPosts = await Promise.all(
posts.map(post => this.postRepo.trx(trx).create({ data: { ...post, authorId: user.id } }))
);
// Send welcome email (outside transaction)
await this.emailService.sendWelcomeEmail(user.email);
return { user, posts: createdPosts };
});
}
}
`
`typescript
class SoftDeleteUserRepository extends BaseRepository
// Override delete
async delete(args: any) {
return this.update({
...args,
data: {
...args.data,
deletedAt: new Date(),
status: 'inactive',
metadata: {
...(args.data?.metadata || {}),
deletedBy: 'system',
deletionReason: args.data?.reason
}
}
});
}
// Custom restore
async restore(id: string, options: { reactivate?: boolean } = {}) {
return this.update({
where: { id },
data: { deletedAt: null, ...(options.reactivate ? { status: 'active' } : {}) }
});
}
}
`
#### Model Name Auto-Detection
`typescript`
// Detects model name from class name
class UserRepository extends BaseRepository
class CachedUserRepository extends CachedRepository
#### Dynamic Transaction Client
`typescript`
// Switches between transaction and regular client
await userRepo.$transaction(async (trx) => {
const user = await userRepo.trx(trx).findUnique({/.../});
// Cleans up transaction reference
});
#### Existence Checks with Select
`typescript`
// Existence checks with field selection
const exists = await userRepo.isExist(
{ email: 'test@example.com' },
{ id: true, email: true }
);
#### Advanced Pagination
`typescript
const result = await userRepo.findManyWithPagination({
page: 1,
pageSize: 10,
where: { status: 'active' },
orderBy: { createdAt: 'desc' },
select: { id: true, email: true },
include: { posts: true }
});
console.log(result.meta);
// {
// page: 1, pageSize: 10, total: 100, totalPages: 10,
// hasNextPage: true, hasPreviousPage: false
// }
`
#### Pattern-Based Cache Flushing
`typescript
// Flush operation cache
await repo.flushOperation('findMany');
// Flush exact cache entry
await repo.flushExact('findUnique', { where: { id: 'xyz' } });
// Flush all cache
await repo.flushAll();
`
#### Cache Key Management
`typescriptmyapp:${Buffer.from(key).toString('base64url')}
// Custom cache key sanitization
setConfig({
cacheConfig: {
cacheKeySanitizer: (key) => `
}
});
#### Granular Cache Control
`typescript
// Per-operation cache control
const users = await userRepo.cache({ cache: true, ttl: 300 }).findMany(
{ where: { status: 'active' } }
);
// Global cache configuration
setConfig({ cacheConfig: { defaultCaching: true, defaultTTL: 3600 } });
`
#### Transaction Timeout Management
`typescript`
// Custom timeout for transactions
const result = await userRepo.$transaction(
async (trx) => { / Complex operations... / },
{ timeout: 10000 }
);
#### Raw Query Support with Types
`typescriptSELECT * FROM "User" WHERE "status" = 'active'
// Typed raw queries
const result = await userRepo.$queryRaw;
// Raw updates with parameters
const affected = await userRepo.$executeRawUPDATE "User" SET "status" = 'inactive' WHERE "id" = ${userId};`
#### Comprehensive Error Types
`typescript`
catch (error) {
if (error instanceof RepositoryError) {
// Handle repository error
} else if (error instanceof CacheError) {
// Handle cache error
}
}
#### Configurable Logging
`typescript[INFO] ${msg}
setConfig({
logger: {
info: (msg) => console.log(),[ERROR] ${msg}
error: (msg, error) => {
Sentry.captureException(error);
console.error();[WARN] ${msg}
},
warn: (msg) => console.warn(),[DEBUG] ${msg}
debug: (msg) => debug()`
}
});
#### Restore Operations with Data
`typescript`
// Restore with data update
await userRepo.restoreById(
userId,
{ status: 'active', metadata: { restoredBy: 'admin' } }
);
#### Bulk Soft Delete
`typescript`
// Soft delete multiple records
await userRepo.deleteMany({
where: { status: 'inactive' },
data: { metadata: { deletedBy: 'system' } }
});
#### Runtime Configuration Changes
`typescript`
// Change configuration at runtime
setConfig({
softDelete: true,
cacheConfig: { defaultCaching: true, defaultTTL: 3600 },
transactionOptions: { timeout: 5000 }
});
`typescript
import { setConfig } from 'prisma-abstraction-alvamind';
setConfig({
softDelete: true,
logger: {
info: (msg) => console.log([INFO] ${msg}),[ERROR] ${msg}
error: (msg) => console.error(),[WARN] ${msg}
warn: (msg) => console.warn(),[DEBUG] ${msg}
debug: (msg) => console.debug()my-app:${key}
},
cacheConfig: {
defaultCaching: true,
defaultTTL: 3600,
cacheKeySanitizer: (key) => `
},
transactionOptions: {
timeout: 5000,
maxRetries: 3
}
});
`typescript
import { Cache } from 'prisma-abstraction-alvamind';
import Redis from 'ioredis';
class RedisCache implements Cache {
constructor(private redis: Redis) {}
async get
const value = await this.redis.get(key);
return value ? JSON.parse(value) : null;
}
async set
const serialized = JSON.stringify(value);
if (ttl) {
await this.redis.setex(key, ttl, serialized);
} else {
await this.redis.set(key, serialized);
}
}
async delete(key: string): Promise
await this.redis.del(key);
}
async clear(): Promise
await this.redis.flushdb();
}
async keys(): Promise
return this.redis.keys('*');
}
}
// Usage
const redis = new Redis();
const cache = new RedisCache(redis);
const userRepo = new CachedUserRepository(cache);
`
We're serious about tests. We've got a ton of 'em, from basic stuff to weird edge cases. Here's the breakdown:
β Configuration & Initialization
β Basic CRUD Operations
β Soft Delete Mechanics
β Transaction Handling
β Raw Query Execution
β Bulk Operations
β Pagination Logic
`$3
`
β Cache Read Operations (findUnique, findMany, findFirst)
β Cache Invalidation (create, update, delete)
β Cache Flushing (all, specific, pattern-based)
β Edge Cases & Error Handling
β Custom Cache Key Sanitization
`$3
`
β Bulk Operations (100 records < 1 second)
β Parallel Operations Handling
β Race Condition Management
β Transaction Rollbacks
β Memory Management
`$3
`
β Invalid JSON Metadata
β Non-existent Records
β Empty Updates
β Cache System Failures
β Transaction Timeouts
`$3
`
Total Tests: 58
Pass Rate: 100%
Test Files: 1
Expectations: 103
Total Duration: 5.38s
Average Test Speed: ~93ms
`$3
| Category | Tests | Coverage |
|----------|-------|----------|
| Basic Operations | 15 | β Create, Read, Update, Delete |
| Caching | 14 | β Read/Write, Invalidation |
| Transactions | 5 | β Commit, Rollback |
| Soft Delete | 4 | β Delete, Restore |
| Concurrency | 4 | β Race Conditions |
| Edge Cases | 8 | β Error Handling |
| Configuration | 4 | β Runtime Changes |
| Performance | 4 | β Bulk Operations |
$3
- Concurrency: 100 parallel ops, no sweat.
- Cache Hit Rate: 99%+ for repeated queries.
- Transaction Safety: 100% rollback on failures.
- Data Integrity: Zero corruption.
- Error Recovery: 100% graceful handling.
$3
- Database: PostgreSQL (Latest)
- Runtime: Bun
- Platform: Docker Container
- Test Framework: Bun Test
- Coverage Tool: Built-in
These tests run on every commit, making sure everything stays solid.
Wanna run the tests yourself? Easy:
`bash
bun test
`π£οΈ Roadmap
Here's the plan for PrismaStack:
High Priority (Next Up):
- [x] More Granular Cache Control: Control caching at the model level.
- [x] Advanced Querying: More complex data retrieval options.
Medium Priority (Coming Soon):
- [ ] Real-time Subscriptions: Real-time data updates.
`typescript
// Add real-time updates support
interface SubscriptionOptions {
filter?: Record;
debounce?: number;
batchSize?: number;
} public subscribe(
callback: (updates: T[]) => void,
options?: SubscriptionOptions
): Unsubscribe
`
- [ ] Batch Operations with Progress: Batch processing with progress tracking.
`typescript
// Add batch processing with progress tracking and chunking
public async batchProcess(
items: T[],
operation: (item: T) => Promise,
options: {
chunkSize?: number;
onProgress?: (progress: number) => void;
parallel?: boolean;
}
)
`
- [ ] Smart Cache Prefetching: Cache loading based on user patterns.
`typescript
// Predictive cache loading based on access patterns
public async prefetch(
patterns: Array<{
operation: string;
args: any;
priority?: 'high' | 'medium' | 'low';
}>,
options?: { background?: boolean }
)
`
- [ ] Built-in Auditing: Track all data changes with metadata.
`typescript
// Track all changes with detailed metadata
interface AuditOptions {
user?: string;
reason?: string;
metadata?: Record;
trackFields?: string[];
} public async withAudit(
operation: () => Promise,
auditOptions: AuditOptions
): Promise
`- [ ] Advanced Search Features: Fuzzy search, weights, highlights, language support, and synonyms.
`typescript
// Enhanced search capabilities
interface SearchOptions {
fuzzy?: boolean;
weights?: Record;
highlight?: boolean;
language?: string;
synonyms?: Record;
} public async search(
query: string,
fields: Array,
options?: SearchOptions
): Promise>
`Lower Priority (Future Enhancements):
- [ ] Data Encryption Layer: Field-level encryption for sensitive data.
`typescript
// Field-level encryption support
interface EncryptionOptions {
algorithm?: string;
fields: string[];
keyRotation?: boolean;
} public enableEncryption(options: EncryptionOptions): this
public async reEncryptField(field: string): Promise
`
- [ ] Smart Data Migration: Easy data migration with validation and rollback.
`typescript
// Intelligent data migration utilities
interface MigrationOptions {
batchSize?: number;
validation?: boolean;
rollback?: boolean;
dryRun?: boolean;
} public async migrate(
transformer: (data: T) => Promise,
options?: MigrationOptions
): Promise
`
- [ ] Versioning Support: Track and revert to previous states of your data.
`typescript
// Add versioning capabilities to entities
interface VersioningOptions {
keepVersions?: number;
compareFields?: string[];
metadata?: Record;
} public async createVersion(id: string, options?: VersioningOptions)
public async revertToVersion(id: string, version: number)
`
- [ ] Performance Analytics: Get insights on query performance and cache efficiency.
`typescript
// Built-in performance monitoring
interface PerformanceMetrics {
queryStats: QueryStatistics[];
cacheEfficiency: number;
slowQueries: SlowQueryInfo[];
recommendations: string[];
} public async getPerformanceMetrics(): Promise
public enableQueryProfiling(options?: ProfilingOptions): this
`- [ ] Automatic Relationship Management: Handle relationships easier.
- [ ] More Cache Adapters: Support for more cache solutions.
- [ ] Improved Docs: More examples and tutorials.
Additional Advanced Features:
- [ ] Read Replicas: Distribute reads across multiple replicas.
`typescript
// Read replica configuration
interface DatabaseConfig {
primary: PrismaClient;
replicas?: PrismaClient[];
} class EnhancedRepository> extends BaseRepository {
private replicas: PrismaClient[];
constructor(config: DatabaseConfig) {
super();
this.replicas = config.replicas || [];
}
private getReadReplica(): PrismaClient {
if (this.replicas.length === 0) {
return this.prisma;
}
const replicaIndex = Math.floor(Math.random() * this.replicas.length);
return this.replicas[replicaIndex];
}
}
`- [ ] Database Sharding: Partition data for better scalability.
`typescript
// Sharding configuration
interface ShardConfig {
strategy: 'range' | 'hash' | 'directory';
shards: Map;
shardKey: string;
} class ShardManager {
constructor(private config: ShardConfig) {}
getShardForQuery(args: any): PrismaClient {
// Implement sharding logic here
}
}
`- [ ] Circuit Breaker Pattern: Prevent cascade failures with auto recovery.
`typescript
// Circuit breaker configuration
interface CircuitBreakerConfig {
failureThreshold: number;
resetTimeout: number;
} class CircuitBreaker {
constructor(private config: CircuitBreakerConfig) {}
isAllowed(): boolean {
// Implement circuit breaker logic here
}
recordFailure(): void {
// Implement failure recording logic here
}
}
`- [ ] Rate Limiting: Control the rate of requests to the database.
`typescript
// Rate limiting configuration
interface RateLimiterConfig {
maxRequests: number;
windowMs: number;
} class RateLimiter {
constructor(private config: RateLimiterConfig) {}
isAllowed(): boolean {
// Implement rate limiting logic here
}
}
`- [ ] Retry Mechanism: Auto retry failed operations with backoff strategies.
`typescript
// Retry mechanism configuration
interface RetryConfig {
maxRetries: number;
backoffStrategy: 'exponential' | 'linear';
} class RetryMechanism {
constructor(private config: RetryConfig) {}
async retry(operation: () => Promise): Promise {
// Implement retry logic here
}
}
`- [ ] Connection Pooling: Manage database connections for better performance.
`typescript
// Connection pooling configuration
interface PoolConfig {
min: number;
max: number;
timeout: number;
} class ConnectionPool {
constructor(private config: PoolConfig) {}
async acquire(): Promise {
// Implement connection pooling logic here
}
release(connection: PrismaClient): void {
// Implement connection release logic here
}
}
`- [ ] TypeScript Code-First to Prisma Schema Generator: Generate Prisma schema from TypeScript models.
`typescript
// TypeScript code-first to Prisma schema generator
function generatePrismaSchema(models: any[]): string {
// Implement schema generation logic here
}
`π Contribution
Wanna help? Hereβs how:
1. Fork the repo.
2. Clone your fork:
git clone https://github.com/alvamind/prisma-abstraction-alvamind.git
3. Create a branch: git checkout -b my-feature
4. Make changes: Code, test, repeat.
5. Commit: git commit -m "Add my feature"
6. Push: git push origin my-feature
7. Open a Pull Request.Before submitting a PR:
- Keep the same code style.
- Write tests.
- Document your code.
- Keep PRs small and focused.
π Donation
Show some love:
- βοΈ Star the repo.
- β€οΈ Sponsor us on GitHub.
π Documentation
Check out our docs for everything you need.
π€ Community & Support
- GitHub Issues
- Discord Community
- Stack Overflow
- Twitter Updates
π Citation
`bibtex
@software{prismastack2024,
author = {Alvamind Development Team},
title = {PrismaStack: Enterprise-Grade Prisma ORM Enhancement Framework},
year = {2024},
publisher = {GitHub},
url = {https://github.com/alvamind/prisma-abstraction-alvamind}
}
``This is "as is", no warranties. Use at your own risk.
Prisma logo and name are trademarks of Prisma Media, Inc. This project ain't affiliated with them. We're an independent community project by @alvamind.
Go build cool stuff with PrismaStack! Hit us up if you got questions. Peace! βοΈ