TypeScript Express tutorial #8. Types of relationships with Postgres and TypeORM

188 阅读2分钟

TypeScript Express Postgres Relationships

// src/entities/user/user.entity.ts

import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
 
@Entity({ name: 'users' })
class UserEntity {
  @PrimaryGeneratedColumn()
  public id!: string;
 
  @Column()
  public name?: string;
 
  @Column()
  public email?: string;
 
  @Column()
  public password?: string;
}
 
export default UserEntity;

One-To-One

// src/entities/user/user.entity.ts

import { Column, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn } from 'typeorm';
import AddressEntity from '../address/address.entity';
 
@Entity({ name: 'user' })
class UserEntity {
  @PrimaryGeneratedColumn()
  public id!: string;
 
  @Column()
  public name?: string;
 
  @Column()
  public email?: string;
 
  @Column()
  public password?: string;

  @OneToOne(() => AddressEntity)
  @JoinColumn()
  public address?: AddressEntity;
}
 
export default UserEntity;
// src/entities/address/address.entity.ts

import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
 
@Entity({name: 'address'})
class AddressEntity {
  @PrimaryGeneratedColumn()
  public id!: string;
 
  @Column()
  public street?: string;
 
  @Column()
  public city?: string;
 
  @Column()
  public country?: string;
}
 
export default AddressEntity;

Inverse relationship

// src/entities/user/user.entity.ts

import { Column, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn } from 'typeorm';
import AddressEntity from '../address/address.entity';
 
@Entity({ name: 'user' })
class UserEntity {
  @PrimaryGeneratedColumn()
  public id!: string;
 
  @Column()
  public name?: string;
 
  @Column()
  public email?: string;
 
  @Column()
  public password?: string;

  @OneToOne(() => AddressEntity, (address: AddressEntity) => address.user)
  @JoinColumn()
  public address?: AddressEntity;
}
 
export default UserEntity;
// src/entities/address/address.entity.ts

import UserEntity from '../../entities/user/user.entity';
import { Column, Entity, OneToOne, PrimaryGeneratedColumn } from 'typeorm';
 
@Entity({name: 'address'})
class AddressEntity {
  @PrimaryGeneratedColumn()
  public id!: string;
 
  @Column()
  public street?: string;
 
  @Column()
  public city?: string;
 
  @Column()
  public country?: string;

  @OneToOne(() => UserEntity, (user: UserEntity) => user.address)
  public user?: UserEntity
}
 
export default AddressEntity;
// src/service/address/address.service.ts
export async function getAllAddresses(
	request: express.Request,
	response: express.Response
) {
	const addressRepository = await getRepository(AddressEntity);
	const addresses = await addressRepository.find({relations: ["user"]});
	response.send(addresses);
}
// src/controller/address/address.controller.ts
import * as express from "express";
import Controller from "../../interfaces/controller.interface";

import * as addressService from "../../service/address/address.service";

class AddressController implements Controller {
	public path = "/address";
	public router = express.Router();
	private addressService = addressService;

	constructor() {
		this.initializeRoutes();
	}

	private initializeRoutes() {
		this.router.get(this.path, this.getAllAddresses);
	}

	private getAllAddresses = (
		request: express.Request,
		response: express.Response
	) => {
		this.addressService.getAllAddresses(request, response);
	};

	
}

export default AddressController;

// src/service/user/user.service.ts
import express from "express";
import PostNotFoundException from "../../exceptions/PostNotFoundException";
import RequestWithUser from "../../interfaces/requestWithUser.interface";
import NotAuthorizedException from "../../exceptions/NotAuthorizedException";
import { getRepository } from "../../utils/connectedToDatabase";
import AddressEntity from "../../entities/address/address.entity";
import UserEntity from "../../entities/user/user.entity";

export async function createUser(
	request: RequestWithUser,
	response: express.Response
) {
	// const postData: Post = request.body;
	const usertRepository = await getRepository(UserEntity);
	const user = new UserEntity();
	user.name = 'John Doe';
	user.email = 'jo@host';
	user.password = '123';
	const address = new AddressEntity();
	address.street = 'street';
	address.city = 'city';
	address.country = 'country';
	user.address = address;
	const createdUser = await usertRepository.save(user);
	response.send(createdUser);

}

export async function getUserById(
	request: express.Request,
	response: express.Response,
	next: express.NextFunction
) {
	const id = request.params.id;
	const userRepository = await getRepository(UserEntity);
	const user = await userRepository.findOneBy({ id });

	if (user) {
		response.send(user);
	} else {
		next(new PostNotFoundException(id));
	}
}
//
import * as express from "express";
import Controller from "../../interfaces/controller.interface";

