You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
367 lines
9.9 KiB
JavaScript
367 lines
9.9 KiB
JavaScript
const assert = require('assert');
|
|
const { ObjectID } = require('bson');
|
|
const db = require('../service/db');
|
|
|
|
const coll = db.collection('document');
|
|
const collStatus = db.collection('document.status');
|
|
|
|
const TYPE_DOMAIN_ROLE = 0;
|
|
const TYPE_PROBLEM = 10;
|
|
const TYPE_PROBLEM_SOLUTION = 11;
|
|
const TYPE_PROBLEM_LIST = 12;
|
|
const TYPE_DISCUSSION_NODE = 20;
|
|
const TYPE_DISCUSSION = 21;
|
|
const TYPE_DISCUSSION_REPLY = 22;
|
|
const TYPE_CONTEST = 30;
|
|
const TYPE_TRAINING = 40;
|
|
const TYPE_FILE = 50;
|
|
const TYPE_HOMEWORK = 60;
|
|
|
|
async function add(
|
|
domainId, content, owner, docType, docId,
|
|
parentType = null, parentId = null, args = {},
|
|
) {
|
|
const _id = new ObjectID();
|
|
const doc = {
|
|
content,
|
|
owner,
|
|
domainId,
|
|
docType,
|
|
docId: docId || _id,
|
|
...args,
|
|
};
|
|
if (parentType || parentId) {
|
|
assert(parentType && parentId);
|
|
doc.parentType = parentType;
|
|
doc.parentId = parentId;
|
|
}
|
|
const res = await coll.insertOne(doc);
|
|
return docId || res.insertedId;
|
|
}
|
|
|
|
function get(domainId, docType, docId) {
|
|
return coll.findOne({ domainId, docType, docId });
|
|
}
|
|
|
|
async function set(domainId, docType, docId, args) {
|
|
const res = await coll.findOneAndUpdate(
|
|
{ domainId, docType, docId },
|
|
{ $set: { args } },
|
|
{ returnOriginal: false },
|
|
);
|
|
return res.value;
|
|
}
|
|
|
|
function deleteOne(domainId, docType, docId) {
|
|
// TODO(twd2): delete status?
|
|
return coll.deleteOne({ domainId, docType, docId });
|
|
}
|
|
|
|
function deleteMulti(domainId, docType, args = {}) {
|
|
return coll.deleteMany({ ...args, domainId, docType });
|
|
}
|
|
|
|
function deleteMultiStatus(domainId, docType, args = {}) {
|
|
return collStatus.deleteMany({ ...args, domainId, docType });
|
|
}
|
|
|
|
function getMulti(domainId, docType, args = {}) {
|
|
return coll.find({ ...args, docType, domainId });
|
|
}
|
|
|
|
async function inc(domainId, docType, docId, key, value) {
|
|
const res = await coll.findOneAndUpdate(
|
|
{ domainId, docType, docId },
|
|
{ $inc: { [key]: value } },
|
|
{ returnOriginal: false },
|
|
);
|
|
return res.value;
|
|
}
|
|
|
|
async function incAndSet(domainId, docType, docId, key, value, args) {
|
|
const res = await coll.findOneAndUpdate(
|
|
{ domainId, docType, docId },
|
|
{ $inc: { [key]: value }, $set: args },
|
|
{ returnOriginal: false },
|
|
);
|
|
return res.value;
|
|
}
|
|
|
|
function count(domainId, docType, query) {
|
|
return coll.find({ ...query, docType, domainId }).count();
|
|
}
|
|
|
|
async function push(domainId, docType, docId, key, content, owner, args) {
|
|
const _id = new ObjectID();
|
|
const doc = await coll.findOneAndUpdate(
|
|
{ domainId, docType, docId },
|
|
{
|
|
$push: {
|
|
[key]: {
|
|
...args, content, owner, _id,
|
|
},
|
|
},
|
|
},
|
|
{ returnOriginal: false },
|
|
);
|
|
return [doc.value, _id];
|
|
}
|
|
|
|
async function pull(domainId, docType, docId, setKey, contents) {
|
|
const res = await coll.findOneAndUpdate(
|
|
{ domainId, docType, docId },
|
|
{ $pull: { [setKey]: { $in: contents } } },
|
|
{ returnOriginal: false },
|
|
);
|
|
return res.value;
|
|
}
|
|
|
|
async function deleteSub(domainId, docType, docId, key, subId) {
|
|
const res = await coll.findOneAndUpdate(
|
|
{ domainId, docType, docId },
|
|
{ $pull: { [key]: { _id: subId } } },
|
|
{ returnOriginal: false },
|
|
);
|
|
return res.value;
|
|
}
|
|
|
|
async function getSub(domainId, docType, docId, key, subId) {
|
|
const doc = await coll.findOne({
|
|
domainId,
|
|
docType,
|
|
docId,
|
|
[key]: { $elemMatch: { _id: subId } },
|
|
});
|
|
if (!doc) return [null, null];
|
|
for (const sdoc of doc[key] || []) {
|
|
if (sdoc._id === subId) {
|
|
return [doc, sdoc];
|
|
}
|
|
}
|
|
return [doc, null];
|
|
}
|
|
|
|
async function setSub(domainId, docType, docId, key, subId, args) {
|
|
const $set = {};
|
|
for (const k in args) {
|
|
$set[`${key}.$.${k}`] = args[k];
|
|
}
|
|
const res = await coll.findOneAndUpdate(
|
|
{
|
|
domainId,
|
|
docType,
|
|
docId,
|
|
[key]: { $elemMatch: { _id: subId } },
|
|
},
|
|
{ $set },
|
|
{ returnOriginal: false },
|
|
);
|
|
return res.value;
|
|
}
|
|
|
|
async function addToSet(domainId, docType, docId, setKey, content) {
|
|
const res = await coll.findOneAndUpdate(
|
|
{ domainId, docType, docId },
|
|
{ $addToSet: { [setKey]: content } },
|
|
{ returnOriginal: false },
|
|
);
|
|
return res.value;
|
|
}
|
|
|
|
function getStatus(domainId, docType, docId, uid) {
|
|
return collStatus.findOne({
|
|
domainId, docType, docId, uid,
|
|
});
|
|
}
|
|
|
|
function getMultiStatus(domainId, docType, args) {
|
|
return collStatus.find({ ...args, docType, domainId });
|
|
}
|
|
|
|
async function setStatus(domainId, docType, docId, uid, args) {
|
|
const res = await collStatus.findOneAndUpdate(
|
|
{
|
|
domainId, docType, docId, uid,
|
|
},
|
|
{ $set: args },
|
|
{ upsert: true, returnOriginal: false },
|
|
);
|
|
return res.value;
|
|
}
|
|
|
|
async function setIfNotStatus(domainId, docType, docId, uid, key, value, ifNot, args) {
|
|
const res = await collStatus.findOneAndUpdate(
|
|
{
|
|
domainId, docType, docId, uid, key: { $not: { $eq: ifNot } },
|
|
},
|
|
{ $set: { [key]: value, args } },
|
|
{ upsert: true, returnOriginal: false },
|
|
);
|
|
return res.value;
|
|
}
|
|
|
|
async function cappedIncStatus(
|
|
domainId, docType, docId, uid,
|
|
key, value, minValue = -1, maxValue = 1,
|
|
) {
|
|
assert(value !== 0);
|
|
const $not = value > 0 ? { $gte: maxValue } : { $lte: minValue };
|
|
const res = await collStatus.findOneAndUpdate(
|
|
{
|
|
domainId, docType, docId, uid, [key]: { $not },
|
|
},
|
|
{ $inc: { key: value } },
|
|
{ upsert: true, returnOriginal: false },
|
|
);
|
|
return res.value;
|
|
}
|
|
|
|
async function incStatus(domainId, docType, docId, uid, key, value) {
|
|
const res = await collStatus.findOneAndUpdate(
|
|
{
|
|
domainId, docType, docId, uid,
|
|
},
|
|
{ $inc: { [key]: value } },
|
|
{ upsert: true, returnOriginal: false },
|
|
);
|
|
return res.value;
|
|
}
|
|
|
|
async function revPushStatus(domainId, docType, docId, uid, key, value) {
|
|
const res = await collStatus.findOneAndUpdate(
|
|
{
|
|
domainId, docType, docId, uid,
|
|
},
|
|
{ $push: { [key]: value }, $inc: { rev: 1 } },
|
|
{ upsert: true, returnOriginal: false },
|
|
);
|
|
return res.value;
|
|
}
|
|
|
|
async function revInitStatus(domainId, docType, docId, uid) {
|
|
const res = await collStatus.findOneAndUpdate(
|
|
{
|
|
domainId, docType, docId, uid,
|
|
},
|
|
{ $inc: { rev: 1 } },
|
|
{ upsert: true, returnOriginal: false },
|
|
);
|
|
return res.value;
|
|
}
|
|
|
|
async function revSetStatus(domainId, docType, docId, uid, rev, args, returnDoc = true) {
|
|
const filter = {
|
|
domainId, docType, docId, uid, rev,
|
|
};
|
|
const update = { $set: args, $inc: { rev: 1 } };
|
|
if (returnDoc) {
|
|
const res = await coll.findOneAndUpdate(filter, update, { returnOriginal: false });
|
|
return res.value;
|
|
}
|
|
const res = await coll.updateOne(filter, update);
|
|
return res;
|
|
}
|
|
|
|
async function ensureIndexes() {
|
|
await coll.createIndex({ domainId: 1, docType: 1, docId: 1 }, { unique: true });
|
|
await coll.createIndex({
|
|
domainId: 1, docType: 1, owner: 1, docId: -1,
|
|
});
|
|
// For problem
|
|
await coll.createIndex({
|
|
domainId: 1, docType: 1, category: 1, docId: 1,
|
|
}, { sparse: true });
|
|
await coll.createIndex({
|
|
domainId: 1, docType: 1, hidden: 1, category: 1, docId: 1,
|
|
}, { sparse: true });
|
|
await coll.createIndex({
|
|
domainId: 1, docType: 1, tag: 1, docId: 1,
|
|
}, { sparse: true });
|
|
await coll.createIndex({
|
|
domainId: 1, docType: 1, hidden: 1, tag: 1, docId: 1,
|
|
}, { sparse: true });
|
|
// For problem solution
|
|
await coll.createIndex({
|
|
domainId: 1, docType: 1, parentType: 1, parentId: 1, vote: -1, docId: -1,
|
|
}, { sparse: true });
|
|
// For discussion
|
|
await coll.createIndex({
|
|
domainId: 1, docType: 1, updateAt: -1, docId: -1,
|
|
}, { sparse: true });
|
|
await coll.createIndex({
|
|
domainId: 1, docType: 1, parentType: 1, parentId: 1, updateAt: -1, docId: -1,
|
|
}, { sparse: true });
|
|
// Hidden doc
|
|
await coll.createIndex({
|
|
domainId: 1, docType: 1, hidden: 1, docId: -1,
|
|
}, { sparse: true });
|
|
// For contest
|
|
await coll.createIndex({ domainId: 1, docType: 1, pids: 1 }, { sparse: true });
|
|
await coll.createIndex({
|
|
domainId: 1, docType: 1, rule: 1, docId: -1,
|
|
}, { sparse: true });
|
|
// For training
|
|
await coll.createIndex({ domainId: 1, docType: 1, 'dag.pids': 1 }, { sparse: true });
|
|
|
|
await collStatus.createIndex({
|
|
domainId: 1, docType: 1, uid: 1, docId: 1,
|
|
}, { unique: true });
|
|
// For rp system
|
|
await collStatus.createIndex({
|
|
domainId: 1, docType: 1, docId: 1, status: 1, rid: 1, rp: 1,
|
|
}, { sparse: true });
|
|
// For contest rule OI
|
|
await collStatus.createIndex({
|
|
domainId: 1, docType: 1, docId: 1, score: -1,
|
|
}, { sparse: true });
|
|
// For contest rule ACM
|
|
await collStatus.createIndex({
|
|
domainId: 1, docType: 1, docId: 1, accept: -1, time: 1,
|
|
}, { sparse: true });
|
|
// For training
|
|
await collStatus.createIndex({
|
|
domainId: 1, docType: 1, uid: 1, enroll: 1, docId: 1,
|
|
}, { sparse: true });
|
|
}
|
|
|
|
global.Hydro.model.document = module.exports = {
|
|
add,
|
|
addToSet,
|
|
cappedIncStatus,
|
|
count,
|
|
deleteMulti,
|
|
deleteMultiStatus,
|
|
deleteOne,
|
|
deleteSub,
|
|
ensureIndexes,
|
|
get,
|
|
getMulti,
|
|
getMultiStatus,
|
|
getStatus,
|
|
getSub,
|
|
inc,
|
|
incAndSet,
|
|
incStatus,
|
|
pull,
|
|
push,
|
|
revInitStatus,
|
|
revPushStatus,
|
|
revSetStatus,
|
|
set,
|
|
setIfNotStatus,
|
|
setStatus,
|
|
setSub,
|
|
|
|
TYPE_DOMAIN_ROLE,
|
|
TYPE_CONTEST,
|
|
TYPE_DISCUSSION,
|
|
TYPE_DISCUSSION_NODE,
|
|
TYPE_DISCUSSION_REPLY,
|
|
TYPE_HOMEWORK,
|
|
TYPE_PROBLEM,
|
|
TYPE_PROBLEM_LIST,
|
|
TYPE_PROBLEM_SOLUTION,
|
|
TYPE_FILE,
|
|
TYPE_TRAINING,
|
|
};
|