diff --git a/backend/src/deals/deals.controller.ts b/backend/src/deals/deals.controller.ts index d2b0a97..f20ee93 100644 --- a/backend/src/deals/deals.controller.ts +++ b/backend/src/deals/deals.controller.ts @@ -1,5 +1,5 @@ import { Controller, Get, Param, Query, HttpException } from "@nestjs/common"; -import { DealsService } from "./deals.service"; +import { DealsService, SortField, SortDirection } from "./deals.service"; import { Deal } from "./interfaces/deal.interface"; @Controller("deals") @@ -12,14 +12,24 @@ export class DealsController { @Query("limit") limit = 1, @Query("category") category: string, @Query("query") query: string, + @Query("sort_field") sortField: SortField, + @Query("sort_direction") sortDirection: SortDirection, ): Promise { + // Category is always needed if (!category) { throw new HttpException("Category must be defined", 500); } if (query) { - return this.dealService.searchItems(category, Number(start), Number(limit), query); + return this.dealService.searchItems( + category, + Number(start), + Number(limit), + query, + sortField, + sortDirection, + ); } else { - return this.dealService.findAll(category, Number(start), Number(limit)); + return this.dealService.findAll(category, Number(start), Number(limit), sortField, sortDirection); } } } diff --git a/backend/src/deals/deals.service.ts b/backend/src/deals/deals.service.ts index abc98da..cfaf6d8 100644 --- a/backend/src/deals/deals.service.ts +++ b/backend/src/deals/deals.service.ts @@ -7,21 +7,95 @@ import { Deal } from "./interfaces/deal.interface"; export class DealsService { constructor(@InjectModel("Deal") private readonly dealModel: Model) {} - async findAll(category: string, start: number, limit: number): Promise { + /** + * Get items by category + * @param category + * @param start amount of items to skip + * @param limit amount of items to return + * @param sortField + * @param sortDirection + */ + async findAll( + category: string, + start: number, + limit: number, + sortField: SortField, + sortDirection: SortDirection, + ): Promise { const deals = await this.dealModel .find({ category }) .skip(start) .limit(limit) + .sort(this.getSortingObject(sortField, sortDirection)) .exec(); return deals; } - async searchItems(category: string, start: number, limit: number, query: string): Promise { + /** + * Uses the text index to search items by category + * @param category + * @param start amount of items to skip + * @param limit amount of items to return + * @param query search string + * @param sortField + * @param sortDirection + */ + async searchItems( + category: string, + start: number, + limit: number, + query: string, + sortField: SortField, + sortDirection: SortDirection, + ): Promise { const deals = await this.dealModel .find({ $text: { $search: query }, category }) .skip(start) .limit(limit) + .sort(this.getSortingObject(sortField, sortDirection)) .exec(); return deals; } + + /** + * Construct the object which is passed into the sort function + * This is needed to easily make the default available + * @param sortField + * @param sortDirection + */ + getSortingObject(sortField: SortField, sortDirection: SortDirection) { + switch (sortField) { + case SortField.date: + return { date: this.getSortingDirectionNumber(sortDirection) }; + case SortField.name: + return { name: this.getSortingDirectionNumber(sortDirection) }; + case SortField.percent: + return { percent: this.getSortingDirectionNumber(sortDirection) }; + case SortField.price: + return { priceNew: this.getSortingDirectionNumber(sortDirection) }; + default: + return {}; + } + } + + /** + * Mongo needs a "1" for ascending sorting and "-1" for descending + * Since this can be mixed up easily this is abstracted to the enum + * @param sortDirection + */ + getSortingDirectionNumber(sortDirection: SortDirection): number { + return sortDirection === SortDirection.asc ? 1 : -1; + } +} + +export enum SortField { + price = "price", + percent = "percent", + name = "name", + date = "date", +} + +export enum SortDirection { + asc = "asc", + desc = "desc", } diff --git a/backend/src/deals/interfaces/deal.interface.ts b/backend/src/deals/interfaces/deal.interface.ts index 168431a..f25dfcf 100644 --- a/backend/src/deals/interfaces/deal.interface.ts +++ b/backend/src/deals/interfaces/deal.interface.ts @@ -2,11 +2,11 @@ import { Document } from "mongoose"; export interface Deal extends Document { readonly name: string; - readonly category: string; - readonly date: string; - readonly percent: string; + readonly category: number; + readonly date: Date; + readonly percent: number; readonly link: string; - readonly priceNew: string; - readonly priceOld: string; + readonly priceNew: number; + readonly priceOld: number; readonly seller: string; } diff --git a/backend/src/deals/schemas/deal.schema.ts b/backend/src/deals/schemas/deal.schema.ts index 5e1d949..c252f91 100644 --- a/backend/src/deals/schemas/deal.schema.ts +++ b/backend/src/deals/schemas/deal.schema.ts @@ -3,12 +3,12 @@ import * as mongoose from "mongoose"; export const DealSchema = new mongoose.Schema( { name: String, - category: String, - date: String, - percent: String, + category: Number, + date: Date, + percent: Number, link: String, - priceNew: String, - priceOld: String, + priceNew: Number, + priceOld: Number, seller: String, }, { collection: "items" },