prisma-abstraction-alvamind v1.0.12
π Prisma-Abstraction Lib | PrismaStack
π Table of Contents
- π― What is PrismaStack?
- π« Why PrismaStack?
- π Perfect For:
- π Features: At a Glance
- π₯ Benefits:
- π Use Cases:
- π¨βπ» Usage Examples:
- π― Advanced Examples:
- π― Advanced Features Deep Dive
- π§ Configuration Deep Dive
- π‘οΈ Battle-Tested Reliability
- π£οΈ Roadmap
- π Contribution
- π Donation
- π Documentation
- π€ Community & Support
- π Citation
- π Disclaimer
- π That's All, Folks!
Enterprise-ready Prisma ORM enhancement framework with advanced caching, repository pattern, performance optimizations, and robust transaction management.
π― What is PrismaStack?
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.
Keywords
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
π« Why PrismaStack?
- 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.
π Perfect For:
- Enterprise Apps
- High-Traffic Systems
- Microservices
- REST APIs
- GraphQL APIs
- E-commerce
- Real-time Apps
- SaaS Products
- Complex Data
π Features: At a Glance
- π 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.
π₯ Benefits:
- π 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.
π Use Cases:
- π 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.
π¨βπ» Usage Examples:
Installation
bun install prisma-abstraction-alvamind @prisma/client
# or
npm install prisma-abstraction-alvamind @prisma/client
# or
yarn add prisma-abstraction-alvamind @prisma/client
Setting Up
prisma/schema.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
}
bunx prisma generate
src/user-repository.ts
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<typeof PrismaClient, 'user'> {}
Basic CRUD
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();
Caching Example
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<T>(key: string): Promise<T | null> {
const value = await this.redis.get(key);
return value ? JSON.parse(value) : null;
}
async set<T>(key: string, value: T, ttl?: number): Promise<void> {
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<void> {
await this.redis.del(key);
}
async clear(): Promise<void> {
await this.redis.flushdb();
}
async keys(): Promise<string[]> {
return this.redis.keys('*');
}
}
// Initialize
const prisma = new PrismaClient();
setPrismaClient(prisma);
setConfig({
cacheConfig: {
defaultCaching: true,
defaultTTL: 60
}
});
class CachedUserRepository extends CachedRepository<typeof PrismaClient, 'user'> {
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();
Soft Delete Example
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();
π― Advanced Examples:
Custom Repository Methods
class UserRepository extends BaseRepository<typeof PrismaClient, 'user'> {
// 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;
});
}
}
Advanced Caching
class CachedUserRepository extends CachedRepository<typeof PrismaClient, 'user'> {
// 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 } });
}
}
Complex Transactions
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 };
});
}
}
Soft Delete with Custom Logic
class SoftDeleteUserRepository extends BaseRepository<typeof PrismaClient, 'user'> {
// 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' } : {}) }
});
}
}
π― Advanced Features Deep Dive
π¦ Repository Pattern Enhancements
Model Name Auto-Detection
// Detects model name from class name
class UserRepository extends BaseRepository<typeof PrismaClient, 'user'> {}
class CachedUserRepository extends CachedRepository<typeof PrismaClient, 'user'> {}
Dynamic Transaction Client
// Switches between transaction and regular client
await userRepo.$transaction(async (trx) => {
const user = await userRepo.trx(trx).findUnique({/*...*/});
// Cleans up transaction reference
});
π Advanced Query Operations
Existence Checks with Select
// Existence checks with field selection
const exists = await userRepo.isExist(
{ email: 'test@example.com' },
{ id: true, email: true }
);
Advanced Pagination
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
// }
π Advanced Caching Features
Pattern-Based Cache Flushing
// 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
// Custom cache key sanitization
setConfig({
cacheConfig: {
cacheKeySanitizer: (key) => `myapp:${Buffer.from(key).toString('base64url')}`
}
});
Granular Cache Control
// 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 } });
β‘ Performance Optimizations
Transaction Timeout Management
// Custom timeout for transactions
const result = await userRepo.$transaction(
async (trx) => { /* Complex operations... */ },
{ timeout: 10000 }
);
Raw Query Support with Types
// Typed raw queries
const result = await userRepo.$queryRaw<User[]>`SELECT * FROM "User" WHERE "status" = 'active'`;
// Raw updates with parameters
const affected = await userRepo.$executeRaw`UPDATE "User" SET "status" = 'inactive' WHERE "id" = ${userId}`;
π‘οΈ Error Handling & Logging
Comprehensive Error Types
catch (error) {
if (error instanceof RepositoryError) {
// Handle repository error
} else if (error instanceof CacheError) {
// Handle cache error
}
}
Configurable Logging
setConfig({
logger: {
info: (msg) => console.log(`[INFO] ${msg}`),
error: (msg, error) => {
Sentry.captureException(error);
console.error(`[ERROR] ${msg}`);
},
warn: (msg) => console.warn(`[WARN] ${msg}`),
debug: (msg) => debug(`[DEBUG] ${msg}`)
}
});
π Soft Delete Enhancements
Restore Operations with Data
// Restore with data update
await userRepo.restoreById(
userId,
{ status: 'active', metadata: { restoredBy: 'admin' } }
);
Bulk Soft Delete
// Soft delete multiple records
await userRepo.deleteMany({
where: { status: 'inactive' },
data: { metadata: { deletedBy: 'system' } }
});
π¨ Flexible Configuration
Runtime Configuration Changes
// Change configuration at runtime
setConfig({
softDelete: true,
cacheConfig: { defaultCaching: true, defaultTTL: 3600 },
transactionOptions: { timeout: 5000 }
});
π§ Configuration Deep Dive
Complete Configuration Options
import { setConfig } from 'prisma-abstraction-alvamind';
setConfig({
softDelete: true,
logger: {
info: (msg) => console.log(`[INFO] ${msg}`),
error: (msg) => console.error(`[ERROR] ${msg}`),
warn: (msg) => console.warn(`[WARN] ${msg}`),
debug: (msg) => console.debug(`[DEBUG] ${msg}`)
},
cacheConfig: {
defaultCaching: true,
defaultTTL: 3600,
cacheKeySanitizer: (key) => `my-app:${key}`
},
transactionOptions: {
timeout: 5000,
maxRetries: 3
}
});
Custom Cache Implementation (Redis Example)
import { Cache } from 'prisma-abstraction-alvamind';
import Redis from 'ioredis';
class RedisCache implements Cache {
constructor(private redis: Redis) {}
async get<T>(key: string): Promise<T | null> {
const value = await this.redis.get(key);
return value ? JSON.parse(value) : null;
}
async set<T>(key: string, value: T, ttl?: number): Promise<void> {
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<void> {
await this.redis.del(key);
}
async clear(): Promise<void> {
await this.redis.flushdb();
}
async keys(): Promise<string[]> {
return this.redis.keys('*');
}
}
// Usage
const redis = new Redis();
const cache = new RedisCache(redis);
const userRepo = new CachedUserRepository(cache);
π‘οΈ Battle-Tested Reliability
We're serious about tests. We've got a ton of 'em, from basic stuff to weird edge cases. Here's the breakdown:
π― Core Functionality Coverage
β Configuration & Initialization
β Basic CRUD Operations
β Soft Delete Mechanics
β Transaction Handling
β Raw Query Execution
β Bulk Operations
β Pagination Logic
β‘ Cache System Tests
β 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
ποΈ Performance & Reliability
β Bulk Operations (100 records < 1 second)
β Parallel Operations Handling
β Race Condition Management
β Transaction Rollbacks
β Memory Management
π¬ Edge Cases & Error Handling
β Invalid JSON Metadata
β Non-existent Records
β Empty Updates
β Cache System Failures
β Transaction Timeouts
π Test Statistics
Total Tests: 58
Pass Rate: 100%
Test Files: 1
Expectations: 103
Total Duration: 5.38s
Average Test Speed: ~93ms
π― Key Test Scenarios
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 |
πͺ Reliability Metrics
- 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.
π Test Environment
- 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:
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.
// Add real-time updates support interface SubscriptionOptions { filter?: Record<string, any>; debounce?: number; batchSize?: number; } public subscribe<T>( callback: (updates: T[]) => void, options?: SubscriptionOptions ): Unsubscribe
Batch Operations with Progress: Batch processing with progress tracking.
// Add batch processing with progress tracking and chunking public async batchProcess<T>( items: T[], operation: (item: T) => Promise<void>, options: { chunkSize?: number; onProgress?: (progress: number) => void; parallel?: boolean; } )
- Smart Cache Prefetching: Cache loading based on user patterns.
// 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.
// Track all changes with detailed metadata interface AuditOptions { user?: string; reason?: string; metadata?: Record<string, any>; trackFields?: string[]; } public async withAudit<T>( operation: () => Promise<T>, auditOptions: AuditOptions ): Promise<T>
Advanced Search Features: Fuzzy search, weights, highlights, language support, and synonyms.
// Enhanced search capabilities interface SearchOptions { fuzzy?: boolean; weights?: Record<string, number>; highlight?: boolean; language?: string; synonyms?: Record<string, string[]>; } public async search<T>( query: string, fields: Array<keyof T>, options?: SearchOptions ): Promise<SearchResult<T>>
Lower Priority (Future Enhancements):
Data Encryption Layer: Field-level encryption for sensitive data.
// Field-level encryption support interface EncryptionOptions { algorithm?: string; fields: string[]; keyRotation?: boolean; } public enableEncryption(options: EncryptionOptions): this public async reEncryptField(field: string): Promise<void>
Smart Data Migration: Easy data migration with validation and rollback.
// Intelligent data migration utilities interface MigrationOptions { batchSize?: number; validation?: boolean; rollback?: boolean; dryRun?: boolean; } public async migrate<T>( transformer: (data: T) => Promise<T>, options?: MigrationOptions ): Promise<MigrationResult>
Versioning Support: Track and revert to previous states of your data.
// Add versioning capabilities to entities interface VersioningOptions { keepVersions?: number; compareFields?: string[]; metadata?: Record<string, any>; } public async createVersion(id: string, options?: VersioningOptions) public async revertToVersion(id: string, version: number)
Performance Analytics: Get insights on query performance and cache efficiency.
// Built-in performance monitoring interface PerformanceMetrics { queryStats: QueryStatistics[]; cacheEfficiency: number; slowQueries: SlowQueryInfo[]; recommendations: string[]; } public async getPerformanceMetrics(): Promise<PerformanceMetrics> 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.
// Read replica configuration interface DatabaseConfig { primary: PrismaClient; replicas?: PrismaClient[]; } class EnhancedRepository<T extends PrismaClientType, Model extends ModelNames<T>> extends BaseRepository<T, Model> { 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.
// Sharding configuration interface ShardConfig { strategy: 'range' | 'hash' | 'directory'; shards: Map<string, PrismaClient>; 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.
// 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.
// 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.
// Retry mechanism configuration interface RetryConfig { maxRetries: number; backoffStrategy: 'exponential' | 'linear'; } class RetryMechanism { constructor(private config: RetryConfig) {} async retry<T>(operation: () => Promise<T>): Promise<T> { // Implement retry logic here } }
Connection Pooling: Manage database connections for better performance.
// Connection pooling configuration interface PoolConfig { min: number; max: number; timeout: number; } class ConnectionPool { constructor(private config: PoolConfig) {} async acquire(): Promise<PrismaClient> { // 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 code-first to Prisma schema generator function generatePrismaSchema(models: any[]): string { // Implement schema generation logic here }
π Contribution
Wanna help? Hereβs how:
- Fork the repo.
- Clone your fork:
git clone https://github.com/alvamind/prisma-abstraction-alvamind.git
- Create a branch:
git checkout -b my-feature
- Make changes: Code, test, repeat.
- Commit:
git commit -m "Add my feature"
- Push:
git push origin my-feature
- 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
π Citation
@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}
}
π Disclaimer
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.
π That's All, Folks!
Go build cool stuff with PrismaStack! Hit us up if you got questions. Peace! βοΈ