Thursday

19-06-2025 Vol 19

Nest Repository Shortcut Methods (TypeORM)

NestJS & TypeORM: Memaksimalkan Produktivitas dengan Shortcut Methods

TypeORM, sebagai ORM yang kuat untuk TypeScript dan JavaScript (Node.js, Browser, React Native, Electron/Desktop), menawarkan sejumlah metode shortcut yang secara signifikan dapat meningkatkan produktivitas Anda saat bekerja dengan database di aplikasi NestJS. Artikel ini akan membahas secara mendalam metode-metode shortcut ini, memberikan contoh praktis, dan menunjukkan bagaimana Anda dapat memanfaatkannya untuk menyederhanakan operasi database Anda.

Mengapa Shortcut Methods Penting?

Shortcut methods TypeORM dirancang untuk menyederhanakan tugas-tugas umum yang sering Anda temui saat berinteraksi dengan database. Alih-alih menulis query kompleks secara manual, Anda dapat menggunakan metode ini untuk melakukan operasi CRUD (Create, Read, Update, Delete) dengan lebih cepat dan efisien. Ini tidak hanya menghemat waktu pengembangan tetapi juga membuat kode Anda lebih mudah dibaca dan dipelihara.

Kerangka Artikel

  1. Pendahuluan
    • Apa itu TypeORM dan mengapa menggunakannya dengan NestJS?
    • Pentingnya shortcut methods dalam TypeORM.
  2. Konfigurasi Awal TypeORM di NestJS
    • Instalasi dan konfigurasi yang diperlukan.
    • Membuat Entity dasar.
    • Mengkonfigurasi modul TypeORM.
  3. Metode Shortcut untuk Operasi CRUD
    • Create (Membuat Data Baru)
      • .create(): Membuat instance Entity baru.
      • .save(): Menyimpan instance Entity ke database.
      • Contoh penggunaan dan skenario umum.
    • Read (Membaca Data)
      • .find(): Mengambil semua data atau data yang cocok dengan kriteria.
      • .findOne(): Mengambil satu entitas berdasarkan ID atau kriteria lain.
      • .findOneBy(): Mengambil satu entitas berdasarkan properti tertentu.
      • .findBy(): Mengambil banyak entitas berdasarkan properti tertentu.
      • .count(): Menghitung jumlah entitas yang cocok dengan kriteria.
      • Contoh penggunaan dan skenario umum dengan opsi query.
    • Update (Memperbarui Data)
      • .update(): Memperbarui data berdasarkan ID atau kriteria.
      • .save(): Memperbarui instance Entity yang sudah ada.
      • Contoh penggunaan dan skenario umum.
    • Delete (Menghapus Data)
      • .delete(): Menghapus data berdasarkan ID atau kriteria.
      • .remove(): Menghapus instance Entity dari database.
      • Contoh penggunaan dan skenario umum.
  4. Metode Shortcut Lanjutan
    • .createQueryBuilder(): Membuat query builder untuk query yang lebih kompleks.
    • .relation(): Bekerja dengan relasi antar entitas.
    • Contoh penggunaan dan skenario umum.
  5. Praktik Terbaik dan Tips
    • Menggunakan DTO (Data Transfer Object) untuk validasi data.
    • Menangani error dengan benar.
    • Mengoptimalkan query untuk performa yang lebih baik.
  6. Kesimpulan
    • Ringkasan manfaat penggunaan shortcut methods TypeORM.
    • Sumber daya lebih lanjut untuk dipelajari.

1. Pendahuluan

