Skip to content

Commit

Permalink
Merge pull request #249 from splitio/storage-typo
Browse files Browse the repository at this point in the history
Fix flagsets typo in storage
  • Loading branch information
emmaz90 authored Sep 25, 2023
2 parents 1c8dff6 + 3036d42 commit 856f8b7
Show file tree
Hide file tree
Showing 17 changed files with 151 additions and 118 deletions.
2 changes: 2 additions & 0 deletions src/storages/AbstractSplitsCacheAsync.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ISplitsCacheAsync } from './types';
import { ISplit } from '../dtos/types';
import { objectAssign } from '../utils/lang/objectAssign';
import { ISet } from '../utils/lang/sets';

/**
* This class provides a skeletal implementation of the ISplitsCacheAsync interface
Expand All @@ -17,6 +18,7 @@ export abstract class AbstractSplitsCacheAsync implements ISplitsCacheAsync {
abstract getChangeNumber(): Promise<number>
abstract getAll(): Promise<ISplit[]>
abstract getSplitNames(): Promise<string[]>
abstract getNamesByFlagSets(flagSets: string[]): Promise<ISet<string>>
abstract trafficTypeExists(trafficType: string): Promise<boolean>
abstract clear(): Promise<boolean | void>

Expand Down
3 changes: 3 additions & 0 deletions src/storages/AbstractSplitsCacheSync.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ISplitsCacheSync } from './types';
import { ISplit } from '../dtos/types';
import { objectAssign } from '../utils/lang/objectAssign';
import { ISet } from '../utils/lang/sets';

/**
* This class provides a skeletal implementation of the ISplitsCacheSync interface
Expand Down Expand Up @@ -78,6 +79,8 @@ export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
return false;
}

abstract getNamesByFlagSets(flagSets: string[]): ISet<string>

}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/storages/KeyBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ export class KeyBuilder {
return `${this.prefix}.trafficType.${trafficType}`;
}

buildFlagsetKey(flagset: string) {
return `${this.prefix}.flagset.${flagset}`;
buildFlagSetKey(flagSet: string) {
return `${this.prefix}.flagset.${flagSet}`;
}

buildSplitKey(splitName: string) {
Expand Down
8 changes: 4 additions & 4 deletions src/storages/__tests__/KeyBuilder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,14 @@ test('KEYS / traffic type keys', () => {

});

test('KEYS / flagset keys', () => {
test('KEYS / flag set keys', () => {
const prefix = 'unit_test.SPLITIO';
const builder = new KeyBuilder(prefix);

const flagsetName = 'flagset_x';
const expectedKey = `${prefix}.flagset.${flagsetName}`;
const flagSetName = 'flagset_x';
const expectedKey = `${prefix}.flagset.${flagSetName}`;

expect(builder.buildFlagsetKey(flagsetName)).toBe(expectedKey);
expect(builder.buildFlagSetKey(flagSetName)).toBe(expectedKey);

});

Expand Down
2 changes: 1 addition & 1 deletion src/storages/__tests__/testUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const something: ISplit = { name: 'something' };
//@ts-ignore
export const somethingElse: ISplit = { name: 'something else' };

// - With flagsets
// - With flag sets

//@ts-ignore
export const featureFlagWithEmptyFS: ISplit = { name: 'ff_empty', sets: [] };
Expand Down
68 changes: 34 additions & 34 deletions src/storages/inLocalStorage/SplitsCacheInLocal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {

private readonly keys: KeyBuilderCS;
private readonly splitFiltersValidation: ISplitFiltersValidation;
private readonly flagsetsFilter: string[];
private readonly flagSetsFilter: string[];
private hasSync?: boolean;
private updateNewFilter?: boolean;

Expand All @@ -26,7 +26,7 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
super();
this.keys = keys;
this.splitFiltersValidation = splitFiltersValidation;
this.flagsetsFilter = this.splitFiltersValidation.groupedFilters.bySet;
this.flagSetsFilter = this.splitFiltersValidation.groupedFilters.bySet;

this._checkExpiration(expirationTimestamp);

Expand Down Expand Up @@ -108,8 +108,8 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
this._incrementCounts(split);
this._decrementCounts(previousSplit);

if (previousSplit) this.removeFromFlagsets(previousSplit.name, previousSplit.sets);
this.addToFlagsets(split);
if (previousSplit) this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
this.addToFlagSets(split);

return true;
} catch (e) {
Expand All @@ -124,7 +124,7 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
localStorage.removeItem(this.keys.buildSplitKey(name));

this._decrementCounts(split);
if (split) this.removeFromFlagsets(split.name, split.sets);
if (split) this.removeFromFlagSets(split.name, split.sets);

return true;
} catch (e) {
Expand Down Expand Up @@ -257,64 +257,64 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
// if the filter didn't change, nothing is done
}

getNamesByFlagsets(flagsets: string[]): ISet<string>{
getNamesByFlagSets(flagSets: string[]): ISet<string>{
let toReturn: ISet<string> = new _Set([]);
flagsets.forEach(flagset => {
const flagsetKey = this.keys.buildFlagsetKey(flagset);
let flagsetFromLocalStorage = localStorage.getItem(flagsetKey);
flagSets.forEach(flagSet => {
const flagSetKey = this.keys.buildFlagSetKey(flagSet);
let flagSetFromLocalStorage = localStorage.getItem(flagSetKey);

if (flagsetFromLocalStorage) {
const flagsetCache = new _Set(JSON.parse(flagsetFromLocalStorage));
toReturn = returnSetsUnion(toReturn, flagsetCache);
if (flagSetFromLocalStorage) {
const flagSetCache = new _Set(JSON.parse(flagSetFromLocalStorage));
toReturn = returnSetsUnion(toReturn, flagSetCache);
}
});
return toReturn;

}

private addToFlagsets(featureFlag: ISplit) {
private addToFlagSets(featureFlag: ISplit) {
if (!featureFlag.sets) return;

featureFlag.sets.forEach(featureFlagset => {
featureFlag.sets.forEach(featureFlagSet => {

if (this.flagsetsFilter.length > 0 && !this.flagsetsFilter.some(filterFlagset => filterFlagset === featureFlagset)) return;
if (this.flagSetsFilter.length > 0 && !this.flagSetsFilter.some(filterFlagSet => filterFlagSet === featureFlagSet)) return;

const flagsetKey = this.keys.buildFlagsetKey(featureFlagset);
const flagSetKey = this.keys.buildFlagSetKey(featureFlagSet);

let flagsetFromLocalStorage = localStorage.getItem(flagsetKey);
if (!flagsetFromLocalStorage) flagsetFromLocalStorage = '[]';
let flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
if (!flagSetFromLocalStorage) flagSetFromLocalStorage = '[]';

const flagsetCache = new _Set(JSON.parse(flagsetFromLocalStorage));
flagsetCache.add(featureFlag.name);
const flagSetCache = new _Set(JSON.parse(flagSetFromLocalStorage));
flagSetCache.add(featureFlag.name);

localStorage.setItem(flagsetKey, JSON.stringify(setToArray(flagsetCache)));
localStorage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
});
}

private removeFromFlagsets(featureFlagName: string, flagsets?: string[]) {
if (!flagsets) return;
private removeFromFlagSets(featureFlagName: string, flagSets?: string[]) {
if (!flagSets) return;

flagsets.forEach(flagset => {
this.removeNames(flagset, featureFlagName);
flagSets.forEach(flagSet => {
this.removeNames(flagSet, featureFlagName);
});
}

private removeNames(flagsetName: string, featureFlagName: string) {
const flagsetKey = this.keys.buildFlagsetKey(flagsetName);
private removeNames(flagSetName: string, featureFlagName: string) {
const flagSetKey = this.keys.buildFlagSetKey(flagSetName);

let flagsetFromLocalStorage = localStorage.getItem(flagsetKey);
let flagSetFromLocalStorage = localStorage.getItem(flagSetKey);

if (!flagsetFromLocalStorage) return;
if (!flagSetFromLocalStorage) return;

const flagsetCache = new _Set(JSON.parse(flagsetFromLocalStorage));
flagsetCache.delete(featureFlagName);
const flagSetCache = new _Set(JSON.parse(flagSetFromLocalStorage));
flagSetCache.delete(featureFlagName);

if (flagsetCache.size === 0) {
localStorage.removeItem(flagsetKey);
if (flagSetCache.size === 0) {
localStorage.removeItem(flagSetKey);
return;
}

localStorage.setItem(flagsetKey, JSON.stringify(setToArray(flagsetCache)));
localStorage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
}

}
44 changes: 22 additions & 22 deletions src/storages/inLocalStorage/__tests__/SplitsCacheInLocal.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ test('SPLIT CACHE / LocalStorage / usesSegments', () => {
expect(cache.usesSegments()).toBe(false); // 0 splits using segments
});

test('SPLIT CACHE / LocalStorage / flagset cache tests', () => {
test('SPLIT CACHE / LocalStorage / flag set cache tests', () => {
// @ts-ignore
const cache = new SplitsCacheInLocal(loggerMock, new KeyBuilderCS('SPLITIO', 'user'), undefined, { groupedFilters: { bySet: ['o', 'n', 'e', 'x'] } });
const emptySet = new _Set([]);
Expand All @@ -174,36 +174,36 @@ test('SPLIT CACHE / LocalStorage / flagset cache tests', () => {
]);
cache.addSplit(featureFlagWithEmptyFS.name, featureFlagWithEmptyFS);

expect(cache.getNamesByFlagsets(['o'])).toEqual(new _Set(['ff_one', 'ff_two']));
expect(cache.getNamesByFlagsets(['n'])).toEqual(new _Set(['ff_one']));
expect(cache.getNamesByFlagsets(['e'])).toEqual(new _Set(['ff_one','ff_three']));
expect(cache.getNamesByFlagsets(['t'])).toEqual(emptySet); // 't' not in filter
expect(cache.getNamesByFlagsets(['o','n','e'])).toEqual(new _Set(['ff_one','ff_two','ff_three']));
expect(cache.getNamesByFlagSets(['o'])).toEqual(new _Set(['ff_one', 'ff_two']));
expect(cache.getNamesByFlagSets(['n'])).toEqual(new _Set(['ff_one']));
expect(cache.getNamesByFlagSets(['e'])).toEqual(new _Set(['ff_one','ff_three']));
expect(cache.getNamesByFlagSets(['t'])).toEqual(emptySet); // 't' not in filter
expect(cache.getNamesByFlagSets(['o','n','e'])).toEqual(new _Set(['ff_one','ff_two','ff_three']));

cache.addSplit(featureFlagOne.name, {...featureFlagOne, sets: ['1']});

expect(cache.getNamesByFlagsets(['1'])).toEqual(emptySet); // '1' not in filter
expect(cache.getNamesByFlagsets(['o'])).toEqual(new _Set(['ff_two']));
expect(cache.getNamesByFlagsets(['n'])).toEqual(emptySet);
expect(cache.getNamesByFlagSets(['1'])).toEqual(emptySet); // '1' not in filter
expect(cache.getNamesByFlagSets(['o'])).toEqual(new _Set(['ff_two']));
expect(cache.getNamesByFlagSets(['n'])).toEqual(emptySet);

cache.addSplit(featureFlagOne.name, {...featureFlagOne, sets: ['x']});
expect(cache.getNamesByFlagsets(['x'])).toEqual(new _Set(['ff_one']));
expect(cache.getNamesByFlagsets(['o','e','x'])).toEqual(new _Set(['ff_one','ff_two','ff_three']));
expect(cache.getNamesByFlagSets(['x'])).toEqual(new _Set(['ff_one']));
expect(cache.getNamesByFlagSets(['o','e','x'])).toEqual(new _Set(['ff_one','ff_two','ff_three']));


cache.removeSplit(featureFlagOne.name);
expect(cache.getNamesByFlagsets(['x'])).toEqual(emptySet);
expect(cache.getNamesByFlagSets(['x'])).toEqual(emptySet);

cache.removeSplit(featureFlagOne.name);
expect(cache.getNamesByFlagsets(['y'])).toEqual(emptySet); // 'y' not in filter
expect(cache.getNamesByFlagsets([])).toEqual(emptySet);
expect(cache.getNamesByFlagSets(['y'])).toEqual(emptySet); // 'y' not in filter
expect(cache.getNamesByFlagSets([])).toEqual(emptySet);

cache.addSplit(featureFlagWithEmptyFS.name, featureFlagWithoutFS);
expect(cache.getNamesByFlagsets([])).toEqual(emptySet);
expect(cache.getNamesByFlagSets([])).toEqual(emptySet);
});

// if FlagSets are not defined, it should store all FlagSets in memory.
test('SPLIT CACHE / LocalStorage / flagset cache tests without filters', () => {
test('SPLIT CACHE / LocalStorage / flag set cache tests without filters', () => {
const cacheWithoutFilters = new SplitsCacheInLocal(loggerMock, new KeyBuilderCS('SPLITIO', 'user'));
const emptySet = new _Set([]);

Expand All @@ -214,10 +214,10 @@ test('SPLIT CACHE / LocalStorage / flagset cache tests without filters', () => {
]);
cacheWithoutFilters.addSplit(featureFlagWithEmptyFS.name, featureFlagWithEmptyFS);

expect(cacheWithoutFilters.getNamesByFlagsets(['o'])).toEqual(new _Set(['ff_one', 'ff_two']));
expect(cacheWithoutFilters.getNamesByFlagsets(['n'])).toEqual(new _Set(['ff_one']));
expect(cacheWithoutFilters.getNamesByFlagsets(['e'])).toEqual(new _Set(['ff_one','ff_three']));
expect(cacheWithoutFilters.getNamesByFlagsets(['t'])).toEqual(new _Set(['ff_two','ff_three']));
expect(cacheWithoutFilters.getNamesByFlagsets(['y'])).toEqual(emptySet);
expect(cacheWithoutFilters.getNamesByFlagsets(['o','n','e'])).toEqual(new _Set(['ff_one','ff_two','ff_three']));
expect(cacheWithoutFilters.getNamesByFlagSets(['o'])).toEqual(new _Set(['ff_one', 'ff_two']));
expect(cacheWithoutFilters.getNamesByFlagSets(['n'])).toEqual(new _Set(['ff_one']));
expect(cacheWithoutFilters.getNamesByFlagSets(['e'])).toEqual(new _Set(['ff_one','ff_three']));
expect(cacheWithoutFilters.getNamesByFlagSets(['t'])).toEqual(new _Set(['ff_two','ff_three']));
expect(cacheWithoutFilters.getNamesByFlagSets(['y'])).toEqual(emptySet);
expect(cacheWithoutFilters.getNamesByFlagSets(['o','n','e'])).toEqual(new _Set(['ff_one','ff_two','ff_three']));
});
44 changes: 22 additions & 22 deletions src/storages/inMemory/SplitsCacheInMemory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ import { ISet, _Set, returnSetsUnion } from '../../utils/lang/sets';
*/
export class SplitsCacheInMemory extends AbstractSplitsCacheSync {

private flagsetsFilter: string[];
private flagSetsFilter: string[];
private splitsCache: Record<string, ISplit> = {};
private ttCache: Record<string, number> = {};
private changeNumber: number = -1;
private splitsWithSegmentsCount: number = 0;
private flagsetsCache: Record<string, ISet<string>> = {};
private flagSetsCache: Record<string, ISet<string>> = {};

constructor(splitFiltersValidation: ISplitFiltersValidation = { queryString: null, groupedFilters: { bySet: [], byName: [], byPrefix: [] }, validFilters: [] }) {
super();
this.flagsetsFilter = splitFiltersValidation.groupedFilters.bySet;
this.flagSetsFilter = splitFiltersValidation.groupedFilters.bySet;
}

clear() {
Expand All @@ -36,7 +36,7 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
this.ttCache[previousTtName]--;
if (!this.ttCache[previousTtName]) delete this.ttCache[previousTtName];

this.removeFromFlagsets(previousSplit.name, previousSplit.sets);
this.removeFromFlagSets(previousSplit.name, previousSplit.sets);

if (usesSegments(previousSplit)) { // Substract from segments count for the previous version of this Split.
this.splitsWithSegmentsCount--;
Expand All @@ -49,7 +49,7 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
// Update TT cache
const ttName = split.trafficTypeName;
this.ttCache[ttName] = (this.ttCache[ttName] || 0) + 1;
this.addToFlagsets(split);
this.addToFlagSets(split);

// Add to segments count for the new version of the Split
if (usesSegments(split)) this.splitsWithSegmentsCount++;
Expand All @@ -69,7 +69,7 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
const ttName = split.trafficTypeName;
this.ttCache[ttName]--; // Update tt cache
if (!this.ttCache[ttName]) delete this.ttCache[ttName];
this.removeFromFlagsets(split.name, split.sets);
this.removeFromFlagSets(split.name, split.sets);

// Update the segments count.
if (usesSegments(split)) this.splitsWithSegmentsCount--;
Expand Down Expand Up @@ -105,10 +105,10 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
return this.getChangeNumber() === -1 || this.splitsWithSegmentsCount > 0;
}

getNamesByFlagsets(flagsets: string[]): ISet<string>{
getNamesByFlagSets(flagSets: string[]): ISet<string>{
let toReturn: ISet<string> = new _Set([]);
flagsets.forEach(flagset => {
const featureFlagNames = this.flagsetsCache[flagset];
flagSets.forEach(flagSet => {
const featureFlagNames = this.flagSetsCache[flagSet];
if (featureFlagNames) {
toReturn = returnSetsUnion(toReturn, featureFlagNames);
}
Expand All @@ -117,29 +117,29 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {

}

private addToFlagsets(featureFlag: ISplit) {
private addToFlagSets(featureFlag: ISplit) {
if (!featureFlag.sets) return;
featureFlag.sets.forEach(featureFlagset => {
featureFlag.sets.forEach(featureFlagSet => {

if (this.flagsetsFilter.length > 0 && !this.flagsetsFilter.some(filterFlagset => filterFlagset === featureFlagset)) return;
if (this.flagSetsFilter.length > 0 && !this.flagSetsFilter.some(filterFlagSet => filterFlagSet === featureFlagSet)) return;

if (!this.flagsetsCache[featureFlagset]) this.flagsetsCache[featureFlagset] = new _Set([]);
if (!this.flagSetsCache[featureFlagSet]) this.flagSetsCache[featureFlagSet] = new _Set([]);

this.flagsetsCache[featureFlagset].add(featureFlag.name);
this.flagSetsCache[featureFlagSet].add(featureFlag.name);
});
}

private removeFromFlagsets(featureFlagName :string, flagsets: string[] | undefined) {
if (!flagsets) return;
flagsets.forEach(flagset => {
this.removeNames(flagset, featureFlagName);
private removeFromFlagSets(featureFlagName :string, flagSets: string[] | undefined) {
if (!flagSets) return;
flagSets.forEach(flagSet => {
this.removeNames(flagSet, featureFlagName);
});
}

private removeNames(flagsetName: string, featureFlagName: string) {
if (!this.flagsetsCache[flagsetName]) return;
this.flagsetsCache[flagsetName].delete(featureFlagName);
if (this.flagsetsCache[flagsetName].size === 0) delete this.flagsetsCache[flagsetName];
private removeNames(flagSetName: string, featureFlagName: string) {
if (!this.flagSetsCache[flagSetName]) return;
this.flagSetsCache[flagSetName].delete(featureFlagName);
if (this.flagSetsCache[flagSetName].size === 0) delete this.flagSetsCache[flagSetName];
}

}
2 changes: 1 addition & 1 deletion src/storages/inMemory/TelemetryCacheInMemory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ export class TelemetryCacheInMemory implements ITelemetryCacheSync {
this.e = false;
}

private streamingEvents: StreamingEvent[] = []
private streamingEvents: StreamingEvent[] = [];

popStreamingEvents() {
return this.streamingEvents.splice(0);
Expand Down
Loading

0 comments on commit 856f8b7

Please sign in to comment.