@absolunet/ioc2.1.0

View on GitHub

cache/services/CacheManager/drivers/DatabaseDriver.js

//--------------------------------------------------------
//-- Node IoC - Cache - Services - Store resolver - Drivers - Database driver
//--------------------------------------------------------

import Driver from './Driver';


/**
 * Cache driver that uses the database to store data.
 *
 * @memberof cache.services.CacheManager.drivers
 * @augments cache.services.CacheManager.drivers.Driver
 * @hideconstructor
 */
class DatabaseDriver extends Driver {

	/**
	 * Class dependencies: <code>['db', 'driver.config', 'helper.date']</code>.
	 *
	 * @type {Array<string>}
	 */
	static get dependencies() {
		return (super.dependencies || []).concat(['db']);
	}

	/**
	 * @inheritdoc
	 */
	async get(key, defaultValue = null) {
		const result = await this.getResult(key);

		return this.getFromResult(result, defaultValue);
	}

	/**
	 * @inheritdoc
	 */
	async put(key, value, seconds = this.driverConfig.expiration || 600) {
		const { connection, driverConfig: { table } } = this;
		const expiresAt = seconds === 0 ? null : this.dateHelper().add(seconds, 'seconds').format('YYYY-MM-DD HH:mm:ss');
		await this.delete(key);

		await connection(table).insert({
			key,
			value: JSON.stringify(value),
			expires_at: expiresAt // eslint-disable-line camelcase
		});
	}

	/**
	 * @inheritdoc
	 */
	forever(key, value) {
		return this.put(key, value, 0);
	}

	/**
	 * @inheritdoc
	 */
	async increment(key, increment = 1) {
		const result = await this.getResult(key);
		const value  = await this.getFromResult(result, 0);
		const seconds = result ? result.expires_at ? this.dateHelper(result.expires_at).unix() - this.now() : null : undefined;

		await this.put(key, value + increment, seconds);
	}

	/**
	 * @inheritdoc
	 */
	decrement(key, decrement = 1) {
		return this.increment(key, decrement * -1);
	}

	/**
	 * @inheritdoc
	 */
	async delete(key) {
		const { connection, driverConfig: { table } } = this;
		await connection(table).where('key', key).delete();
	}

	/**
	 * @inheritdoc
	 */
	async flush() {
		const { connection, driverConfig: { table } } = this;
		await connection(table).delete();
	}

	/**
	 * Get full database result from key.
	 *
	 * @param {string} key - The cache key.
	 * @returns {Promise<{key: string, value: string, expires_at: string|null}|undefined>} The cache database entry.
	 */
	async getResult(key) {
		const { connection, driverConfig: { table } } = this;
		const [result] = await connection.select().from(table).where('key', key);

		return result;
	}

	/**
	 * Get value from result.
	 *
	 * @param {{key: string, value: string, expires_at: string|null}|undefined} result - The cache database entry.
	 * @param {*} [defaultValue] - The default value to use if the result is empty, expired or not parsable.
	 * @returns {Promise<*>} The cached value.
	 */
	async getFromResult(result, defaultValue = null) {
		if (!result) {
			return defaultValue;
		}


		if (result.expires_at && this.dateHelper(result.expires_at).isBefore(this.dateHelper.now())) {
			await this.delete(result.key);

			return defaultValue;
		}

		try {
			return JSON.parse(result.value);
		} catch (error) {
			await this.delete(result.key);

			return defaultValue;
		}
	}

	/**
	 * Connection instance based on configuration.
	 *
	 * @type {Knex}
	 */
	get connection() {
		return this.db.getConnection(this.driverConfig.connection);
	}

}


export default DatabaseDriver;