diff --git a/src/routes/getSearchSegments.ts b/src/routes/getSearchSegments.ts index 3d5e467..d8fc860 100644 --- a/src/routes/getSearchSegments.ts +++ b/src/routes/getSearchSegments.ts @@ -1,8 +1,9 @@ import { Request, Response } from "express"; import { db } from "../databases/databases"; -import { ActionType, Category, DBSegment, Service, VideoID } from "../types/segments.model"; +import { ActionType, Category, DBSegment, Service, VideoID, SortableFields } from "../types/segments.model"; import { getService } from "../utils/getService"; -const segmentsPerPage = 10; +const maxSegmentsPerPage = 100; +const defaultSegmentsPerPage = 10; type searchSegmentResponse = { segmentCount: number, @@ -19,6 +20,42 @@ function getSegmentsFromDBByVideoID(videoID: VideoID, service: Service): Promise ) as Promise; } +function getSortField(...value: T[]): SortableFields { + const fieldByName = Object.values(SortableFields).reduce((acc, fieldName) => { + acc[fieldName.toLowerCase()] = fieldName; + + return acc; + }, {} as Record); + + for (const name of value) { + if (name?.trim()?.toLowerCase() in fieldByName) { + return fieldByName[name.trim().toLowerCase()]; + } + } + + return SortableFields.timeSubmitted; +} + +function getLimit(value: T): number { + const limit = Number(value); + if (Number.isInteger(limit) + && limit >= 1 + && limit <= maxSegmentsPerPage) { + return limit; + } + + return defaultSegmentsPerPage; +} + +function getPage(value: T): number { + const page = Number(value); + if (Number.isInteger(page) && page >= 0) { + return page; + } + + return 0; +} + /** * * Returns what would be sent to the client. @@ -62,8 +99,10 @@ async function handleGetSegments(req: Request, res: Response): Promise) { - const startIndex = 0+(page*segmentsPerPage); - const endIndex = segmentsPerPage+(page*segmentsPerPage); +function filterSegments(segments: DBSegment[], filters: Record, page: number, limit: number, sortBy: SortableFields, sortDir: string) { + const startIndex = 0+(page*limit); + const endIndex = limit+(page*limit); const filteredSegments = segments.filter((segment) => !((segment.votes < filters.minVotes || segment.votes > filters.maxVotes) || (segment.views < filters.minViews || segment.views > filters.maxViews) @@ -114,10 +153,27 @@ function filterSegments(segments: DBSegment[], page: number, filters: Record { + const key = sortDir === "desc" ? 1 : -1; + if (a[sortBy] < b[sortBy]) { + return key; + } + + if (a[sortBy] > b[sortBy]) { + return -key; + } + + return 0; + }); + } + return { segmentCount: filteredSegments.length, page, segments: filteredSegments.slice(startIndex, endIndex) + }; } diff --git a/src/types/segments.model.ts b/src/types/segments.model.ts index a94bd8e..ba613c4 100644 --- a/src/types/segments.model.ts +++ b/src/types/segments.model.ts @@ -107,4 +107,12 @@ export interface LockCategory { reason: string, videoID: VideoID, userID: UserID -} \ No newline at end of file +} + +export enum SortableFields { + timeSubmitted = "timeSubmitted", + startTime = "startTime", + endTime = "endTime", + votes = "votes", + views = "views", +} diff --git a/test/cases/getSearchSegments.ts b/test/cases/getSearchSegments.ts index 2852f90..0084204 100644 --- a/test/cases/getSearchSegments.ts +++ b/test/cases/getSearchSegments.ts @@ -281,4 +281,222 @@ describe("getSearchSegments", () => { }) .catch(err => done(err)); }); + + it("Should be able to get with custom limit", (done) => { + client.get(endpoint, { params: { videoID: "searchTest4", limit: 2 } }) + .then(res => { + assert.strictEqual(res.status, 200); + const data = res.data; + const segments = data.segments; + assert.strictEqual(data.segmentCount, 12); + assert.strictEqual(data.page, 0); + assert.strictEqual(segments.length, 2); + done(); + }) + .catch(err => done(err)); + }); + + it("Should be able to get with custom limit(2) and page(2)", (done) => { + client.get(endpoint, { params: { videoID: "searchTest4", limit: 2, page: 2 } }) + .then(res => { + assert.strictEqual(res.status, 200); + const data = res.data; + const segments = data.segments; + assert.strictEqual(data.segmentCount, 12); + assert.strictEqual(data.page, 2); + assert.strictEqual(segments.length, 2); + assert.strictEqual(segments[0].UUID, "search-page1-5"); + assert.strictEqual(segments[1].UUID, "search-page1-6"); + done(); + }) + .catch(err => done(err)); + }); + + it("Should be able to get with over range page", (done) => { + client.get(endpoint, { params: { videoID: "searchTest4", limit: 2, page: 2000 } }) + .then(res => { + assert.strictEqual(res.status, 200); + const data = res.data; + const segments = data.segments; + assert.strictEqual(data.segmentCount, 12); + assert.strictEqual(data.page, 2000); + assert.strictEqual(segments.length, 0); + done(); + }) + .catch(err => done(err)); + }); + + it("Should be able to get with invalid page (=-100)", (done) => { + client.get(endpoint, { params: { videoID: "searchTest4", page: -100 } }) + .then(res => { + assert.strictEqual(res.status, 200); + const data = res.data; + const segments = data.segments; + assert.strictEqual(data.segmentCount, 12); + assert.strictEqual(data.page, 0); + assert.strictEqual(segments.length, 10); + done(); + }) + .catch(err => done(err)); + }); + + it("Should be able to get with invalid page (=text)", (done) => { + client.get(endpoint, { params: { videoID: "searchTest4", page: "hello" } }) + .then(res => { + assert.strictEqual(res.status, 200); + const data = res.data; + const segments = data.segments; + assert.strictEqual(data.segmentCount, 12); + assert.strictEqual(data.page, 0); + assert.strictEqual(segments.length, 10); + done(); + }) + .catch(err => done(err)); + }); + + it("Should be use default limit if invalid limit query (=0)", (done) => { + client.get(endpoint, { params: { videoID: "searchTest4", limit: 0 } }) + .then(res => { + assert.strictEqual(res.status, 200); + const data = res.data; + const segments = data.segments; + assert.strictEqual(data.segmentCount, 12); + assert.strictEqual(data.page, 0); + assert.strictEqual(segments[0].UUID, "search-page1-1"); + assert.strictEqual(segments[1].UUID, "search-page1-2"); + assert.strictEqual(segments[2].UUID, "search-page1-3"); + assert.strictEqual(segments[3].UUID, "search-page1-4"); + assert.strictEqual(segments[4].UUID, "search-page1-5"); + assert.strictEqual(segments[5].UUID, "search-page1-6"); + assert.strictEqual(segments[6].UUID, "search-page1-7"); + assert.strictEqual(segments[7].UUID, "search-page1-8"); + assert.strictEqual(segments[8].UUID, "search-page1-9"); + assert.strictEqual(segments[9].UUID, "search-page1-10"); + done(); + }) + .catch(err => done(err)); + }); + + it("Should be use default limit if invalid limit query (=-100)", (done) => { + client.get(endpoint, { params: { videoID: "searchTest4", limit: -100 } }) + .then(res => { + assert.strictEqual(res.status, 200); + const data = res.data; + const segments = data.segments; + assert.strictEqual(data.segmentCount, 12); + assert.strictEqual(data.page, 0); + assert.strictEqual(segments[0].UUID, "search-page1-1"); + assert.strictEqual(segments[1].UUID, "search-page1-2"); + assert.strictEqual(segments[2].UUID, "search-page1-3"); + assert.strictEqual(segments[3].UUID, "search-page1-4"); + assert.strictEqual(segments[4].UUID, "search-page1-5"); + assert.strictEqual(segments[5].UUID, "search-page1-6"); + assert.strictEqual(segments[6].UUID, "search-page1-7"); + assert.strictEqual(segments[7].UUID, "search-page1-8"); + assert.strictEqual(segments[8].UUID, "search-page1-9"); + assert.strictEqual(segments[9].UUID, "search-page1-10"); + done(); + }) + .catch(err => done(err)); + }); + + it("Should be use default limit if invalid limit query (=text)", (done) => { + client.get(endpoint, { params: { videoID: "searchTest4", limit: "hello" } }) + .then(res => { + assert.strictEqual(res.status, 200); + const data = res.data; + const segments = data.segments; + assert.strictEqual(data.segmentCount, 12); + assert.strictEqual(data.page, 0); + assert.strictEqual(segments[0].UUID, "search-page1-1"); + assert.strictEqual(segments[1].UUID, "search-page1-2"); + assert.strictEqual(segments[2].UUID, "search-page1-3"); + assert.strictEqual(segments[3].UUID, "search-page1-4"); + assert.strictEqual(segments[4].UUID, "search-page1-5"); + assert.strictEqual(segments[5].UUID, "search-page1-6"); + assert.strictEqual(segments[6].UUID, "search-page1-7"); + assert.strictEqual(segments[7].UUID, "search-page1-8"); + assert.strictEqual(segments[8].UUID, "search-page1-9"); + assert.strictEqual(segments[9].UUID, "search-page1-10"); + done(); + }) + .catch(err => done(err)); + }); + + it("Should be use default limit if invalid limit query (=2000)", (done) => { + client.get(endpoint, { params: { videoID: "searchTest4", limit: 2000 } }) + .then(res => { + assert.strictEqual(res.status, 200); + const data = res.data; + const segments = data.segments; + assert.strictEqual(data.segmentCount, 12); + assert.strictEqual(data.page, 0); + assert.strictEqual(segments[0].UUID, "search-page1-1"); + assert.strictEqual(segments[1].UUID, "search-page1-2"); + assert.strictEqual(segments[2].UUID, "search-page1-3"); + assert.strictEqual(segments[3].UUID, "search-page1-4"); + assert.strictEqual(segments[4].UUID, "search-page1-5"); + assert.strictEqual(segments[5].UUID, "search-page1-6"); + assert.strictEqual(segments[6].UUID, "search-page1-7"); + assert.strictEqual(segments[7].UUID, "search-page1-8"); + assert.strictEqual(segments[8].UUID, "search-page1-9"); + assert.strictEqual(segments[9].UUID, "search-page1-10"); + done(); + }) + .catch(err => done(err)); + }); + + it("Should be able to get sorted result (desc)", (done) => { + client.get(endpoint, { params: { videoID: "searchTest4", sortBy: "endTime", sortDir: "desc" } }) + .then(res => { + assert.strictEqual(res.status, 200); + const data = res.data; + const segments = data.segments; + assert.strictEqual(data.segmentCount, 12); + assert.strictEqual(data.page, 0); + assert.strictEqual(segments[0].UUID, "search-page2-2"); + assert.strictEqual(segments[1].UUID, "search-page2-1"); + assert.strictEqual(segments[2].UUID, "search-page1-10"); + assert.strictEqual(segments[3].UUID, "search-page1-9"); + assert.strictEqual(segments[4].UUID, "search-page1-8"); + done(); + }) + .catch(err => done(err)); + }); + + it("Should be able to get sorted result (asc)", (done) => { + client.get(endpoint, { params: { videoID: "searchTest4", sortBy: "endTime" } }) + .then(res => { + assert.strictEqual(res.status, 200); + const data = res.data; + const segments = data.segments; + assert.strictEqual(data.segmentCount, 12); + assert.strictEqual(data.page, 0); + assert.strictEqual(segments[0].UUID, "search-page1-1"); + assert.strictEqual(segments[1].UUID, "search-page1-2"); + assert.strictEqual(segments[2].UUID, "search-page1-3"); + assert.strictEqual(segments[3].UUID, "search-page1-4"); + assert.strictEqual(segments[4].UUID, "search-page1-5"); + done(); + }) + .catch(err => done(err)); + }); + + it("Should be use default sorted if invalid sort field", (done) => { + client.get(endpoint, { params: { videoID: "searchTest4", sortBy: "not exist", sortDir: "desc" } }) + .then(res => { + assert.strictEqual(res.status, 200); + const data = res.data; + const segments = data.segments; + assert.strictEqual(data.segmentCount, 12); + assert.strictEqual(data.page, 0); + assert.strictEqual(segments[0].UUID, "search-page1-1"); + assert.strictEqual(segments[1].UUID, "search-page1-2"); + assert.strictEqual(segments[2].UUID, "search-page1-3"); + assert.strictEqual(segments[3].UUID, "search-page1-4"); + assert.strictEqual(segments[4].UUID, "search-page1-5"); + done(); + }) + .catch(err => done(err)); + }); });