-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
141 lines (118 loc) · 4.27 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
const init = (mongoose, args = {}) => {
const Schema = mongoose.Schema;
const types = args.types || ["like"];
const ownerModelName = args.owner || "User";
const populateOptions = {
path: "reactions"
};
const ReactionSchema = new Schema({
type: {type: Schema.Types.String, required: true, enum: types},
owner: {type: Schema.Types.ObjectId, required: true, ref: ownerModelName}
}, {versionKey: false});
const Reaction = mongoose.model('Reaction', ReactionSchema);
/**
* Counts the reactions for the given document and saves the result in reactionsCount
*
* @param doc
* @returns {*}
*/
const countReactionTypes = function (doc) {
doc.reactionsCount = {};
for (let i = 0; i < types.length; i++) {
let type = types[i];
doc.reactionsCount[type] = doc.reactions.filter(r => r.owner && r.type === type).length
}
return doc;
};
/**
* Auto population plugin
* @param next
*/
const autoPopulateReactions = function (next) {
this.populate(populateOptions);
next();
};
/**
* Plugin for enabling a reaction functionality to a schema.
* There are 2 reaction types: like, dislike
* The data is autopopulated and a count for every reaction type is saved in the document
*
* @param schema
* @param options
*/
const plugin = (schema, options) => {
let reactionsCount = {};
for (let i = 0; i < types.length; i++) {
let type = types[i];
reactionsCount[type] = {type: Number, default: 0};
}
schema.add({
reactions: [{type: Schema.Types.ObjectId, ref: "Reaction", default: []}],
reactionsCount
});
schema.post('init', countReactionTypes);
schema
.pre('findOne', autoPopulateReactions)
.pre('find', autoPopulateReactions);
schema.methods.addReaction = function (reactionType, owner) {
let newReaction = new Reaction({
owner: owner._id,
type: reactionType
});
return newReaction.save()
.then(() => {
this.reactions = this.reactions.concat([newReaction]);
return this.save()
.then(() => {
return countReactionTypes(this);
})
});
};
schema.methods.removeReaction = function (reactionType, owner) {
for (let i = 0; i < this.reactions.length; i++) {
let r = this.reactions[i];
if (r.owner && r.owner._id.toString() === owner._id.toString() && r.type === reactionType) {
this.reactions.pull({_id: r._id});
Reaction.deleteMany({_id: r._id}).exec();
return this.save().then(() => {
return countReactionTypes(this);
});
}
}
return this;
};
schema.methods.toggleReaction = function (reactionType, owner) {
for (let i = 0; i < this.reactions.length; i++) {
let r = this.reactions[i];
if (r.owner && r.owner._id.toString() === owner._id.toString()) {
this.reactions.pull({_id: r._id});
Reaction.deleteMany({_id: r._id}).exec();
if (r.type !== reactionType) {
break;
} else {
return this.save().then(() => {
return countReactionTypes(this);
});
}
}
}
let newReaction = new Reaction({
owner: owner._id,
type: reactionType
});
return newReaction.save()
.then(() => {
this.reactions = this.reactions.concat([newReaction]);
return this.save()
.then(() => {
return countReactionTypes(this);
})
});
};
};
return {
model: Reaction,
plugin
}
};
module.exports = init;