Вместо непосредственной работы с базами данных SQL я обнаружил, что использование TypeORM значительно упрощает процесс работы с базами данных и сокращает время разработки. Поэтому я хотел бы рекомендовать использовать TypeORM всем, кто хочет более эффективно работать с базами данных.
TypeORM — это библиотека объектно-реляционного сопоставления (ORM) для TypeScript и JavaScript, которая позволяет разработчикам работать с реляционными базами данных с использованием методов объектно-ориентированного программирования. Он предоставляет богатый набор функций для определения схемы базы данных, запроса данных и управления соединениями с базой данных. TypeORM поддерживает несколько систем баз данных, включая MySQL, PostgreSQL, Oracle и SQLite.
NestJS обеспечивает встроенную поддержку TypeORM, позволяя разработчикам использовать его для взаимодействия с базами данных в своих приложениях. NestJS использует внедрение зависимостей для предоставления экземпляров Repository
классов другим компонентам в приложении. Разработчики могут определить класс Provider
для класса Repository
, а затем внедрить его в другие компоненты, которым необходимо взаимодействовать с базой данных. NestJS также предоставляет встроенную поддержку для определения контроллеров, служб и модулей, использующих репозитории TypeORM, что упрощает создание сложных приложений, управляемых базой данных.
Вот пример простого приложения NestJS CRUD, использующего PostgreSQL в качестве базы данных и библиотеку TypeORM в качестве ORM.
Во-первых, давайте создадим новую базу данных PostgreSQL и создадим таблицу с именем todos
:
CREATE DATABASE nestjs_postgres_crud; CREATE TABLE todos ( id SERIAL PRIMARY KEY, title TEXT NOT NULL, description TEXT, completed BOOLEAN NOT NULL DEFAULT FALSE );
В PostgreSQL serial
— это псевдотип данных, используемый для определения столбца с автоинкрементом. Когда столбец определен как serial
, PostgreSQL автоматически создает объект последовательности и устанавливает значение столбца по умолчанию на следующее значение последовательности. Это означает, что каждый раз, когда в таблицу вставляется новая строка, значение столбца serial
будет автоматически увеличиваться на 1.
Далее давайте создадим сущность Todo
с помощью TypeORM:
// src/todo/todo.entity.ts import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; @Entity() export class Todo { @PrimaryGeneratedColumn() id: number; @Column() title: string; @Column({ nullable: true }) description: string; @Column({ default: false }) completed: boolean; }
TypeORM предоставляет ряд декораторов, которые можно использовать для определения структуры сущностей в базе данных. Вот некоторые из наиболее часто используемых декораторов:
@Entity()
: Этот декоратор используется для определения нового объекта в TypeORM. Его следует применять к классу, представляющему объект.@Column()
: этот декоратор используется для определения нового столбца в объекте. Его следует применять к свойству, представляющему столбец.@PrimaryGeneratedColumn()
: этот декоратор используется для определения нового столбца первичного ключа в объекте. Его следует применять к свойству, представляющему первичный ключ.
Теперь давайте создадим TodoService
, который будет обрабатывать операции CRUD:
// src/todo/todo.service.ts import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { Todo } from './todo.entity'; @Injectable() export class TodoService { constructor( @InjectRepository(Todo) private readonly todoRepository: Repository<Todo>, ) {} async findAll(): Promise<Todo[]> { return this.todoRepository.find(); } async findById(id: number): Promise<Todo> { return this.todoRepository.findOne(id); } async create(todo: Todo): Promise<Todo> { return this.todoRepository.save(todo); } async update(id: number, todo: Todo): Promise<Todo> { await this.todoRepository.update(id, todo); return this.todoRepository.findOne(id); } async delete(id: number): Promise<void> { await this.todoRepository.delete(id); } }
@InjectRepository
— это декоратор, предоставляемый пакетом @nestjs/typeorm
в NestJS, который можно использовать для внедрения экземпляра репозитория TypeORM в службу или контроллер.
Когда вы добавляете декоратор @InjectRepository
к свойству класса или параметру конструктора, NestJS автоматически внедряет экземпляр соответствующего репозитория во время выполнения. Например, в классе TodoService
следующая строка:
@InjectRepository(Todo) private readonly todoRepository: Repository<Todo>,
внедряет экземпляр класса Repository<Todo>
, который представляет репозиторий TypeORM для сущности Todo
.
Декоратор @InjectRepository
работает, используя систему внедрения зависимостей, предоставляемую NestJS. Под капотом он создает новый экземпляр репозитория для каждого запроса и гарантирует, что один и тот же экземпляр используется на протяжении всего жизненного цикла запроса. Это помогает избежать проблем с репозиториями с отслеживанием состояния и гарантирует, что каждый запрос обрабатывается независимо.
Класс Repository
в TypeORM предоставляет несколько методов CRUD (создание, чтение, обновление, удаление) для работы с сущностями в базе данных. Вот некоторые из наиболее часто используемых методов:
find(options?: FindManyOptions<Entity>): Promise<Entity[]>
: возвращает массив всех объектов, соответствующих указанным критериямFindManyOptions
, или пустой массив, если объекты не найдены.findOne(id: string | number | Date | ObjectID, options?: FindOneOptions<Entity>): Promise<Entity | undefined>
: возвращает один объект, соответствующий указанному идентификатору или критериям, илиundefined
, если объект не найден.save(entity: Entity, options?: SaveOptions): Promise<Entity>
: Сохраняет указанный объект в базе данных и возвращает сохраненный объект.update(criteria: string | number | Date | ObjectID | FindConditions<Entity>, partialEntity: QueryDeepPartialEntity<Entity>): Promise<UpdateResult>
: обновляет один или несколько объектов, соответствующих указанным критериям, и возвращает объект, содержащий информацию об операции обновления.delete(criteria: string | number | Date | ObjectID | FindConditions<Entity>): Promise<DeleteResult>
: удаляет один или несколько объектов, соответствующих указанным критериям, и возвращает объект, содержащий информацию об операции удаления.count(options?: FindManyOptions<Entity>): Promise<number>
: возвращает общее количество объектов, соответствующих указаннымFindManyOptions
критериям.
Эти методы позволяют выполнять основные операции CRUD над сущностями в базе данных с помощью лаконичного и выразительного API. Они также предоставляют мощные возможности для запросов, сортировки и фильтрации сущностей, упрощая написание сложных запросов к базе данных без необходимости написания необработанного SQL.
Наконец, давайте создадим TodoController
, который будет обрабатывать HTTP-запросы:
// src/todo/todo.controller.ts import { Controller, Get, Post, Put, Delete, Param, Body } from '@nestjs/common'; import { Todo } from './todo.entity'; import { TodoService } from './todo.service'; @Controller('todos') export class TodoController { constructor(private readonly todoService: TodoService) {} @Get() async findAll(): Promise<Todo[]> { return this.todoService.findAll(); } @Get(':id') async findById(@Param('id') id: string): Promise<Todo> { return this.todoService.findById(parseInt(id, 10)); } @Post() async create(@Body() todo: Todo): Promise<Todo> { return this.todoService.create(todo); } @Put(':id') async update(@Param('id') id: string, @Body() todo: Todo): Promise<Todo> { return this.todoService.update(parseInt(id, 10), todo); } @Delete(':id') async delete(@Param('id') id: string): Promise<void> { return this.todoService.delete(parseInt(id, 10)); } }
Вот и все! Теперь вы можете запустить сервер NestJS с помощью npm run start:dev
и протестировать API с помощью таких инструментов, как Postman или curl.
В моем следующем сообщении в блоге я более подробно рассмотрю TypeORM и покажу, как расширить приложение Todo, чтобы включить отношения «один ко многим». Это захватывающая возможность изучить весь потенциал TypeORM, и я верю, что читатели найдут ее интересной и информативной. Так что обязательно следите за ним!
Если вы найдете эту информацию полезной, поддержите меня и следите за обновлениями.🙂