NestJS, framework progresif Node.js untuk membangun aplikasi sisi server yang efisien dan terukur, sering digunakan bersama dengan TypeORM, sebuah Object-Relational Mapper (ORM) yang mendukung TypeScript dan JavaScript. Kombinasi ini menyediakan lingkungan pengembangan yang kuat dan efisien untuk berinteraksi dengan database.

  • Apa itu TypeORM? TypeORM adalah ORM yang memungkinkan Anda untuk berinteraksi dengan database menggunakan objek dan kelas JavaScript/TypeScript, alih-alih menulis query SQL mentah. Ini menyederhanakan proses pengembangan dan meningkatkan pemeliharaan kode.
  • Mengapa Menggunakan TypeORM dengan NestJS? NestJS dan TypeORM saling melengkapi dengan baik. NestJS menyediakan struktur aplikasi yang terorganisir, sementara TypeORM menyederhanakan interaksi dengan database. Kombinasi ini mempercepat pengembangan, meningkatkan kualitas kode, dan mempermudah pemeliharaan aplikasi.

Salah satu fitur utama TypeORM adalah serangkaian metode shortcut yang menyederhanakan operasi database yang umum. Metode-metode ini memungkinkan Anda untuk melakukan operasi CRUD (Create, Read, Update, Delete) dengan lebih cepat dan efisien, mengurangi boilerplate code dan meningkatkan produktivitas.

2. Konfigurasi Awal TypeORM di NestJS

Sebelum kita dapat menggunakan shortcut methods TypeORM, kita perlu mengkonfigurasi TypeORM di aplikasi NestJS kita.

Instalasi

Pertama, instal paket yang diperlukan:

npm install --save @nestjs/typeorm typeorm mysql2
  # atau untuk database lain
  npm install --save pg pg-hstore # Untuk PostgreSQL
  npm install --save sqlite3 # Untuk SQLite
  

Pastikan Anda menginstal driver database yang sesuai (misalnya, mysql2 untuk MySQL, pg dan pg-hstore untuk PostgreSQL, sqlite3 untuk SQLite).

Membuat Entity

Selanjutnya, kita perlu membuat Entity yang merepresentasikan tabel database kita. Misalnya, kita akan membuat Entity User:

// src/user/user.entity.ts
  import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

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

    @Column({ length: 50 })
    firstName: string;

    @Column({ length: 50 })
    lastName: string;

    @Column({ default: true })
    isActive: boolean;
  }
  

Dalam contoh ini:

  • @Entity() mendeklarasikan kelas User sebagai Entity TypeORM.
  • @PrimaryGeneratedColumn() mendeklarasikan kolom id sebagai primary key yang di-generate secara otomatis.
  • @Column() mendeklarasikan kolom-kolom lain seperti firstName, lastName, dan isActive.

Mengkonfigurasi Modul TypeORM

Sekarang, kita perlu mengkonfigurasi modul TypeORM di aplikasi NestJS kita. Kita akan mengimpor TypeOrmModule dan mengkonfigurasi koneksi database:

// src/app.module.ts
  import { Module } from '@nestjs/common';
  import { TypeOrmModule } from '@nestjs/typeorm';
  import { User } from './user/user.entity';

  @Module({
    imports: [
      TypeOrmModule.forRoot({
        type: 'mysql', // atau 'postgres', 'sqlite', dll.
        host: 'localhost',
        port: 3306,
        username: 'your_username',
        password: 'your_password',
        database: 'your_database',
        entities: [User],
        synchronize: true, // Jangan gunakan ini di produksi!
      }),
      TypeOrmModule.forFeature([User]),
    ],
    controllers: [],
    providers: [],
  })
  export class AppModule {}
  

Dalam contoh ini:

  • TypeOrmModule.forRoot() mengkonfigurasi koneksi database global. Pastikan untuk mengganti placeholder dengan kredensial database Anda yang sebenarnya. Perhatian: Jangan gunakan synchronize: true di lingkungan produksi, karena dapat menyebabkan hilangnya data. Lebih baik gunakan migrasi database.
  • TypeOrmModule.forFeature([User]) mendaftarkan Entity User ke dalam modul saat ini. Ini memungkinkan kita untuk menginjeksikan Repository User ke dalam service atau controller kita.

3. Metode Shortcut untuk Operasi CRUD

Setelah kita mengkonfigurasi TypeORM, kita dapat mulai menggunakan shortcut methods untuk melakukan operasi CRUD.

