const { getDB } = require('../../../utils/mongo') let db = null // Database Name const dbName = 'coder' // Collections constant const TOPIC_TAGS_COLLECTION = 'topic-tags' const TOPIC_CATEGORIES_COLLECTION = 'topic-categories' const TOPIC_LIST_COLLECTION = 'topic-list' const TOPIC_COMMENTS_COLLECTION = 'topic-comments' const USERS_COLLECTION = 'users' // page size const PAGE_SIZE = 2 // TODO убрать из export? const connect = async () => { db = await getDB(dbName) } const getCategories = async () => { // TODO при первом запросе db = null if (db === null) { throw new Error('no db connection') } const collection = db.collection(TOPIC_CATEGORIES_COLLECTION) const categories = await collection.find({ }).project({ _id: 0, }).toArray() if (categories.length === 0) { const newCategories = require('./forum/categories.json').body collection.insertMany(newCategories) return newCategories } return categories } const getCategoryByPath = async (path) => { if (db === null) { throw new Error('no db connection') } const collection = db.collection(TOPIC_CATEGORIES_COLLECTION) const category = await collection.findOne({ path, }, { projection: { _id: 0, }, }) if (!category) { throw new Error('No data') } return category } const getTopicById = async (id) => { if (db === null) { throw new Error('no db connection') } const topicsCollection = db.collection(TOPIC_LIST_COLLECTION) const topic = await topicsCollection .aggregate([ { $match: { id: Number(id), }, }, { $limit: 1, }, { $lookup: { from: USERS_COLLECTION, localField: 'authorId', foreignField: 'id', as: 'author', }, }, { $unwind: '$author', }, { $lookup: { from: TOPIC_TAGS_COLLECTION, localField: 'tagsId', foreignField: 'id', as: 'tags', }, }, { $project: { id: 0, categoryId: 0, authorId: 0, tagsId: 0, 'author.id': 0, 'author._id': 0, 'tags.id': 0, 'tags._id': 0, _id: 0, }, }, ]) .toArray() if (topic.length === 0) { throw new Error('No data') } return topic[0] } const getCommentsByTopicId = async (id, page) => { if (db === null) { throw new Error('no db connection') } if (page === undefined) { page = 1 } const commentsCollection = db.collection(TOPIC_COMMENTS_COLLECTION) let count = await commentsCollection.count({ }, { limit: 1, }) if (count === 0) { const newComments = require('./forum/topic-comments.json').body commentsCollection.insertMany(newComments) } const comments = await commentsCollection .aggregate([ { $match: { topicId: Number(id), }, }, { $skip: PAGE_SIZE * Number(page) - PAGE_SIZE, }, { $limit: PAGE_SIZE, }, { $lookup: { from: USERS_COLLECTION, localField: 'authorId', foreignField: 'id', as: 'author', }, }, { $unwind: '$author', }, { $project: { topicId: 0, authorId: 0, 'author.id': 0, 'author._id': 0, _id: 0, }, }, ]) .toArray() // pagination count = await commentsCollection.count({ topicId: Number(id), }) const result = { page, pageSize: PAGE_SIZE, total: count, totalPages: Math.ceil(count / PAGE_SIZE), comments, } return result } const getTopicsByCategoryId = async (id, page) => { if (db === null) { throw new Error('no db connection') } if (page === undefined) { page = 1 } const topicsCollection = db.collection(TOPIC_LIST_COLLECTION) let count = await topicsCollection.count({ }, { limit: 1, }) if (count === 0) { const newTopics = require('./forum/topic-list.json').body.items topicsCollection.insertMany(newTopics) } // TODO delete after auth implementation const usersCollection = db.collection(USERS_COLLECTION) const usersCount = await usersCollection.count({ }, { limit: 1, }) if (usersCount === 0) { const newUsers = require('./forum/users.json').body usersCollection.insertMany(newUsers) } const topics = await topicsCollection .aggregate([ { $match: { categoryId: Number(id), }, }, { $skip: PAGE_SIZE * Number(page) - PAGE_SIZE, }, { $limit: PAGE_SIZE, }, { $lookup: { from: USERS_COLLECTION, localField: 'authorId', foreignField: 'id', as: 'author', }, }, { $unwind: '$author', }, { $project: { id: 1, title: 1, commentCount: 1, viewCount: 1, voteCount: 1, creationDate: 1, 'author.name': 1, 'author.avatar': 1, _id: 0, }, }, ]) .toArray() if (topics.length === 0) { throw new Error('No data') } // pagination count = await topicsCollection.count({ categoryId: Number(id), }) const result = { page, pageSize: PAGE_SIZE, total: count, totalPages: Math.ceil(count / PAGE_SIZE), topics, } return result } const getTags = async () => { if (db === null) { throw new Error('no db connection') } const tagsCollection = db.collection(TOPIC_TAGS_COLLECTION) const count = await tagsCollection.count({ }, { limit: 1, }) if (count === 0) { const newTags = require('./forum/topic-tags.json').body tagsCollection.insertMany(newTags) } const tags = await tagsCollection.find({ }).project({ _id: 0, }).toArray() if (tags.length === 0) { throw new Error('No data') } return tags } const findTags = async (value) => { if (db === null) { throw new Error('no db connection') } const tagsCollection = db.collection(TOPIC_TAGS_COLLECTION) const tags = await tagsCollection .find({ name: { $regex: `${value}`, }, }) .project({ _id: 0, }) .toArray() return tags } const insertTag = async (value) => { if (db === null) { throw new Error('no db connection') } const tagsCollection = db.collection(TOPIC_TAGS_COLLECTION) // TODO no fast, reimplement const count = await tagsCollection.estimatedDocumentCount() await tagsCollection.insertOne({ id: count + 1, name: value, numTopics: 0, }) return count + 1 } const insertComment = async (comment) => { if (db === null) { throw new Error('no db connection') } const commentsCollection = db.collection(TOPIC_COMMENTS_COLLECTION) // TODO no fast, reimplement // TODO может перейти на _id? const count = await commentsCollection.estimatedDocumentCount() const currentTime = Math.round(new Date().getTime() / 1000) await commentsCollection.insertOne({ id: count + 1, topicId: comment.topicId, voteCount: 0, content: comment.content, updationDate: currentTime, creationDate: currentTime, authorId: comment.authorId, authorIsModerator: false, isOwnPost: false, }) return comment } const insertTopic = async (topic) => { if (db === null) { throw new Error('no db connection') } const topicsCollection = db.collection(TOPIC_LIST_COLLECTION) // TODO no fast, reimplement // TODO может перейти на _id? const count = await topicsCollection.estimatedDocumentCount() const currentTime = Math.round(new Date().getTime() / 1000) const tagsId = [] if (topic.tags) { for (let index = 0; index < topic.tags.length; index++) { const tag = topic.tags[index] if (tag.id === 0) { const tagId = await insertTag(tag.name) tagsId.push(tagId) } else { tagsId.push(tag.id) } } } const result = await topicsCollection.insertOne({ id: count + 1, categoryId: topic.categoryId, title: topic.title, commentCount: 0, viewCount: 0, tagsId, voteCount: 0, voteStatus: 0, content: topic.content, updationDate: currentTime, creationDate: currentTime, authorId: topic.authorId, isOwnPost: true, }) if (!result.insertedId) { throw new Error('Insert data failed, try again later') } return count + 1 } module.exports = { connect, getTags, findTags, insertTag, getCategories, getTopicsByCategoryId, getTopicById, getCommentsByTopicId, insertComment, insertTopic, getCategoryByPath, }