const ObjectID = require("mongodb").ObjectID; const {connect} = require('mm') module.exports = async (dbName='hipstagram') => { const {Savable, slice} = await connect(dbName) async function getModels({id}){ const SlicedSavable = slice([id, 'user']) class User extends SlicedSavable { constructor(...params){ super(...params) //TODO: calc likes count by getter (no two-way relation for this to avoid overflow on many Kilos of likes //cached like count, which incremented and decremented // //following and followers array } static get relations(){ //don't needed due to ___owner in most cases return { avatar : "userAvatar", incomings: "to", followers: ["following"], following: ["followers"], } } static get guestRelations(){ return ["followers"] } } SlicedSavable.addClass(User) class OwnerSlicedSavable extends SlicedSavable { get owner(){ if (!this.___owner) return this.___owner return SlicedSavable.m.User.findOne({_id: ObjectID(this.___owner)}) } } class Like extends OwnerSlicedSavable { constructor(...params){ super(...params) //TODO: //entity //entityLikesCount? } static get relations(){ return { } } static get defaultPermissions(){ return { //savable refs, objectid's, words like 'tags' or 'roles' read: ['owner', 'user'], write: ['owner'], create: ['user'], delete: ['owner'], /*permission * TODO: permissions for read and write permissions * */ } } } SlicedSavable.addClass(Like) class Post extends OwnerSlicedSavable { constructor(...params){ super(...params) //TODO: calc likes count by getter (no two-way relation for this to avoid overflow on many Kilos of likes //cached like count, which incremented and decremented // } get likes(){ return (async () => { let result = [] for (let like of SlicedSavable.m.Like.find({'post._id': this._id}, {limit: [100], sort: ['_id', 1]})){ try {await like; result.push(like) } catch(e) {} } return result; })() } static get relations(){ return { images: ["posts"], comments: "post", directs: "post", collections: ["posts"] } } static get guestRelations(){ return ["comments", "directs"] } static get defaultPermissions(){ return { //savable refs, objectid's, words like 'tags' or 'roles' read: ['owner', 'user'], write: ['owner'], create: ['user'], delete: ['owner', 'admin'], /*permission * TODO: permissions for read and write permissions * */ } } } SlicedSavable.addClass(Post) class Image extends OwnerSlicedSavable { constructor(...params){ super(...params) } static async fromFileData(fileData){ let image = new Image({}) image.fileData = fileData image.url = `images/${fileData.filename}` image.originalFileName = fileData.originalname await image.save() return image; } async save(...params){ if (this.userAvatar){ if (this.userAvatar._id.toString() !== id){ throw new ReferenceError(`You can't set ava for other user`) } } return await super.save(...params) } static get relations(){ return { userAvatar: "avatar", //if it is ava posts: ["images"], //if in post: m2m with posts directs: "image", //if in direct: m2o with directs } } } SlicedSavable.addClass(Image) class Comment extends OwnerSlicedSavable { constructor(...params){ super(...params) //TODO: calc likes count by getter (no two-way relation for this to avoid overflow on many Kilos of likes //cached like count, which incremented and decremented } static get relations(){ return { post: ["comments"], answers: "answerTo", answerTo: ["answers"], } } static get guestRelations(){ return ["answers"] } } SlicedSavable.addClass(Comment) class Direct extends OwnerSlicedSavable { constructor(...params){ super(...params) } static get relations(){ return { to: ["incomings"], image: ["directs"], likes: "entity", } } static get guestRelations(){ return ["to", "likes"] } } SlicedSavable.addClass(Direct) class Collection extends OwnerSlicedSavable { constructor(...params){ super(...params) } static get relations(){ return { posts: "collections" } } } SlicedSavable.addClass(Collection) const thisUser = await Savable.m.User.findOne({_id: ObjectID(id)}) return {models: { SlicedSavable, ...SlicedSavable.classes }, thisUser} } return { Savable, slice, getModels } }