From a1e2aba304dbba44bbc4c1004d510bce4d2a0093 Mon Sep 17 00:00:00 2001 From: undefined Date: Tue, 29 Oct 2024 03:08:29 +0800 Subject: [PATCH] core: store problem content in seperate collection --- packages/hydrooj/src/interface.ts | 2 +- packages/hydrooj/src/model/problem.ts | 41 +++++++++++++++++---------- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/packages/hydrooj/src/interface.ts b/packages/hydrooj/src/interface.ts index 7feedcc25..35cff9dc2 100644 --- a/packages/hydrooj/src/interface.ts +++ b/packages/hydrooj/src/interface.ts @@ -241,7 +241,7 @@ declare module './model/problem' { docId: number; pid: string; title: string; - content: string; + content: ({ id: string, name: string, lang: string } | { from: string, name: string, lang: string })[]; nSubmit: number; nAccept: number; tag: string[]; diff --git a/packages/hydrooj/src/model/problem.ts b/packages/hydrooj/src/model/problem.ts index 2c80800d9..e8c533d16 100644 --- a/packages/hydrooj/src/model/problem.ts +++ b/packages/hydrooj/src/model/problem.ts @@ -90,6 +90,8 @@ export class ProblemModel { 'reference', 'maintainer', ]; + static collContent = db.collection('problem.content'); + static default = { _id: new ObjectId(), domainId: 'system', @@ -98,7 +100,7 @@ export class ProblemModel { pid: '', owner: 1, title: '*', - content: '', + content: [], html: false, nSubmit: 0, nAccept: 0, @@ -119,7 +121,7 @@ export class ProblemModel { pid: null, owner: 1, title: '*', - content: 'Deleted Problem', + content: [], html: false, nSubmit: 0, nAccept: 0, @@ -133,7 +135,7 @@ export class ProblemModel { }; static async add( - domainId: string, pid: string = '', title: string, content: string, owner: number, + domainId: string, pid: string = '', title: string, content: ProblemDoc['content'], owner: number, tag: string[] = [], meta: ProblemCreateOptions = {}, ) { const [doc] = await ProblemModel.getMulti(domainId, {}) @@ -148,7 +150,7 @@ export class ProblemModel { static async addWithId( domainId: string, docId: number, pid: string = '', title: string, - content: string, owner: number, tag: string[] = [], + content: ProblemDoc['content'], owner: number, tag: string[] = [], meta: ProblemCreateOptions = {}, ) { const ddoc = await DomainModel.get(domainId); @@ -188,6 +190,11 @@ export class ProblemModel { return res; } + static async getContent(contentIds: string[]) { + const content = await ProblemModel.collContent.find({ _id: { $in: contentIds } }).toArray(); + return Object.fromEntries(content.map((i) => [i._id.toString(), i.content])); + } + static getMulti(domainId: string, query: Filter, projection = ProblemModel.PROJECTION_LIST) { return document.getMulti(domainId, document.TYPE_PROBLEM, query, projection).sort({ sort: 1 }); } @@ -234,7 +241,7 @@ export class ProblemModel { if (pid && (/^[0-9]+$/.test(pid) || await ProblemModel.get(target, pid))) pid = ''; if (!pid && original.pid && !await ProblemModel.get(target, original.pid)) pid = original.pid; return await ProblemModel.add( - target, pid, original.title, original.content, + target, pid, original.title, original.content.map((i) => ({ name: i.name, lang: i.lang, from: 'id' in i ? i.id : i.from })), original.owner, original.tag, { hidden: original.hidden, reference: { domainId, pid: _id } }, ); } @@ -611,16 +618,20 @@ export class ProblemModel { nAccept: pdoc.nAccept, difficulty: pdoc.difficulty, }); - await fs.writeFile(problemYaml, problemYamlContent); - try { - const c = JSON.parse(pdoc.content); - for (const key of Object.keys(c)) { - const problemContent = path.join(problemPath, `problem_${key}.md`); - await fs.writeFile(problemContent, typeof c[key] === 'string' ? c[key] : JSON.stringify(c[key])); - } - } catch (e) { - const problemContent = path.join(problemPath, 'problem.md'); - await fs.writeFile(problemContent, pdoc.content); + const [c] = await Promise.all([ + ProblemModel.getContent(pdoc.content.map((i) => ('id' in i ? i.id : i.from))), + fs.writeFile(problemYaml, problemYamlContent), + ]); + for (const i of pdoc.content) { + await fs.writeFile(path.join(problemPath, `problem_${'id' in i ? i.id : i.from}.md`), [ + '---', + yaml.dump({ + name: i.name, + lang: i.lang, + }), + '---', + c['id' in i ? i.id : i.from], + ].join('\n')); } if ((pdoc.data || []).length) { const testdataPath = path.join(problemPath, 'testdata');