Create (Membuat Data Baru)

Ada dua metode utama untuk membuat data baru:

.create()

Metode .create() digunakan untuk membuat instance baru dari Entity. Metode ini tidak menyimpan data ke database, tetapi hanya membuat objek dalam memori.

// src/user/user.service.ts
  import { Injectable } from '@nestjs/common';
  import { InjectRepository } from '@nestjs/typeorm';
  import { Repository } from 'typeorm';
  import { User } from './user.entity';

  @Injectable()
  export class UserService {
    constructor(
      @InjectRepository(User)
      private usersRepository: Repository<User>,
    ) {}

    async createUser(firstName: string, lastName: string): Promise<User> {
      const user = this.usersRepository.create({
        firstName,
        lastName,
      });

      return user;
    }
  }
  

Dalam contoh ini, this.usersRepository.create() membuat instance baru dari Entity User dengan properti firstName dan lastName.

.save()

Metode .save() digunakan untuk menyimpan instance Entity ke database. Metode ini dapat digunakan untuk membuat data baru atau memperbarui data yang sudah ada.

// src/user/user.service.ts
  import { Injectable } from '@nestjs/common';
  import { InjectRepository } from '@nestjs/typeorm';
  import { Repository } from 'typeorm';
  import { User } from './user.entity';

  @Injectable()
  export class UserService {
    constructor(
      @InjectRepository(User)
      private usersRepository: Repository<User>,
    ) {}

    async createUser(firstName: string, lastName: string): Promise<User> {
      const user = this.usersRepository.create({
        firstName,
        lastName,
      });

      return this.usersRepository.save(user);
    }
  }
  

Dalam contoh ini, this.usersRepository.save(user) menyimpan instance User ke database. Jika instance User belum ada di database (misalnya, id belum ada), maka akan dibuat baris baru. Jika instance User sudah ada (misalnya, id sudah ada), maka baris yang ada akan diperbarui.

Contoh Penggunaan dan Skenario Umum

Berikut adalah contoh penggunaan .create() dan .save() dalam sebuah controller NestJS:

// src/user/user.controller.ts
  import { Controller, Post, Body } from '@nestjs/common';
  import { UserService } from './user.service';

  @Controller('users')
  export class UserController {
    constructor(private readonly userService: UserService) {}

    @Post()
    async createUser(
      @Body('firstName') firstName: string,
      @Body('lastName') lastName: string,
    ) {
      return this.userService.createUser(firstName, lastName);
    }
  }
  

Dalam skenario ini, ketika klien mengirimkan permintaan POST ke endpoint /users dengan body yang berisi firstName dan lastName, controller akan memanggil userService.createUser() untuk membuat dan menyimpan user baru ke database.

Read (Membaca Data)

TypeORM menyediakan beberapa metode shortcut untuk membaca data dari database:

.find()

Metode .find() digunakan untuk mengambil semua data dari tabel, atau data yang cocok dengan kriteria tertentu. Metode ini mengembalikan array dari entitas.

// Mengambil semua user
  const allUsers = await this.usersRepository.find();

  // Mengambil user dengan isActive = true
  const activeUsers = await this.usersRepository.find({
    where: {
      isActive: true,
    },
  });
  

Anda dapat menggunakan opsi where untuk menentukan kriteria pencarian. Opsi ini menerima objek yang berisi properti dan nilai yang akan dicocokkan.

.findOne()

Metode .findOne() digunakan untuk mengambil satu entitas berdasarkan ID atau kriteria lain. Jika tidak ada entitas yang cocok, metode ini mengembalikan undefined.

// Mengambil user berdasarkan ID
  const user = await this.usersRepository.findOne({
    where: {
      id: 1,
    },
  });

  // Mengambil user berdasarkan firstName dan lastName
  const user = await this.usersRepository.findOne({
    where: {
      firstName: 'John',
      lastName: 'Doe',
    },
  });
  

