Skip to content

Commit 3b574d9

Browse files
committed
feat: allow sorting on /api/logs
1 parent 1130a96 commit 3b574d9

5 files changed

Lines changed: 95 additions & 4 deletions

File tree

lib/database/utilities/QueryBuilder.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,31 @@ class QueryBuilder {
4444
return this;
4545
}
4646

47+
/**
48+
* Set the order of elements.
49+
*
50+
* @param {String|Array} order Either a string or an array of strings.
51+
* @returns {Object} The current QueryBuilder instance.
52+
*/
53+
orderBy(order) {
54+
if (Array.isArray(order)) {
55+
for (const orderElement of order) {
56+
this.orderBy(orderElement);
57+
}
58+
return this;
59+
}
60+
61+
if (!this.options.order) {
62+
this.options.order = [];
63+
}
64+
65+
if (order.startsWith('-')) {
66+
this.options.order.push([order.substr(1), 'DESC']);
67+
} else {
68+
this.options.order.push([order, 'ASC']);
69+
}
70+
}
71+
4772
/**
4873
* Returns the implementation specific query.
4974
*

lib/domain/dtos/GetAllLogsDto.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,17 @@ const FilterDto = attributes({
2424
const QueryDto = attributes({
2525
filter: FilterDto,
2626
page: PaginationDto,
27-
})(class QueryDto {});
27+
sort: {
28+
type: Array,
29+
itemType: String,
30+
},
31+
})(class QueryDto {
32+
// eslint-disable-next-line require-jsdoc
33+
get sort() {
34+
const val = this.get('sort');
35+
return !val ? val : val.join('').split(',');
36+
}
37+
});
2838

2939
const GetAllLogsDto = attributes({
3040
query: QueryDto,

lib/usecases/log/GetAllLogsUseCase.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class GetAllLogsUseCase {
3434
async execute(dto = {}) {
3535
const queryBuilder = new QueryBuilder();
3636
const { query = {} } = dto;
37-
const { filter, page = {} } = query;
37+
const { filter, page = {}, sort = ['-id'] } = query;
3838

3939
if (filter) {
4040
const { origin } = filter;
@@ -47,6 +47,8 @@ class GetAllLogsUseCase {
4747
queryBuilder.limit(limit);
4848
queryBuilder.offset(offset);
4949

50+
queryBuilder.orderBy(sort);
51+
5052
return TransactionHelper.provide(() => LogRepository.findAll(queryBuilder));
5153
}
5254
}

spec/openapi.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ paths:
2929
- $ref: '#/components/parameters/filterOrigin'
3030
- $ref: '#/components/parameters/pageOffset'
3131
- $ref: '#/components/parameters/pageLimit'
32+
- $ref: '#/components/parameters/sortLogs'
3233
responses:
3334
'200':
3435
$ref: '#/components/responses/ArrayOfLogs'
@@ -109,6 +110,19 @@ components:
109110
type: integer
110111
minimum: 0
111112
default: 0
113+
sortLogs:
114+
in: query
115+
name: sort
116+
description: The sort order of the returned items.
117+
required: false
118+
schema:
119+
type: array
120+
items:
121+
type: string
122+
default:
123+
- -id
124+
style: form
125+
explode: false
112126
responses:
113127
ArrayOfLogs:
114128
description: Expected response to a valid request.

test/e2e/logs.test.js

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ module.exports = () => {
109109

110110
it('should support pagination, offset 0 and limit 1', (done) => {
111111
request(server)
112-
.get('/api/logs?page[offset]=0&page[limit]=1')
112+
.get('/api/logs?page[offset]=0&page[limit]=1&sort=id')
113113
.expect(200)
114114
.end((err, res) => {
115115
if (err) {
@@ -129,7 +129,7 @@ module.exports = () => {
129129

130130
it('should support pagination, offset 1 and limit 1', (done) => {
131131
request(server)
132-
.get('/api/logs?page[offset]=1&page[limit]=1')
132+
.get('/api/logs?page[offset]=1&page[limit]=1&sort=id')
133133
.expect(200)
134134
.end((err, res) => {
135135
if (err) {
@@ -167,6 +167,46 @@ module.exports = () => {
167167
done();
168168
});
169169
});
170+
171+
it('should support sorting, id DESC', (done) => {
172+
request(server)
173+
.get('/api/logs?sort=-id')
174+
.expect(200)
175+
.end((err, res) => {
176+
if (err) {
177+
done(err);
178+
return;
179+
}
180+
181+
// Response must satisfy the OpenAPI specification
182+
expect(res).to.satisfyApiSpec;
183+
184+
const { data } = res.body;
185+
expect(data[0].entryId).to.be.greaterThan(data[1].entryId);
186+
187+
done();
188+
});
189+
});
190+
191+
it('should support sorting, id ASC', (done) => {
192+
request(server)
193+
.get('/api/logs?sort=id')
194+
.expect(200)
195+
.end((err, res) => {
196+
if (err) {
197+
done(err);
198+
return;
199+
}
200+
201+
// Response must satisfy the OpenAPI specification
202+
expect(res).to.satisfyApiSpec;
203+
204+
const { data } = res.body;
205+
expect(data[1].entryId).to.be.greaterThan(data[0].entryId);
206+
207+
done();
208+
});
209+
});
170210
});
171211

172212
describe('POST /api/logs', () => {

0 commit comments

Comments
 (0)