Creating a PostgreSQL database
get orbstack and install it to get a docker environment.
create docker-compose.yml and add it to your .gitignore.
version: "3"
services:
postgres:
container_name: postgres
image: postgres:latest
ports:
- "5432:5432"
volumes:
- /data/postgres:/data/postgres
env_file:
- docker.env
networks:
- postgres
pgadmin:
links:
- postgres:postgres
container_name: pgadmin
image: dpage/pgadmin4
ports:
- "8080:80"
volumes:
- /data/pgadmin:/root/.pgadmin
env_file:
- docker.env
networks:
- postgres
networks:
postgres:
driver: bridge
create docker.env and add it to your .gitignore.
POSTGRES_USER=admin
POSTGRES_PASSWORD=admin
POSTGRES_DB=nestjs
PGADMIN_DEFAULT_EMAIL=admin@admin.com
PGADMIN_DEFAULT_PASSWORD=admin
docker-compose up
you can connect your postgres db with vscode mysql extention or navicat or pgadmin as you prefered.
pnpm i @nestjs/config
// src/app.module/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { PostsModule } from '../modules/posts/posts.module';
import { ConfigModule } from '@nestjs/config';
@Module({
imports: [PostsModule, ConfigModule.forRoot()],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
create .env and add it to your .gitignore.
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_USER=admin
POSTGRES_PASSWORD=admin
POSTGRES_DB=nestjs
PORT=5000
Validating environment variables
pnpm i joi
// src/app.module/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { PostsModule } from '../modules/posts/posts.module';
import { ConfigModule } from '@nestjs/config';
import * as Joi from 'joi';
@Module({
imports: [
PostsModule,
// TODO: why ?
ConfigModule.forRoot({
validationSchema: Joi.object({
POSTGRES_HOST: Joi.string().required(),
POSTGRES_PORT: Joi.number().required(),
POSTGRES_USER: Joi.string().required(),
POSTGRES_PASSWORD: Joi.string().required(),
POSTGRES_DB: Joi.string().required(),
PORT: Joi.number(),
}),
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
pnpm i @nestjs/typeorm typeorm pg
nest g mo modules/database
// src/modules/database/database.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule, ConfigService } from '@nestjs/config';
@Module({
imports: [
// TODO: why
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
type: 'postgres',
host: configService.get('POSTGRES_HOST'),
port: configService.get('POSTGRES_PORT'),
username: configService.get('POSTGRES_USER'),
password: configService.get('POSTGRES_PASSWORD'),
database: configService.get('POSTGRES_DB'),
entities: [__dirname + '/../**/*.entity{.ts,.js}'],
synchronize: true,
}),
}),
],
})
export class DatabaseModule {}
import DatabaseModule.
// src/app.module/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { PostsModule } from '../modules/posts/posts.module';
import { ConfigModule } from '@nestjs/config';
import * as Joi from 'joi';
import { DatabaseModule } from '../modules/database/database.module';
@Module({
imports: [
PostsModule,
ConfigModule.forRoot({
validationSchema: Joi.object({
POSTGRES_HOST: Joi.string().required(),
POSTGRES_PORT: Joi.number().required(),
POSTGRES_USER: Joi.string().required(),
POSTGRES_PASSWORD: Joi.string().required(),
POSTGRES_DB: Joi.string().required(),
PORT: Joi.number(),
}),
}),
DatabaseModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Entities
// src/modules/posts/entities/post.entity.ts
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
class Post {
@PrimaryGeneratedColumn()
public id: number;
@Column()
public title: string;
@Column()
public content: string;
}
export default Post;
// src/modules/posts/entities/post.entity.ts
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity({ name: 'posts' })
class PostEntity {
@PrimaryGeneratedColumn()
public id: number;
@Column()
public title: string;
@Column()
public content: string;
}
export default PostEntity;
Repositories
// src/modules/posts/posts.module.ts
import { Module } from '@nestjs/common';
import { PostsService } from './posts.service';
import { PostsController } from './posts.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import PostEntity from './entities/post.entity';
@Module({
imports: [TypeOrmModule.forFeature([PostEntity])],
controllers: [PostsController],
providers: [PostsService],
})
export class PostsModule {}
// src/modules/posts/posts.service.ts
import { Injectable } from '@nestjs/common';
import { CreatePostDto } from './dto/create-post.dto';
import { UpdatePostDto } from './dto/update-post.dto';
import { InjectRepository } from '@nestjs/typeorm';
import PostEntity from './entities/post.entity';
import { Repository } from 'typeorm';
@Injectable()
export class PostsService {
constructor(
@InjectRepository(PostEntity)
private postRepository: Repository<PostEntity>,
) {}
//...
}
Finding
// src/modules/posts/posts.service.ts
import { Injectable } from '@nestjs/common';
import { CreatePostDto } from './dto/create-post.dto';
import { UpdatePostDto } from './dto/update-post.dto';
import { InjectRepository } from '@nestjs/typeorm';
import PostEntity from './entities/post.entity';
import { Repository } from 'typeorm';
@Injectable()
export class PostsService {
constructor(
@InjectRepository(PostEntity)
private postRepository: Repository<PostEntity>,
) {}
//...
findAll() {
return this.postsRepository.find();
}
//...
}
// src/modules/posts/posts.service.ts
//...
async findOne(id: number) {
const post = await this.postsRepository.findOneBy({ id });
if (post) {
return post;
}
throw new HttpException('Post not found', HttpStatus.NOT_FOUND);
}
Creating
// src/modules/posts/posts.service.ts
async create(createPostDto: CreatePostDto) {
const newPost = await this.postsRepository.create(createPostDto);
await this.postsRepository.save(newPost);
return newPost;
}
Modifying
// src/modules/posts/posts.service.ts
async update(id: number, updatePostDto: UpdatePostDto) {
await this.postsRepository.update(id, updatePostDto);
const updatedPost = await this.postsRepository.findOneBy({ id });
if (updatedPost) {
return updatedPost;
}
throw new HttpException('Post not found', HttpStatus.NOT_FOUND);
}
Deleting
// src/modules/posts/posts.service.ts
async remove(id: number) {
const deleteResponse = await this.postsRepository.delete(id);
if (!deleteResponse.affected) {
throw new HttpException('Post not found', HttpStatus.NOT_FOUND);
}
}
ref: