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
- Pendahuluan
- Apa itu TypeORM dan mengapa menggunakannya dengan NestJS?
- Pentingnya shortcut methods dalam TypeORM.
- Konfigurasi Awal TypeORM di NestJS
- Instalasi dan konfigurasi yang diperlukan.
- Membuat Entity dasar.
- Mengkonfigurasi modul TypeORM.
- 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.
- Create (Membuat Data Baru)
- Metode Shortcut Lanjutan
.createQueryBuilder()
: Membuat query builder untuk query yang lebih kompleks..relation()
: Bekerja dengan relasi antar entitas.- Contoh penggunaan dan skenario umum.
- Praktik Terbaik dan Tips
- Menggunakan DTO (Data Transfer Object) untuk validasi data.
- Menangani error dengan benar.
- Mengoptimalkan query untuk performa yang lebih baik.
- 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 kelasUser
sebagai Entity TypeORM.@PrimaryGeneratedColumn()
mendeklarasikan kolomid
sebagai primary key yang di-generate secara otomatis.@Column()
mendeklarasikan kolom-kolom lain sepertifirstName
,lastName
, danisActive
.
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 gunakansynchronize: true
di lingkungan produksi, karena dapat menyebabkan hilangnya data. Lebih baik gunakan migrasi database.TypeOrmModule.forFeature([User])
mendaftarkan EntityUser
ke dalam modul saat ini. Ini memungkinkan kita untuk menginjeksikan RepositoryUser
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 exceptionNotFoundException
.
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 aliasuser
untuk EntityUser
..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
, danoffset
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.
“`