import validationMiddleware from "../../middleware/validation.middleware";
import CreatePostDto from "../../dto/posts/post.dto";
import authMiddleware from '../../middleware/auth.middleware';
import RequestWithUser from '../../interfaces/requestWithUser.interface';

import * as userService from "../../service/user/user.service";

class UserController implements Controller {
	public path = "/users";
	public router = express.Router();
	private userService = userService;

	constructor() {
		this.initializeRoutes();
	}

	private initializeRoutes() {
		this.router.get(`${this.path}/:id`, this.getUserById);

		this.router.post(
			this.path,
			// validationMiddleware(CreatePostDto),
			this.createUser as any
		);
	}

	private getUserById = (
		request: express.Request,
		response: express.Response,
		next: express.NextFunction
	) => {
		this.userService.getUserById(request, response, next);
	};

	private createUser = (
		request: RequestWithUser,
		response: express.Response
	) => {
		this.userService.createUser(request, response);
	};
}

export default UserController;

// src/server.ts

import 'dotenv/config';
import 'reflect-metadata';
import App from './app';
import PostsController from './controller/posts/post.controller';
import UserController from './controller/user/user.controller';

(async () => {

  const app = new App(
    [
      new PostsController(),
      new UserController(),
    ],
  );
  app.listen();
})();

image.png

image.png

One-To-Many and Many-To-One

// src/entities/user/user.entity.ts
import { Column, Entity, JoinColumn, OneToMany, OneToOne, PrimaryGeneratedColumn } from 'typeorm';
import AddressEntity from '../address/address.entity';
import PostEntity from '../../entities/post/post.entity';
 
@Entity({ name: 'user' })
class UserEntity {
  @PrimaryGeneratedColumn()
  public id!: string;
 
  @Column()
  public name?: string;
 
  @Column()
  public email?: string;
 
  @Column()
  public password?: string;

  @OneToOne(() => AddressEntity, (address: AddressEntity) => address.user, {
    cascade: true,
    eager: true,
  })
  @JoinColumn()
  public address?: AddressEntity;

  @OneToMany(() => PostEntity, (post: PostEntity) => post.author)
  public posts?: PostEntity[];
}
 
export default UserEntity;
// src/entities/post/post.entity.ts
import UserEntity from "../../entities/user/user.entity";
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from "typeorm";

@Entity({ name: "post" })
class PostEntity {
	@PrimaryGeneratedColumn()
	public id?: number;

	@Column()
	public title!: string;

	@Column()
	public content!: string;

	@ManyToOne(() => UserEntity, (author: UserEntity) => author.posts)
	public author?: UserEntity;
}

export default PostEntity;

// src/service/posts/post.service.ts

export async function createPost(
	request: RequestWithUser,
	response: express.Response
) {
	const postData: Post = request.body;
	const postRepository = await getRepository(PostEntity);
	const userRepository = await getRepository(UserEntity);


	const user = await userRepository.findOneBy({ id: request.user.id });
	if (!user) {
		throw new NotAuthorizedException();
	}

	const postEntity = new PostEntity();
	postEntity.author = user;
	postEntity.title = postData.title;
	postEntity.content = postData.content;
	const createdPost = await postRepository.save(postEntity);

	response.send(createdPost);
}

Many-To-Many

// src/entities/post/post.entity.ts
import UserEntity from "../../entities/user/user.entity";
import { Column, Entity, JoinTable, ManyToMany, ManyToOne, PrimaryGeneratedColumn } from "typeorm";
import CategoryEntity from '../category/category.entiry';

@Entity({ name: "post" })
class PostEntity {
	@PrimaryGeneratedColumn()
	public id?: number;

	@Column()
	public title!: string;

	@Column()
	public content!: string;

	@ManyToOne(() => UserEntity, (author: UserEntity) => author.posts)
	public author?: UserEntity;

	@ManyToMany(() => CategoryEntity, (category: CategoryEntity) => category.posts)
	@JoinTable()
	categories?: CategoryEntity[];
}

export default PostEntity;
// src/entities/category/category.entity.ts
import PostEntity from '../../entities/post/post.entity';
import { Column, Entity, ManyToMany, PrimaryGeneratedColumn } from 'typeorm';
 
@Entity({name: 'category'})
class CategoryEntity {
  @PrimaryGeneratedColumn()
  public id!: string;
 
  @Column()
  public name!: string;
 
  @Column()
  public pid!: string;

  @ManyToMany(() => PostEntity, (post: PostEntity) => post.categories)
  public posts?: PostEntity[];
}
 
export default CategoryEntity;
// src/service/category/category.service.ts

