Skip to content

Commit

Permalink
feat: data pagination
Browse files Browse the repository at this point in the history
  • Loading branch information
marklai1998 committed Jul 7, 2023
1 parent 5b82225 commit 512cf72
Show file tree
Hide file tree
Showing 17 changed files with 240 additions and 54 deletions.
3 changes: 3 additions & 0 deletions src/constants/pagination.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const defaultOffset = 0
export const defaultMaxLimit = 30
export const defaultLimit = defaultMaxLimit / 2
13 changes: 11 additions & 2 deletions src/modules/fares/fares.controller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Controller, Get, Query } from '@nestjs/common'

import { defaultLimit, defaultOffset } from '../../constants/pagination.js'
import { ListFaresQueryDto } from './fares.dto.js'
import { FaresService } from './fares.service.js'

Expand All @@ -8,7 +9,15 @@ export class FaresController {
constructor(private readonly fareService: FaresService) {}

@Get()
listFares(@Query() { from, to }: ListFaresQueryDto) {
return this.fareService.listFares({ from, to })
listFares(
@Query()
{
from,
to,
offset = defaultOffset,
limit = defaultLimit,
}: ListFaresQueryDto
) {
return this.fareService.listFares({ from, to, offset, limit })
}
}
24 changes: 23 additions & 1 deletion src/modules/fares/fares.dto.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,34 @@
import { IsEnum, IsOptional } from 'class-validator'
import { ArgsType, Field, Int } from '@nestjs/graphql'
import { Type } from 'class-transformer'
import { IsEnum, IsInt, IsOptional, Max, Min } from 'class-validator'
import { StopCode } from 'mtr-kit'

import { defaultMaxLimit } from '../../constants/pagination.js'

@ArgsType()
export class ListFaresQueryDto {
@IsEnum(StopCode)
@IsOptional()
@Field(() => StopCode, { nullable: true })
from?: StopCode

@IsEnum(StopCode)
@IsOptional()
@Field(() => StopCode, { nullable: true })
to?: StopCode

@Type(() => Number)
@IsInt()
@Min(0)
@IsOptional()
@Field(() => Int, { nullable: true })
offset?: number

@Type(() => Number)
@IsInt()
@Max(defaultMaxLimit)
@Min(0)
@IsOptional()
@Field(() => Int, { nullable: true })
limit?: number
}
14 changes: 10 additions & 4 deletions src/modules/fares/fares.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Args, Query, Resolver } from '@nestjs/graphql'
import { StopCode } from 'mtr-kit'

import { defaultLimit, defaultOffset } from '../../constants/pagination.js'
import { ListFaresQueryDto } from './fares.dto.js'
import { Fare } from './fares.model.js'
import { FaresService } from './fares.service.js'

Expand All @@ -10,9 +11,14 @@ export class FaresResolver {

@Query(() => [Fare])
fares(
@Args('from', { type: () => StopCode, nullable: true }) from: StopCode,
@Args('to', { type: () => StopCode, nullable: true }) to: StopCode
@Args()
{
from,
to,
offset = defaultOffset,
limit = defaultLimit,
}: ListFaresQueryDto
) {
return this.faresService.listFares({ from, to })
return this.faresService.listFares({ from, to, offset, limit })
}
}
19 changes: 17 additions & 2 deletions src/modules/fares/fares.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Injectable } from '@nestjs/common'
import { Interval, Timeout } from '@nestjs/schedule'
import { LineCode, StopCode, fareApi, stops } from 'mtr-kit'
import { drop, take } from 'ramda'

import { normalizeStopName } from '../../utils/normalizeStopName.js'

Expand Down Expand Up @@ -116,10 +117,24 @@ export class FaresService {
this.fares = [...mtrFares, ...airportExpressFares]
}

