UNPKG

@vendure/core

Version:

A modern, headless ecommerce framework

151 lines 6.76 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SqlCacheStrategy = void 0; const cache_ttl_provider_1 = require("../../cache/cache-ttl-provider"); const instrument_decorator_1 = require("../../common/instrument-decorator"); const index_1 = require("../../config/index"); const index_2 = require("../../connection/index"); const cache_item_entity_1 = require("./cache-item.entity"); const cache_tag_entity_1 = require("./cache-tag.entity"); /** * @description * A {@link CacheStrategy} that stores cached items in the database. This * is the strategy used by the {@link DefaultCachePlugin}. * * @since 3.1.0 * @docsCategory cache */ let SqlCacheStrategy = class SqlCacheStrategy { constructor(config) { this.cacheSize = 10000; if (config === null || config === void 0 ? void 0 : config.cacheSize) { this.cacheSize = config.cacheSize; } this.ttlProvider = (config === null || config === void 0 ? void 0 : config.cacheTtlProvider) || new cache_ttl_provider_1.DefaultCacheTtlProvider(); } init(injector) { this.connection = injector.get(index_2.TransactionalConnection); this.configService = injector.get(index_1.ConfigService); } async get(key) { const hit = await this.connection.rawConnection.getRepository(cache_item_entity_1.CacheItem).findOne({ where: { key, }, }); if (hit) { if (!hit.expiresAt || (hit.expiresAt && this.ttlProvider.getTime() < hit.expiresAt.getTime())) { try { return JSON.parse(hit.value); } catch (e) { /* */ } } else { await this.connection.rawConnection.getRepository(cache_item_entity_1.CacheItem).delete({ key, }); } } } async set(key, value, options) { const cacheSize = await this.connection.rawConnection.getRepository(cache_item_entity_1.CacheItem).count(); if (cacheSize >= this.cacheSize) { // evict oldest const subQuery1 = this.connection.rawConnection .getRepository(cache_item_entity_1.CacheItem) .createQueryBuilder('item') .select('item.id', 'item_id') .orderBy('item.insertedAt', 'DESC') .limit(1000) .offset(Math.max(this.cacheSize - 1, 1)); const subQuery2 = this.connection.rawConnection .createQueryBuilder() .select('t.item_id') .from(`(${subQuery1.getQuery()})`, 't'); const qb = this.connection.rawConnection .getRepository(cache_item_entity_1.CacheItem) .createQueryBuilder('cache_item') .delete() .from(cache_item_entity_1.CacheItem, 'cache_item') .where(`cache_item.id IN (${subQuery2.getQuery()})`); try { await qb.execute(); } catch (e) { index_1.Logger.error(`An error occurred when attempting to prune the cache: ${e.message}`); } } const item = await this.connection.rawConnection.getRepository(cache_item_entity_1.CacheItem).upsert(new cache_item_entity_1.CacheItem({ key, insertedAt: new Date(), value: JSON.stringify(value), expiresAt: (options === null || options === void 0 ? void 0 : options.ttl) ? new Date(this.ttlProvider.getTime() + options.ttl) : undefined, }), ['key']); if (options === null || options === void 0 ? void 0 : options.tags) { for (const tag of options.tags) { try { await this.connection.rawConnection.getRepository(cache_tag_entity_1.CacheTag).upsert({ tag, item: item.identifiers[0], }, ['tag', 'itemId']); } catch (e) { index_1.Logger.error(`Error inserting tag`, e.message); } } } } async delete(key) { await this.connection.rawConnection.getRepository(cache_item_entity_1.CacheItem).delete({ key, }); } async invalidateTags(tags) { await this.connection.withTransaction(async (ctx) => { const itemIds = await this.connection .getRepository(ctx, cache_tag_entity_1.CacheTag) .createQueryBuilder('cache_tag') .select('cache_tag.itemId') .where('cache_tag.tag IN (:...tags)', { tags }) .groupBy('cache_tag.itemId') .groupBy('cache_tag.id') .getMany(); await this.connection .getRepository(ctx, cache_tag_entity_1.CacheTag) .createQueryBuilder('cache_tag') .delete() .where('cache_tag.tag IN (:...tags)', { tags }) .execute(); if (itemIds.length) { const ids = itemIds.map(i => i.itemId); const batchSize = 1000; for (let i = 0; i < itemIds.length; i += batchSize) { const batch = ids.slice(i, batchSize); try { await this.connection.getRepository(ctx, cache_item_entity_1.CacheItem).delete(batch); } catch (e) { index_1.Logger.error(`Error deleting items`, e.message); } } } }); } }; exports.SqlCacheStrategy = SqlCacheStrategy; exports.SqlCacheStrategy = SqlCacheStrategy = __decorate([ (0, instrument_decorator_1.Instrument)(), __metadata("design:paramtypes", [Object]) ], SqlCacheStrategy); //# sourceMappingURL=sql-cache-strategy.js.map