Getting Started with TypeORM: A Beginners Guide

admin
admin

What is TypeORM?

TypeORM is an Object-Relational Mapping (ORM) library specifically designed for TypeScript and JavaScript frameworks. It allows developers to interact with databases using objects rather than traditional SQL queries. With TypeORM, you can simplify data management in your applications by leveraging interfaces, decorators, and other TypeScript benefits. It supports multiple database systems, including MySQL, PostgreSQL, SQLite, and Microsoft SQL Server, providing flexibility in deployment choices.

Why Choose TypeORM?

  1. TypeScript Support: TypeORM is built with TypeScript in mind. This ensures strong typing, allowing developers to catch errors during compile-time rather than runtime.
  2. Active Record and Data Mapper Patterns: Supports both patterns, offering various ways to organize your application logic according to your preferences.
  3. Migration Feature: TypeORM has a built-in migration system to manage database schema changes, making it easier to maintain your application’s database structure.
  4. Query Builder: Provides a powerful query building interface to create complex SQL queries using programmatic methods.
  5. Eager and Lazy Loading: Supports advanced loading strategies for related entities, promoting efficient data management.

Setting Up TypeORM

Step 1: Install Required Packages

To get started with TypeORM, you need to install it along with the database driver you plan to use. For example, if you’re using PostgreSQL, you’d execute the following command:

npm install typeorm reflect-metadata pg

Make sure to also install TypeScript:

npm install typescript --save-dev

You’ll also need to create a tsconfig.json file to configure TypeScript compilation settings. You can generate one with:

npx tsc --init

Adjust the TypeScript configuration according to your needs.

Step 2: Create a Connection

TypeORM requires a database connection to function. Create a new file, ormconfig.ts, and add the following code to configure your database connection:

import { DataSource } from "typeorm";

export const AppDataSource = new DataSource({
    type: "postgres", // Your database type
    host: "localhost",
    port: 5432, // PostgreSQL default port
    username: "your_username",
    password: "your_password",
    database: "your_database",
    synchronize: true, // Auto-sync models to the database
    logging: false,
    entities: [__dirname + "/entity/*.ts"], // Define the location of your entities
    migrations: [__dirname + "/migration/*.ts"],
    subscribers: [],
});

Step 3: Create Your First Entity

Entities in TypeORM represent database tables. Create a new directory called entity and add a file named User.ts. Inside, define your entity like so:

import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";

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

    @Column()
    firstName: string;

    @Column()
    lastName: string;

    @Column()
    age: number;
}

This code snippet defines a User entity with id, firstName, lastName, and age columns.

Step 4: Initialize the Connection

To utilize TypeORM, you must establish the connection defined earlier. Create an index.ts file and add the following code:

import "reflect-metadata";
import { AppDataSource } from "./ormconfig";

AppDataSource.initialize()
    .then(() => {
        console.log("Data Source has been initialized!");
        // You can now perform database operations
    })
    .catch((err) => {
        console.error("Error during Data Source initialization:", err);
    });

This code establishes a connection to the database and prints a success message to the console.

Working with Repositories

TypeORM introduces the concept of repositories, which provide an abstraction layer to interact with the database. Replace the content inside the then function with the following code to create, read, update, and delete users:

import { User } from "./entity/User";

// Create a new user
const createUser = async () => {
    const userRepository = AppDataSource.getRepository(User);
    const user = new User();
    user.firstName = "John";
    user.lastName = "Doe";
    user.age = 25;

    await userRepository.save(user);
    console.log("User has been saved: ", user);
};

// Read users
const readUsers = async () => {
    const userRepository = AppDataSource.getRepository(User);
    const users = await userRepository.find();
    console.log("Loaded users: ", users);
};

// Update a user
const updateUser = async (id: number) => {
    const userRepository = AppDataSource.getRepository(User);
    let user = await userRepository.findOneBy({ id });
    if (user) {
        user.age = 26;
        await userRepository.save(user);
        console.log("User updated: ", user);
    }
};

// Delete a user
const deleteUser = async (id: number) => {
    const userRepository = AppDataSource.getRepository(User);
    await userRepository.delete(id);
    console.log("User deleted with id: ", id);
};

// Call functions to test
createUser().then(() => {
    readUsers();
});

Migrations

For managing changes in your database schema, TypeORM allows you to create migrations. These are essential when working in a team environment or production setup.

To generate a migration, run the following CLI command:

npx typeorm migration:generate -n UserMigration

This generates a migration file and you can adjust the up and down methods according to your schema changes. To run the migration, use:

npx typeorm migration:run

Query Builder

TypeORM also provides a powerful Query Builder for constructing complex SQL queries. For instance, to find users older than a certain age, you can use:

const usersAboveAge = await AppDataSource
    .getRepository(User)
    .createQueryBuilder("user")
    .where("user.age > :age", { age: 20 })
    .getMany();

console.log("Users older than 20: ", usersAboveAge);

Error Handling

Building robust applications involves gracefully handling errors. Wrap your database operations in try-catch blocks:

try {
    await createUser();
} catch (error) {
    console.error("Failed to create user: ", error);
}

Eager and Lazy Loading

When fetching related entities, you can opt for either eager or lazy loading. Eager loading retrieves related entities in the initial query:

const users = await userRepository.find({ relations: ["posts"] }); // Assuming User has a relation with Post

In contrast, lazy loading requires you to use a promise-like syntax:

const user = await userRepository.findOne({ where: { id } });
const posts = await user.posts; // Fetches the posts when accessed

Testing

When developing applications, implementing tests is best practice. TypeORM can be tested using various JavaScript testing frameworks like Jest or Mocha. Mock the database connection for unit tests or use a separate database instance for integration tests.

Resources

To expand your knowledge of TypeORM, consider the following resources:

  • Official Documentation: Comprehensive and regularly updated, the TypeORM documentation is your primary source for information.
  • TypeORM GitHub Repository: In addition to code examples, the repository contains issues and discussions that can provide valuable insights.
  • Community Forums and Stack Overflow: Engage with the TypeORM community for specific questions and experience sharing.

By following this guide, you’ll be well on your way to successfully implementing TypeORM in your projects. Understanding its core concepts will enable you to build efficient databases and web applications with ease.

Leave a Reply

Your email address will not be published. Required fields are marked *