import { StorageProviderConstructor } from '../types/StorageProviderConstructor'; import { IStorageProvider } from './interface/IStorageProvider'; import { StorageProvider } from './StorageProvider'; import { Database } from './Database'; import * as Sequelize from 'sequelize'; /** * Represents an entry in a `SequelizeProvider` db table * following the Model the provider uses */ type Entry = { key: string, value: string }; /** * Represents a Model entry returned from `.findByPrimary()`. * Guaranteed to return a string in this representation because a * `StorageProvider` is guaranteed to only store, and thus retrieve, strings */ type ReturnedModel = { get(key: string): string }; export enum Dialect { Postgres, SQLite } export function SequelizeProvider(url: string, dialect: Dialect): StorageProviderConstructor { return class extends StorageProvider implements IStorageProvider { private _name: string; private _url: string; private _backend: Database; private _model: Sequelize.Model; public constructor(name: string) { super(); this._name = name; this._url = url; // Lazy load sequelize const seq: typeof Sequelize = require('sequelize'); this._backend = Database.instance(url); this._model = this._backend.db.define(name, { key: { type: seq.STRING, allowNull: false, primaryKey: true }, value: (dialect === Dialect.Postgres || dialect === Dialect.SQLite) ? seq.TEXT : seq.TEXT('long') }, { timestamps: false, freezeTableName: true }); } public async init(): Promise { await this._backend.init(); await this._backend.db.sync(); } public async keys(): Promise { return ( await this._model.findAll()).map(r => r.key); } public async get(key: string): Promise { if (typeof key === 'undefined') throw new TypeError('Key must be provided'); if (typeof key !== 'string') throw new TypeError('Key must be a string'); const entry: ReturnedModel = await this._model.findByPrimary(key); if (entry === null) return; return entry.get('value'); } public async set(key: string, value: string): Promise { if (typeof key === 'undefined') throw new TypeError('Key must be provided'); if (typeof key !== 'string') throw new TypeError('Key must be a string'); if (typeof value === 'undefined') throw new TypeError('Value must be provided'); if (typeof value !== 'string') throw new TypeError('Value must be a string'); await this._model.upsert({ key, value }); } public async remove(key: string): Promise { if (typeof key === 'undefined') throw new TypeError('Key must be provided'); if (typeof key !== 'string') throw new TypeError('Key must be a string'); await this._model.destroy({ where: { key }}); } public async clear(): Promise { await this._model.destroy({ where: {} }); } }; }