@hazeljs/prisma 0.2.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,576 @@
1
+ # @hazeljs/prisma
2
+
3
+ **Prisma ORM Integration for HazelJS**
4
+
5
+ First-class Prisma support with repository pattern, automatic migrations, and type-safe database access.
6
+
7
+ [![npm version](https://img.shields.io/npm/v/@hazeljs/prisma.svg)](https://www.npmjs.com/package/@hazeljs/prisma)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
+
10
+ ## Features
11
+
12
+ - ๐ŸŽฏ **Type-Safe Queries** - Full TypeScript support with Prisma
13
+ - ๐Ÿ—๏ธ **Repository Pattern** - Clean data access layer
14
+ - ๐ŸŽจ **Decorator Support** - `@PrismaModel` decorator
15
+ - ๐Ÿ”„ **Transaction Support** - Built-in transaction management
16
+ - ๐Ÿ“Š **Query Builder** - Fluent query interface
17
+ - ๐Ÿ”Œ **Dependency Injection** - Seamless DI integration
18
+ - ๐Ÿงช **Testing Utilities** - Mock Prisma for testing
19
+ - ๐Ÿ“ˆ **Connection Pooling** - Automatic connection management
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install @hazeljs/prisma @prisma/client
25
+ npm install -D prisma
26
+ ```
27
+
28
+ ## Quick Start
29
+
30
+ ### 1. Initialize Prisma
31
+
32
+ ```bash
33
+ npx prisma init
34
+ ```
35
+
36
+ ### 2. Define Schema
37
+
38
+ ```prisma
39
+ // prisma/schema.prisma
40
+ generator client {
41
+ provider = "prisma-client-js"
42
+ }
43
+
44
+ datasource db {
45
+ provider = "postgresql"
46
+ url = env("DATABASE_URL")
47
+ }
48
+
49
+ model User {
50
+ id String @id @default(uuid())
51
+ email String @unique
52
+ name String
53
+ posts Post[]
54
+ createdAt DateTime @default(now())
55
+ updatedAt DateTime @updatedAt
56
+ }
57
+
58
+ model Post {
59
+ id String @id @default(uuid())
60
+ title String
61
+ content String?
62
+ published Boolean @default(false)
63
+ authorId String
64
+ author User @relation(fields: [authorId], references: [id])
65
+ createdAt DateTime @default(now())
66
+ updatedAt DateTime @updatedAt
67
+ }
68
+ ```
69
+
70
+ ### 3. Generate Prisma Client
71
+
72
+ ```bash
73
+ npx prisma generate
74
+ npx prisma migrate dev --name init
75
+ ```
76
+
77
+ ### 4. Configure Module
78
+
79
+ ```typescript
80
+ import { HazelModule } from '@hazeljs/core';
81
+ import { PrismaModule } from '@hazeljs/prisma';
82
+
83
+ @HazelModule({
84
+ imports: [
85
+ PrismaModule.forRoot({
86
+ connectionString: process.env.DATABASE_URL,
87
+ }),
88
+ ],
89
+ })
90
+ export class AppModule {}
91
+ ```
92
+
93
+ ### 5. Create Repository
94
+
95
+ ```typescript
96
+ import { Injectable } from '@hazeljs/core';
97
+ import { PrismaService, BaseRepository, PrismaModel } from '@hazeljs/prisma';
98
+
99
+ @Injectable()
100
+ @PrismaModel('User')
101
+ export class UserRepository extends BaseRepository {
102
+ constructor(prisma: PrismaService) {
103
+ super(prisma);
104
+ }
105
+
106
+ // Custom methods
107
+ async findByEmail(email: string) {
108
+ return this.prisma.user.findUnique({ where: { email } });
109
+ }
110
+
111
+ async findWithPosts(id: string) {
112
+ return this.prisma.user.findUnique({
113
+ where: { id },
114
+ include: { posts: true },
115
+ });
116
+ }
117
+ }
118
+ ```
119
+
120
+ ### 6. Use in Service
121
+
122
+ ```typescript
123
+ import { Injectable } from '@hazeljs/core';
124
+
125
+ @Injectable()
126
+ export class UserService {
127
+ constructor(private userRepository: UserRepository) {}
128
+
129
+ async create(data: { email: string; name: string }) {
130
+ return this.userRepository.create({ data });
131
+ }
132
+
133
+ async findAll() {
134
+ return this.userRepository.findMany();
135
+ }
136
+
137
+ async findOne(id: string) {
138
+ return this.userRepository.findUnique({ where: { id } });
139
+ }
140
+
141
+ async update(id: string, data: any) {
142
+ return this.userRepository.update({
143
+ where: { id },
144
+ data,
145
+ });
146
+ }
147
+
148
+ async delete(id: string) {
149
+ return this.userRepository.delete({ where: { id } });
150
+ }
151
+ }
152
+ ```
153
+
154
+ ## Base Repository
155
+
156
+ The `BaseRepository` provides common CRUD operations:
157
+
158
+ ```typescript
159
+ class BaseRepository {
160
+ // Create
161
+ create(args: Prisma.UserCreateArgs): Promise<User>;
162
+ createMany(args: Prisma.UserCreateManyArgs): Promise<Prisma.BatchPayload>;
163
+
164
+ // Read
165
+ findUnique(args: Prisma.UserFindUniqueArgs): Promise<User | null>;
166
+ findFirst(args: Prisma.UserFindFirstArgs): Promise<User | null>;
167
+ findMany(args?: Prisma.UserFindManyArgs): Promise<User[]>;
168
+ count(args?: Prisma.UserCountArgs): Promise<number>;
169
+
170
+ // Update
171
+ update(args: Prisma.UserUpdateArgs): Promise<User>;
172
+ updateMany(args: Prisma.UserUpdateManyArgs): Promise<Prisma.BatchPayload>;
173
+ upsert(args: Prisma.UserUpsertArgs): Promise<User>;
174
+
175
+ // Delete
176
+ delete(args: Prisma.UserDeleteArgs): Promise<User>;
177
+ deleteMany(args?: Prisma.UserDeleteManyArgs): Promise<Prisma.BatchPayload>;
178
+ }
179
+ ```
180
+
181
+ ## Transactions
182
+
183
+ ### Using PrismaService
184
+
185
+ ```typescript
186
+ @Injectable()
187
+ export class TransferService {
188
+ constructor(private prisma: PrismaService) {}
189
+
190
+ async transfer(fromId: string, toId: string, amount: number) {
191
+ return this.prisma.$transaction(async (tx) => {
192
+ // Deduct from sender
193
+ await tx.account.update({
194
+ where: { id: fromId },
195
+ data: { balance: { decrement: amount } },
196
+ });
197
+
198
+ // Add to receiver
199
+ await tx.account.update({
200
+ where: { id: toId },
201
+ data: { balance: { increment: amount } },
202
+ });
203
+
204
+ // Create transaction record
205
+ return tx.transaction.create({
206
+ data: { fromId, toId, amount },
207
+ });
208
+ });
209
+ }
210
+ }
211
+ ```
212
+
213
+ ### Using Repository
214
+
215
+ ```typescript
216
+ @Injectable()
217
+ export class OrderService {
218
+ constructor(
219
+ private orderRepository: OrderRepository,
220
+ private inventoryRepository: InventoryRepository,
221
+ private prisma: PrismaService
222
+ ) {}
223
+
224
+ async createOrder(userId: string, items: OrderItem[]) {
225
+ return this.prisma.$transaction(async (tx) => {
226
+ // Create order
227
+ const order = await tx.order.create({
228
+ data: {
229
+ userId,
230
+ items: { create: items },
231
+ },
232
+ });
233
+
234
+ // Update inventory
235
+ for (const item of items) {
236
+ await tx.inventory.update({
237
+ where: { productId: item.productId },
238
+ data: { quantity: { decrement: item.quantity } },
239
+ });
240
+ }
241
+
242
+ return order;
243
+ });
244
+ }
245
+ }
246
+ ```
247
+
248
+ ## Advanced Queries
249
+
250
+ ### Relations
251
+
252
+ ```typescript
253
+ @Injectable()
254
+ export class UserRepository extends BaseRepository {
255
+ async findWithRelations(id: string) {
256
+ return this.prisma.user.findUnique({
257
+ where: { id },
258
+ include: {
259
+ posts: {
260
+ where: { published: true },
261
+ orderBy: { createdAt: 'desc' },
262
+ },
263
+ profile: true,
264
+ },
265
+ });
266
+ }
267
+ }
268
+ ```
269
+
270
+ ### Pagination
271
+
272
+ ```typescript
273
+ @Injectable()
274
+ export class PostRepository extends BaseRepository {
275
+ async findPaginated(page: number, limit: number) {
276
+ const skip = (page - 1) * limit;
277
+
278
+ const [posts, total] = await Promise.all([
279
+ this.prisma.post.findMany({
280
+ skip,
281
+ take: limit,
282
+ orderBy: { createdAt: 'desc' },
283
+ }),
284
+ this.prisma.post.count(),
285
+ ]);
286
+
287
+ return {
288
+ data: posts,
289
+ meta: {
290
+ page,
291
+ limit,
292
+ total,
293
+ totalPages: Math.ceil(total / limit),
294
+ },
295
+ };
296
+ }
297
+ }
298
+ ```
299
+
300
+ ### Filtering
301
+
302
+ ```typescript
303
+ @Injectable()
304
+ export class ProductRepository extends BaseRepository {
305
+ async search(query: string, filters: {
306
+ category?: string;
307
+ minPrice?: number;
308
+ maxPrice?: number;
309
+ inStock?: boolean;
310
+ }) {
311
+ return this.prisma.product.findMany({
312
+ where: {
313
+ AND: [
314
+ {
315
+ OR: [
316
+ { name: { contains: query, mode: 'insensitive' } },
317
+ { description: { contains: query, mode: 'insensitive' } },
318
+ ],
319
+ },
320
+ filters.category ? { category: filters.category } : {},
321
+ filters.minPrice ? { price: { gte: filters.minPrice } } : {},
322
+ filters.maxPrice ? { price: { lte: filters.maxPrice } } : {},
323
+ filters.inStock ? { stock: { gt: 0 } } : {},
324
+ ],
325
+ },
326
+ });
327
+ }
328
+ }
329
+ ```
330
+
331
+ ### Aggregations
332
+
333
+ ```typescript
334
+ @Injectable()
335
+ export class AnalyticsRepository {
336
+ constructor(private prisma: PrismaService) {}
337
+
338
+ async getOrderStats() {
339
+ return this.prisma.order.aggregate({
340
+ _sum: { total: true },
341
+ _avg: { total: true },
342
+ _count: true,
343
+ _max: { total: true },
344
+ _min: { total: true },
345
+ });
346
+ }
347
+
348
+ async getRevenueByMonth() {
349
+ return this.prisma.$queryRaw`
350
+ SELECT
351
+ DATE_TRUNC('month', "createdAt") as month,
352
+ SUM(total) as revenue,
353
+ COUNT(*) as orders
354
+ FROM "Order"
355
+ GROUP BY month
356
+ ORDER BY month DESC
357
+ `;
358
+ }
359
+ }
360
+ ```
361
+
362
+ ## Middleware
363
+
364
+ Add Prisma middleware for logging, soft deletes, etc:
365
+
366
+ ```typescript
367
+ @Injectable()
368
+ export class PrismaService extends PrismaClient {
369
+ constructor() {
370
+ super();
371
+
372
+ // Logging middleware
373
+ this.$use(async (params, next) => {
374
+ const before = Date.now();
375
+ const result = await next(params);
376
+ const after = Date.now();
377
+
378
+ console.log(`Query ${params.model}.${params.action} took ${after - before}ms`);
379
+ return result;
380
+ });
381
+
382
+ // Soft delete middleware
383
+ this.$use(async (params, next) => {
384
+ if (params.action === 'delete') {
385
+ params.action = 'update';
386
+ params.args['data'] = { deletedAt: new Date() };
387
+ }
388
+
389
+ if (params.action === 'deleteMany') {
390
+ params.action = 'updateMany';
391
+ if (params.args.data != undefined) {
392
+ params.args.data['deletedAt'] = new Date();
393
+ } else {
394
+ params.args['data'] = { deletedAt: new Date() };
395
+ }
396
+ }
397
+
398
+ return next(params);
399
+ });
400
+ }
401
+ }
402
+ ```
403
+
404
+ ## Seeding
405
+
406
+ ```typescript
407
+ // prisma/seed.ts
408
+ import { PrismaClient } from '@prisma/client';
409
+
410
+ const prisma = new PrismaClient();
411
+
412
+ async function main() {
413
+ // Create users
414
+ const alice = await prisma.user.create({
415
+ data: {
416
+ email: 'alice@example.com',
417
+ name: 'Alice',
418
+ posts: {
419
+ create: [
420
+ {
421
+ title: 'First Post',
422
+ content: 'Hello World!',
423
+ published: true,
424
+ },
425
+ ],
426
+ },
427
+ },
428
+ });
429
+
430
+ const bob = await prisma.user.create({
431
+ data: {
432
+ email: 'bob@example.com',
433
+ name: 'Bob',
434
+ },
435
+ });
436
+
437
+ console.log({ alice, bob });
438
+ }
439
+
440
+ main()
441
+ .catch((e) => {
442
+ console.error(e);
443
+ process.exit(1);
444
+ })
445
+ .finally(async () => {
446
+ await prisma.$disconnect();
447
+ });
448
+ ```
449
+
450
+ Add to `package.json`:
451
+
452
+ ```json
453
+ {
454
+ "prisma": {
455
+ "seed": "ts-node prisma/seed.ts"
456
+ }
457
+ }
458
+ ```
459
+
460
+ Run seed:
461
+
462
+ ```bash
463
+ npx prisma db seed
464
+ ```
465
+
466
+ ## Testing
467
+
468
+ ### Mock Prisma Service
469
+
470
+ ```typescript
471
+ import { TestingModule } from '@hazeljs/core';
472
+ import { UserService } from './user.service';
473
+ import { UserRepository } from './user.repository';
474
+
475
+ describe('UserService', () => {
476
+ let service: UserService;
477
+ let repository: UserRepository;
478
+
479
+ const mockPrisma = {
480
+ user: {
481
+ create: jest.fn(),
482
+ findMany: jest.fn(),
483
+ findUnique: jest.fn(),
484
+ update: jest.fn(),
485
+ delete: jest.fn(),
486
+ },
487
+ };
488
+
489
+ beforeEach(async () => {
490
+ const module = await TestingModule.create({
491
+ providers: [
492
+ UserService,
493
+ {
494
+ provide: UserRepository,
495
+ useValue: {
496
+ create: mockPrisma.user.create,
497
+ findMany: mockPrisma.user.findMany,
498
+ findUnique: mockPrisma.user.findUnique,
499
+ update: mockPrisma.user.update,
500
+ delete: mockPrisma.user.delete,
501
+ },
502
+ },
503
+ ],
504
+ });
505
+
506
+ service = module.get(UserService);
507
+ repository = module.get(UserRepository);
508
+ });
509
+
510
+ it('should create a user', async () => {
511
+ const userData = { email: 'test@example.com', name: 'Test' };
512
+ mockPrisma.user.create.mockResolvedValue({ id: '1', ...userData });
513
+
514
+ const result = await service.create(userData);
515
+
516
+ expect(result).toEqual({ id: '1', ...userData });
517
+ expect(mockPrisma.user.create).toHaveBeenCalledWith({ data: userData });
518
+ });
519
+ });
520
+ ```
521
+
522
+ ## Best Practices
523
+
524
+ 1. **Use Repositories** - Encapsulate data access logic
525
+ 2. **Type Safety** - Leverage Prisma's generated types
526
+ 3. **Transactions** - Use transactions for related operations
527
+ 4. **Indexes** - Add indexes for frequently queried fields
528
+ 5. **Migrations** - Always use migrations, never modify schema directly
529
+ 6. **Connection Pooling** - Configure appropriate pool size
530
+ 7. **Error Handling** - Handle Prisma errors gracefully
531
+ 8. **Soft Deletes** - Implement soft deletes with middleware
532
+
533
+ ## Migration Commands
534
+
535
+ ```bash
536
+ # Create migration
537
+ npx prisma migrate dev --name add_user_role
538
+
539
+ # Apply migrations
540
+ npx prisma migrate deploy
541
+
542
+ # Reset database
543
+ npx prisma migrate reset
544
+
545
+ # Generate client
546
+ npx prisma generate
547
+
548
+ # Open Prisma Studio
549
+ npx prisma studio
550
+ ```
551
+
552
+ ## Examples
553
+
554
+ See the [examples](../../example/src/prisma) directory for complete working examples.
555
+
556
+ ## Testing
557
+
558
+ ```bash
559
+ npm test
560
+ ```
561
+
562
+ ## Contributing
563
+
564
+ Contributions are welcome! Please read our [Contributing Guide](../../CONTRIBUTING.md) for details.
565
+
566
+ ## License
567
+
568
+ MIT ยฉ [HazelJS](https://hazeljs.com)
569
+
570
+ ## Links
571
+
572
+ - [Documentation](https://hazeljs.com/docs/packages/prisma)
573
+ - [Prisma Docs](https://www.prisma.io/docs)
574
+ - [GitHub](https://github.com/hazel-js/hazeljs)
575
+ - [Issues](https://github.com/hazeljs/hazel-js/issues)
576
+ - [Discord](https://discord.gg/hazeljs)
@@ -0,0 +1,45 @@
1
+ import { PrismaService } from './prisma.service';
2
+ export type PrismaModel = {
3
+ id: number;
4
+ [key: string]: unknown;
5
+ };
6
+ export type WhereUniqueInput = {
7
+ id?: number;
8
+ [key: string]: unknown;
9
+ };
10
+ export type UpdateInput = {
11
+ [key: string]: unknown;
12
+ };
13
+ type PrismaModelDelegate = {
14
+ findMany: () => Promise<unknown[]>;
15
+ findUnique: (args: {
16
+ where: WhereUniqueInput;
17
+ }) => Promise<unknown | null>;
18
+ create: (args: {
19
+ data: unknown;
20
+ }) => Promise<unknown>;
21
+ update: (args: {
22
+ where: WhereUniqueInput;
23
+ data: UpdateInput;
24
+ }) => Promise<unknown>;
25
+ delete: (args: {
26
+ where: WhereUniqueInput;
27
+ }) => Promise<unknown>;
28
+ count: (args?: unknown) => Promise<number>;
29
+ };
30
+ export declare abstract class BaseRepository<T extends PrismaModel> {
31
+ protected readonly prisma: PrismaService;
32
+ protected readonly model: string;
33
+ constructor(prisma: PrismaService, model: string);
34
+ protected get prismaClient(): PrismaService;
35
+ protected get modelDelegate(): PrismaModelDelegate;
36
+ protected handleError(error: unknown): never;
37
+ findMany(): Promise<T[]>;
38
+ findOne(where: WhereUniqueInput): Promise<T | null>;
39
+ create(data: Omit<T, 'id'>): Promise<T>;
40
+ update(where: WhereUniqueInput, data: UpdateInput): Promise<T>;
41
+ delete(where: WhereUniqueInput): Promise<T>;
42
+ count(args?: unknown): Promise<number>;
43
+ }
44
+ export {};
45
+ //# sourceMappingURL=base.repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.repository.d.ts","sourceRoot":"","sources":["../src/base.repository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAKjD,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,QAAQ,EAAE,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACnC,UAAU,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,gBAAgB,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAC3E,MAAM,EAAE,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD,MAAM,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,gBAAgB,CAAC;QAAC,IAAI,EAAE,WAAW,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACnF,MAAM,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,gBAAgB,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAChE,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC5C,CAAC;AAEF,8BACsB,cAAc,CAAC,CAAC,SAAS,WAAW;IAItD,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,aAAa;IAH1C,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBAGZ,MAAM,EAAE,aAAa,EACxC,KAAK,EAAE,MAAM;IAKf,SAAS,KAAK,YAAY,IAAI,aAAa,CAE1C;IAED,SAAS,KAAK,aAAa,IAAI,mBAAmB,CAEjD;IAED,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK;IA4BtC,QAAQ,IAAI,OAAO,CAAC,CAAC,EAAE,CAAC;IAKxB,OAAO,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAKnD,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAKvC,MAAM,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC;IAK9D,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,CAAC,CAAC;IAK3C,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;CAG7C"}
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.BaseRepository = void 0;
16
+ const core_1 = require("@hazeljs/core");
17
+ const prisma_service_1 = require("./prisma.service");
18
+ const library_1 = require("@prisma/client/runtime/library");
19
+ const core_2 = __importDefault(require("@hazeljs/core"));
20
+ let BaseRepository = class BaseRepository {
21
+ constructor(prisma, model) {
22
+ this.prisma = prisma;
23
+ this.model = model;
24
+ }
25
+ get prismaClient() {
26
+ return this.prisma;
27
+ }
28
+ get modelDelegate() {
29
+ return this.prismaClient[this.model];
30
+ }
31
+ handleError(error) {
32
+ core_2.default.error('Database error:', error);
33
+ if (error instanceof library_1.PrismaClientKnownRequestError) {
34
+ let errorMessage;
35
+ let target;
36
+ switch (error.code) {
37
+ case 'P2002':
38
+ target = error.meta?.target;
39
+ errorMessage = `Unique constraint violation on field${target ? `s: ${target.join(', ')}` : ''}`;
40
+ break;
41
+ case 'P2025':
42
+ errorMessage = 'Record not found';
43
+ break;
44
+ case 'P2003':
45
+ errorMessage = 'Foreign key constraint violation';
46
+ break;
47
+ default:
48
+ errorMessage = `Database error: ${error.message}`;
49
+ }
50
+ throw new Error(errorMessage);
51
+ }
52
+ throw new Error(`Database error: ${error.message}`);
53
+ }
54
+ async findMany() {
55
+ const result = await this.modelDelegate.findMany();
56
+ return result;
57
+ }
58
+ async findOne(where) {
59
+ const result = await this.modelDelegate.findUnique({ where });
60
+ return result;
61
+ }
62
+ async create(data) {
63
+ const result = await this.modelDelegate.create({ data });
64
+ return result;
65
+ }
66
+ async update(where, data) {
67
+ const result = await this.modelDelegate.update({ where, data });
68
+ return result;
69
+ }
70
+ async delete(where) {
71
+ const result = await this.modelDelegate.delete({ where });
72
+ return result;
73
+ }
74
+ async count(args) {
75
+ return this.modelDelegate.count(args);
76
+ }
77
+ };
78
+ exports.BaseRepository = BaseRepository;
79
+ exports.BaseRepository = BaseRepository = __decorate([
80
+ (0, core_1.Injectable)(),
81
+ __metadata("design:paramtypes", [prisma_service_1.PrismaService, String])
82
+ ], BaseRepository);
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @hazeljs/prisma - Prisma integration for HazelJS
3
+ */
4
+ export { PrismaModule } from './prisma.module';
5
+ export { PrismaService } from './prisma.service';
6
+ export { BaseRepository, type PrismaModel, type WhereUniqueInput, type UpdateInput, } from './base.repository';
7
+ export { Repository } from './repository.decorator';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EACL,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,WAAW,GACjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ /**
3
+ * @hazeljs/prisma - Prisma integration for HazelJS
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Repository = exports.BaseRepository = exports.PrismaService = exports.PrismaModule = void 0;
7
+ var prisma_module_1 = require("./prisma.module");
8
+ Object.defineProperty(exports, "PrismaModule", { enumerable: true, get: function () { return prisma_module_1.PrismaModule; } });
9
+ var prisma_service_1 = require("./prisma.service");
10
+ Object.defineProperty(exports, "PrismaService", { enumerable: true, get: function () { return prisma_service_1.PrismaService; } });
11
+ var base_repository_1 = require("./base.repository");
12
+ Object.defineProperty(exports, "BaseRepository", { enumerable: true, get: function () { return base_repository_1.BaseRepository; } });
13
+ var repository_decorator_1 = require("./repository.decorator");
14
+ Object.defineProperty(exports, "Repository", { enumerable: true, get: function () { return repository_decorator_1.Repository; } });
@@ -0,0 +1,3 @@
1
+ export declare class PrismaModule {
2
+ }
3
+ //# sourceMappingURL=prisma.module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma.module.d.ts","sourceRoot":"","sources":["../src/prisma.module.ts"],"names":[],"mappings":"AAGA,qBAIa,YAAY;CAAG"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.PrismaModule = void 0;
10
+ const core_1 = require("@hazeljs/core");
11
+ const prisma_service_1 = require("./prisma.service");
12
+ let PrismaModule = class PrismaModule {
13
+ };
14
+ exports.PrismaModule = PrismaModule;
15
+ exports.PrismaModule = PrismaModule = __decorate([
16
+ (0, core_1.Module)({
17
+ providers: [prisma_service_1.PrismaService],
18
+ exports: [prisma_service_1.PrismaService],
19
+ })
20
+ ], PrismaModule);
@@ -0,0 +1,7 @@
1
+ import { PrismaClient } from '@prisma/client';
2
+ export declare class PrismaService extends PrismaClient {
3
+ constructor();
4
+ onModuleInit(): Promise<void>;
5
+ onModuleDestroy(): Promise<void>;
6
+ }
7
+ //# sourceMappingURL=prisma.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma.service.d.ts","sourceRoot":"","sources":["../src/prisma.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAwB9C,qBACa,aAAc,SAAQ,YAAY;;IAoCvC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAU7B,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;CASvC"}
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.PrismaService = void 0;
16
+ const core_1 = require("@hazeljs/core");
17
+ const client_1 = require("@prisma/client");
18
+ const core_2 = __importDefault(require("@hazeljs/core"));
19
+ function isQueryEvent(event) {
20
+ return 'query' in event && 'params' in event && 'duration' in event;
21
+ }
22
+ function isErrorEvent(event) {
23
+ return 'message' in event;
24
+ }
25
+ let PrismaService = class PrismaService extends client_1.PrismaClient {
26
+ constructor() {
27
+ super({
28
+ log: [
29
+ {
30
+ emit: 'event',
31
+ level: 'query',
32
+ },
33
+ {
34
+ emit: 'event',
35
+ level: 'error',
36
+ },
37
+ ],
38
+ });
39
+ this.$on('query', (e) => {
40
+ if (isQueryEvent(e)) {
41
+ core_2.default.debug(`Query: ${e.query}`);
42
+ core_2.default.debug(`Params: ${e.params}`);
43
+ core_2.default.debug(`Duration: ${e.duration}ms`);
44
+ }
45
+ });
46
+ this.$on('error', (e) => {
47
+ if (isErrorEvent(e)) {
48
+ core_2.default.error('Prisma Error:', e);
49
+ }
50
+ });
51
+ }
52
+ async onModuleInit() {
53
+ try {
54
+ await this.$connect();
55
+ core_2.default.info('Connected to database');
56
+ }
57
+ catch (error) {
58
+ core_2.default.error('Failed to connect to database:', error);
59
+ throw error;
60
+ }
61
+ }
62
+ async onModuleDestroy() {
63
+ try {
64
+ await this.$disconnect();
65
+ core_2.default.info('Disconnected from database');
66
+ }
67
+ catch (error) {
68
+ core_2.default.error('Error disconnecting from database:', error);
69
+ throw error;
70
+ }
71
+ }
72
+ };
73
+ exports.PrismaService = PrismaService;
74
+ exports.PrismaService = PrismaService = __decorate([
75
+ (0, core_1.Injectable)(),
76
+ __metadata("design:paramtypes", [])
77
+ ], PrismaService);
@@ -0,0 +1,5 @@
1
+ import { RepositoryOptions } from '@hazeljs/core';
2
+ import 'reflect-metadata';
3
+ export declare function Repository(options: RepositoryOptions): ClassDecorator;
4
+ export declare function InjectRepository(): ParameterDecorator;
5
+ //# sourceMappingURL=repository.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.decorator.d.ts","sourceRoot":"","sources":["../src/repository.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,kBAAkB,CAAC;AAE1B,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,cAAc,CAIrE;AAED,wBAAgB,gBAAgB,IAAI,kBAAkB,CA0BrD"}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Repository = Repository;
4
+ exports.InjectRepository = InjectRepository;
5
+ require("reflect-metadata");
6
+ function Repository(options) {
7
+ return function (target) {
8
+ Reflect.defineMetadata('hazel:repository', options, target);
9
+ };
10
+ }
11
+ function InjectRepository() {
12
+ return function (target, propertyKey, parameterIndex) {
13
+ if (!propertyKey) {
14
+ throw new Error('InjectRepository decorator must be used on a method parameter');
15
+ }
16
+ const repositoryType = Reflect.getMetadata('design:paramtypes', target, propertyKey)[parameterIndex];
17
+ const model = Reflect.getMetadata('hazel:repository:model', repositoryType);
18
+ if (!model) {
19
+ throw new Error(`Repository ${repositoryType.name} is not decorated with @Repository`);
20
+ }
21
+ const repositories = Reflect.getMetadata('hazel:repositories', target) || [];
22
+ repositories.push({
23
+ index: parameterIndex,
24
+ model,
25
+ });
26
+ Reflect.defineMetadata('hazel:repositories', repositories, target);
27
+ };
28
+ }
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@hazeljs/prisma",
3
+ "version": "0.2.0-beta.1",
4
+ "description": "Prisma ORM integration for HazelJS framework",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "test": "jest --coverage --passWithNoTests",
13
+ "lint": "eslint \"src/**/*.ts\"",
14
+ "lint:fix": "eslint \"src/**/*.ts\" --fix",
15
+ "clean": "rm -rf dist"
16
+ },
17
+ "dependencies": {
18
+ "@hazeljs/core": "file:../core",
19
+ "@prisma/client": "^6.8.2"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "^20.17.50",
23
+ "@typescript-eslint/eslint-plugin": "^8.18.2",
24
+ "@typescript-eslint/parser": "^8.18.2",
25
+ "eslint": "^8.56.0",
26
+ "jest": "^29.7.0",
27
+ "prisma": "^6.8.2",
28
+ "ts-jest": "^29.1.2",
29
+ "typescript": "^5.3.3"
30
+ },
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/hazel-js/hazeljs.git",
37
+ "directory": "packages/prisma"
38
+ },
39
+ "keywords": [
40
+ "hazeljs",
41
+ "prisma",
42
+ "orm",
43
+ "database"
44
+ ],
45
+ "author": "Muhammad Arslan <marslan@hazeljs.com>",
46
+ "license": "MIT"
47
+ }