-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #111 from Canner/feature/implement-offset-pagination
Feature: Implement offset and limit of data sources
- Loading branch information
Showing
47 changed files
with
998 additions
and
130 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,3 +10,5 @@ sample: | |
id: '1' | ||
profile: duck | ||
profile: duck | ||
pagination: | ||
mode: offset |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
packages/build/src/lib/schema-parser/middleware/extractPaginationParams.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { | ||
APISchema, | ||
FieldDataType, | ||
FieldInType, | ||
PaginationMode, | ||
RequestSchema, | ||
} from '@vulcan-sql/core'; | ||
import { RawAPISchema, SchemaParserMiddleware } from './middleware'; | ||
|
||
export class ExtractPaginationParams extends SchemaParserMiddleware { | ||
public async handle(schemas: RawAPISchema, next: () => Promise<void>) { | ||
await next(); | ||
const transformedSchemas = schemas as APISchema; | ||
const paginationParameters: RequestSchema[] = []; | ||
if (transformedSchemas.pagination?.mode === PaginationMode.OFFSET) { | ||
paginationParameters.push({ | ||
fieldName: 'limit', | ||
fieldIn: FieldInType.QUERY, | ||
description: | ||
'Offset-based Pagination: The maximum number of rows to return. default: 20', | ||
type: FieldDataType.STRING, // We should use STRING type here but not NUMBER because of the issue from normalizeStringValue function (it throw error when input is undefined) | ||
validators: [{ name: 'integer', args: { min: 0 } }], | ||
constraints: [], | ||
}); | ||
paginationParameters.push({ | ||
fieldName: 'offset', | ||
fieldIn: FieldInType.QUERY, | ||
description: | ||
'Offset-based Pagination: The offset from the row. default: 0', | ||
type: FieldDataType.STRING, | ||
validators: [{ name: 'integer', args: { min: 0 } }], | ||
constraints: [], | ||
}); | ||
} | ||
|
||
// merge parameters | ||
for (const param of paginationParameters) { | ||
const existed = transformedSchemas.request.find( | ||
(req) => | ||
req.fieldName === param.fieldName && req.fieldIn === param.fieldIn | ||
); | ||
if (existed) { | ||
existed.description = existed.description || param.description; | ||
existed.validators = [...existed.validators, ...param.validators]; | ||
} else { | ||
transformedSchemas.request.push(param); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
packages/build/src/lib/schema-parser/middleware/transformPaginationMode.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { PaginationMode } from '@vulcan-sql/core'; | ||
import { RawAPISchema, SchemaParserMiddleware } from './middleware'; | ||
|
||
// pagination.mode: offset -> OFFSET | ||
export class TransformPaginationMode extends SchemaParserMiddleware { | ||
public async handle(schemas: RawAPISchema, next: () => Promise<void>) { | ||
if (schemas.pagination?.mode) | ||
schemas.pagination.mode = | ||
schemas.pagination.mode.toUpperCase() as PaginationMode; | ||
return next(); | ||
} | ||
} |
138 changes: 138 additions & 0 deletions
138
packages/build/test/schema-parser/middleware/extractPaginationParams.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import { RawAPISchema } from '@vulcan-sql/build/schema-parser'; | ||
import { ExtractPaginationParams } from '@vulcan-sql/build/schema-parser/middleware/extractPaginationParams'; | ||
import { | ||
Constraint, | ||
FieldDataType, | ||
FieldInType, | ||
PaginationMode, | ||
} from '@vulcan-sql/core'; | ||
|
||
it('Should do nothing when there is no pagination mode configured', async () => { | ||
// Arrange | ||
const schema: RawAPISchema = { | ||
sourceName: 'some-name', | ||
}; | ||
const extractPaginationParams = new ExtractPaginationParams(); | ||
// Act | ||
await extractPaginationParams.handle(schema, async () => Promise.resolve()); | ||
// Assert | ||
expect(schema).toEqual(schema); | ||
}); | ||
|
||
it('Should add limit and offset when pagination mode is OFFSET', async () => { | ||
// Arrange | ||
const schema: RawAPISchema = { | ||
sourceName: 'some-name', | ||
request: [], | ||
pagination: { | ||
mode: PaginationMode.OFFSET, | ||
}, | ||
}; | ||
const extractPaginationParams = new ExtractPaginationParams(); | ||
// Act | ||
await extractPaginationParams.handle(schema, async () => Promise.resolve()); | ||
// Assert | ||
expect(schema.request?.length).toBe(2); | ||
expect(schema.request).toContainEqual( | ||
expect.objectContaining({ | ||
fieldName: 'limit', | ||
fieldIn: FieldInType.QUERY, | ||
description: | ||
'Offset-based Pagination: The maximum number of rows to return. default: 20', | ||
}) | ||
); | ||
expect(schema.request).toContainEqual( | ||
expect.objectContaining({ | ||
fieldName: 'offset', | ||
fieldIn: FieldInType.QUERY, | ||
description: | ||
'Offset-based Pagination: The offset from the row. default: 0', | ||
}) | ||
); | ||
}); | ||
|
||
it('Should merge parameters when some parameters have been defined', async () => { | ||
// Arrange | ||
const schema: RawAPISchema = { | ||
sourceName: 'some-name', | ||
request: [ | ||
{ | ||
fieldName: 'limit', | ||
fieldIn: FieldInType.QUERY, | ||
description: 'Existed one', | ||
type: FieldDataType.STRING, | ||
validators: [{ name: 'integer', args: { min: -4 } }], | ||
constraints: [], | ||
}, | ||
], | ||
pagination: { | ||
mode: PaginationMode.OFFSET, | ||
}, | ||
}; | ||
const extractPaginationParams = new ExtractPaginationParams(); | ||
// Act | ||
await extractPaginationParams.handle(schema, async () => Promise.resolve()); | ||
// Assert | ||
expect(schema.request?.length).toBe(2); | ||
expect(schema.request).toContainEqual( | ||
expect.objectContaining({ | ||
fieldName: 'limit', | ||
fieldIn: FieldInType.QUERY, | ||
description: 'Existed one', | ||
validators: [ | ||
{ name: 'integer', args: { min: -4 } }, | ||
{ name: 'integer', args: { min: 0 } }, | ||
], | ||
}) | ||
); | ||
expect(schema.request).toContainEqual( | ||
expect.objectContaining({ | ||
fieldName: 'offset', | ||
fieldIn: FieldInType.QUERY, | ||
description: | ||
'Offset-based Pagination: The offset from the row. default: 0', | ||
}) | ||
); | ||
}); | ||
|
||
it('Should override the description of parameters when the existed one is empty', async () => { | ||
// Arrange | ||
const schema: RawAPISchema = { | ||
sourceName: 'some-name', | ||
request: [ | ||
{ | ||
fieldName: 'limit', | ||
fieldIn: FieldInType.QUERY, | ||
description: '', | ||
type: FieldDataType.STRING, | ||
validators: [], | ||
constraints: [Constraint.Required()], | ||
}, | ||
], | ||
pagination: { | ||
mode: PaginationMode.OFFSET, | ||
}, | ||
}; | ||
const extractPaginationParams = new ExtractPaginationParams(); | ||
// Act | ||
await extractPaginationParams.handle(schema, async () => Promise.resolve()); | ||
// Assert | ||
expect(schema.request?.length).toBe(2); | ||
expect(schema.request).toContainEqual( | ||
expect.objectContaining({ | ||
fieldName: 'limit', | ||
fieldIn: FieldInType.QUERY, | ||
description: | ||
'Offset-based Pagination: The maximum number of rows to return. default: 20', | ||
constraints: [Constraint.Required()], | ||
}) | ||
); | ||
expect(schema.request).toContainEqual( | ||
expect.objectContaining({ | ||
fieldName: 'offset', | ||
fieldIn: FieldInType.QUERY, | ||
description: | ||
'Offset-based Pagination: The offset from the row. default: 0', | ||
}) | ||
); | ||
}); |
30 changes: 30 additions & 0 deletions
30
packages/build/test/schema-parser/middleware/transformPaginationMode.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { RawAPISchema } from '@vulcan-sql/build/schema-parser'; | ||
import { TransformPaginationMode } from '@vulcan-sql/build/schema-parser/middleware/transformPaginationMode'; | ||
import { PaginationMode } from '@vulcan-sql/core'; | ||
|
||
it('Should do nothing when there is no pagination mode configured', async () => { | ||
// Arrange | ||
const schema: RawAPISchema = { | ||
sourceName: 'some-name', | ||
}; | ||
const transformPaginationMode = new TransformPaginationMode(); | ||
// Act | ||
await transformPaginationMode.handle(schema, async () => Promise.resolve()); | ||
// Assert | ||
expect(schema).toEqual(schema); | ||
}); | ||
|
||
it('Should transform pagination mode when it has been configured', async () => { | ||
// Arrange | ||
const schema: RawAPISchema = { | ||
sourceName: 'some-name', | ||
pagination: { | ||
mode: 'oFfSeT' as any, | ||
}, | ||
}; | ||
const transformPaginationMode = new TransformPaginationMode(); | ||
// Act | ||
await transformPaginationMode.handle(schema, async () => Promise.resolve()); | ||
// Assert | ||
expect(schema.pagination?.mode).toEqual(PaginationMode.OFFSET); | ||
}); |
Oops, something went wrong.