Sama seperti .find(), Anda dapat menggunakan opsi where untuk menentukan kriteria pencarian.

.findOneBy()

Metode .findOneBy() digunakan untuk mengambil satu entitas berdasarkan properti tertentu. Ini adalah cara yang lebih ringkas daripada menggunakan .findOne() dengan klausa `where` jika Anda hanya ingin mencari berdasarkan kesamaan properti.

// Mengambil user berdasarkan firstName
  const user = await this.usersRepository.findOneBy({
    firstName: 'John',
  });
  

.findBy()

Metode .findBy() digunakan untuk mengambil banyak entitas berdasarkan properti tertentu. Sama seperti .findOneBy(), ini menyederhanakan proses pencarian daripada menggunakan .find() dengan klausa `where`.

// Mengambil semua user dengan isActive = true
  const activeUsers = await this.usersRepository.findBy({
    isActive: true,
  });
  

.count()

Metode .count() digunakan untuk menghitung jumlah entitas yang cocok dengan kriteria tertentu.

// Menghitung jumlah semua user
  const totalUsers = await this.usersRepository.count();

  // Menghitung jumlah user dengan isActive = true
  const activeUsersCount = await this.usersRepository.count({
    where: {
      isActive: true,
    },
  });
  

Contoh Penggunaan dan Skenario Umum dengan Opsi Query

Berikut adalah contoh penggunaan metode-metode read dalam sebuah controller:

// src/user/user.controller.ts
  import { Controller, Get, Param, NotFoundException } from '@nestjs/common';
  import { UserService } from './user.service';

  @Controller('users')
  export class UserController {
    constructor(private readonly userService: UserService) {}

    @Get()
    async getAllUsers() {
      return this.userService.getAllUsers();
    }

    @Get(':id')
    async getUserById(@Param('id') id: string) {
      const user = await this.userService.getUserById(parseInt(id));
      if (!user) {
        throw new NotFoundException('User not found');
      }
      return user;
    }
  }
  
// src/user/user.service.ts
  import { Injectable } from '@nestjs/common';
  import { InjectRepository } from '@nestjs/typeorm';
  import { Repository } from 'typeorm';
  import { User } from './user.entity';

  @Injectable()
  export class UserService {
    constructor(
      @InjectRepository(User)
      private usersRepository: Repository<User>,
    ) {}

    async getAllUsers(): Promise<User[]> {
      return this.usersRepository.find();
    }

    async getUserById(id: number): Promise<User> {
      return this.usersRepository.findOne({
        where: {
          id: id,
        },
      });
    }
  }
  

Dalam skenario ini:

  • Permintaan GET ke /users akan mengambil semua user dari database.
  • Permintaan GET ke /users/:id akan mengambil user dengan ID yang sesuai. Jika user tidak ditemukan, akan dilemparkan exception NotFoundException.

Update (Memperbarui Data)

TypeORM menyediakan dua metode utama untuk memperbarui data:

.update()

Metode .update() digunakan untuk memperbarui data berdasarkan ID atau kriteria. Metode ini tidak memerlukan instance Entity, dan dapat memperbarui data secara langsung di database.

// Memperbarui firstName user dengan ID 1
  await this.usersRepository.update(1, {
    firstName: 'Jane',
  });

  // Memperbarui semua user yang tidak aktif menjadi aktif
  await this.usersRepository.update(
    { isActive: false },
    { isActive: true },
  );
  

Metode .update() menerima dua argumen: kriteria pencarian (misalnya, ID atau objek dengan properti dan nilai) dan objek dengan properti dan nilai yang akan diperbarui.

.save()

Metode .save() juga dapat digunakan untuk memperbarui data. Dalam hal ini, Anda harus mengambil instance Entity terlebih dahulu, mengubah propertinya, dan kemudian menyimpannya kembali ke database.

