UNPKG

@surv-co/prisma-typeorm-db-utils

Version:

Transform Prisma schemas to TypeORM entities with NestJS integration and fast pg-mem testing

429 lines (340 loc) โ€ข 12.5 kB
# @surv-co/prisma-typeorm-db-utils **Transform Prisma schemas to TypeORM datasources with NestJS integration and testing support.** [![npm version](https://badge.fury.io/js/%40surv-co%2Fprisma-typeorm-db-utils.svg)](https://www.npmjs.com/package/@surv-co/prisma-typeorm-db-utils) [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/) ## Why use this library? - ๐Ÿ”„ **Prisma Schema โ†’ TypeORM Datasource** - Complete transformation in one step - ๐Ÿงช **Fast pg-mem testing** - In-memory PostgreSQL for lightning-fast tests - ๐Ÿ—๏ธ **Ready-to-use NestJS modules** - Drop-in TypeORM and repository integration for both testing (pg-mem) and production (PostgreSQL) - ๐ŸŽฏ **Type-safe throughout** - Full TypeScript support with proper error handling - ๐Ÿ“ฆ **Simple API** - Just a few imports to get everything working ## Core Features ### 1. **Complete Testing Setup (pg-mem)** - Schema to TypeORM Datasource Transform your Prisma schema directly into a working TypeORM datasource with pg-mem database: ```typescript import { createPrismaToPgMemTypeormDatasourceGenerator } from '@surv-co/prisma-typeorm-db-utils'; // Your Prisma schema const schema = ` model User { id String @id @default(uuid()) email String @unique name String? posts Post[] } model Post { id String @id @default(uuid()) title String content String? authorId String author User @relation(fields: [authorId], references: [id]) } `; // Generate complete TypeORM datasource const generator = createPrismaToPgMemTypeormDatasourceGenerator(); const result = await generator.generateDatasource({ schema, entities: [User, Post] // Your TypeORM entity classes }); if (result._tag === 'Right') { const { datasource } = result.right; // Use datasource for testing - fully configured with pg-mem database const userRepository = datasource.getRepository(User); const newUser = await userRepository.save({ email: 'test@example.com' }); } ``` ### 2. **NestJS DataSource Integration (pg-mem)** - Injectable TYPEORM_DATASOURCE Automatically provides a TypeORM datasource with pg-mem for fast testing: ```typescript import { Module } from '@nestjs/common'; import { TypeORMPgMemModule } from '@surv-co/prisma-typeorm-db-utils'; import { User, Post } from './entities'; @Module({ imports: [ TypeORMPgMemModule.forRoot({ entities: [User, Post], prismaSchema: ` model User { id String @id @default(uuid()) email String @unique name String? posts Post[] } model Post { id String @id @default(uuid()) title String content String? authorId String author User @relation(fields: [authorId], references: [id]) } ` }), // Other modules can now inject TYPEORM_DATASOURCE ], }) export class AppModule {} ``` > **Note:** The `synchronize` option is not supported for pg-mem. The schema is always created from the provided `prismaSchema`. --- ### 3. **Production/PostgreSQL Integration** - Real PostgreSQL Datasource Use the `TypeORMPostgresModule` to connect to a real PostgreSQL database in production or staging environments: ```typescript import { Module } from '@nestjs/common'; import { TypeORMPostgresModule } from '@surv-co/prisma-typeorm-db-utils'; import { User, Post } from './entities'; @Module({ imports: [ TypeORMPostgresModule.forRoot({ entities: [User, Post], host: 'localhost', port: 5432, username: 'postgres', password: 'password', database: 'mydb', // synchronize: false, // Not supported! See note below logging: false, ssl: false // or provide SSL config for production }), // Other modules can now inject TYPEORM_DATASOURCE ], }) export class AppModule {} ``` - **Entities**: Register your TypeORM entity classes - **Connection**: Provide all PostgreSQL connection details - **SSL/Logging**: Configure as needed for your environment > **Important:** The `synchronize` option is **not supported** for the real PostgreSQL datasource. You must run your database migrations before using the datasource. This module does not auto-sync or create the schema in PostgreSQL. --- ### 4. **Repository Factory Function** - createTypeORMRepositoryFactory Create repository operations from any TypeORM datasource: ```typescript import { createPrismaToPgMemTypeormDatasourceGenerator, createTypeORMRepositoryFactory } from '@surv-co/prisma-typeorm-db-utils'; import { Entity, PrimaryColumn, Column } from 'typeorm'; @Entity() class User { @PrimaryColumn('uuid') id: string; @Column('varchar') email: string; @Column('varchar', { nullable: true }) name: string; } const schema = ` model User { id String @id @default(uuid()) email String @unique name String? } `; // Complete setup in one step const generator = createPrismaToPgMemTypeormDatasourceGenerator(); const result = await generator.generateDatasource({ schema, entities: [User] }); if (result._tag === 'Right') { const { datasource } = result.right; // Create repository factory from the datasource const repositoryFactory = createTypeORMRepositoryFactory(datasource); const userRepository = repositoryFactory(User); // Use functional repository operations const createResult = await userRepository.create({ email: 'test@example.com', name: 'Test User' })(); if (createResult._tag === 'Right') { console.log('User created:', createResult.right); } } ``` ### 5. **NestJS Repository Integration** - Injectable REPOSITORY_OPERATIONS Provides a repository factory that works with any datasource: ```typescript import { Injectable, Inject } from '@nestjs/common'; import { REPOSITORY_OPERATIONS } from '@surv-co/prisma-typeorm-db-utils'; import { User } from './entities/User'; @Injectable() export class UserService { private userRepository; constructor( @Inject(REPOSITORY_OPERATIONS) repositoryFactory: any ) { this.userRepository = repositoryFactory(User); } async createUser(userData: Partial<User>) { const result = await this.userRepository.create(userData)(); if (result._tag === 'Right') { return result.right; } throw new Error(result.left.message); } } ``` ### 6. **Entity Generator** - TypeORM Entities from Prisma Schema Generate TypeORM entity classes from your Prisma schema: ```typescript import { createPrismaToEntitiesGenerator } from '@surv-co/prisma-typeorm-db-utils'; const generator = createPrismaToEntitiesGenerator(); const result = await generator.generateEntities(schema)(); if (result._tag === 'Right') { console.log('Generated TypeORM entities:'); result.right.forEach(entityCode => { console.log(entityCode); }); } ``` ## Quick Start ### 1. Install ```bash npm install @surv-co/prisma-typeorm-db-utils ``` ### 2. Basic Usage ```typescript import { createPrismaToPgMemTypeormDatasourceGenerator, TypeORMPgMemModule, TypeORMPostgresModule, // <-- NEW: for real PostgreSQL RepositoryModule, REPOSITORY_OPERATIONS } from '@surv-co/prisma-typeorm-db-utils'; ``` ### 3. Complete NestJS Setup (pg-mem and postgres) ```typescript // app.module.ts import { Module } from '@nestjs/common'; import { TypeORMPgMemModule, TypeORMPostgresModule, RepositoryModule } from '@surv-co/prisma-typeorm-db-utils'; import { User, Post } from './entities'; @Module({ imports: [ // For fast in-memory testing TypeORMPgMemModule.forRoot({ entities: [User, Post], prismaSchema: `...` }), // For production with real PostgreSQL // TypeORMPostgresModule.forRoot({ // entities: [User, Post], // host: 'localhost', // port: 5432, // username: 'postgres', // password: 'password', // database: 'mydb', // // synchronize: false, // Not supported! // logging: false, // ssl: false // }), RepositoryModule, ], }) export class AppModule {} ``` > **Note:** For pg-mem, schema is always created from the provided `prismaSchema`. For PostgreSQL, you must run your migrations before using the datasource. The module does not auto-sync or create the schema. ### 4. Testing Setup ```typescript // user.service.spec.ts import { Test } from '@nestjs/testing'; import { createPrismaToPgMemTypeormDatasourceGenerator } from '@surv-co/prisma-typeorm-db-utils'; import { UserService } from './user.service'; describe('UserService', () => { let service: UserService; let cleanup: () => Promise<void>; beforeEach(async () => { // Create complete testing environment from schema const generator = createPrismaToPgMemTypeormDatasourceGenerator(); const result = await generator.generateDatasource({ schema: prismaSchemaString, entities: [User, Post] }); if (result._tag === 'Right') { const { datasource, database } = result.right; cleanup = database.cleanup; const module = await Test.createTestingModule({ imports: [RepositoryModule], providers: [UserService], }) .overrideProvider('TYPEORM_DATASOURCE') .useValue(datasource) .compile(); service = module.get<UserService>(UserService); } }); afterEach(async () => { await cleanup(); }); it('should create a user', async () => { const user = await service.createUser({ email: 'test@example.com', name: 'Test User' }); expect(user.email).toBe('test@example.com'); }); }); ``` ## Core API ### Primary Functions ```typescript // Complete schema to datasource transformation createPrismaToPgMemTypeormDatasourceGenerator() // NestJS modules TypeORMPgMemModule.forRoot({ entities: [...], prismaSchema: '...' }) // Provides TYPEORM_DATASOURCE (pg-mem) TypeORMPostgresModule.forRoot({ entities: [...], host, port, username, password, database, ... }) // Provides TYPEORM_DATASOURCE (PostgreSQL) RepositoryModule // Provides REPOSITORY_OPERATIONS // Repository factory function createTypeORMRepositoryFactory(dataSource) // Entity generation createPrismaToEntitiesGenerator() ``` ### Core Exports ```typescript import { // Main integration - Prisma schema to complete TypeORM datasource createPrismaToPgMemTypeormDatasourceGenerator, // NestJS modules TypeORMPgMemModule, // Provides TYPEORM_DATASOURCE (pg-mem) TypeORMPostgresModule, // Provides TYPEORM_DATASOURCE (PostgreSQL) RepositoryModule, // Provides REPOSITORY_OPERATIONS REPOSITORY_OPERATIONS, // Repository factory injection token // Individual functions createTypeORMRepositoryFactory, // Repository factory function createPrismaToEntitiesGenerator, // Entity generator // Testing utilities createTestTypeORMClient, // Low-level pg-mem client createPostgresTypeORMClient, // Low-level Postgres client // Types type RepositoryOperations, type TableConfig, type ColumnConfig } from '@surv-co/prisma-typeorm-db-utils'; ``` ## Environment Configuration ### All Environments - **pg-mem**: Uses in-memory database for fast testing and development. No external dependencies. The schema is always created from the provided `prismaSchema`. - **PostgreSQL**: Uses real PostgreSQL connection for production/staging. You must run your migrations before using the datasource. The module does not auto-sync or create the schema. ## TypeORM Features Supported - โœ… **Complete datasource creation** from Prisma schema - โœ… **Entity generation** with proper decorators - โœ… **Relationships** (@ManyToOne, @OneToMany, @JoinColumn) - โœ… **UUID primary keys** with auto-generation - โœ… **Composite primary keys** with defaults - โœ… **Snake case naming** (camelCase โ†’ snake_case) - โœ… **Unique constraints** and indexes - โœ… **Nullable fields** and default values ## Error Handling All operations use functional error handling: ```typescript const result = await someOperation(); if (result._tag === 'Right') { const data = result.right; // Success case } else { const error = result.left; // Error case console.error('Operation failed:', error.message); } ``` ## Requirements - Node.js 18+ - TypeScript 4.9+ - NestJS 10+ (for NestJS features) - TypeORM 0.3+ ## License MIT --- **Need help?** Open an issue on GitHub for support.