unleash-server
Version:
Unleash is an enterprise ready feature flag service. It provides different strategies for handling feature flags.
222 lines • 7.99 kB
JavaScript
import NotFoundError from '../../../error/notfound-error.js';
export default class FakeFeatureToggleStore {
constructor() {
this.features = [];
}
async archive(featureName) {
const feature = this.features.find((f) => f.name === featureName);
if (feature) {
feature.archived = true;
return feature;
}
throw new NotFoundError(`Could not find feature flag with name ${featureName}`);
}
async batchArchive(featureNames) {
const features = this.features.filter((feature) => featureNames.includes(feature.name));
for (const feature of features) {
feature.archived = true;
}
return features;
}
async batchStale(featureNames, stale) {
const features = this.features.filter((feature) => featureNames.includes(feature.name));
for (const feature of features) {
feature.stale = stale;
}
return features;
}
async batchDelete(featureNames) {
this.features = this.features.filter((feature) => !featureNames.includes(feature.name));
return Promise.resolve();
}
async batchRevive(featureNames) {
const features = this.features.filter((f) => featureNames.includes(f.name));
for (const feature of features) {
feature.archived = false;
}
return features;
}
disableAllEnvironmentsForFeatures(names) {
throw new Error('Method not implemented.');
}
async count(query = { archived: false }) {
return this.getAll(query).then((features) => features.length);
}
async getAllByNames(names) {
return this.features.filter((f) => names.includes(f.name));
}
async getProjectId(name) {
if (name === undefined) {
return Promise.resolve(undefined);
}
return Promise.resolve(this.get(name).then((f) => f.project));
}
getFilterQuery(query) {
return (f) => {
let projectMatch = true;
if ('project' in query) {
projectMatch = f.project === query.project;
}
let archiveMatch = true;
if ('archived' in query) {
archiveMatch = (f.archived ?? false) === query.archived;
}
let staleMatch = true;
if ('stale' in query) {
staleMatch = (f.stale ?? false) === query.stale;
}
return projectMatch && archiveMatch && staleMatch;
};
}
async create(project, data) {
const inserted = { ...data, project };
this.features.push(inserted);
return inserted;
}
async delete(key) {
this.features.splice(this.features.findIndex((f) => f.name === key), 1);
}
async deleteAll() {
this.features = [];
}
destroy() { }
async exists(key) {
return this.features.some((f) => f.name === key);
}
async get(key) {
const feature = this.features.find((f) => f.name === key);
if (feature) {
return feature;
}
throw new NotFoundError(`Could not find feature with name ${key}`);
}
async getAll(query = { archived: false }) {
return this.features.filter(this.getFilterQuery(query));
}
async getFeatureMetadata(name) {
return this.get(name);
}
async getBy(query) {
return this.features.filter(this.getFilterQuery(query));
}
async revive(featureName) {
const revive = this.features.find((f) => f.name === featureName);
if (revive) {
revive.archived = false;
}
return this.update(revive.project, revive);
}
async getFeatureToggleList(query, userId, archived = false) {
return this.features.filter((feature) => feature.archived !== archived);
}
async getPlaygroundFeatures(query) {
return this.features.filter((feature) => feature);
}
async update(project, data) {
const exists = await this.exists(data.name);
if (exists) {
const id = this.features.findIndex((f) => f.name === data.name);
const old = this.features.find((f) => f.name === data.name);
const updated = { project, ...old, ...data };
this.features.splice(id, 1);
this.features.push(updated);
return updated;
}
throw new NotFoundError('Could not find feature to update');
}
async setLastSeen(data) {
const envArrays = data.reduce((acc, feature) => {
const { environment, featureName } = feature;
if (!acc[environment]) {
acc[environment] = [];
}
acc[environment].push(featureName);
return acc;
}, {});
for (const env of Object.keys(envArrays)) {
const toggleNames = envArrays[env];
if (toggleNames && Array.isArray(toggleNames)) {
toggleNames.forEach((t) => {
const toUpdate = this.features.find((f) => f.name === t);
if (toUpdate) {
toUpdate.lastSeenAt = new Date();
}
});
}
}
}
async getAllVariants() {
const features = await this.getAll();
const variants = features.flatMap((feature) => ({
featureName: feature.name,
environment: 'development',
variants: feature.variants,
enabled: true,
}));
return Promise.resolve(variants);
}
async getVariantsForEnv(featureName, environment_name) {
const feature = await this.get(featureName);
// there's no way to filter by environment in the fake store
return feature.variants;
}
async saveVariants(project, featureName, newVariants) {
const feature = await this.get(featureName);
feature.variants = newVariants;
return feature;
}
async saveVariantsOnEnv(featureName, environment, newVariants) {
await this.saveVariants('default', featureName, newVariants);
return Promise.resolve(newVariants);
}
async countByDate(queryModifiers) {
return this.features.filter((feature) => {
if (feature.archived === queryModifiers.archived) {
return true;
}
if (feature.project === queryModifiers.project) {
return true;
}
if (queryModifiers.date &&
new Date(feature[queryModifiers.dateAccessor]).getTime() >=
new Date(queryModifiers.date).getTime()) {
return true;
}
const featureDate = new Date(feature[queryModifiers.dateAccessor]).getTime();
if (queryModifiers.range &&
featureDate >= new Date(queryModifiers.range[0]).getTime() &&
featureDate <= new Date(queryModifiers.range[1]).getTime()) {
return true;
}
}).length;
}
dropAllVariants() {
this.features.forEach((feature) => {
feature.variants = [];
});
return Promise.resolve();
}
updatePotentiallyStaleFeatures() {
throw new Error('Method not implemented.');
}
isPotentiallyStale() {
throw new Error('Method not implemented.');
}
async getFeatureTypeCounts(params) {
const typeCounts = this.features.reduce((acc, feature) => {
if (!feature.type) {
return acc;
}
if (!acc[feature.type]) {
acc[feature.type] = { type: feature.type, count: 0 };
}
acc[feature.type].count += 1;
return acc;
}, {});
return Object.values(typeCounts);
}
setCreatedByUserId(batchSize) {
throw new Error('Method not implemented.');
}
}
//# sourceMappingURL=fake-feature-toggle-store.js.map