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) { static async queryPage(paginater: Paginater, where, order, largeData) {
if (!paginater.pageCnt) return []; if (!paginater.pageCnt) return [];
let queryBuilder = where instanceof TypeORM.SelectQueryBuilder const queryBuilder = where instanceof TypeORM.SelectQueryBuilder
? where ? where
: this.createQueryBuilder().where(where); : this.createQueryBuilder().where(where);
if (order) queryBuilder.orderBy(order); if (order) queryBuilder.orderBy(order);
queryBuilder = queryBuilder.skip((paginater.currPage - 1) * paginater.perPage) queryBuilder.skip((paginater.currPage - 1) * paginater.perPage)
.take(paginater.perPage); .take(paginater.perPage);
if (largeData) { if (largeData) {
const rawResult = await queryBuilder.select('id').getRawMany(); const rawResult = await queryBuilder.select('id').getRawMany();
@ -50,18 +50,58 @@ export default class Model extends TypeORM.BaseEntity {
return queryBuilder.getMany(); 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) { static async queryRange(range: any[], where, order) {
range[0] = parseInt(range[0]); range[0] = parseInt(range[0]);
range[1] = parseInt(range[1]); range[1] = parseInt(range[1]);
let queryBuilder = where instanceof TypeORM.SelectQueryBuilder const queryBuilder = where instanceof TypeORM.SelectQueryBuilder
? where ? where
: this.createQueryBuilder().where(where); : this.createQueryBuilder().where(where);
if (order) queryBuilder.orderBy(order); if (order) queryBuilder.orderBy(order);
queryBuilder = queryBuilder.skip(range[0] - 1) queryBuilder.skip(range[0] - 1)
.take(range[1] - range[0] + 1); .take(range[1] - range[0] + 1);
return queryBuilder.getMany(); return queryBuilder.getMany();
} }

15
modules/submission.js

@ -103,16 +103,21 @@ app.get('/submissions', async (req, res) => {
isFiltered = true; isFiltered = true;
} }
let paginate = syzoj.utils.paginate(await JudgeState.countQuery(query), req.query.page, syzoj.config.page.judge_state); query.orderBy({
let judge_state = await JudgeState.queryPage(paginate, query, { id: "DESC" }, true); 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 judge_state.forEachAsync(async obj => {
await obj.loadRelationships(); await obj.loadRelationships();
if (obj.problem.type !== 'submit-answer') obj.code_length = obj.code.length; if (obj.problem.type !== 'submit-answer') obj.code_length = obj.code.length;
}) });
res.render('submissions', { res.render('submissions', {
// judge_state: judge_state,
items: judge_state.map(x => ({ items: judge_state.map(x => ({
info: getSubmissionInfo(x, displayConfig), info: getSubmissionInfo(x, displayConfig),
token: (x.pending && x.task_id != null) ? jwt.sign({ token: (x.pending && x.task_id != null) ? jwt.sign({
@ -123,7 +128,7 @@ app.get('/submissions', async (req, res) => {
result: getRoughResult(x, displayConfig, true), result: getRoughResult(x, displayConfig, true),
running: false, running: false,
})), })),
paginate: paginate, paginate: queryResult.meta,
pushType: 'rough', pushType: 'rough',
form: req.query, form: req.query,
displayConfig: displayConfig, 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) { removeTitleTag(s) {
return s.replace(/「[\S\s]+?」/, ''); return s.replace(/「[\S\s]+?」/, '');
}, },

2
views/submissions.ejs

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

Loading…
Cancel
Save