// Mengambil user berdasarkan ID
  const user = await this.usersRepository.findOne({
    where: {
      id: 1,
    },
  });

  // Memperbarui firstName user
  user.firstName = 'Jane';

  // Menyimpan perubahan ke database
  await this.usersRepository.save(user);
  

Metode .save() lebih fleksibel daripada .update(), karena memungkinkan Anda untuk melakukan logika tambahan sebelum menyimpan perubahan ke database. Namun, metode ini juga lebih lambat, karena memerlukan dua operasi database (read dan write).

Contoh Penggunaan dan Skenario Umum

Berikut adalah contoh penggunaan metode update dalam sebuah service:

// src/user/user.service.ts
  import { Injectable } from '@nestjs/common';
  import { InjectRepository } from '@nestjs/typeorm';
  import { Repository } from 'typeorm';
  import { User } from './user.entity';

  @Injectable()
  export class UserService {
    constructor(
      @InjectRepository(User)
      private usersRepository: Repository<User>,
    ) {}

    async updateUser(id: number, firstName: string): Promise<void> {
      await this.usersRepository.update(id, { firstName });
    }
  }
  

Dalam skenario ini, userService.updateUser() digunakan untuk memperbarui firstName user dengan ID yang diberikan.

Delete (Menghapus Data)

TypeORM menyediakan dua metode utama untuk menghapus data:

.delete()

Metode .delete() digunakan untuk menghapus data berdasarkan ID atau kriteria. Metode ini tidak memerlukan instance Entity, dan dapat menghapus data secara langsung di database.

// Menghapus user dengan ID 1
  await this.usersRepository.delete(1);

  // Menghapus semua user yang tidak aktif
  await this.usersRepository.delete({ isActive: false });
  

Metode .delete() menerima satu argumen: kriteria pencarian (misalnya, ID atau objek dengan properti dan nilai).

.remove()

Metode .remove() digunakan untuk menghapus instance Entity dari database. Dalam hal ini, Anda harus mengambil instance Entity terlebih dahulu, dan kemudian menghapusnya.

// Mengambil user berdasarkan ID
  const user = await this.usersRepository.findOne({
    where: {
      id: 1,
    },
  });

  // Menghapus user
  await this.usersRepository.remove(user);
  

Metode .remove() lebih fleksibel daripada .delete(), karena memungkinkan Anda untuk melakukan logika tambahan sebelum menghapus data. Namun, metode ini juga lebih lambat, karena memerlukan dua operasi database (read dan write).

Contoh Penggunaan dan Skenario Umum

Berikut adalah contoh penggunaan metode delete dalam sebuah service:

// src/user/user.service.ts
  import { Injectable } from '@nestjs/common';
  import { InjectRepository } from '@nestjs/typeorm';
  import { Repository } from 'typeorm';
  import { User } from './user.entity';

  @Injectable()
  export class UserService {
    constructor(
      @InjectRepository(User)
      private usersRepository: Repository<User>,
    ) {}

    async deleteUser(id: number): Promise<void> {
      await this.usersRepository.delete(id);
    }
  }
  

Dalam skenario ini, userService.deleteUser() digunakan untuk menghapus user dengan ID yang diberikan.

4. Metode Shortcut Lanjutan

Selain metode shortcut CRUD, TypeORM menyediakan metode shortcut lanjutan yang memungkinkan Anda untuk melakukan query yang lebih kompleks dan bekerja dengan relasi antar entitas.

.createQueryBuilder()

Metode .createQueryBuilder() digunakan untuk membuat query builder, yang memungkinkan Anda untuk membuat query SQL yang kompleks menggunakan API yang lebih intuitif.

// Mendapatkan semua user yang aktif dan memiliki nama depan yang dimulai dengan 'J'
  const users = await this.usersRepository
    .createQueryBuilder('user')
    .where('user.isActive = :isActive', { isActive: true })
    .andWhere('user.firstName LIKE :firstName', { firstName: 'J%' })
    .getMany();
  

