feat: implement TagsModule with service, controller, and endpoints
Added TagsModule to manage tags, including a TagsService for querying and sorting by popularity or recency. Created TagsController with endpoint to retrieve paginated and searchable tag data. Integrated with database and relevant schemas.
This commit is contained in:
23
backend/src/tags/tags.controller.ts
Normal file
23
backend/src/tags/tags.controller.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import {
|
||||||
|
Controller,
|
||||||
|
DefaultValuePipe,
|
||||||
|
Get,
|
||||||
|
ParseIntPipe,
|
||||||
|
Query,
|
||||||
|
} from "@nestjs/common";
|
||||||
|
import { TagsService } from "./tags.service";
|
||||||
|
|
||||||
|
@Controller("tags")
|
||||||
|
export class TagsController {
|
||||||
|
constructor(private readonly tagsService: TagsService) {}
|
||||||
|
|
||||||
|
@Get()
|
||||||
|
findAll(
|
||||||
|
@Query("limit", new DefaultValuePipe(10), ParseIntPipe) limit: number,
|
||||||
|
@Query("offset", new DefaultValuePipe(0), ParseIntPipe) offset: number,
|
||||||
|
@Query("query") query?: string,
|
||||||
|
@Query("sort") sort?: "popular" | "recent",
|
||||||
|
) {
|
||||||
|
return this.tagsService.findAll({ limit, offset, query, sortBy: sort });
|
||||||
|
}
|
||||||
|
}
|
||||||
12
backend/src/tags/tags.module.ts
Normal file
12
backend/src/tags/tags.module.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { Module } from "@nestjs/common";
|
||||||
|
import { DatabaseModule } from "../database/database.module";
|
||||||
|
import { TagsController } from "./tags.controller";
|
||||||
|
import { TagsService } from "./tags.service";
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [DatabaseModule],
|
||||||
|
controllers: [TagsController],
|
||||||
|
providers: [TagsService],
|
||||||
|
exports: [TagsService],
|
||||||
|
})
|
||||||
|
export class TagsModule {}
|
||||||
53
backend/src/tags/tags.service.ts
Normal file
53
backend/src/tags/tags.service.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import { Injectable } from "@nestjs/common";
|
||||||
|
import { desc, eq, ilike, sql } from "drizzle-orm";
|
||||||
|
import { DatabaseService } from "../database/database.service";
|
||||||
|
import { contentsToTags, tags } from "../database/schemas";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TagsService {
|
||||||
|
constructor(private readonly databaseService: DatabaseService) {}
|
||||||
|
|
||||||
|
async findAll(options: {
|
||||||
|
limit: number;
|
||||||
|
offset: number;
|
||||||
|
query?: string;
|
||||||
|
sortBy?: "popular" | "recent";
|
||||||
|
}) {
|
||||||
|
const { limit, offset, query, sortBy } = options;
|
||||||
|
|
||||||
|
let whereClause = sql`1=1`;
|
||||||
|
if (query) {
|
||||||
|
whereClause = ilike(tags.name, `%${query}%`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pour la popularité, on compte le nombre d'associations dans contentsToTags
|
||||||
|
if (sortBy === "popular") {
|
||||||
|
const data = await this.databaseService.db
|
||||||
|
.select({
|
||||||
|
id: tags.id,
|
||||||
|
name: tags.name,
|
||||||
|
slug: tags.slug,
|
||||||
|
count: sql<number>`count(${contentsToTags.contentId})`.as("usage_count"),
|
||||||
|
})
|
||||||
|
.from(tags)
|
||||||
|
.leftJoin(contentsToTags, eq(tags.id, contentsToTags.tagId))
|
||||||
|
.where(whereClause)
|
||||||
|
.groupBy(tags.id)
|
||||||
|
.orderBy(desc(sql`usage_count`))
|
||||||
|
.limit(limit)
|
||||||
|
.offset(offset);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await this.databaseService.db
|
||||||
|
.select()
|
||||||
|
.from(tags)
|
||||||
|
.where(whereClause)
|
||||||
|
.orderBy(sortBy === "recent" ? desc(tags.createdAt) : desc(tags.name))
|
||||||
|
.limit(limit)
|
||||||
|
.offset(offset);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user