From 4cb34bef1dddb19f05214eee8514635ee8c9477a Mon Sep 17 00:00:00 2001 From: nour-aldin Date: Fri, 26 Sep 2025 01:47:11 +0300 Subject: [PATCH] Added prisma methods: - findUniqueOrThrow - findFirstOrThrow - updateManyAndReturn - count - aggregate - groupBy --- .../__tests__/ExposedPrismaRepository.test.ts | 89 ++++++++++++++++++- .../__tests__/PrismaProxy.test.ts | 89 ++++++++++++++++++- .../EncapsulatedPrismaRepository.ts.hbs | 36 ++++++++ .../generator/ExposedPrismaRepository.ts.hbs | 36 ++++++++ .../generator/IPrismaDelegate.ts.hbs | 24 +++++ .../generator/IndexGeneration.ts | 2 +- .../generator/PrismaProxy.ts.hbs | 36 ++++++++ 7 files changed, 307 insertions(+), 5 deletions(-) diff --git a/packages/prisma-generator-vault/src/prisma-generator-vault/__tests__/ExposedPrismaRepository.test.ts b/packages/prisma-generator-vault/src/prisma-generator-vault/__tests__/ExposedPrismaRepository.test.ts index 660035e..dc8cc46 100644 --- a/packages/prisma-generator-vault/src/prisma-generator-vault/__tests__/ExposedPrismaRepository.test.ts +++ b/packages/prisma-generator-vault/src/prisma-generator-vault/__tests__/ExposedPrismaRepository.test.ts @@ -3,17 +3,21 @@ import { ExposedPrismaRepository } from "../../../test/prisma/prisma-vault" class UserPrismaProxy extends ExposedPrismaRepository {} -describe("prisma proxy", () => { +describe("ExposedPrismaRepository", () => { let client: PrismaClient let proxy: UserPrismaProxy - beforeEach(async () => { + beforeAll(async () => { client = new PrismaClient() proxy = new UserPrismaProxy(client.user, client) + }) + + beforeEach(async () => { await proxy.deleteMany({}) }) afterAll(async () => { + await proxy.deleteMany({}) await client.$disconnect() }) @@ -24,4 +28,85 @@ describe("prisma proxy", () => { expect(user?.id).toEqual(record.id) expect(user?.posts).toBeDefined() }) + + it("exposes findUniqueOrThrow - success case", async () => { + const record = await proxy.create({ data: { email: "jane@example.com", firstName: "Jane", lastName: "Doe" } }) + const user = await proxy.findUniqueOrThrow({ where: { id: record.id }, include: { posts: true } }) + expect(user).not.toBeNull() + expect(user.id).toEqual(record.id) + expect(user.email).toEqual("jane@example.com") + expect(user.firstName).toEqual("Jane") + expect(user.lastName).toEqual("Doe") + expect(user.posts).toBeDefined() + }) + + it("exposes findUniqueOrThrow - throws error when record not found", async () => { + const nonExistentId = 999999 + await expect(proxy.findUniqueOrThrow({ where: { id: nonExistentId } })).rejects.toThrow() + }) + + it("exposes findFirstOrThrow - success case", async () => { + const record = await proxy.create({ data: { email: "jane@example.com", firstName: "Jane", lastName: "Doe" } }) + const user = await proxy.findFirstOrThrow({ where: { id: record.id }, include: { posts: true } }) + expect(user).not.toBeNull() + expect(user.id).toEqual(record.id) + expect(user.email).toEqual("jane@example.com") + expect(user.firstName).toEqual("Jane") + expect(user.lastName).toEqual("Doe") + expect(user.posts).toBeDefined() + }) + + it("exposes findFirstOrThrow - throws error when record not found", async () => { + const nonExistentId = 999999 + await expect(proxy.findFirstOrThrow({ where: { id: nonExistentId } })).rejects.toThrow() + }) + + it("exposes updateManyAndReturn", async () => { + await proxy.createManyAndReturn({ + data: [ + { email: "john@example.com", firstName: "John", lastName: "Doe" }, + { email: "max@example.com", firstName: "Max", lastName: "Doe" }, + ], + }) + + const updatedRecords = await proxy.updateManyAndReturn({ + where: { + lastName: "Doe", + }, + data: { + lastName: "Update_Many", + }, + }) + + expect(updatedRecords.every(record => record.lastName === "Update_Many")).toBe(true) + }) + + it("exposes count", async () => { + const record = await proxy.create({ data: { email: "bob@example.com", firstName: "Bob", lastName: "Smith" } }) + + const count = await proxy.count({ + where: { + id: record.id, + }, + }) + + expect(count).toBe(1) + }) + + it("exposes aggregate", async () => { + await proxy.createManyAndReturn({ + data: [ + { email: "john@example.com", firstName: "John", lastName: "Doe" }, + { email: "max@example.com", firstName: "Max", lastName: "Doe" }, + ], + }) + + const clientsAgg = await proxy.aggregate({ + _count: { + id: true, + }, + }) + + expect(clientsAgg._count.id).toBe(2) + }) }) diff --git a/packages/prisma-generator-vault/src/prisma-generator-vault/__tests__/PrismaProxy.test.ts b/packages/prisma-generator-vault/src/prisma-generator-vault/__tests__/PrismaProxy.test.ts index 82f59c1..0408c66 100644 --- a/packages/prisma-generator-vault/src/prisma-generator-vault/__tests__/PrismaProxy.test.ts +++ b/packages/prisma-generator-vault/src/prisma-generator-vault/__tests__/PrismaProxy.test.ts @@ -5,17 +5,21 @@ class UserPrismaProxy extends PrismaProxy {} //class UserRepository extends EncapsulatedRepository<"user"> {} -describe("prisma proxy", () => { +describe("PrismaProxy", () => { let client: PrismaClient let proxy: UserPrismaProxy - beforeEach(async () => { + beforeAll(async () => { client = new PrismaClient() proxy = new UserPrismaProxy(client.user, client) + }) + + beforeEach(async () => { await proxy.deleteMany({}) }) afterAll(async () => { + await proxy.deleteMany({}) await client.$disconnect() }) @@ -25,4 +29,85 @@ describe("prisma proxy", () => { expect(user).not.toBeNull() expect(user?.id).toEqual(record.id) }) + + it("exposes findUniqueOrThrow - success case", async () => { + const record = await proxy.create({ data: { email: "bob@example.com", firstName: "Bob", lastName: "Smith" } }) + const user = await proxy.findUniqueOrThrow({ where: { id: record.id }, include: { posts: true } }) + expect(user).not.toBeNull() + expect(user.id).toEqual(record.id) + expect(user.email).toEqual("bob@example.com") + expect(user.firstName).toEqual("Bob") + expect(user.lastName).toEqual("Smith") + expect(user.posts).toBeDefined() + }) + + it("exposes findUniqueOrThrow - throws error when record not found", async () => { + const nonExistentId = 888888 + await expect(proxy.findUniqueOrThrow({ where: { id: nonExistentId } })).rejects.toThrow() + }) + + it("exposes findFirstOrThrow - success case", async () => { + const record = await proxy.create({ data: { email: "bob@example.com", firstName: "Bob", lastName: "Smith" } }) + const user = await proxy.findFirstOrThrow({ where: { id: record.id }, include: { posts: true } }) + expect(user).not.toBeNull() + expect(user.id).toEqual(record.id) + expect(user.email).toEqual("bob@example.com") + expect(user.firstName).toEqual("Bob") + expect(user.lastName).toEqual("Smith") + expect(user.posts).toBeDefined() + }) + + it("exposes findFirstOrThrow - throws error when record not found", async () => { + const nonExistentId = 888888 + await expect(proxy.findFirstOrThrow({ where: { id: nonExistentId } })).rejects.toThrow() + }) + + it("exposes updateManyAndReturn", async () => { + await proxy.createManyAndReturn({ + data: [ + { email: "john@example.com", firstName: "John", lastName: "Doe" }, + { email: "max@example.com", firstName: "Max", lastName: "Doe" }, + ], + }) + + const updatedRecords = await proxy.updateManyAndReturn({ + where: { + lastName: "Doe", + }, + data: { + lastName: "Update_Many", + }, + }) + + expect(updatedRecords.every(record => record.lastName === "Update_Many")).toBe(true) + }) + + it("exposes count", async () => { + const record = await proxy.create({ data: { email: "bob@example.com", firstName: "Bob", lastName: "Smith" } }) + + const count = await proxy.count({ + where: { + id: record.id, + }, + }) + + expect(count).toBe(1) + }) + + it("exposes aggregate", async () => { + await proxy.createManyAndReturn({ + data: [ + { email: "john@example.com", firstName: "John", lastName: "Doe" }, + { email: "max@example.com", firstName: "Max", lastName: "Doe" }, + ], + }) + + const clientsAgg = await proxy.aggregate({ + _count: { + id: true, + }, + }) + + expect(clientsAgg._count.id).toBe(2) + }) }) diff --git a/packages/prisma-generator-vault/src/prisma-generator-vault/generator/EncapsulatedPrismaRepository.ts.hbs b/packages/prisma-generator-vault/src/prisma-generator-vault/generator/EncapsulatedPrismaRepository.ts.hbs index 2bfb41e..de3db2f 100644 --- a/packages/prisma-generator-vault/src/prisma-generator-vault/generator/EncapsulatedPrismaRepository.ts.hbs +++ b/packages/prisma-generator-vault/src/prisma-generator-vault/generator/EncapsulatedPrismaRepository.ts.hbs @@ -45,6 +45,12 @@ export abstract class EncapsulatedPrismaRepository>( + args: TArgs + ): PrismaPromise> { + return this.prismaProxy.findFirstOrThrow(args) + } + protected findMany>( args: TArgs ): PrismaPromise> { @@ -57,6 +63,12 @@ export abstract class EncapsulatedPrismaRepository>( + args: TArgs + ): PrismaPromise> { + return this.prismaProxy.findUniqueOrThrow(args) + } + protected update>( args: TArgs ): PrismaPromise> { @@ -69,11 +81,35 @@ export abstract class EncapsulatedPrismaRepository>( + args: TArgs + ): PrismaPromise> { + return this.prismaProxy.updateManyAndReturn(args) + } + protected upsert>( args: TArgs ): PrismaPromise> { return this.prismaProxy.upsert(args) } + + protected count>( + args: TArgs + ): PrismaPromise> { + return this.prismaProxy.count(args) + } + + protected aggregate>( + args: TArgs + ): PrismaPromise> { + return this.prismaProxy.aggregate(args) + } + + protected groupBy>( + args: TArgs + ): PrismaPromise> { + return this.prismaProxy.groupBy(args) + } protected $transaction(...args: Parameters) { return this.prismaProxy.$transaction(...args) diff --git a/packages/prisma-generator-vault/src/prisma-generator-vault/generator/ExposedPrismaRepository.ts.hbs b/packages/prisma-generator-vault/src/prisma-generator-vault/generator/ExposedPrismaRepository.ts.hbs index f0d0944..47eebe4 100644 --- a/packages/prisma-generator-vault/src/prisma-generator-vault/generator/ExposedPrismaRepository.ts.hbs +++ b/packages/prisma-generator-vault/src/prisma-generator-vault/generator/ExposedPrismaRepository.ts.hbs @@ -45,6 +45,12 @@ export abstract class ExposedPrismaRepository>( + args: TArgs + ): PrismaPromise> { + return this.prismaProxy.findFirstOrThrow(args) + } + findMany>( args: TArgs ): PrismaPromise> { @@ -57,6 +63,12 @@ export abstract class ExposedPrismaRepository>( + args: TArgs + ): PrismaPromise> { + return this.prismaProxy.findUniqueOrThrow(args) + } + update>( args: TArgs ): PrismaPromise> { @@ -69,11 +81,35 @@ export abstract class ExposedPrismaRepository>( + args: TArgs + ): PrismaPromise> { + return this.prismaProxy.updateManyAndReturn(args) + } + upsert>( args: TArgs ): PrismaPromise> { return this.prismaProxy.upsert(args) } + + count>( + args: TArgs + ): PrismaPromise> { + return this.prismaProxy.count(args) + } + + aggregate>( + args: TArgs + ): PrismaPromise> { + return this.prismaProxy.aggregate(args) + } + + groupBy>( + args: TArgs + ): PrismaPromise> { + return this.prismaProxy.groupBy(args) + } $transaction(...args: Parameters) { return this.prismaProxy.$transaction(...args) diff --git a/packages/prisma-generator-vault/src/prisma-generator-vault/generator/IPrismaDelegate.ts.hbs b/packages/prisma-generator-vault/src/prisma-generator-vault/generator/IPrismaDelegate.ts.hbs index 236f5c9..c411068 100644 --- a/packages/prisma-generator-vault/src/prisma-generator-vault/generator/IPrismaDelegate.ts.hbs +++ b/packages/prisma-generator-vault/src/prisma-generator-vault/generator/IPrismaDelegate.ts.hbs @@ -23,6 +23,10 @@ export interface IPrismaDelegate { args: Prisma.Args ): PrismaPromise, "findFirst">> + findFirstOrThrow( + args: Prisma.Args + ): PrismaPromise, "findFirstOrThrow">> + findMany( args: Prisma.Args ): PrismaPromise, "findMany">> @@ -31,6 +35,10 @@ export interface IPrismaDelegate { args: Prisma.Args ): PrismaPromise, "findUnique">> + findUniqueOrThrow( + args: Prisma.Args + ): PrismaPromise, "findUniqueOrThrow">> + update( args: Prisma.Args ): PrismaPromise, "update">> @@ -38,9 +46,25 @@ export interface IPrismaDelegate { updateMany( args: Prisma.Args ): PrismaPromise, "updateMany">> + + updateManyAndReturn( + args: Prisma.Args + ): PrismaPromise, "updateManyAndReturn">> upsert( args: Prisma.Args ): PrismaPromise, "upsert">> + + count( + args: Prisma.Args + ): PrismaPromise, "count">> + + aggregate( + args: Prisma.Args + ): PrismaPromise, "aggregate">> + + groupBy( + args: Prisma.Args + ): PrismaPromise, "groupBy">> } diff --git a/packages/prisma-generator-vault/src/prisma-generator-vault/generator/IndexGeneration.ts b/packages/prisma-generator-vault/src/prisma-generator-vault/generator/IndexGeneration.ts index a9701c8..0d276ab 100644 --- a/packages/prisma-generator-vault/src/prisma-generator-vault/generator/IndexGeneration.ts +++ b/packages/prisma-generator-vault/src/prisma-generator-vault/generator/IndexGeneration.ts @@ -19,7 +19,7 @@ export class IndexGeneration extends FileGeneration { const { exportAsTypes, exportConstants } = this.fileExportMap[filePath] return `export ${exportAsTypes ? "type " : ""}{ ${exportConstants.join(", ")} } from "./${basename( filePath - ).replace(/\.ts$/, ".js")}"` + ).replace(/\.ts$/, "")}"` }) this.writeFile(exportLines.join("\n")) return [this.fileName] diff --git a/packages/prisma-generator-vault/src/prisma-generator-vault/generator/PrismaProxy.ts.hbs b/packages/prisma-generator-vault/src/prisma-generator-vault/generator/PrismaProxy.ts.hbs index d405cc2..0687e20 100644 --- a/packages/prisma-generator-vault/src/prisma-generator-vault/generator/PrismaProxy.ts.hbs +++ b/packages/prisma-generator-vault/src/prisma-generator-vault/generator/PrismaProxy.ts.hbs @@ -40,6 +40,12 @@ export class PrismaProxy> { return this.model.findFirst(args) } + findFirstOrThrow>( + args: TArgs + ): PrismaPromise> { + return this.model.findFirstOrThrow(args) + } + findMany>( args: TArgs ): PrismaPromise> { @@ -52,6 +58,12 @@ export class PrismaProxy> { return this.model.findUnique(args) } + findUniqueOrThrow>( + args: TArgs + ): PrismaPromise> { + return this.model.findUniqueOrThrow(args) + } + update>( args: TArgs ): PrismaPromise> { @@ -64,12 +76,36 @@ export class PrismaProxy> { return this.model.updateMany(args) } + updateManyAndReturn>( + args: TArgs + ): PrismaPromise> { + return this.model.updateManyAndReturn(args) + } + upsert>( args: TArgs ): PrismaPromise> { return this.model.upsert(args) } + count>( + args: TArgs + ): PrismaPromise> { + return this.model.count(args) + } + + aggregate>( + args: TArgs + ): PrismaPromise> { + return this.model.aggregate(args) + } + + groupBy>( + args: TArgs + ): PrismaPromise> { + return this.model.groupBy(args) + } + $transaction(...args: Parameters) { return this.prismaClient.$transaction(...args) }