From ec72fd2cdfdf4fdf417dba0413052de220784087 Mon Sep 17 00:00:00 2001 From: dagmawig Date: Sun, 10 Apr 2022 18:14:29 -0500 Subject: [PATCH] feat: update trees route to support planted date range filter --- __tests__/e2e/trees.spec.ts | 19 +++++++++++++++++++ docs/api/spec/query-api.yaml | 5 +++++ server/infra/database/TreeRepository.ts | 22 ++++++++++++++++++++++ server/models/Tree.ts | 12 +++++++++++- server/routers/treesRouter.ts | 21 ++++++++++++++++++--- 5 files changed, 75 insertions(+), 4 deletions(-) diff --git a/__tests__/e2e/trees.spec.ts b/__tests__/e2e/trees.spec.ts index 49831fd8..b74a0bc9 100644 --- a/__tests__/e2e/trees.spec.ts +++ b/__tests__/e2e/trees.spec.ts @@ -50,6 +50,25 @@ describe('trees', () => { 1000 * 60, ); + it( + 'trees?startDate=2021-02-26&endDate=2021-12-22', + async () => { + const response = await supertest(app).get( + '/trees?startDate=2021-02-26&endDate=2021-12-22', + ); + expect(response.status).toBe(200); + for (let i = 0; i < response.body.trees.length; i++) { + expect( + new Date(response.body.trees[i].time_created).getTime(), + ).toBeGreaterThanOrEqual(new Date('2021-02-26T00:00:00Z').getTime()); + expect( + new Date(response.body.trees[i].time_created).getTime(), + ).toBeLessThan(new Date('2021-12-23T00:00:00Z').getTime()); + } + }, + 1000 * 60, + ); + it( 'trees/featured', async () => { diff --git a/docs/api/spec/query-api.yaml b/docs/api/spec/query-api.yaml index 2b6fb3a9..8934f7fe 100644 --- a/docs/api/spec/query-api.yaml +++ b/docs/api/spec/query-api.yaml @@ -82,6 +82,11 @@ paths: - schema: type: string in: query + name: startDate & endDate + description: Filter by date range + - schema: + type: string + in: query /trees/featured: get: summary: get featured tree list diff --git a/server/infra/database/TreeRepository.ts b/server/infra/database/TreeRepository.ts index 18f638c6..2bac3616 100644 --- a/server/infra/database/TreeRepository.ts +++ b/server/infra/database/TreeRepository.ts @@ -23,4 +23,26 @@ export default class TreeRepository extends BaseRepository { const object = await this.session.getDB().raw(sql); return object.rows; } + + async getByDateRange( + date_range: { startDate: string; endDate: string }, + options: FilterOptions, + ) { + const { limit, offset } = options; + const startDateISO = `${date_range.startDate }T00:00:00.000Z`; + const endDateISO = new Date( + new Date(`${date_range.endDate }T00:00:00.000Z`).getTime() + 86400000, + ).toISOString(); + const sql = ` + SELECT + * + FROM trees + WHERE time_created >= '${startDateISO}'::timestamp + AND time_created < '${endDateISO}'::timestamp + LIMIT ${limit} + OFFSET ${offset} + `; + const object = await this.session.getDB().raw(sql); + return object.rows; + } } diff --git a/server/models/Tree.ts b/server/models/Tree.ts index 953df453..072a1a2f 100644 --- a/server/models/Tree.ts +++ b/server/models/Tree.ts @@ -4,7 +4,10 @@ import Tree from 'interfaces/Tree'; import { delegateRepository } from '../infra/database/delegateRepository'; import TreeRepository from '../infra/database/TreeRepository'; -type Filter = Partial<{ organization_id: number }>; +type Filter = Partial<{ + organization_id: number; + date_range: { startDate: string; endDate: string }; +}>; function getByFilter( treeRepository: TreeRepository, @@ -17,6 +20,13 @@ function getByFilter( options, ); return trees; + } if (filter.date_range) { + log.warn('using date range filter...'); + const trees = await treeRepository.getByDateRange( + filter.date_range, + options, + ); + return trees; } const trees = await treeRepository.getByFilter(filter, options); return trees; diff --git a/server/routers/treesRouter.ts b/server/routers/treesRouter.ts index 66b12f14..8090d4ab 100644 --- a/server/routers/treesRouter.ts +++ b/server/routers/treesRouter.ts @@ -6,7 +6,11 @@ import TreeRepository from '../infra/database/TreeRepository'; import TreeModel from '../models/Tree'; const router = express.Router(); -type Filter = Partial<{ planter_id: number; organization_id: number }>; +type Filter = Partial<{ + planter_id: number; + organization_id: number; + date_range: { startDate: string; endDate: string }; +}>; router.get( '/featured', @@ -43,22 +47,33 @@ router.get( organization_id: Joi.number().integer().min(0), limit: Joi.number().integer().min(1).max(1000), offset: Joi.number().integer().min(0), + startDate: Joi.string().regex(/^\d{4}-\d{2}-\d{2}$/), + endDate: Joi.string().regex(/^\d{4}-\d{2}-\d{2}$/), }), ); - const { limit = 20, offset = 0, planter_id, organization_id } = req.query; + const { + limit = 20, + offset = 0, + planter_id, + organization_id, + startDate, + endDate, + } = req.query; const repo = new TreeRepository(new Session()); const filter: Filter = {}; if (planter_id) { filter.planter_id = planter_id; } else if (organization_id) { filter.organization_id = organization_id; + } else if (startDate && endDate) { + filter.date_range = { startDate, endDate }; } const result = await TreeModel.getByFilter(repo)(filter, { limit, offset, }); res.send({ - total: null, + total: startDate && endDate ? result.length : null, offset, limit, trees: result,