import express from "express";
import PostNotFoundException from "../../exceptions/PostNotFoundException";
import RequestWithUser from "../../interfaces/requestWithUser.interface";
import NotAuthorizedException from "../../exceptions/NotAuthorizedException";
import { getRepository } from "../../utils/connectedToDatabase";
import CreateCategoryDto from "dto/category/category.dto";
import CategoryEntity from "../../entities/category/category.entiry";

export async function createCategory(
	request: RequestWithUser,
	response: express.Response
) {
	const categoryData: CreateCategoryDto = request.body;
	const categoryRepository = await getRepository(CategoryEntity);
	const categoryEntity = new CategoryEntity();
	categoryEntity.name = categoryData.name;
	categoryEntity.pid = categoryData.pid!;
	const createdCategory = await categoryRepository.save(categoryEntity);

	response.send(createdCategory);
}

export async function getAllCategories(
	request: express.Request,
	response: express.Response
) {
	const categoryRepository = await getRepository(CategoryEntity);
	const addresses = await categoryRepository.find();
	response.send(addresses);
}

export async function getCategoryById(
	request: express.Request,
	response: express.Response,
	next: express.NextFunction
) {
	const id = request.params.id;
	const categoryRepository = await getRepository(CategoryEntity);
	const category = await categoryRepository.findOneBy({ id });

	if (category) {
		response.send(category);
	} else {
		next(new PostNotFoundException(id));
	}
}

export async function modifyCategory(
	request: express.Request,
	response: express.Response,
	next: express.NextFunction
) {
	const id = request.params.id;
	const catigoryData: CreateCategoryDto = request.body;
	const categoryRepository = await getRepository(CategoryEntity);

	const category = await categoryRepository.findOneBy({ id });

	if (category) {
		category.name = catigoryData.name;
		category.pid = catigoryData.pid!;
		await categoryRepository.save(category);
		response.send(category);
	} else {
		next(new PostNotFoundException(id));
	}
}

export async function deleteCategory(
	request: express.Request,
	response: express.Response,
	next: express.NextFunction
) {
	const id = request.params.id;
	const postRepository = await getRepository(CategoryEntity);

	const post = await postRepository.delete(id);

	console.log("delete post: ", post);

	if (post) {
		response.send(200);
	} else {
		next(new PostNotFoundException(id));
	}
}

// src/controller/category/category.controller.ts
import * as express from "express";
import Controller from "../../interfaces/controller.interface";

import validationMiddleware from "../../middleware/validation.middleware";
import authMiddleware from '../../middleware/auth.middleware';
import RequestWithUser from '../../interfaces/requestWithUser.interface';

import * as categoryService from "../../service/category/category.service";

class CategoryController implements Controller {
	public path = "/categories";
	public router = express.Router();
	private categoryService = categoryService;

	constructor() {
		this.initializeRoutes();
	}

	private initializeRoutes() {
		this.router.get(this.path, this.getAllCategories);
		this.router.get(`${this.path}/:id`, this.getCategoryById);
		this.router.patch(`${this.path}/:id`, this.modifyCategory);
		this.router.delete(`${this.path}/:id`, this.deleteCategory);
		this.router.post(
			this.path,
			// validationMiddleware(CreatePostDto),
			this.createCategory as any
		);
	}

	private getAllCategories = (
		request: express.Request,
		response: express.Response
	) => {
		this.categoryService.getAllCategories(request, response);
	};


	private getCategoryById = (
		request: express.Request,
		response: express.Response,
		next: express.NextFunction
	) => {
		this.categoryService.getCategoryById(request, response, next);
	};

	private modifyCategory = (
		request: express.Request,
		response: express.Response,
		next: express.NextFunction
	) => {
		this.categoryService.modifyCategory(request, response, next);
	};

	private createCategory = (
		request: RequestWithUser,
		response: express.Response
	) => {
		this.categoryService.createCategory(request, response);
	};

	private deleteCategory = (
		request: express.Request,
		response: express.Response,
		next: express.NextFunction
	) => {
		this.categoryService.deleteCategory(request, response, next);
	};
}

export default CategoryController;

// src/dto/category/category.dto.ts
import { IsString } from 'class-validator';

class CreateCategoryDto {
  @IsString()
  public name!: string;

  @IsString()
  public pid?: string;

}

export default CreateCategoryDto;
// src/server.ts
import 'dotenv/config';
import 'reflect-metadata';
import App from './app';
import PostsController from './controller/posts/post.controller';
import UserController from './controller/user/user.controller';
import CategoryController from './controller/category/category.controller';

(async () => {

  const app = new App(
    [
      new PostsController(),
      new UserController(),
      new CategoryController()
    ],
  );
  app.listen();
})();

image.png

image.png

source