import { Prisma, PrismaClient } from '@prisma/client'; class Chunk implements Iterable { protected constructor( private readonly values: readonly T[], private readonly size: number ) {} *[Symbol.iterator]() { const copy = [...this.values]; if (copy.length === 0) yield undefined; while (copy.length) yield copy.splice(0, this.size); } map(mapper: (items?: T[]) => U): U[] { return Array.from(this).map((items) => mapper(items)); } static of(values: readonly U[]) { return { by: (size: number) => new Chunk(values, size) }; } } export type Queryable = ( p: PrismaClient, vs?: T[] ) => Prisma.PrismaPromise; export class BatchPrismaClient { constructor( private readonly prisma: PrismaClient, private readonly size = 32_000 ) {} over(values: readonly T[]) { return { with: (queryable: Queryable) => this.prisma.$transaction( Chunk.of(values) .by(this.size) .map((vs) => queryable(this.prisma, vs)) ) }; } }