D11 要在应用里添加分类功能。分类也可以看成是应用里的一种实体,我们可以创建一个模块专门去处理分类相关的东西。
src/modules/category/category.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm'; import { Post } from '../post/post.entity'; @Entity() export class Category { @PrimaryGeneratedColumn() id: number; @Column() name: string; @Column() alias: string; @OneToMany(type => Post, post => post.category) posts: Post[]; }
上面定义了一个简单的分类实体,里面有 id、name 还有 alias 字段。name 是分类的名字,alias 表示分类的一个别名,比如一个中文分类可以对应一个英文的别名。
在分类实里面定义了它跟 Post 这种实体之间的一对多的关系,一个分类可以对应多个文章内容。这个关系里描述了关系关联的实体的 type 是 Post,在 Post 那一边儿,对应的关系应该是 post.category,也就是 Post 实体上应该有一个叫 category 的关系。
src/modules/post/post.entity.ts
@ManyToOne(type => Category, category => category.posts) category: Category;
上面用 @ManyToOne 在 Post 实体上定义了一个叫 category 的关系,这个关系关联的实体类型是 Category,在分类实体那里对应的关系应该是 category.posts 。
我们可以利用存储的分类与文章内容的关系,比如在获取文章列表的时候可以按照内容的分类筛选一下,先添加一个装饰器处理一下请求地址里的查询参数:
src/core/decorators/list-options.decorator.ts
import { createParamDecorator } from '@nestjs/common'; export const ListOptions = createParamDecorator((data, req) => { let { categories } = req.query; if (categories) { categories = categories.split('-'); } return { categories } });
src/modules/post/post.controller.ts
@Get() @UseInterceptors(ClassSerializerInterceptor) async index( @ListOptions() options: ListOptionsInterface ) { return await this.postService.index(options); }
src/modules/post/post.service.ts
async index(options: ListOptionsInterface) { const { categories } = options; const queryBuilder = await this.postRepository .createQueryBuilder('post'); queryBuilder.leftJoinAndSelect('post.user', 'user'); queryBuilder.leftJoinAndSelect('post.category', 'category'); if (categories) { queryBuilder.where('category.alias IN (:...categories)', { categories }); } const entities = queryBuilder.getMany(); return entities; }
像上面这样改进一下文章内容的控制器方法还有对应的服务方法。这样在请求获取内容列表的时候,可以在请求地址里添加 categories 查询参数,它的值可以是一组分类实体的别名。比如:localhost:3000/posts?categories=landscape-emotion 。
这个地址里 categories 这个查询参数的值是 landscape-emotion,ListOptions 装饰器可以把这个字符串处理成一个数组然后把这个数组交给它装饰的参数。