mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-03 23:00:14 -05:00
Added caching to TierRepository
refs https://github.com/TryGhost/Toolbox/issues/515 Tiers are very frequently queried and we want to reduce the number of DB calls we're making. We can store the Tiers in-memory, using the existing in-memory repository patterns, but still persisting writes the the database. We also have to update our test helpers, because they were bypassing the repository for writes, but using it for reads resulting in an invalid cache
This commit is contained in:
parent
6ab862568c
commit
c0ca7b16f6
5 changed files with 73 additions and 19 deletions
|
@ -1,4 +1,5 @@
|
|||
const {Tier} = require('@tryghost/tiers');
|
||||
const nql = require('@tryghost/nql');
|
||||
|
||||
/**
|
||||
* @typedef {import('@tryghost/tiers/lib/TiersAPI').ITierRepository} ITierRepository
|
||||
|
@ -8,6 +9,11 @@ const {Tier} = require('@tryghost/tiers');
|
|||
* @implements {ITierRepository}
|
||||
*/
|
||||
module.exports = class TierRepository {
|
||||
/** @type {import('@tryghost/tiers/lib/Tier')[]} */
|
||||
#store = [];
|
||||
/** @type {Object.<string, true>} */
|
||||
#ids = {};
|
||||
|
||||
/** @type {Object} */
|
||||
#ProductModel;
|
||||
|
||||
|
@ -24,6 +30,32 @@ module.exports = class TierRepository {
|
|||
this.#DomainEvents = deps.DomainEvents;
|
||||
}
|
||||
|
||||
async init() {
|
||||
this.#store = [];
|
||||
this.#ids = {};
|
||||
const models = await this.#ProductModel.findAll({
|
||||
withRelated: ['benefits']
|
||||
});
|
||||
for (const model of models) {
|
||||
const tier = await Tier.create(this.mapToTier(model));
|
||||
this.#store.push(tier);
|
||||
this.#ids[tier.id.toHexString()] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('@tryghost/tiers/lib/Tier')} tier
|
||||
* @returns {any}
|
||||
*/
|
||||
toPrimitive(tier) {
|
||||
return {
|
||||
...tier,
|
||||
active: (tier.status === 'active'),
|
||||
type: tier.type,
|
||||
id: tier.id.toHexString()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
@ -54,16 +86,12 @@ module.exports = class TierRepository {
|
|||
* @returns {Promise<import('@tryghost/tiers/lib/Tier')[]>}
|
||||
*/
|
||||
async getAll(options = {}) {
|
||||
const collection = await this.#ProductModel.findAll({...options, withRelated: ['benefits']});
|
||||
|
||||
const result = [];
|
||||
|
||||
for (const model of collection.models) {
|
||||
const tier = await Tier.create(this.mapToTier(model));
|
||||
result.push(tier);
|
||||
}
|
||||
|
||||
return result;
|
||||
const filter = nql(options.filter, {});
|
||||
return Promise.all(this.#store.slice().filter((item) => {
|
||||
return filter.queryJSON(this.toPrimitive(item));
|
||||
}).map((tier) => {
|
||||
return Tier.create(tier);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -71,9 +99,15 @@ module.exports = class TierRepository {
|
|||
* @returns {Promise<import('@tryghost/tiers/lib/Tier')>}
|
||||
*/
|
||||
async getById(id) {
|
||||
const model = await this.#ProductModel.findOne({id: id.toHexString()}, {withRelated: ['benefits']});
|
||||
const found = this.#store.find((item) => {
|
||||
return item.id.equals(id);
|
||||
});
|
||||
|
||||
return await Tier.create(this.mapToTier(model));
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Tier.create(found);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,14 +133,20 @@ module.exports = class TierRepository {
|
|||
benefits: tier.benefits.map(name => ({name}))
|
||||
};
|
||||
|
||||
const existing = await this.#ProductModel.findOne({id: data.id}, {require: false});
|
||||
const toSave = await Tier.create(tier);
|
||||
|
||||
if (!existing) {
|
||||
await this.#ProductModel.add(data);
|
||||
} else {
|
||||
if (this.#ids[tier.id.toHexString()]) {
|
||||
const existing = this.#store.findIndex((item) => {
|
||||
return item.id.equals(tier.id);
|
||||
});
|
||||
await this.#ProductModel.edit(data, {
|
||||
id: data.id
|
||||
});
|
||||
this.#store.splice(existing, 1, toSave);
|
||||
} else {
|
||||
await this.#ProductModel.add(data);
|
||||
this.#store.push(toSave);
|
||||
this.#ids[tier.id.toHexString()] = true;
|
||||
}
|
||||
|
||||
for (const event of tier.events) {
|
||||
|
|
|
@ -22,6 +22,10 @@ class TiersServiceWrapper {
|
|||
}
|
||||
};
|
||||
|
||||
await repository.init();
|
||||
|
||||
this.repository = repository;
|
||||
|
||||
this.api = new TiersAPI({
|
||||
repository,
|
||||
slugService
|
||||
|
|
|
@ -891,6 +891,10 @@ const getFixtureOps = (toDos) => {
|
|||
}
|
||||
});
|
||||
|
||||
fixtureOps.push(() => {
|
||||
return require('../../core/server/services/tiers').repository?.init();
|
||||
});
|
||||
|
||||
return fixtureOps;
|
||||
};
|
||||
|
||||
|
|
|
@ -1237,6 +1237,9 @@ DataGenerator.forKnex = (function () {
|
|||
slug: 'gold',
|
||||
active: true,
|
||||
type: 'paid',
|
||||
currency: 'usd',
|
||||
monthly_price: 500,
|
||||
yearly_price: 5000,
|
||||
visibility: 'public',
|
||||
benefits: [],
|
||||
created_by: DataGenerator.Content.users[0].id,
|
||||
|
|
|
@ -92,12 +92,15 @@ class StripeMocker {
|
|||
* @returns
|
||||
*/
|
||||
async createTier({name, currency, monthly_price, yearly_price}) {
|
||||
return await models.Product.add({
|
||||
const result = await tiers.api.add({
|
||||
name: name ?? ('Tier ' + this.#generateRandomId()),
|
||||
type: 'paid',
|
||||
currency: currency.toUpperCase(),
|
||||
monthly_price,
|
||||
yearly_price
|
||||
monthlyPrice: monthly_price,
|
||||
yearlyPrice: yearly_price
|
||||
});
|
||||
return await models.Product.findOne({
|
||||
id: result.id.toHexString()
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue