/** * @typedef {import('./Milestone')} Milestone * @typedef {import('./MilestonesService').IMilestoneRepository} IMilestoneRepository */ /** * @implements {IMilestoneRepository} */ module.exports = class InMemoryMilestoneRepository { /** @type {Milestone[]} */ #store = []; /** @type {Object.} */ #ids = {}; /** @type {import('@tryghost/domain-events')} */ #DomainEvents; /** * @param {object} deps * @param {import('@tryghost/domain-events')} deps.DomainEvents */ constructor(deps) { this.#DomainEvents = deps.DomainEvents; } /** * @param {Milestone} milestone * * @returns {Promise} */ 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; } for (const event of milestone.events) { this.#DomainEvents.dispatch(event); } } /** * @param {'arr'|'members'} type * @param {string} [currency] * * @returns {Promise} */ 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} */ 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 * @param {string} [currency] * * @returns {Promise} */ 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} */ 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'; }); } };