@ournet/news-data
Version:
Ournet news data module
256 lines (255 loc) • 9.88 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const debug = require("debug")("ournet:news-data");
const domain_1 = require("@ournet/domain");
const news_domain_1 = require("@ournet/news-domain");
const dynamo_event_1 = require("./dynamo-event");
const topic_event_1 = require("./topic-event");
const helpers_1 = require("../helpers");
const dynamo_latest_event_1 = require("./dynamo-latest-event");
const ms = require("ms");
class DynamoEventRepository extends domain_1.BaseRepository {
constructor(client, tableSuffix) {
super(new news_domain_1.EventValidator());
this.model = new dynamo_event_1.EventModel(client, tableSuffix);
this.latestModel = new dynamo_latest_event_1.LatestEventModel(client, tableSuffix);
this.topicModel = new topic_event_1.TopicEventModel(client, tableSuffix);
}
async similarByTopics(params, options) {
const index = this.topicModel.topicLastEventsIndexName();
const rangeKey = helpers_1.buildDateRangeKey(params);
const latestResults = await domain_1.mapPromise(params.topicIds, (topicId) => this.topicModel.query({
index,
attributes: ["eventId"],
hashKey: topicId,
limit: params.limit,
rangeKey,
order: "DESC"
}));
let allEventIds = [];
for (const eventIds of latestResults.values()) {
allEventIds = allEventIds.concat((eventIds.items || []).map((item) => item.eventId));
}
if (allEventIds.length === 0) {
return [];
}
const idsMap = allEventIds.reduce((dic, id) => {
if (!dic[id]) {
dic[id] = 0;
}
dic[id]++;
return dic;
}, {});
if (params.exceptId) {
delete idsMap[params.exceptId];
}
debug(`Similar events ids map: ${idsMap}`);
const ids = domain_1.uniq(Object.keys(idsMap)
.map((id) => ({ id, count: idsMap[id] }))
.sort((a, b) => b.count - a.count)
.map((item) => item.id)).slice(0, params.limit);
if (ids.length === 0) {
return [];
}
debug(`Similar events ids: ${ids}`);
return this.getByIds(ids, options);
}
async viewNewsEvent(id) {
const item = await this.model.get({ id }, { attributes: ["id", "countViews"] });
if (!item) {
throw new Error(`Not found event id=${id}`);
}
const countViews = item.countViews + 1;
await this.update({ id, set: { countViews } });
return countViews;
}
async innerCreate(data) {
const createdItem = await this.model.create(dynamo_event_1.DynamoEventHelper.mapFromEvent(data));
const item = dynamo_event_1.DynamoEventHelper.mapToEvent(createdItem);
await this.latestModel.create(dynamo_latest_event_1.DynamoLatestEventHelper.mapFromEvent(item));
if (item.topics) {
await this.putTopicEvent(item, item.id, item.createdAt, item.topics);
}
return item;
}
async innerUpdate(data) {
const updatedItem = await this.model.update({
remove: data.delete,
key: { id: data.id },
set: data.set && dynamo_event_1.DynamoEventHelper.mapFromPartialEvent(data.set)
});
const item = dynamo_event_1.DynamoEventHelper.mapToEvent(updatedItem);
if (item.topics && item.topics.length && data.set && data.set.createdAt) {
await this.putTopicEvent(item, item.id, item.createdAt, item.topics);
}
return item;
}
async delete(id) {
const oldItem = await this.model.delete({ id });
return !!oldItem;
}
async exists(id) {
const item = await this.getById(id, { fields: ["id"] });
return !!item;
}
async getById(id, options) {
const item = await this.model.get({ id }, options && { attributes: options.fields });
if (!item) {
return item;
}
return dynamo_event_1.DynamoEventHelper.mapToEvent(item);
}
async getByIds(ids, options) {
const items = await this.model.getItems(ids.map((id) => ({ id })), options && { attributes: options.fields });
const list = items.map((item) => dynamo_event_1.DynamoEventHelper.mapToEvent(item));
return helpers_1.sortEntitiesByIds(ids, list);
}
async latest(params, options) {
const localeKey = dynamo_event_1.DynamoEventHelper.createLocaleKey(params);
const rangeKey = helpers_1.buildDateRangeKey(params);
const latestResults = await this.latestModel.query({
attributes: ["eventId"],
hashKey: localeKey,
limit: params.limit,
rangeKey,
order: "DESC"
});
if (!latestResults.items || latestResults.items.length === 0) {
return [];
}
const ids = domain_1.uniq(latestResults.items.map((item) => item.eventId)).slice(0, 100);
return this.getByIds(ids, options);
}
async latestByTopic(params, options) {
const index = this.topicModel.topicLastEventsIndexName();
const hashKey = params.topicId;
const rangeKey = helpers_1.buildDateRangeKey(params);
const result = await this.topicModel.query({
index,
hashKey,
limit: params.limit,
rangeKey,
order: "DESC",
attributes: ["eventId"]
});
if (!result.items || result.items.length === 0) {
return [];
}
const ids = domain_1.uniq(result.items.map((item) => item.eventId)).slice(0, 100);
return this.getByIds(ids, options);
}
async count(params) {
const localeKey = dynamo_latest_event_1.DynamoLatestEventHelper.createLocaleKey(params);
const rangeKey = helpers_1.buildDateRangeKey(params);
const result = await this.latestModel.query({
select: "COUNT",
hashKey: localeKey,
rangeKey
});
return result.count;
}
async countByTopic(params) {
const index = this.topicModel.topicLastEventsIndexName();
const hashKey = params.topicId;
const rangeKey = helpers_1.buildDateRangeKey(params);
const result = await this.topicModel.query({
index,
select: "COUNT",
hashKey,
rangeKey
});
return result.count;
}
async topTopics(params) {
const latestEvents = await this.latest(Object.assign({}, params, { limit: 50 }), { fields: ["id", "topics"] });
if (!latestEvents.length) {
return [];
}
const topMap = {};
for (const item of latestEvents) {
if (item.topics && item.topics.length) {
for (const topic of item.topics) {
const id = topic.id;
if (!topMap[id]) {
topMap[id] = 1;
}
else {
topMap[id]++;
}
}
}
}
const topList = Object.keys(topMap)
.map((id) => ({ id, count: topMap[id] }))
.sort((a, b) => b.count - a.count)
.slice(0, params.limit);
return topList;
}
async trendingTopics(params) {
const now = Date.now();
const midDate = new Date(now + ms(params.period))
.toISOString()
.substr(0, 13);
const endDate = new Date(now + ms(params.period) * 2)
.toISOString()
.substr(0, 13);
const topTopics = await Promise.all([
this.topTopics({
country: params.country,
lang: params.lang,
limit: 100,
minDate: midDate,
maxDate: endDate
}),
this.topTopics({
country: params.country,
lang: params.lang,
limit: 100,
maxDate: midDate
})
]);
const firstLentgh = topTopics[0].length;
const allTopTopics = topTopics[0].concat(topTopics[1]);
const topMap = {};
allTopTopics.forEach((item, i) => {
const id = item.id;
if (i < firstLentgh) {
topMap[id] = item.count * -1;
}
else {
if (topMap[id] === undefined) {
topMap[id] = item.count;
}
else {
topMap[id] += item.count;
}
}
});
const topList = Object.keys(topMap)
.map((id) => ({ id, count: topMap[id] }))
.sort((a, b) => b.count - a.count)
.slice(0, params.limit);
return topList;
}
async putTopicEvent(locale, eventId, createdAt, topics) {
const items = topic_event_1.TopicEventHelper.create(locale, eventId, createdAt, topics);
for (const item of items) {
await this.topicModel.put(item);
}
}
async deleteStorage() {
await Promise.all([
this.latestModel.deleteTable(),
this.model.deleteTable(),
this.topicModel.deleteTable()
]);
}
async createStorage() {
await Promise.all([
this.latestModel.createTable(),
this.model.createTable(),
this.topicModel.createTable()
]);
}
}
exports.DynamoEventRepository = DynamoEventRepository;