All files / src/lib/db strategy-store.ts

88.24% Statements 30/34
50% Branches 1/2
78.95% Functions 15/19
88.24% Lines 30/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166      69x               69x               69x                   69x           87x 87x       12x           12x       7x             7x                       1x                   2x       2x 2x       17x 17x       55x 7x   48x                     26x     26x                   218x                 194x         2x           2x       1x                 22x 22x       3x           69x  
import { Knex } from 'knex';
import { Logger, LogProvider } from '../logger';
 
import NotFoundError from '../error/notfound-error';
import {
    IEditableStrategy,
    IMinimalStrategyRow,
    IStrategy,
    IStrategyStore,
} from '../types/stores/strategy-store';
 
const STRATEGY_COLUMNS = [
    'name',
    'description',
    'parameters',
    'built_in',
    'deprecated',
    'display_name',
];
const TABLE = 'strategies';
 
interface IStrategyRow {
    name: string;
    built_in: number;
    description: string;
    parameters: object[];
    deprecated: boolean;
    display_name: string;
}
export default class StrategyStore implements IStrategyStore {
    private db: Knex;
 
    private logger: Logger;
 
    constructor(db: Knex, getLogger: LogProvider) {
        this.db = db;
        this.logger = getLogger('strategy-store.ts');
    }
 
    async getAll(): Promise<IStrategy[]> {
        const rows = await this.db
            .select(STRATEGY_COLUMNS)
            .from(TABLE)
            .orderBy('sort_order', 'asc')
            .orderBy('name', 'asc');
 
        return rows.map(this.rowToStrategy);
    }
 
    async getEditableStrategies(): Promise<IEditableStrategy[]> {
        const rows = await this.db
            .select(STRATEGY_COLUMNS)
            .from(TABLE)
            .where({ built_in: 0 }) // eslint-disable-line
            .orderBy('sort_order', 'asc')
            .orderBy('name', 'asc');
 
        return rows.map(this.rowToEditableStrategy);
    }
 
    async getStrategy(name: string): Promise<IStrategy> {
        return this.db
            .first(STRATEGY_COLUMNS)
            .from(TABLE)
            .where({ name })
            .then(this.rowToStrategy);
    }
 
    async delete(name: string): Promise<void> {
        await this.db(TABLE).where({ name }).del();
    }
 
    async deleteAll(): Promise<void> {
        await this.db(TABLE).del();
    }
 
    destroy(): void {}
 
    async exists(name: string): Promise<boolean> {
        const result = await this.db.raw(
            `SELECT EXISTS (SELECT 1 FROM ${TABLE} WHERE name = ?) AS present`,
            [name],
        );
        const { present } = result.rows[0];
        return present;
    }
 
    async get(name: string): Promise<IStrategy> {
        const row = await this.db(TABLE).where({ name }).first();
        return this.rowToStrategy(row);
    }
 
    rowToStrategy(row: IStrategyRow): IStrategy {
        if (!row) {
            throw new NotFoundError('No strategy found');
        }
        return {
            displayName: row.display_name,
            name: row.name,
            editable: row.built_in !== 1,
            description: row.description,
            parameters: row.parameters,
            deprecated: row.deprecated,
        };
    }
 
    rowToEditableStrategy(row: IStrategyRow): IEditableStrategy {
        Iif (!row) {
            throw new NotFoundError('No strategy found');
        }
        return {
            name: row.name,
            description: row.description,
            parameters: row.parameters,
            deprecated: row.deprecated,
        };
    }
 
    // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
    eventDataToRow(data): IMinimalStrategyRow {
        return {
            name: data.name,
            description: data.description,
            parameters: JSON.stringify(data.parameters),
        };
    }
 
    // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
    async createStrategy(data): Promise<void> {
        await this.db(TABLE).insert(this.eventDataToRow(data));
    }
 
    // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
    async updateStrategy(data): Promise<void> {
        await this.db(TABLE)
            .where({ name: data.name })
            .update(this.eventDataToRow(data));
    }
 
    async deprecateStrategy({ name }: Pick<IStrategy, 'name'>): Promise<void> {
        await this.db(TABLE).where({ name }).update({ deprecated: true });
    }
 
    async reactivateStrategy({ name }: Pick<IStrategy, 'name'>): Promise<void> {
        await this.db(TABLE).where({ name }).update({ deprecated: false });
    }
 
    async deleteStrategy({ name }: Pick<IStrategy, 'name'>): Promise<void> {
        await this.db(TABLE).where({ name }).del();
    }
 
    // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
    async importStrategy(data): Promise<void> {
        const rowData = this.eventDataToRow(data);
        await this.db(TABLE).insert(rowData).onConflict(['name']).merge();
    }
 
    async dropCustomStrategies(): Promise<void> {
        await this.db(TABLE)
            .where({ built_in: 0 }) // eslint-disable-line
            .delete();
    }
}
 
module.exports = StrategyStore;