🗃️Database Integration

Learn to interact with relational and NoSQL databases using TypeORM and Prisma.

🏗️ TypeORM Deep Dive

Welcome to the TypeORM Deep Dive chapter! In this section, we'll explore how to connect your NestJS application with a PostgreSQL database using TypeORM. You'll learn about defining entities, running migrations, and managing relationships between database tables.

💡 What is TypeORM?

TypeORM is a popular ORM (Object-Relational Mapping) tool for TypeScript and JavaScript applications. It allows you to define your database schema using classes (entities) and provides tools for querying, managing relationships, and performing migrations.

💡 Setting Up PostgreSQL Connection

import { Module } from '@nestjs/common';
import { TypeOrmModule } from 'typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: 'localhost',
      port: 5432,
      username: 'your_user',
      password: 'your_password',
      database: 'nestjs_db',
      entities: ['dist/entities/**/*.js'],
      synchronize: false
    })
  ]
})
export class DatabaseModule {}

💡 Defining Your First Entity

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({
    unique: true,
    length: 255
  })
  email: string;

  @Column({
    nullable: false
  })
  username: string;

💡 Running Migrations

  • Run `npm run typeorm migration:create -name "Initial migration"` to create a new migration file.
  • Open the generated migration file and define your schema changes.
  • Execute `npm run typeorm migration:run` to apply migrations.

💡 Best Practices for Migrations

  • Always use descriptive names for your migrations.
  • Keep each migration focused on a single change or feature.
  • Test migrations in development before deploying to production.

💡 Entity Relationships

TypeORM supports various relationship types including one-to-one, one-to-many, and many-to-many. Let's explore how to define these relationships.

@Entity()
export class Post {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @Column()
  content: string;

  @ManyToMany(() => Tag)
  tags: Tag[];

💡 Eager vs Lazy Loading

Understand the difference between eager loading (loading all relationships at once) and lazy loading (loading relationships on demand). Use these strategies to optimize your application's performance.

const post = await getRepository(Post)
  .createQueryBuilder('post')
  .leftJoinAndSelect('post.tags', 'tags')
  .where('post.id = :id', { id: 1 })
  .getOne();

💡 Transactions in TypeORM

Learn how to manage database transactions for consistency and reliability. Use transactions when performing operations that must succeed or fail as a single unit.

const transaction = await dataSource.createTransaction();
try {
  // Perform your database operations
  await transaction.commit();
} catch (error) {
  await transaction.rollback();
}

💡 Schema Design Principles

  • Always use meaningful and descriptive names for tables and columns.
  • Avoid using default settings without understanding their impact on production.
  • Use appropriate data types to optimize storage and query performance.

🔬 Prisma as an Alternative ORM

Welcome to the world of modern database querying with Prisma! If you've ever worked with TypeORM or other ORMs and felt limited by their capabilities, Prisma is here to change your perspective. In this chapter, we'll explore how to set up Prisma in your NestJS project, model your database schema using the powerful Prisma schema language, and perform sophisticated database operations using the generated Prisma client.

💡 Why Prisma?

  • Prisma provides a developer-first experience with its intuitive query builder and schema-driven development approach.
  • Leverage TypeScript from the start with strongly typed models and operations.
  • Enjoy first-class support for relationships, filters, and advanced querying techniques.
  • Benefit from powerful tooling like Prisma Studio for visual data exploration.

Getting Started

To integrate Prisma into your NestJS project, follow these steps:

  • Install the necessary dependencies by running: npm install prisma @prisma/client --save
  • Create a new `prisma` directory in your project root.
  • Initialize Prisma by running `npx prisma init` and selecting your database provider.
npx prisma init

💡 Defining Your Schema

Prisma uses the Prisma schema language to define your database models. This schema-driven approach allows you to generate both the database schema and client code from a single source of truth.

// prisma/schema.prisma

database 'mysql' {
  url = env('DATABASE_URL')
  schema = 'public'
}

model User {
  id Int @id
  email String @unique
  name String
  posts Post[]
}

model Post {
  id Int @id
  title String
  content String
  author User @relation(fields: [authorId], references: [id])
  authorId Int
}

💡 Key Features of Prisma

  • Relationships: Define and query relationships between models using intuitive syntax.
  • Filters: Apply complex filters to your queries using AND, OR, NOT operators.
  • Query Builder: Use a fluent API for building and executing database operations.
  • Transactions: Perform atomic database operations with ease.

CRUD Operations

Prisma's query builder provides a consistent API for performing CRUD operations on your models.

// Create
const user = await prisma.user.create({
  data: {
    email: 'john.doe@example.com',
    name: 'John Doe'
  }
});

// Read
const users = await prisma.user.findMany({
  where: {
    email: { contains: 'example' }
  },
  orderBy: {
    name: 'asc'
  }
});

// Update
const updatedUser = await prisma.user.update({
  where: { id: 1 },
  data: { name: 'Jane Doe' }
});

// Delete
const deletedUser = await prisma.user.delete({
  where: { id: 1 }
});

💡 Exploring Relationships

Prisma makes it easy to work with relationships between models.

// One-to-Many
const userWithPosts = await prisma.user.findUnique({
  where: { id: 1 },
  include: {
    posts: true
  }
});

// Many-to-Many
const userWithRoles = await prisma.user.findUnique({
  where: { id: 1 },
  include: {
    roles: true
  }
});

Prisma Studio and Tooling

Prisma comes with a suite of tools to help you visualize and interact with your database.

  • Launch Prisma Studio using `npx prisma studio` for visual data exploration.
  • Use the Prisma CLI for schema validation, migration, and other operations.
  • Generate API documentation using `npx prisma doc`.

💡 Comparing Prisma to TypeORM

  • Prisma provides a more modern, developer-friendly experience compared to TypeORM.
  • Prisma's schema-driven approach reduces boilerplate code.
  • Prisma excels in complex queries and relationships out of the box.

Best Practices

  • Use schema-driven development to keep your database schema in sync with your application logic.
  • Leverage TypeScript's static typing for safer and more maintainable code.
  • Take advantage of Prisma's built-in validation and error handling.

💡 When to Use Prisma?

  • For applications requiring complex querying and relationships.
  • When you want a modern, type-safe ORM experience.
  • In scenarios where developer productivity and tooling are critical.

Quiz

Question 1 of 12

What is the purpose of TypeORM's §synchronize§ option?

  • Sync entity schemas with the database
  • Enable automatic migrations
  • Disable foreign key constraints