npm package: @surv-co/prisma-typeorm-db-utils
Description: Transform Prisma schemas to TypeORM entities with NestJS integration and fast pg-mem testing
Author: SURV Co
Latest version: 4.0.5

# @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.