Browse Source

Optimize submissions pagination query

pull/6/head
Menci 5 years ago
parent
commit
33c61c7a83
  1. 60
      models/common.ts
  2. 15
      modules/submission.js
  3. 13
      utility.js
  4. 2
      views/submissions.ejs

60
models/common.ts

@ -33,14 +33,14 @@ export default class Model extends TypeORM.BaseEntity {
static async queryPage(paginater: Paginater, where, order, largeData) {
if (!paginater.pageCnt) return [];
let queryBuilder = where instanceof TypeORM.SelectQueryBuilder
? where
: this.createQueryBuilder().where(where);
const queryBuilder = where instanceof TypeORM.SelectQueryBuilder
? where
: this.createQueryBuilder().where(where);
if (order) queryBuilder.orderBy(order);
queryBuilder = queryBuilder.skip((paginater.currPage - 1) * paginater.perPage)
.take(paginater.perPage);
queryBuilder.skip((paginater.currPage - 1) * paginater.perPage)
.take(paginater.perPage);
if (largeData) {
const rawResult = await queryBuilder.select('id').getRawMany();
@ -50,18 +50,58 @@ export default class Model extends TypeORM.BaseEntity {
return queryBuilder.getMany();
}
static async queryPageWithLargeData(queryBuilder, { currPageTop, currPageBottom, perPage }, type) {
const queryBuilderBak = queryBuilder.clone();
const result = {
meta: {
hasPrevPage: false,
hasNextPage: false,
top: 0,
bottom: 0
},
data: []
};
queryBuilder.take(perPage);
if (type === -1) {
if (currPageTop != null) queryBuilder.andWhere('id > :currPageTop', { currPageTop });
} else if (type === 1) {
if (currPageBottom != null) queryBuilder.andWhere('id < :currPageBottom', { currPageBottom });
}
result.data = await queryBuilder.getMany();
if (result.data.length === 0) return result;
const queryBuilderHasPrev = queryBuilderBak.clone(),
queryBuilderHasNext = queryBuilderBak;
result.meta.top = result.data[0].id;
result.meta.bottom = result.data[result.data.length - 1].id;
result.meta.hasPrevPage = !!(await queryBuilderHasPrev.andWhere('id > :id', {
id: result.meta.top
}).take(1).getOne());
result.meta.hasNextPage = !!(await queryBuilderHasNext.andWhere('id < :id', {
id: result.meta.bottom
}).take(1).getOne());
return result;
}
static async queryRange(range: any[], where, order) {
range[0] = parseInt(range[0]);
range[1] = parseInt(range[1]);
let queryBuilder = where instanceof TypeORM.SelectQueryBuilder
? where
: this.createQueryBuilder().where(where);
const queryBuilder = where instanceof TypeORM.SelectQueryBuilder
? where
: this.createQueryBuilder().where(where);
if (order) queryBuilder.orderBy(order);
queryBuilder = queryBuilder.skip(range[0] - 1)
.take(range[1] - range[0] + 1);
queryBuilder.skip(range[0] - 1)
.take(range[1] - range[0] + 1);
return queryBuilder.getMany();
}

15
modules/submission.js

@ -103,16 +103,21 @@ app.get('/submissions', async (req, res) => {
isFiltered = true;
}
let paginate = syzoj.utils.paginate(await JudgeState.countQuery(query), req.query.page, syzoj.config.page.judge_state);
let judge_state = await JudgeState.queryPage(paginate, query, { id: "DESC" }, true);
query.orderBy({
id: "DESC"
});
const queryResult = await JudgeState.queryPageWithLargeData(query, syzoj.utils.paginateLargeData(
req.query.currPageTop, req.query.currPageBottom, syzoj.config.page.judge_state
), parseInt(req.query.page));
const judge_state = queryResult.data;
await judge_state.forEachAsync(async obj => {
await obj.loadRelationships();
if (obj.problem.type !== 'submit-answer') obj.code_length = obj.code.length;
})
});
res.render('submissions', {
// judge_state: judge_state,
items: judge_state.map(x => ({
info: getSubmissionInfo(x, displayConfig),
token: (x.pending && x.task_id != null) ? jwt.sign({
@ -123,7 +128,7 @@ app.get('/submissions', async (req, res) => {
result: getRoughResult(x, displayConfig, true),
running: false,
})),
paginate: paginate,
paginate: queryResult.meta,
pushType: 'rough',
form: req.query,
displayConfig: displayConfig,

13
utility.js

@ -245,6 +245,19 @@ module.exports = {
}
};
},
paginateLargeData(currPageTop, currPageBottom, perPage) {
function parseIntOrNull(x) {
if (typeof x === 'string') x = parseInt(x);
if (typeof x !== 'number' || isNaN(x)) return null;
return x;
}
return {
currPageTop: parseIntOrNull(currPageTop),
currPageBottom: parseIntOrNull(currPageBottom),
perPage
};
},
removeTitleTag(s) {
return s.replace(/「[\S\s]+?」/, '');
},

2
views/submissions.ejs

@ -116,7 +116,7 @@
</div>
<% } else { %>
<br>
<% include page %>
<% include page_largedata %>
<% } %>
</div>

Loading…
Cancel
Save