rate-core 0.0.6 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +207 -103
- package/lib/rate.js +35 -0
- package/package.json +4 -2
- package/src/core.ts +1 -1
- package/src/index.ts +160 -87
- package/src/rate.ts +87 -17
package/lib/index.js
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __extends = (this && this.__extends) || (function () {
|
|
3
|
+
var extendStatics = function (d, b) {
|
|
4
|
+
extendStatics = Object.setPrototypeOf ||
|
|
5
|
+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
6
|
+
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
|
7
|
+
return extendStatics(d, b);
|
|
8
|
+
};
|
|
9
|
+
return function (d, b) {
|
|
10
|
+
extendStatics(d, b);
|
|
11
|
+
function __() { this.constructor = d; }
|
|
12
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
13
|
+
};
|
|
14
|
+
})();
|
|
2
15
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
16
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
17
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -40,15 +53,14 @@ function __export(m) {
|
|
|
40
53
|
}
|
|
41
54
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
55
|
__export(require("./rate"));
|
|
43
|
-
var
|
|
44
|
-
function
|
|
56
|
+
var ReactionService = (function () {
|
|
57
|
+
function ReactionService(find, repository, infoRepository, commentRepository, reactionRepository, queryURL) {
|
|
45
58
|
this.find = find;
|
|
46
59
|
this.repository = repository;
|
|
47
60
|
this.infoRepository = infoRepository;
|
|
48
61
|
this.commentRepository = commentRepository;
|
|
49
|
-
this.
|
|
62
|
+
this.reactionRepository = reactionRepository;
|
|
50
63
|
this.queryURL = queryURL;
|
|
51
|
-
this.rate = this.rate.bind(this);
|
|
52
64
|
this.search = this.search.bind(this);
|
|
53
65
|
this.load = this.load.bind(this);
|
|
54
66
|
this.getRate = this.getRate.bind(this);
|
|
@@ -60,48 +72,7 @@ var RateService = (function () {
|
|
|
60
72
|
this.getComments = this.getComments.bind(this);
|
|
61
73
|
this.getComment = this.getComment.bind(this);
|
|
62
74
|
}
|
|
63
|
-
|
|
64
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
65
|
-
var info, r0, exist, r1, sr, history, res;
|
|
66
|
-
return __generator(this, function (_a) {
|
|
67
|
-
switch (_a.label) {
|
|
68
|
-
case 0:
|
|
69
|
-
rate.time = new Date();
|
|
70
|
-
return [4, this.infoRepository.load(rate.id)];
|
|
71
|
-
case 1:
|
|
72
|
-
info = _a.sent();
|
|
73
|
-
if (!!info) return [3, 3];
|
|
74
|
-
return [4, this.repository.insert(rate, true)];
|
|
75
|
-
case 2:
|
|
76
|
-
r0 = _a.sent();
|
|
77
|
-
return [2, r0];
|
|
78
|
-
case 3: return [4, this.repository.load(rate.id, rate.author)];
|
|
79
|
-
case 4:
|
|
80
|
-
exist = _a.sent();
|
|
81
|
-
if (!!exist) return [3, 6];
|
|
82
|
-
return [4, this.repository.insert(rate)];
|
|
83
|
-
case 5:
|
|
84
|
-
r1 = _a.sent();
|
|
85
|
-
return [2, r1];
|
|
86
|
-
case 6:
|
|
87
|
-
sr = { review: exist.review, rate: exist.rate, time: exist.time };
|
|
88
|
-
if (exist.histories && exist.histories.length > 0) {
|
|
89
|
-
history = exist.histories;
|
|
90
|
-
history.push(sr);
|
|
91
|
-
rate.histories = history;
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
rate.histories = [sr];
|
|
95
|
-
}
|
|
96
|
-
return [4, this.repository.update(rate, exist.rate)];
|
|
97
|
-
case 7:
|
|
98
|
-
res = _a.sent();
|
|
99
|
-
return [2, res];
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
};
|
|
104
|
-
RateService.prototype.search = function (s, limit, offset, fields) {
|
|
75
|
+
ReactionService.prototype.search = function (s, limit, offset, fields) {
|
|
105
76
|
var _this = this;
|
|
106
77
|
return this.find(s, limit, offset, fields).then(function (res) {
|
|
107
78
|
if (!_this.queryURL) {
|
|
@@ -131,19 +102,19 @@ var RateService = (function () {
|
|
|
131
102
|
}
|
|
132
103
|
});
|
|
133
104
|
};
|
|
134
|
-
|
|
105
|
+
ReactionService.prototype.load = function (id, author) {
|
|
135
106
|
return this.repository.load(id, author);
|
|
136
107
|
};
|
|
137
|
-
|
|
108
|
+
ReactionService.prototype.getRate = function (id, author) {
|
|
138
109
|
return this.repository.load(id, author);
|
|
139
110
|
};
|
|
140
|
-
|
|
141
|
-
return this.
|
|
111
|
+
ReactionService.prototype.setUseful = function (id, author, userId) {
|
|
112
|
+
return this.reactionRepository.save(id, author, userId, 1);
|
|
142
113
|
};
|
|
143
|
-
|
|
144
|
-
return this.
|
|
114
|
+
ReactionService.prototype.removeUseful = function (id, author, userId) {
|
|
115
|
+
return this.reactionRepository.remove(id, author, userId);
|
|
145
116
|
};
|
|
146
|
-
|
|
117
|
+
ReactionService.prototype.comment = function (comment) {
|
|
147
118
|
var _this = this;
|
|
148
119
|
return this.repository.load(comment.id, comment.author).then(function (checkRate) {
|
|
149
120
|
if (!checkRate) {
|
|
@@ -155,7 +126,7 @@ var RateService = (function () {
|
|
|
155
126
|
}
|
|
156
127
|
});
|
|
157
128
|
};
|
|
158
|
-
|
|
129
|
+
ReactionService.prototype.removeComment = function (commentId, userId) {
|
|
159
130
|
var _this = this;
|
|
160
131
|
return this.commentRepository.load(commentId).then(function (comment) {
|
|
161
132
|
if (comment) {
|
|
@@ -171,7 +142,7 @@ var RateService = (function () {
|
|
|
171
142
|
}
|
|
172
143
|
});
|
|
173
144
|
};
|
|
174
|
-
|
|
145
|
+
ReactionService.prototype.updateComment = function (comment) {
|
|
175
146
|
var _this = this;
|
|
176
147
|
return this.commentRepository.load(comment.commentId).then(function (exist) {
|
|
177
148
|
if (!exist) {
|
|
@@ -195,63 +166,164 @@ var RateService = (function () {
|
|
|
195
166
|
}
|
|
196
167
|
});
|
|
197
168
|
};
|
|
198
|
-
|
|
199
|
-
return this.commentRepository.getComments(id, author, limit);
|
|
200
|
-
};
|
|
201
|
-
RateService.prototype.getComment = function (id) {
|
|
202
|
-
return this.commentRepository.load(id);
|
|
203
|
-
};
|
|
204
|
-
return RateService;
|
|
205
|
-
}());
|
|
206
|
-
exports.RateService = RateService;
|
|
207
|
-
var CommentQuery = (function () {
|
|
208
|
-
function CommentQuery(find, repository, queryURL) {
|
|
209
|
-
this.find = find;
|
|
210
|
-
this.repository = repository;
|
|
211
|
-
this.queryURL = queryURL;
|
|
212
|
-
this.load = this.load.bind(this);
|
|
213
|
-
this.search = this.search.bind(this);
|
|
214
|
-
this.getComments = this.getComments.bind(this);
|
|
215
|
-
}
|
|
216
|
-
CommentQuery.prototype.load = function (id, ctx) {
|
|
217
|
-
return this.repository.load(id, ctx);
|
|
218
|
-
};
|
|
219
|
-
CommentQuery.prototype.getComments = function (id, author, limit) {
|
|
220
|
-
return this.repository.getComments(id, author, limit);
|
|
221
|
-
};
|
|
222
|
-
CommentQuery.prototype.search = function (s, limit, offset, fields) {
|
|
169
|
+
ReactionService.prototype.getComments = function (id, author, limit) {
|
|
223
170
|
var _this = this;
|
|
224
|
-
return this.
|
|
225
|
-
if (
|
|
226
|
-
|
|
171
|
+
return this.commentRepository.getComments(id, author, limit).then(function (comments) {
|
|
172
|
+
if (_this.queryURL) {
|
|
173
|
+
var ids = [];
|
|
174
|
+
for (var _i = 0, comments_1 = comments; _i < comments_1.length; _i++) {
|
|
175
|
+
var comment = comments_1[_i];
|
|
176
|
+
ids.push(comment.userId);
|
|
177
|
+
}
|
|
178
|
+
return _this.queryURL(ids).then(function (urls) {
|
|
179
|
+
for (var _i = 0, comments_2 = comments; _i < comments_2.length; _i++) {
|
|
180
|
+
var comment = comments_2[_i];
|
|
181
|
+
var i = binarySearch(urls, comment.userId);
|
|
182
|
+
if (i >= 0) {
|
|
183
|
+
comment.userURL = urls[i].url;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return comments;
|
|
187
|
+
});
|
|
227
188
|
}
|
|
228
189
|
else {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
190
|
+
return comments;
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
};
|
|
194
|
+
ReactionService.prototype.getComment = function (id) {
|
|
195
|
+
var _this = this;
|
|
196
|
+
return this.commentRepository.load(id).then(function (comment) {
|
|
197
|
+
if (comment && _this.queryURL) {
|
|
198
|
+
return _this.queryURL([id]).then(function (urls) {
|
|
199
|
+
var i = binarySearch(urls, comment.userId);
|
|
200
|
+
if (i >= 0) {
|
|
201
|
+
comment.userURL = urls[i].url;
|
|
234
202
|
}
|
|
235
|
-
return
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
203
|
+
return comment;
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
return comment;
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
};
|
|
211
|
+
return ReactionService;
|
|
212
|
+
}());
|
|
213
|
+
exports.ReactionService = ReactionService;
|
|
214
|
+
var RateService = (function (_super) {
|
|
215
|
+
__extends(RateService, _super);
|
|
216
|
+
function RateService(find, repository, infoRepository, commentRepository, reactionRepository, queryURL) {
|
|
217
|
+
var _this = _super.call(this, find, repository, infoRepository, commentRepository, reactionRepository, queryURL) || this;
|
|
218
|
+
_this.rate = _this.rate.bind(_this);
|
|
219
|
+
return _this;
|
|
220
|
+
}
|
|
221
|
+
RateService.prototype.rate = function (rate) {
|
|
222
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
223
|
+
var info, r0, exist, r1, sr, history, res;
|
|
224
|
+
return __generator(this, function (_a) {
|
|
225
|
+
switch (_a.label) {
|
|
226
|
+
case 0:
|
|
227
|
+
rate.time = new Date();
|
|
228
|
+
return [4, this.infoRepository.exist(rate.id)];
|
|
229
|
+
case 1:
|
|
230
|
+
info = _a.sent();
|
|
231
|
+
if (!!info) return [3, 3];
|
|
232
|
+
return [4, this.repository.insert(rate, true)];
|
|
233
|
+
case 2:
|
|
234
|
+
r0 = _a.sent();
|
|
235
|
+
return [2, r0];
|
|
236
|
+
case 3: return [4, this.repository.load(rate.id, rate.author)];
|
|
237
|
+
case 4:
|
|
238
|
+
exist = _a.sent();
|
|
239
|
+
if (!!exist) return [3, 6];
|
|
240
|
+
return [4, this.repository.insert(rate)];
|
|
241
|
+
case 5:
|
|
242
|
+
r1 = _a.sent();
|
|
243
|
+
return [2, r1];
|
|
244
|
+
case 6:
|
|
245
|
+
sr = { review: exist.review, rate: exist.rate, time: exist.time };
|
|
246
|
+
if (exist.histories && exist.histories.length > 0) {
|
|
247
|
+
history = exist.histories;
|
|
248
|
+
history.push(sr);
|
|
249
|
+
rate.histories = history;
|
|
242
250
|
}
|
|
243
|
-
|
|
244
|
-
|
|
251
|
+
else {
|
|
252
|
+
rate.histories = [sr];
|
|
253
|
+
}
|
|
254
|
+
return [4, this.repository.update(rate, exist.rate)];
|
|
255
|
+
case 7:
|
|
256
|
+
res = _a.sent();
|
|
257
|
+
return [2, res];
|
|
245
258
|
}
|
|
246
|
-
|
|
247
|
-
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
};
|
|
262
|
+
return RateService;
|
|
263
|
+
}(ReactionService));
|
|
264
|
+
exports.RateService = RateService;
|
|
265
|
+
function avg(n) {
|
|
266
|
+
var sum = 0;
|
|
267
|
+
for (var _i = 0, n_1 = n; _i < n_1.length; _i++) {
|
|
268
|
+
var s = n_1[_i];
|
|
269
|
+
sum = sum + s;
|
|
270
|
+
}
|
|
271
|
+
return sum / n.length;
|
|
272
|
+
}
|
|
273
|
+
exports.avg = avg;
|
|
274
|
+
var RatesService = (function (_super) {
|
|
275
|
+
__extends(RatesService, _super);
|
|
276
|
+
function RatesService(find, repository, infoRepository, commentRepository, reactionRepository, queryURL) {
|
|
277
|
+
var _this = _super.call(this, find, repository, infoRepository, commentRepository, reactionRepository, queryURL) || this;
|
|
278
|
+
_this.rate = _this.rate.bind(_this);
|
|
279
|
+
return _this;
|
|
280
|
+
}
|
|
281
|
+
RatesService.prototype.rate = function (rate) {
|
|
282
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
283
|
+
var info, r0, exist, r1, sr, history, res;
|
|
284
|
+
return __generator(this, function (_a) {
|
|
285
|
+
switch (_a.label) {
|
|
286
|
+
case 0: return [4, this.infoRepository.exist(rate.id)];
|
|
287
|
+
case 1:
|
|
288
|
+
info = _a.sent();
|
|
289
|
+
if (rate.rates && rate.rates.length > 0) {
|
|
290
|
+
rate.rate = avg(rate.rates);
|
|
291
|
+
}
|
|
292
|
+
rate.time = new Date();
|
|
293
|
+
if (!!info) return [3, 3];
|
|
294
|
+
return [4, this.repository.insert(rate, true)];
|
|
295
|
+
case 2:
|
|
296
|
+
r0 = _a.sent();
|
|
297
|
+
return [2, r0];
|
|
298
|
+
case 3: return [4, this.repository.load(rate.id, rate.author)];
|
|
299
|
+
case 4:
|
|
300
|
+
exist = _a.sent();
|
|
301
|
+
if (!!exist) return [3, 6];
|
|
302
|
+
return [4, this.repository.insert(rate)];
|
|
303
|
+
case 5:
|
|
304
|
+
r1 = _a.sent();
|
|
305
|
+
return [2, r1];
|
|
306
|
+
case 6:
|
|
307
|
+
sr = { review: exist.review, rates: exist.rates, time: exist.time };
|
|
308
|
+
if (exist.histories && exist.histories.length > 0) {
|
|
309
|
+
history = exist.histories;
|
|
310
|
+
history.push(sr);
|
|
311
|
+
rate.histories = history;
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
rate.histories = [sr];
|
|
315
|
+
}
|
|
316
|
+
return [4, this.repository.update(rate, exist.rate)];
|
|
317
|
+
case 7:
|
|
318
|
+
res = _a.sent();
|
|
319
|
+
return [2, res];
|
|
248
320
|
}
|
|
249
|
-
}
|
|
321
|
+
});
|
|
250
322
|
});
|
|
251
323
|
};
|
|
252
|
-
return
|
|
253
|
-
}());
|
|
254
|
-
exports.
|
|
324
|
+
return RatesService;
|
|
325
|
+
}(ReactionService));
|
|
326
|
+
exports.RatesService = RatesService;
|
|
255
327
|
function binarySearch(ar, el) {
|
|
256
328
|
var m = 0;
|
|
257
329
|
var n = ar.length - 1;
|
|
@@ -312,6 +384,38 @@ var RateValidator = (function () {
|
|
|
312
384
|
return RateValidator;
|
|
313
385
|
}());
|
|
314
386
|
exports.RateValidator = RateValidator;
|
|
387
|
+
var RatesValidator = (function () {
|
|
388
|
+
function RatesValidator(attributes, check, max, length) {
|
|
389
|
+
this.attributes = attributes;
|
|
390
|
+
this.check = check;
|
|
391
|
+
this.max = max;
|
|
392
|
+
this.length = length;
|
|
393
|
+
this.validate = this.validate.bind(this);
|
|
394
|
+
}
|
|
395
|
+
RatesValidator.prototype.validate = function (rate) {
|
|
396
|
+
var errs = this.check(rate, this.attributes);
|
|
397
|
+
if (!rate.rates || rate.rates.length === 0) {
|
|
398
|
+
var err = createError('rates', 'required');
|
|
399
|
+
errs.push(err);
|
|
400
|
+
return Promise.resolve(errs);
|
|
401
|
+
}
|
|
402
|
+
if (rate.rates.length !== this.length) {
|
|
403
|
+
var err = createError('rates', 'length', this.length);
|
|
404
|
+
errs.push(err);
|
|
405
|
+
return Promise.resolve(errs);
|
|
406
|
+
}
|
|
407
|
+
for (var _i = 0, _a = rate.rates; _i < _a.length; _i++) {
|
|
408
|
+
var r = _a[_i];
|
|
409
|
+
if (r > this.max) {
|
|
410
|
+
var err = createError('rates', 'max', this.max);
|
|
411
|
+
errs.push(err);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return Promise.resolve(errs);
|
|
415
|
+
};
|
|
416
|
+
return RatesValidator;
|
|
417
|
+
}());
|
|
418
|
+
exports.RatesValidator = RatesValidator;
|
|
315
419
|
function createError(field, code, param) {
|
|
316
420
|
if (!code) {
|
|
317
421
|
code = 'string';
|
package/lib/rate.js
CHANGED
|
@@ -116,3 +116,38 @@ exports.info10Model = {
|
|
|
116
116
|
type: 'number',
|
|
117
117
|
}
|
|
118
118
|
};
|
|
119
|
+
exports.rateInfoModel = {
|
|
120
|
+
id: {
|
|
121
|
+
key: true
|
|
122
|
+
},
|
|
123
|
+
rate: {
|
|
124
|
+
type: 'number',
|
|
125
|
+
},
|
|
126
|
+
count: {
|
|
127
|
+
type: 'integer',
|
|
128
|
+
},
|
|
129
|
+
score: {
|
|
130
|
+
type: 'number',
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
exports.ratesModel = {
|
|
134
|
+
id: {
|
|
135
|
+
key: true,
|
|
136
|
+
match: 'equal'
|
|
137
|
+
},
|
|
138
|
+
author: {
|
|
139
|
+
key: true,
|
|
140
|
+
match: 'equal'
|
|
141
|
+
},
|
|
142
|
+
rate: {
|
|
143
|
+
type: 'number'
|
|
144
|
+
},
|
|
145
|
+
rates: {
|
|
146
|
+
required: true,
|
|
147
|
+
type: 'integers'
|
|
148
|
+
},
|
|
149
|
+
time: {
|
|
150
|
+
type: 'datetime'
|
|
151
|
+
},
|
|
152
|
+
review: {},
|
|
153
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rate-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "rate",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -17,9 +17,11 @@
|
|
|
17
17
|
},
|
|
18
18
|
"repository": {
|
|
19
19
|
"type": "git",
|
|
20
|
-
"url": "git@github.com/core-ts/
|
|
20
|
+
"url": "git@github.com/core-ts/reaction"
|
|
21
21
|
},
|
|
22
22
|
"keywords": [
|
|
23
|
+
"reaction",
|
|
24
|
+
"reaction core",
|
|
23
25
|
"rate",
|
|
24
26
|
"rate core"
|
|
25
27
|
]
|
package/src/core.ts
CHANGED
|
@@ -78,7 +78,7 @@ export interface ViewRepository<T, ID> {
|
|
|
78
78
|
keys?(): string[];
|
|
79
79
|
all?(ctx?: any): Promise<T[]>;
|
|
80
80
|
load(id: ID, ctx?: any): Promise<T|null>;
|
|
81
|
-
exist
|
|
81
|
+
exist(id: ID, ctx?: any): Promise<boolean>;
|
|
82
82
|
}
|
|
83
83
|
export interface Repository<T, ID> extends ViewRepository<T, ID> {
|
|
84
84
|
insert(obj: T, ctx?: any): Promise<number>;
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Attributes, Search, SearchResult } from './core';
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
BaseRate, BaseRepository, Comment, InfoRepository, Rate, RateCommentRepository, RateFilter, Rater, RateReactionRepository,
|
|
4
|
+
Rates, RatesFilter, ShortComment, ShortRate, ShortRates
|
|
5
5
|
} from './rate';
|
|
6
6
|
|
|
7
7
|
export * from './rate';
|
|
@@ -10,14 +10,13 @@ export interface URL {
|
|
|
10
10
|
id: string;
|
|
11
11
|
url: string;
|
|
12
12
|
}
|
|
13
|
-
export class
|
|
14
|
-
constructor(protected find: Search<
|
|
15
|
-
public repository:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
this.rate = this.rate.bind(this);
|
|
13
|
+
export class ReactionService<R extends BaseRate, F, O> {
|
|
14
|
+
constructor(protected find: Search<R, F>,
|
|
15
|
+
public repository: BaseRepository<R>,
|
|
16
|
+
protected infoRepository: InfoRepository<O>,
|
|
17
|
+
protected commentRepository: RateCommentRepository,
|
|
18
|
+
protected reactionRepository: RateReactionRepository,
|
|
19
|
+
protected queryURL?: (ids: string[]) => Promise<URL[]>) {
|
|
21
20
|
this.search = this.search.bind(this);
|
|
22
21
|
this.load = this.load.bind(this);
|
|
23
22
|
this.getRate = this.getRate.bind(this);
|
|
@@ -29,30 +28,7 @@ export class RateService<O> implements Rater {
|
|
|
29
28
|
this.getComments = this.getComments.bind(this);
|
|
30
29
|
this.getComment = this.getComment.bind(this);
|
|
31
30
|
}
|
|
32
|
-
|
|
33
|
-
rate.time = new Date();
|
|
34
|
-
const info = await this.infoRepository.load(rate.id);
|
|
35
|
-
if (!info) {
|
|
36
|
-
const r0 = await this.repository.insert(rate, true);
|
|
37
|
-
return r0;
|
|
38
|
-
}
|
|
39
|
-
const exist = await this.repository.load(rate.id, rate.author);
|
|
40
|
-
if (!exist) {
|
|
41
|
-
const r1 = await this.repository.insert(rate);
|
|
42
|
-
return r1;
|
|
43
|
-
}
|
|
44
|
-
const sr: ShortRate = { review: exist.review, rate: exist.rate, time: exist.time };
|
|
45
|
-
if (exist.histories && exist.histories.length > 0) {
|
|
46
|
-
const history = exist.histories;
|
|
47
|
-
history.push(sr);
|
|
48
|
-
rate.histories = history;
|
|
49
|
-
} else {
|
|
50
|
-
rate.histories = [sr];
|
|
51
|
-
}
|
|
52
|
-
const res = await this.repository.update(rate, exist.rate);
|
|
53
|
-
return res;
|
|
54
|
-
}
|
|
55
|
-
search(s: RateFilter, limit?: number, offset?: number | string, fields?: string[]): Promise<SearchResult<Rate>> {
|
|
31
|
+
search(s: F, limit?: number, offset?: number | string, fields?: string[]): Promise<SearchResult<R>> {
|
|
56
32
|
return this.find(s, limit, offset, fields).then(res => {
|
|
57
33
|
if (!this.queryURL) {
|
|
58
34
|
return res;
|
|
@@ -77,17 +53,17 @@ export class RateService<O> implements Rater {
|
|
|
77
53
|
}
|
|
78
54
|
});
|
|
79
55
|
}
|
|
80
|
-
load(id: string, author: string): Promise<
|
|
56
|
+
load(id: string, author: string): Promise<R | null> {
|
|
81
57
|
return this.repository.load(id, author);
|
|
82
58
|
}
|
|
83
|
-
getRate(id: string, author: string): Promise<
|
|
59
|
+
getRate(id: string, author: string): Promise<R | null> {
|
|
84
60
|
return this.repository.load(id, author);
|
|
85
61
|
}
|
|
86
62
|
setUseful(id: string, author: string, userId: string): Promise<number> {
|
|
87
|
-
return this.
|
|
63
|
+
return this.reactionRepository.save(id, author, userId, 1);
|
|
88
64
|
}
|
|
89
65
|
removeUseful(id: string, author: string, userId: string): Promise<number> {
|
|
90
|
-
return this.
|
|
66
|
+
return this.reactionRepository.remove(id, author, userId);
|
|
91
67
|
}
|
|
92
68
|
comment(comment: Comment): Promise<number> {
|
|
93
69
|
return this.repository.load(comment.id, comment.author).then(checkRate => {
|
|
@@ -128,75 +104,146 @@ export class RateService<O> implements Rater {
|
|
|
128
104
|
exist.histories = [c];
|
|
129
105
|
}
|
|
130
106
|
exist.comment = comment.comment;
|
|
131
|
-
const res =
|
|
107
|
+
const res = this.commentRepository.update(exist);
|
|
132
108
|
return res;
|
|
133
109
|
}
|
|
134
110
|
});
|
|
135
111
|
}
|
|
136
112
|
getComments(id: string, author: string, limit?: number): Promise<Comment[]> {
|
|
137
|
-
return this.commentRepository.getComments(id, author, limit)
|
|
113
|
+
return this.commentRepository.getComments(id, author, limit).then(comments => {
|
|
114
|
+
if (this.queryURL) {
|
|
115
|
+
const ids: string[] = [];
|
|
116
|
+
for (const comment of comments) {
|
|
117
|
+
ids.push(comment.userId);
|
|
118
|
+
}
|
|
119
|
+
return this.queryURL(ids).then(urls => {
|
|
120
|
+
for (const comment of comments) {
|
|
121
|
+
const i = binarySearch(urls, comment.userId);
|
|
122
|
+
if (i >= 0) {
|
|
123
|
+
comment.userURL = urls[i].url;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return comments;
|
|
127
|
+
});
|
|
128
|
+
} else {
|
|
129
|
+
return comments;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
138
132
|
}
|
|
139
|
-
getComment(id: string): Promise<Comment|null> {
|
|
140
|
-
return this.commentRepository.load(id)
|
|
133
|
+
getComment(id: string): Promise<Comment | null> {
|
|
134
|
+
return this.commentRepository.load(id).then(comment => {
|
|
135
|
+
if (comment && this.queryURL) {
|
|
136
|
+
return this.queryURL([id]).then(urls => {
|
|
137
|
+
const i = binarySearch(urls, comment.userId);
|
|
138
|
+
if (i >= 0) {
|
|
139
|
+
comment.userURL = urls[i].url;
|
|
140
|
+
}
|
|
141
|
+
return comment;
|
|
142
|
+
});
|
|
143
|
+
} else {
|
|
144
|
+
return comment;
|
|
145
|
+
}
|
|
146
|
+
});
|
|
141
147
|
}
|
|
142
148
|
}
|
|
143
149
|
export interface CommentRepository {
|
|
144
|
-
load(commentId: string, ctx?: any): Promise<Comment|null>;
|
|
150
|
+
load(commentId: string, ctx?: any): Promise<Comment | null>;
|
|
145
151
|
getComments(id: string, author: string, limit?: number): Promise<Comment[]>;
|
|
146
152
|
}
|
|
147
153
|
// tslint:disable-next-line:max-classes-per-file
|
|
148
|
-
export class
|
|
149
|
-
constructor(
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
154
|
+
export class RateService<O> extends ReactionService<Rate, RateFilter, O> implements Rater<Rate, RateFilter> {
|
|
155
|
+
constructor(find: Search<Rate, RateFilter>,
|
|
156
|
+
repository: BaseRepository<Rate>,
|
|
157
|
+
infoRepository: InfoRepository<O>,
|
|
158
|
+
commentRepository: RateCommentRepository,
|
|
159
|
+
reactionRepository: RateReactionRepository,
|
|
160
|
+
queryURL?: (ids: string[]) => Promise<URL[]>) {
|
|
161
|
+
super(find, repository, infoRepository, commentRepository, reactionRepository, queryURL);
|
|
162
|
+
this.rate = this.rate.bind(this);
|
|
153
163
|
}
|
|
154
|
-
|
|
155
|
-
|
|
164
|
+
async rate(rate: Rate): Promise<number> {
|
|
165
|
+
rate.time = new Date();
|
|
166
|
+
const info = await this.infoRepository.exist(rate.id);
|
|
167
|
+
if (!info) {
|
|
168
|
+
const r0 = await this.repository.insert(rate, true);
|
|
169
|
+
return r0;
|
|
170
|
+
}
|
|
171
|
+
const exist = await this.repository.load(rate.id, rate.author);
|
|
172
|
+
if (!exist) {
|
|
173
|
+
const r1 = await this.repository.insert(rate);
|
|
174
|
+
return r1;
|
|
175
|
+
}
|
|
176
|
+
const sr: ShortRate = { review: exist.review, rate: exist.rate, time: exist.time };
|
|
177
|
+
if (exist.histories && exist.histories.length > 0) {
|
|
178
|
+
const history = exist.histories;
|
|
179
|
+
history.push(sr);
|
|
180
|
+
rate.histories = history;
|
|
181
|
+
} else {
|
|
182
|
+
rate.histories = [sr];
|
|
183
|
+
}
|
|
184
|
+
const res = await this.repository.update(rate, exist.rate);
|
|
185
|
+
return res;
|
|
156
186
|
}
|
|
157
|
-
|
|
158
|
-
|
|
187
|
+
}
|
|
188
|
+
export function avg(n: number[]): number {
|
|
189
|
+
let sum = 0;
|
|
190
|
+
for (const s of n) {
|
|
191
|
+
sum = sum + s;
|
|
159
192
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
193
|
+
return sum / n.length;
|
|
194
|
+
}
|
|
195
|
+
// tslint:disable-next-line:max-classes-per-file
|
|
196
|
+
export class RatesService<O> extends ReactionService<Rates, RatesFilter, O> implements Rater<Rates, RatesFilter> {
|
|
197
|
+
constructor(find: Search<Rates, RatesFilter>,
|
|
198
|
+
repository: BaseRepository<Rates>,
|
|
199
|
+
infoRepository: InfoRepository<O>,
|
|
200
|
+
commentRepository: RateCommentRepository,
|
|
201
|
+
reactionRepository: RateReactionRepository,
|
|
202
|
+
queryURL?: (ids: string[]) => Promise<URL[]>) {
|
|
203
|
+
super(find, repository, infoRepository, commentRepository, reactionRepository, queryURL);
|
|
204
|
+
this.rate = this.rate.bind(this);
|
|
205
|
+
}
|
|
206
|
+
async rate(rate: Rates): Promise<number> {
|
|
207
|
+
const info = await this.infoRepository.exist(rate.id);
|
|
208
|
+
if (rate.rates && rate.rates.length > 0) {
|
|
209
|
+
rate.rate = avg(rate.rates);
|
|
210
|
+
}
|
|
211
|
+
rate.time = new Date();
|
|
212
|
+
if (!info) {
|
|
213
|
+
const r0 = await this.repository.insert(rate, true);
|
|
214
|
+
return r0;
|
|
215
|
+
}
|
|
216
|
+
const exist = await this.repository.load(rate.id, rate.author);
|
|
217
|
+
if (!exist) {
|
|
218
|
+
const r1 = await this.repository.insert(rate);
|
|
219
|
+
return r1;
|
|
220
|
+
}
|
|
221
|
+
const sr: ShortRates = { review: exist.review, rates: exist.rates, time: exist.time };
|
|
222
|
+
if (exist.histories && exist.histories.length > 0) {
|
|
223
|
+
const history = exist.histories;
|
|
224
|
+
history.push(sr);
|
|
225
|
+
rate.histories = history;
|
|
226
|
+
} else {
|
|
227
|
+
rate.histories = [sr];
|
|
228
|
+
}
|
|
229
|
+
const res = await this.repository.update(rate, exist.rate);
|
|
230
|
+
return res;
|
|
184
231
|
}
|
|
185
232
|
}
|
|
186
233
|
function binarySearch(ar: URL[], el: string): number {
|
|
187
234
|
let m = 0;
|
|
188
235
|
let n = ar.length - 1;
|
|
189
236
|
while (m <= n) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
237
|
+
// tslint:disable-next-line:no-bitwise
|
|
238
|
+
const k = (n + m) >> 1;
|
|
239
|
+
const cmp = compare(el, ar[k].id);
|
|
240
|
+
if (cmp > 0) {
|
|
241
|
+
m = k + 1;
|
|
242
|
+
} else if (cmp < 0) {
|
|
243
|
+
n = k - 1;
|
|
244
|
+
} else {
|
|
245
|
+
return k;
|
|
246
|
+
}
|
|
200
247
|
}
|
|
201
248
|
return -m - 1;
|
|
202
249
|
}
|
|
@@ -206,7 +253,7 @@ function compare(s1: string, s2: string): number {
|
|
|
206
253
|
interface ErrorMessage {
|
|
207
254
|
field: string;
|
|
208
255
|
code: string;
|
|
209
|
-
param?: string|number|Date;
|
|
256
|
+
param?: string | number | Date;
|
|
210
257
|
message?: string;
|
|
211
258
|
}
|
|
212
259
|
// tslint:disable-next-line:max-classes-per-file
|
|
@@ -239,6 +286,32 @@ export class RateValidator {
|
|
|
239
286
|
}
|
|
240
287
|
}
|
|
241
288
|
}
|
|
289
|
+
// tslint:disable-next-line:max-classes-per-file
|
|
290
|
+
export class RatesValidator {
|
|
291
|
+
constructor(protected attributes: Attributes, protected check: (obj: any, attributes: Attributes) => ErrorMessage[], protected max: number, protected length: number) {
|
|
292
|
+
this.validate = this.validate.bind(this);
|
|
293
|
+
}
|
|
294
|
+
validate(rate: Rates): Promise<ErrorMessage[]> {
|
|
295
|
+
const errs = this.check(rate, this.attributes);
|
|
296
|
+
if (!rate.rates || rate.rates.length === 0) {
|
|
297
|
+
const err = createError('rates', 'required');
|
|
298
|
+
errs.push(err);
|
|
299
|
+
return Promise.resolve(errs);
|
|
300
|
+
}
|
|
301
|
+
if (rate.rates.length !== this.length) {
|
|
302
|
+
const err = createError('rates', 'length', this.length);
|
|
303
|
+
errs.push(err);
|
|
304
|
+
return Promise.resolve(errs);
|
|
305
|
+
}
|
|
306
|
+
for (const r of rate.rates) {
|
|
307
|
+
if (r > this.max) {
|
|
308
|
+
const err = createError('rates', 'max', this.max);
|
|
309
|
+
errs.push(err);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return Promise.resolve(errs);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
242
315
|
function createError(field: string, code?: string, param?: string | number | Date): ErrorMessage {
|
|
243
316
|
if (!code) {
|
|
244
317
|
code = 'string';
|
package/src/rate.ts
CHANGED
|
@@ -4,12 +4,13 @@ export interface RateId {
|
|
|
4
4
|
id: string;
|
|
5
5
|
author: string;
|
|
6
6
|
}
|
|
7
|
-
|
|
8
|
-
export interface Rate {
|
|
9
|
-
id: string;
|
|
7
|
+
export interface BaseRate {
|
|
10
8
|
author: string;
|
|
11
9
|
authorURL?: string;
|
|
12
10
|
rate: number;
|
|
11
|
+
}
|
|
12
|
+
export interface Rate extends BaseRate {
|
|
13
|
+
id: string;
|
|
13
14
|
time: Date;
|
|
14
15
|
review: string;
|
|
15
16
|
usefulCount: number;
|
|
@@ -30,24 +31,56 @@ export interface RateFilter extends Filter {
|
|
|
30
31
|
usefulCount?: number;
|
|
31
32
|
replyCount?: number;
|
|
32
33
|
}
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
export interface RateInfo {
|
|
35
|
+
id: string;
|
|
36
|
+
rate: number;
|
|
37
|
+
count: number;
|
|
38
|
+
score: number;
|
|
39
|
+
}
|
|
40
|
+
export interface ShortRates {
|
|
41
|
+
rates: number[];
|
|
42
|
+
time: Date;
|
|
43
|
+
review: string;
|
|
44
|
+
}
|
|
45
|
+
export interface Rates extends BaseRate {
|
|
46
|
+
id: string;
|
|
47
|
+
rates: number[];
|
|
48
|
+
time: Date;
|
|
49
|
+
review: string;
|
|
50
|
+
usefulCount: number;
|
|
51
|
+
replyCount: number;
|
|
52
|
+
histories?: ShortRates[];
|
|
53
|
+
}
|
|
54
|
+
export interface RatesFilter extends RateFilter {
|
|
55
|
+
rates?: number[];
|
|
56
|
+
rate1: number;
|
|
57
|
+
rate2: number;
|
|
58
|
+
rate3: number;
|
|
59
|
+
rate4: number;
|
|
60
|
+
rate5: number;
|
|
61
|
+
rate6: number;
|
|
62
|
+
rate7: number;
|
|
63
|
+
rate8: number;
|
|
64
|
+
rate9: number;
|
|
65
|
+
rate10: number;
|
|
66
|
+
}
|
|
67
|
+
export interface BaseRepository<R> {
|
|
35
68
|
// save(obj: Rate, info?: T, ctx?: any): Promise<number>;
|
|
36
|
-
insert(rate:
|
|
37
|
-
update(rate:
|
|
38
|
-
load(id: string, author: string): Promise<
|
|
39
|
-
}
|
|
40
|
-
export interface Rater {
|
|
41
|
-
search(s:
|
|
42
|
-
load(id: string, author: string): Promise<
|
|
43
|
-
rate(rate:
|
|
69
|
+
insert(rate: R, newInfo?: boolean): Promise<number>;
|
|
70
|
+
update(rate: R, oldRate: number): Promise<number>;
|
|
71
|
+
load(id: string, author: string): Promise<R | null>;
|
|
72
|
+
}
|
|
73
|
+
export interface Rater<R, F extends Filter> {
|
|
74
|
+
search(s: F, limit?: number, offset?: number | string, fields?: string[], ctx?: any): Promise<SearchResult<R>>;
|
|
75
|
+
load(id: string, author: string): Promise<R | null>;
|
|
76
|
+
rate(rate: R): Promise<number>;
|
|
44
77
|
setUseful(id: string, author: string, userId: string, ctx?: any): Promise<number>;
|
|
45
78
|
removeUseful(id: string, author: string, userId: string, ctx?: any): Promise<number>;
|
|
46
79
|
comment(comment: Comment): Promise<number>;
|
|
47
80
|
removeComment(id: string, author: string, ctx?: any): Promise<number>;
|
|
48
81
|
updateComment(comment: Comment): Promise<number>;
|
|
49
82
|
getComments(id: string, author: string, limit?: number): Promise<Comment[]>;
|
|
50
|
-
getComment(id: string): Promise<Comment|null>;
|
|
83
|
+
getComment(id: string): Promise<Comment | null>;
|
|
51
84
|
}
|
|
52
85
|
export interface RateReactionRepository {
|
|
53
86
|
remove(id: string, author: string, userId: string, ctx?: any): Promise<number>;
|
|
@@ -60,9 +93,9 @@ export interface RateCommentRepository extends Repository<Comment, string> {
|
|
|
60
93
|
}
|
|
61
94
|
|
|
62
95
|
export interface Query<T, ID, S> {
|
|
63
|
-
search: (s: S, limit?: number, skip?: number|string, fields?: string[]) => Promise<SearchResult<T>>;
|
|
64
|
-
metadata?(): Attributes|undefined;
|
|
65
|
-
load(id: ID, ctx?: any): Promise<T|null>;
|
|
96
|
+
search: (s: S, limit?: number, skip?: number | string, fields?: string[]) => Promise<SearchResult<T>>;
|
|
97
|
+
metadata?(): Attributes | undefined;
|
|
98
|
+
load(id: ID, ctx?: any): Promise<T | null>;
|
|
66
99
|
}
|
|
67
100
|
export interface RateCommentQuery extends Query<Comment, string, CommentFilter> {
|
|
68
101
|
getComments(id: string, author: string, limit?: number): Promise<Comment[]>;
|
|
@@ -247,3 +280,40 @@ export interface CommentFilter extends Filter {
|
|
|
247
280
|
time?: Date;
|
|
248
281
|
updatedAt?: Date;
|
|
249
282
|
}
|
|
283
|
+
|
|
284
|
+
export const rateInfoModel: Attributes = {
|
|
285
|
+
id: {
|
|
286
|
+
key: true
|
|
287
|
+
},
|
|
288
|
+
rate: {
|
|
289
|
+
type: 'number',
|
|
290
|
+
},
|
|
291
|
+
count: {
|
|
292
|
+
type: 'integer',
|
|
293
|
+
},
|
|
294
|
+
score: {
|
|
295
|
+
type: 'number',
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
export const ratesModel: Attributes = {
|
|
300
|
+
id: {
|
|
301
|
+
key: true,
|
|
302
|
+
match: 'equal'
|
|
303
|
+
},
|
|
304
|
+
author: {
|
|
305
|
+
key: true,
|
|
306
|
+
match: 'equal'
|
|
307
|
+
},
|
|
308
|
+
rate: {
|
|
309
|
+
type: 'number'
|
|
310
|
+
},
|
|
311
|
+
rates: {
|
|
312
|
+
required: true,
|
|
313
|
+
type: 'integers'
|
|
314
|
+
},
|
|
315
|
+
time: {
|
|
316
|
+
type: 'datetime'
|
|
317
|
+
},
|
|
318
|
+
review: {},
|
|
319
|
+
};
|