async listFares({ from, to }: { from?: StopCode; to?: StopCode }) {
return this.fares.filter(
async listFares({
from,
to,
offset,
limit,
}: {
from?: StopCode
to?: StopCode
offset?: number
limit?: number
}) {
const res = this.fares.filter(
item => (!from || item.from === from) && (!to || item.to === to)
)

const withOffset = offset ? drop(offset, res) : res
const withLimit = limit ? take(limit, withOffset) : withOffset
return withLimit
}

listLineStopFares(_: LineCode, stop: StopCode) {
Expand Down
11 changes: 8 additions & 3 deletions src/modules/lines/lines.controller.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Controller, Get, Param } from '@nestjs/common'
import { Controller, Get, Param, Query } from '@nestjs/common'
import { LineCode, StopCode } from 'mtr-kit'

import { defaultLimit, defaultOffset } from '../../constants/pagination.js'
import { SchedulesService } from '../schedules/schedules.service.js'
import { ListLinesQueryDto } from './lines.dto.js'
import { LinesService } from './lines.service.js'

@Controller('/api/v1/lines')
Expand All @@ -12,8 +14,11 @@ export class LinesController {
) {}

@Get()
listLines() {
return this.linesService.listLines()
listLines(
@Query()
{ offset = defaultOffset, limit = defaultLimit }: ListLinesQueryDto
) {
return this.linesService.listLines({ offset, limit })
}

@Get(':line')
Expand Down
23 changes: 23 additions & 0 deletions src/modules/lines/lines.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ArgsType, Field, Int } from '@nestjs/graphql'
import { Type } from 'class-transformer'
import { IsInt, IsOptional, Max, Min } from 'class-validator'

import { defaultMaxLimit } from '../../constants/pagination.js'

@ArgsType()
export class ListLinesQueryDto {
@Type(() => Number)
@IsInt()
@Min(0)
@IsOptional()
@Field(() => Int, { nullable: true })
offset?: number

@Type(() => Number)
@IsInt()
@Max(defaultMaxLimit)
@Min(0)
@IsOptional()
@Field(() => Int, { nullable: true })
limit?: number
}
9 changes: 7 additions & 2 deletions src/modules/lines/lines.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Args, Parent, Query, ResolveField, Resolver } from '@nestjs/graphql'
import { LineCode, StopCode } from 'mtr-kit'

import { defaultLimit, defaultOffset } from '../../constants/pagination.js'
import { Schedule } from '../schedules/schedules.model.js'
import { SchedulesService } from '../schedules/schedules.service.js'
import { ListLinesQueryDto } from './lines.dto.js'
import { Line, LineStop } from './lines.model.js'
import { LinesService } from './lines.service.js'

Expand All @@ -11,8 +13,11 @@ export class LinesResolver {
constructor(private readonly linesService: LinesService) {}

@Query(() => [Line])
lines() {
return this.linesService.listLines()
lines(
@Args()
{ offset = defaultOffset, limit = defaultLimit }: ListLinesQueryDto
) {
return this.linesService.listLines({ offset, limit })
}

@Query(() => Line)
Expand Down
10 changes: 7 additions & 3 deletions src/modules/lines/lines.service.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { Injectable } from '@nestjs/common'
import { LineCode, StopCode, lineMap, lines } from 'mtr-kit'
import { omit } from 'ramda'
import { drop, omit, take } from 'ramda'

@Injectable()
export class LinesService {
listLines() {
return lines.map(omit(['stops']))
listLines({ offset, limit }: { offset?: number; limit?: number }) {
const res = lines.map(omit(['stops']))

const withOffset = offset ? drop(offset, res) : res
const withLimit = limit ? take(limit, withOffset) : withOffset
return withLimit
}

getLine({ line }: { line: LineCode }) {
Expand Down
16 changes: 13 additions & 3 deletions src/modules/schedules/schedules.controller.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
import { Controller, Get } from '@nestjs/common'
import { Controller, Get, Query } from '@nestjs/common'

import { defaultLimit, defaultOffset } from '../../constants/pagination.js'
import { ListSchedulesQueryDto } from './schedules.dto.js'
import { SchedulesService } from './schedules.service.js'

@Controller('/api/v1/schedules')
export class SchedulesController {
constructor(private readonly schedulesService: SchedulesService) {}

@Get()
listSchedules() {
return this.schedulesService.listSchedules()
listSchedules(
@Query()
{
line,
stop,
offset = defaultOffset,
limit = defaultLimit,
}: ListSchedulesQueryDto
) {
return this.schedulesService.listSchedules({ line, stop, offset, limit })
}
}
34 changes: 34 additions & 0 deletions src/modules/schedules/schedules.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { ArgsType, Field, Int } from '@nestjs/graphql'
import { Type } from 'class-transformer'
import { IsEnum, IsInt, IsOptional, Max, Min } from 'class-validator'
import { LineCode, StopCode } from 'mtr-kit'

import { defaultMaxLimit } from '../../constants/pagination.js'

@ArgsType()
export class ListSchedulesQueryDto {
@IsEnum(LineCode)
@IsOptional()
@Field(() => LineCode, { nullable: true })
line?: LineCode

@IsEnum(StopCode)
@IsOptional()
@Field(() => StopCode, { nullable: true })
stop?: StopCode

@Type(() => Number)
@IsInt()
@Min(0)
@IsOptional()
@Field(() => Int, { nullable: true })
offset?: number

@Type(() => Number)
@IsInt()
@Max(defaultMaxLimit)
@Min(0)
@IsOptional()
@Field(() => Int, { nullable: true })
limit?: number
}
16 changes: 13 additions & 3 deletions src/modules/schedules/schedules.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Query, Resolver } from '@nestjs/graphql'
import { Args, Query, Resolver } from '@nestjs/graphql'

import { defaultLimit, defaultOffset } from '../../constants/pagination.js'
import { ListSchedulesQueryDto } from './schedules.dto.js'
import { Schedule } from './schedules.model.js'
import { SchedulesService } from './schedules.service.js'

Expand All @@ -8,7 +10,15 @@ export class SchedulesResolver {
constructor(private readonly schedulesService: SchedulesService) {}

@Query(() => [Schedule])
stops() {
return this.schedulesService.listSchedules()
schedules(
@Args()
{
line,
stop,
offset = defaultOffset,
limit = defaultLimit,
}: ListSchedulesQueryDto
) {
return this.schedulesService.listSchedules({ line, stop, offset, limit })
}
}
46 changes: 25 additions & 21 deletions src/modules/schedules/schedules.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Injectable } from '@nestjs/common'
import { LineCode, StopCode, lineMap, lines } from 'mtr-kit'
import { drop, take } from 'ramda'

import { NormalizedSchedule, scheduleMap } from '../../worker.js'

Expand All @@ -22,31 +23,34 @@ export class SchedulesService {
.filter((v): v is NonNullable<typeof v> => Boolean(v))
}

listStopSchedules({ stop }: { stop: StopCode }) {
return lines
.filter(line => line.stops.some(item => item.stop === stop))
.reduce<({ line: LineCode } & NormalizedSchedule)[]>(
(acc, { line }) => [
listSchedules({
line,
stop,
offset,
limit,
}: {
line?: LineCode
stop?: StopCode
offset?: number
limit?: number
}) {
const res = lines
.reduce<({ line: LineCode; stop: StopCode } & NormalizedSchedule)[]>(
(acc, item) => [
...acc,
...this.listLineStopSchedules({ line, stop }),
...this.listLineSchedules({ line: item.line }).map(scheduleItem => ({
line: item.line,
...scheduleItem,
})),
],
[]
)
.filter((v): v is NonNullable<typeof v> => Boolean(v))
}
.filter(
item => (!line || item.line === line) && (!stop || item.stop === stop)
)

listSchedules() {
return lines.reduce<
({ line: LineCode; stop: StopCode } & NormalizedSchedule)[]
>(
(acc, { line }) => [
...acc,
...this.listLineSchedules({ line }).map(item => ({
line,
...item,
})),
],
[]
)
const withOffset = offset ? drop(offset, res) : res
const withLimit = limit ? take(limit, withOffset) : withOffset
return withLimit
}
}
Loading

0 comments on commit 512cf72

Please sign in to comment.