Dalam contoh ini:

  • .createQueryBuilder('user') membuat query builder dengan alias user untuk Entity User.
  • .where('user.isActive = :isActive', { isActive: true }) menambahkan klausa WHERE untuk memfilter user yang aktif.
  • .andWhere('user.firstName LIKE :firstName', { firstName: 'J%' }) menambahkan klausa AND untuk memfilter user yang memiliki nama depan yang dimulai dengan ‘J’.
  • .getMany() mengeksekusi query dan mengembalikan array dari entitas yang cocok.

Query builder menyediakan berbagai metode untuk membangun query yang kompleks, termasuk:

  • .select(): Menentukan kolom yang akan diambil.
  • .leftJoinAndSelect(), .innerJoinAndSelect(), .leftJoin(), .innerJoin(): Melakukan join dengan tabel lain.
  • .orderBy(): Mengurutkan hasil.
  • .limit(): Membatasi jumlah hasil.
  • .offset(): Menentukan offset untuk paginasi.

.relation()

Metode .relation() digunakan untuk bekerja dengan relasi antar entitas. TypeORM mendukung berbagai jenis relasi, termasuk:

  • One-to-one
  • One-to-many
  • Many-to-one
  • Many-to-many

Misalnya, jika kita memiliki Entity Post yang memiliki relasi many-to-one dengan Entity User (setiap post ditulis oleh seorang user), kita dapat menggunakan metode .relation() untuk mengambil semua post dari user tertentu:

// Mendefinisikan Entity Post
  import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm';
  import { User } from './user.entity';

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

    @Column({ length: 255 })
    title: string;

    @Column({ type: 'text' })
    content: string;

    @ManyToOne(() => User, (user) => user.posts)
    author: User;
  }
  
// src/post/post.service.ts
  import { Injectable } from '@nestjs/common';
  import { InjectRepository } from '@nestjs/typeorm';
  import { Repository } from 'typeorm';
  import { Post } from './post.entity';
  import { User } from '../user/user.entity';

  @Injectable()
  export class PostService {
    constructor(
      @InjectRepository(Post)
      private postsRepository: Repository<Post>,
    ) {}

    async getPostsByAuthor(authorId: number): Promise<Post[]> {
      return this.postsRepository.find({
        where: {
          author: {
            id: authorId,
          },
        },
      });
    }
  }
  

Dalam contoh ini, kita menggunakan opsi where untuk memfilter post berdasarkan ID author. Kita dapat mengakses properti relasi (author) dan kemudian properti dari Entity yang terkait (id).

5. Praktik Terbaik dan Tips

Berikut adalah beberapa praktik terbaik dan tips untuk menggunakan shortcut methods TypeORM secara efektif:

  • Menggunakan DTO (Data Transfer Object) untuk Validasi Data: Gunakan DTO untuk memvalidasi data yang masuk sebelum menyimpannya ke database. Ini membantu mencegah kesalahan dan meningkatkan keamanan.
  • Menangani Error dengan Benar: Pastikan untuk menangani error dengan benar saat berinteraksi dengan database. Gunakan try-catch blocks untuk menangkap exception dan memberikan pesan error yang bermakna.
  • Mengoptimalkan Query untuk Performa yang Lebih Baik: Hindari mengambil terlalu banyak data yang tidak perlu. Gunakan opsi query seperti select, limit, dan offset untuk mengoptimalkan query dan meningkatkan performa.

6. Kesimpulan

Metode shortcut TypeORM menyediakan cara yang efisien dan mudah untuk melakukan operasi database yang umum di aplikasi NestJS. Dengan menggunakan metode-metode ini, Anda dapat menyederhanakan kode Anda, meningkatkan produktivitas, dan mempermudah pemeliharaan aplikasi.

Untuk mempelajari lebih lanjut tentang TypeORM, Anda dapat merujuk ke sumber daya berikut:

Dengan memahami dan menerapkan metode shortcut TypeORM dengan baik, Anda dapat membangun aplikasi NestJS yang lebih efisien dan terukur.

“`

omcoding

Leave a Reply

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