Skip to content

Commit

Permalink
Merge pull request #14 from ThreeDify/pagination
Browse files Browse the repository at this point in the history
Add pagination in reconstructions API.
  • Loading branch information
silwalanish authored Nov 22, 2020
2 parents f783c74 + a4ec73a commit 7f7b0cb
Show file tree
Hide file tree
Showing 13 changed files with 302 additions and 40 deletions.
7 changes: 7 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import { Options as SwaggerOptions } from 'swagger-jsdoc';

import packageJson from '../package.json';

import { SortOrder } from './domain/PaginationQuery';
import GoogleAPIConfig from './domain/GoogleAPIConfig';
import PaginationConfig from './domain/PaginationConfig';

interface Config {
port: number;
Expand All @@ -24,6 +26,7 @@ interface Config {
accessTokenConfig: SignOptions;
refreshTokenConfig: SignOptions;
googleAPIConfig?: GoogleAPIConfig;
paginationConfig: PaginationConfig;
}

const config: Config = {
Expand Down Expand Up @@ -74,6 +77,10 @@ const config: Config = {
refresh_token: process.env.GOOGLE_REFRESH_TOKEN || '',
upload_directory_id: process.env.GOOGLE_DRIVE_UPLOAD_FOLDER_ID || '',
},
paginationConfig: {
minPageSize: 10,
defaultOrder: SortOrder.ASC,
},
};

export default config;
26 changes: 18 additions & 8 deletions src/controllers/reconstructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import Debug, { Debugger } from 'debug';
import { Request, NextFunction, Response } from 'express';

import Reconstruction from '../models/Reconstruction';
import PaginationQuery from '../domain/PaginationQuery';
import PaginatedResult from '../domain/PaginatedResult';
import { getPaginationQuery } from '../utils/pagination';
import NewReconstruction from '../domain/NewReconstruction';
import reconstructionService from '../services/reconstructions';
import { AuthRequestWithFiles } from '../middlewares/uploadImage';
Expand All @@ -11,13 +14,17 @@ const debug: Debugger = Debug('threedify:controller:reconstructions');

export async function index(
req: Request,
res: Response<Reconstruction[]>,
res: Response<PaginatedResult<Reconstruction>>,
next: NextFunction
) {
try {
let reconstructions:
| Reconstruction[]
| undefined = await reconstructionService.fetchAllReconstructions();
const paginationQuery: PaginationQuery = getPaginationQuery(req.query);

const reconstructions:
| PaginatedResult<Reconstruction>
| undefined = await reconstructionService.fetchAllReconstructions(
paginationQuery
);

if (reconstructions) {
res.json(reconstructions);
Expand Down Expand Up @@ -73,14 +80,17 @@ export async function reconstruction(

export async function userReconstruction(
req: Request,
res: Response<Reconstruction[]>,
res: Response<PaginatedResult<Reconstruction>>,
next: NextFunction
) {
try {
let reconstructions:
| Reconstruction[]
const paginationQuery: PaginationQuery = getPaginationQuery(req.query);

const reconstructions:
| PaginatedResult<Reconstruction>
| undefined = await reconstructionService.fetchReconstructionByUserId(
+req.params.userId
+req.params.userId,
paginationQuery
);

if (reconstructions) {
Expand Down
38 changes: 38 additions & 0 deletions src/domain/PaginatedResult.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* @swagger
*
* components:
* schemas:
* PaginatedResult:
* type: object
* properties:
* data:
* type: array
* items: {}
* total:
* type: number
* pageSize:
* type: number
* currentPage:
* type: number
* hasNextPage:
* type: boolean
* hasPrevPage:
* type: boolean
* currentPageSize:
* type: number
*/

import { Model } from 'objection';

export interface PaginatedResult<T extends Model> {
data: T[];
total: number;
pageSize: number;
currentPage: number;
hasNextPage: boolean;
hasPrevPage: boolean;
currentPageSize: number;
}

export default PaginatedResult;
8 changes: 8 additions & 0 deletions src/domain/PaginationConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { SortOrder } from './PaginationQuery';

export interface PaginationConfig {
minPageSize: number;
defaultOrder: SortOrder;
}

export default PaginationConfig;
53 changes: 53 additions & 0 deletions src/domain/PaginationQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* @swagger
*
* components:
* parameters:
* page:
* in: query
* name: page
* description: The page to fetch data from.
* schema:
* type: number
* minimum: 1
* default: 1
* size:
* in: query
* name: size
* description: Size of the page.
* schema:
* type: number
* minimum: 1
* default: 10
* filters:
* in: query
* name: filters
* description: Filters to apply to generate pages. For multiple filters, use comma(,) separated value.
* required: false
* schema:
* type: string
* order:
* in: query
* name: order
* description: The order to sort the result in .
* schema:
* type: string
* enum:
* - ASC
* - DESC
* default: ASC
*/

export enum SortOrder {
ASC = 'ASC',
DSC = 'DESC',
}

export interface PaginationQuery {
page: number;
size: number;
filters: string[];
order: SortOrder;
}

export default PaginationQuery;
4 changes: 2 additions & 2 deletions src/models/Image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ const TABLE_NAME: string = 'images';
* type: number
* uploadedByUser:
* $ref: '#/components/schemas/User'
* created_at:
* createdAt:
* type: string
* format: date-time
* updated_at:
* updatedAt:
* type: string
* format: date-time
* responses:
Expand Down
61 changes: 53 additions & 8 deletions src/models/Reconstruction.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Model } from 'objection';
import { Model, QueryBuilder } from 'objection';

import User from './User';
import Image from './Image';
Expand Down Expand Up @@ -31,27 +31,47 @@ const TABLE_NAME: string = 'reconstructions';
* type: number
* createdByUser:
* $ref: '#/components/schemas/User'
* created_at:
* createdAt:
* type: string
* format: date-time
* updated_at:
* updatedAt:
* type: string
* format: date-time
* parameters:
* reconstruction_filters:
* in: query
* name: filters
* description: Filters to apply to generate pages. For multiple filters, use comma(,) separated value.<br>
* Use filters to select only some data. For example, `inQueue` filters reconstruction that are in queue.<br>
* This can also be used to order data. For example, `orderByCreatedAt` sorts data by createdAt field.
* required: false
* schema:
* type: string
* enum:
* - orderByCreatedAt
* - inQueue
* - inProgress
* - completed
* responses:
* Reconstruction:
* description: Reconstruction data in JSON response.
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Reconstruction'
* ReconstructionArray:
* description: Array of Reconstruction data in JSON response.
* PaginatedReconstructionResult:
* description: Paginated array of Reconstruction data in JSON response.
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: '#/components/schemas/Reconstruction'
* allOf:
* - $ref: '#/components/schemas/PaginatedResult'
* - type: object
* properties:
* data:
* type: array
* items:
* $ref: '#/components/schemas/Reconstruction'
*/
export class Reconstruction extends Model {
id!: number;
Expand All @@ -69,6 +89,31 @@ export class Reconstruction extends Model {
return TABLE_NAME;
}

static get modifiers() {
return {
inQueue(builder: QueryBuilder<Reconstruction>) {
const { ref } = Reconstruction;

builder.where(ref('state'), '=', ReconstructionState.INQUEUE);
},
inProgress(builder: QueryBuilder<Reconstruction>) {
const { ref } = Reconstruction;

builder.where(ref('state'), '=', ReconstructionState.INPROGRESS);
},
completed(builder: QueryBuilder<Reconstruction>) {
const { ref } = Reconstruction;

builder.where(ref('state'), '=', ReconstructionState.COMPLETED);
},
orderByCreatedAt(builder: QueryBuilder<Reconstruction>) {
const { ref } = Reconstruction;

builder.orderBy(ref('createdAt'), builder.context().sortOrder || 'ASC');
},
};
}

static get relationMappings() {
return {
createdByUser: {
Expand Down
20 changes: 13 additions & 7 deletions src/models/User.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Model } from 'objection';
import { Model, QueryBuilder } from 'objection';

const TABLE_NAME: string = 'users';

Expand Down Expand Up @@ -29,10 +29,10 @@ const TABLE_NAME: string = 'users';
* type: string
* rawPassword:
* type: string
* created_at:
* createdAt:
* type: string
* format: date-time
* updated_at:
* updatedAt:
* type: string
* format: date-time
* responses:
Expand All @@ -59,8 +59,8 @@ export class User extends Model {
lastName!: string;
firstName!: string;

created_at?: Date;
updated_at?: Date;
createdAt?: Date;
updatedAt?: Date;

rawPassword?: string;

Expand All @@ -70,8 +70,14 @@ export class User extends Model {

static get modifiers() {
return {
defaultSelect(builder: any) {
builder.select('id', 'username', 'lastName', 'firstName');
defaultSelect(builder: QueryBuilder<User>) {
const { ref } = User;
builder.select(
ref('id'),
ref('username'),
ref('lastName'),
ref('firstName')
);
},
};
}
Expand Down
7 changes: 6 additions & 1 deletion src/routers/reconstructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@ const imageUploadMiddlewares = uploadImages('images');
* /reconstructions:
* get:
* description: End point to fetch all reconstructions.
* parameters:
* - $ref: '#/components/parameters/page'
* - $ref: '#/components/parameters/size'
* - $ref: '#/components/parameters/reconstruction_filters'
* - $ref: '#/components/parameters/order'
* responses:
* 200:
* $ref: '#/components/responses/ReconstructionArray'
* $ref: '#/components/responses/PaginatedReconstructionResult'
* 404:
* $ref: '#/components/responses/HTTPError'
* 500:
Expand Down
6 changes: 5 additions & 1 deletion src/routers/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,13 @@ router.get('/:userId(\\d+)', authenticate, UserController.user);
* - name: user_id
* in: path
* description: Id of user to fetch reconstructions.
* - $ref: '#/components/parameters/page'
* - $ref: '#/components/parameters/size'
* - $ref: '#/components/parameters/reconstruction_filters'
* - $ref: '#/components/parameters/order'
* responses:
* 200:
* $ref: '#/components/responses/ReconstructionArray'
* $ref: '#/components/responses/PaginatedReconstructionResult'
* 401:
* $ref: '#/components/responses/HTTPError'
* 404:
Expand Down
Loading

0 comments on commit 7f7b0cb

Please sign in to comment.