mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-14 00:19:16 +01:00
https://linear.app/unleash/issue/2-1403/consider-refactoring-the-way-tags-are-fetched-for-the-events This adds 2 methods to `EventService`: - `storeEvent`; - `storeEvents`; This allows us to run event-specific logic inside these methods. In the case of this PR, this means fetching the feature tags in case the event contains a `featureName` and there are no tags specified in the event. This prevents us from having to remember to fetch the tags in order to store feature-related events except for very specific cases, like the deletion of a feature - You can't fetch tags for a feature that no longer exists, so in that case we need to pre-fetch the tags before deleting the feature. This also allows us to do any event-specific post-processing to the event before reaching the DB layer. In general I think it's also nicer that we reference the event service instead of the event store directly. There's a lot of changes and a lot of files touched, but most of it is boilerplate to inject the `eventService` where needed instead of using the `eventStore` directly. Hopefully this will be a better approach than https://github.com/Unleash/unleash/pull/4729 --------- Co-authored-by: Gastón Fournier <gaston@getunleash.io>
156 lines
4.7 KiB
TypeScript
156 lines
4.7 KiB
TypeScript
import { Logger } from '../logger';
|
|
import { IUnleashConfig } from '../types/option';
|
|
import { IUnleashStores } from '../types/stores';
|
|
import {
|
|
IMinimalStrategy,
|
|
IStrategy,
|
|
IStrategyStore,
|
|
} from '../types/stores/strategy-store';
|
|
import NotFoundError from '../error/notfound-error';
|
|
import EventService from './event-service';
|
|
|
|
const strategySchema = require('./strategy-schema');
|
|
const NameExistsError = require('../error/name-exists-error');
|
|
const {
|
|
STRATEGY_CREATED,
|
|
STRATEGY_DELETED,
|
|
STRATEGY_DEPRECATED,
|
|
STRATEGY_REACTIVATED,
|
|
STRATEGY_UPDATED,
|
|
} = require('../types/events');
|
|
|
|
class StrategyService {
|
|
private logger: Logger;
|
|
|
|
private strategyStore: IStrategyStore;
|
|
|
|
private eventService: EventService;
|
|
|
|
constructor(
|
|
{ strategyStore }: Pick<IUnleashStores, 'strategyStore'>,
|
|
{ getLogger }: Pick<IUnleashConfig, 'getLogger'>,
|
|
eventService: EventService,
|
|
) {
|
|
this.strategyStore = strategyStore;
|
|
this.eventService = eventService;
|
|
this.logger = getLogger('services/strategy-service.js');
|
|
}
|
|
|
|
async getStrategies(): Promise<IStrategy[]> {
|
|
return this.strategyStore.getAll();
|
|
}
|
|
|
|
async getStrategy(name: string): Promise<IStrategy> {
|
|
return this.strategyStore.get(name);
|
|
}
|
|
|
|
async removeStrategy(
|
|
strategyName: string,
|
|
userName: string,
|
|
): Promise<void> {
|
|
const strategy = await this.strategyStore.get(strategyName);
|
|
await this._validateEditable(strategy);
|
|
await this.strategyStore.delete(strategyName);
|
|
await this.eventService.storeEvent({
|
|
type: STRATEGY_DELETED,
|
|
createdBy: userName,
|
|
data: {
|
|
name: strategyName,
|
|
},
|
|
});
|
|
}
|
|
|
|
async deprecateStrategy(
|
|
strategyName: string,
|
|
userName: string,
|
|
): Promise<void> {
|
|
if (await this.strategyStore.exists(strategyName)) {
|
|
// Check existence
|
|
await this.strategyStore.deprecateStrategy({ name: strategyName });
|
|
await this.eventService.storeEvent({
|
|
type: STRATEGY_DEPRECATED,
|
|
createdBy: userName,
|
|
data: {
|
|
name: strategyName,
|
|
},
|
|
});
|
|
} else {
|
|
throw new NotFoundError(
|
|
`Could not find strategy with name ${strategyName}`,
|
|
);
|
|
}
|
|
}
|
|
|
|
async reactivateStrategy(
|
|
strategyName: string,
|
|
userName: string,
|
|
): Promise<void> {
|
|
await this.strategyStore.get(strategyName); // Check existence
|
|
await this.strategyStore.reactivateStrategy({ name: strategyName });
|
|
await this.eventService.storeEvent({
|
|
type: STRATEGY_REACTIVATED,
|
|
createdBy: userName,
|
|
data: {
|
|
name: strategyName,
|
|
},
|
|
});
|
|
}
|
|
|
|
async createStrategy(
|
|
value: IMinimalStrategy,
|
|
userName: string,
|
|
): Promise<IStrategy> {
|
|
const strategy = await strategySchema.validateAsync(value);
|
|
strategy.deprecated = false;
|
|
await this._validateStrategyName(strategy);
|
|
await this.strategyStore.createStrategy(strategy);
|
|
await this.eventService.storeEvent({
|
|
type: STRATEGY_CREATED,
|
|
createdBy: userName,
|
|
data: strategy,
|
|
});
|
|
return this.strategyStore.get(strategy.name);
|
|
}
|
|
|
|
async updateStrategy(
|
|
input: IMinimalStrategy,
|
|
userName: string,
|
|
): Promise<void> {
|
|
const value = await strategySchema.validateAsync(input);
|
|
const strategy = await this.strategyStore.get(input.name);
|
|
await this._validateEditable(strategy);
|
|
await this.strategyStore.updateStrategy(value);
|
|
await this.eventService.storeEvent({
|
|
type: STRATEGY_UPDATED,
|
|
createdBy: userName,
|
|
data: value,
|
|
});
|
|
}
|
|
|
|
private _validateStrategyName(
|
|
data: Pick<IStrategy, 'name'>,
|
|
): Promise<Pick<IStrategy, 'name'>> {
|
|
return new Promise((resolve, reject) => {
|
|
this.strategyStore
|
|
.get(data.name)
|
|
.then(() =>
|
|
reject(
|
|
new NameExistsError(
|
|
`Strategy with name ${data.name} already exist!`,
|
|
),
|
|
),
|
|
)
|
|
.catch(() => resolve(data));
|
|
});
|
|
}
|
|
|
|
// This check belongs in the store.
|
|
_validateEditable(strategy: IStrategy): void {
|
|
if (strategy.editable === false) {
|
|
throw new Error(`Cannot edit strategy ${strategy.name}`);
|
|
}
|
|
}
|
|
}
|
|
export default StrategyService;
|
|
module.exports = StrategyService;
|