2023-02-07 13:47:35 +03:00
|
|
|
/**
|
|
|
|
* @typedef {import('./Milestone')} Milestone
|
2023-02-15 10:23:31 +03:00
|
|
|
* @typedef {import('./MilestonesService').IMilestoneRepository} IMilestoneRepository
|
2023-02-07 13:47:35 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @implements {IMilestoneRepository}
|
|
|
|
*/
|
|
|
|
module.exports = class InMemoryMilestoneRepository {
|
|
|
|
/** @type {Milestone[]} */
|
|
|
|
#store = [];
|
|
|
|
|
|
|
|
/** @type {Object.<string, true>} */
|
|
|
|
#ids = {};
|
|
|
|
|
2023-02-15 13:06:13 +03:00
|
|
|
/** @type {import('@tryghost/domain-events')} */
|
|
|
|
#DomainEvents;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {object} deps
|
|
|
|
* @param {import('@tryghost/domain-events')} deps.DomainEvents
|
|
|
|
*/
|
|
|
|
constructor(deps) {
|
|
|
|
this.#DomainEvents = deps.DomainEvents;
|
|
|
|
}
|
|
|
|
|
2023-02-07 13:47:35 +03:00
|
|
|
/**
|
|
|
|
* @param {Milestone} milestone
|
|
|
|
*
|
|
|
|
* @returns {Promise<void>}
|
|
|
|
*/
|
|
|
|
async save(milestone) {
|
|
|
|
if (this.#ids[milestone.id.toHexString()]) {
|
|
|
|
const existingIndex = this.#store.findIndex((item) => {
|
|
|
|
return item.id.equals(milestone.id);
|
|
|
|
});
|
|
|
|
this.#store.splice(existingIndex, 1, milestone);
|
|
|
|
} else {
|
|
|
|
this.#store.push(milestone);
|
|
|
|
this.#ids[milestone.id.toHexString()] = true;
|
2023-02-15 14:57:38 +03:00
|
|
|
}
|
2023-02-15 13:06:13 +03:00
|
|
|
|
2023-02-15 14:57:38 +03:00
|
|
|
for (const event of milestone.events) {
|
|
|
|
this.#DomainEvents.dispatch(event);
|
2023-02-07 13:47:35 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {'arr'|'members'} type
|
2023-02-13 17:29:01 +03:00
|
|
|
* @param {string} [currency]
|
2023-02-07 13:47:35 +03:00
|
|
|
*
|
|
|
|
* @returns {Promise<Milestone>}
|
|
|
|
*/
|
|
|
|
async getLatestByType(type, currency = 'usd') {
|
|
|
|
if (type === 'arr') {
|
|
|
|
return this.#store
|
|
|
|
.filter(item => item.type === type && item.currency === currency)
|
|
|
|
// sort by created at desc
|
|
|
|
.sort((a, b) => (b.createdAt.valueOf() - a.createdAt.valueOf()))
|
|
|
|
// if we end up with more values created at the same time, pick the highest value
|
|
|
|
.sort((a, b) => b.value - a.value)[0];
|
|
|
|
} else {
|
|
|
|
return this.#store
|
|
|
|
.filter(item => item.type === type)
|
|
|
|
// sort by created at desc
|
|
|
|
.sort((a, b) => (b.createdAt.valueOf() - a.createdAt.valueOf()))
|
|
|
|
// if we end up with more values created at the same time, pick the highest value
|
|
|
|
.sort((a, b) => b.value - a.value)[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @returns {Promise<Milestone>}
|
|
|
|
*/
|
|
|
|
async getLastEmailSent() {
|
|
|
|
return this.#store
|
|
|
|
.filter(item => item.emailSentAt)
|
|
|
|
// sort by emailSentAt desc
|
|
|
|
.sort((a, b) => (b.emailSentAt.valueOf() - a.emailSentAt.valueOf()))
|
|
|
|
// if we end up with more values with the same datetime, pick the highest value
|
|
|
|
.sort((a, b) => b.value - a.value)[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {number} value
|
2023-02-13 17:29:01 +03:00
|
|
|
* @param {string} [currency]
|
2023-02-07 13:47:35 +03:00
|
|
|
*
|
|
|
|
* @returns {Promise<Milestone>}
|
|
|
|
*/
|
|
|
|
async getByARR(value, currency = 'usd') {
|
|
|
|
// find a milestone of the ARR type by a given value
|
|
|
|
return this.#store.find((item) => {
|
|
|
|
return item.value === value && item.type === 'arr' && item.currency === currency;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {number} value
|
|
|
|
*
|
|
|
|
* @returns {Promise<Milestone>}
|
|
|
|
*/
|
|
|
|
async getByCount(value) {
|
|
|
|
// find a milestone of the members type by a given value
|
|
|
|
return this.#store.find((item) => {
|
|
|
|
return item.value === value && item.type === 'members';
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|