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:
Mathis HERRIOT
2026-01-08 15:27:11 +01:00
parent a0836c8392
commit da5f18bf92
3 changed files with 88 additions and 0 deletions

View 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 });
}
}

View 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 {}

View 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;
}
}