Skip to content

Commit dc1ea50

Browse files
Merge pull request #420 from splitio/inlocalstorage_wrapper
[Custom InLocalStorage] Refactor InLocal caches to use a storage interface based on the Web LocalStorage API
2 parents d5cdf7f + 07dedd7 commit dc1ea50

File tree

10 files changed

+134
-117
lines changed

10 files changed

+134
-117
lines changed

src/storages/__tests__/RBSegmentsCacheSync.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import { IRBSegmentsCacheSync } from '../types';
66
import { fullSettings } from '../../utils/settingsValidation/__tests__/settings.mocks';
77

88
const cacheInMemory = new RBSegmentsCacheInMemory();
9-
const cacheInLocal = new RBSegmentsCacheInLocal(fullSettings, new KeyBuilderCS('SPLITIO', 'user'));
9+
// eslint-disable-next-line no-undef
10+
const cacheInLocal = new RBSegmentsCacheInLocal(fullSettings, new KeyBuilderCS('SPLITIO', 'user'), localStorage);
1011

1112
describe.each([cacheInMemory, cacheInLocal])('Rule-based segments cache sync (Memory & LocalStorage)', (cache: IRBSegmentsCacheSync) => {
1213

src/storages/inLocalStorage/MySegmentsCacheInLocal.ts

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,28 @@ import { isNaNNumber } from '../../utils/lang';
33
import { AbstractMySegmentsCacheSync } from '../AbstractMySegmentsCacheSync';
44
import type { MySegmentsKeyBuilder } from '../KeyBuilderCS';
55
import { LOG_PREFIX, DEFINED } from './constants';
6+
import { StorageAdapter } from '../types';
67

78
export class MySegmentsCacheInLocal extends AbstractMySegmentsCacheSync {
89

910
private readonly keys: MySegmentsKeyBuilder;
1011
private readonly log: ILogger;
12+
private readonly storage: StorageAdapter;
1113

12-
constructor(log: ILogger, keys: MySegmentsKeyBuilder) {
14+
constructor(log: ILogger, keys: MySegmentsKeyBuilder, storage: StorageAdapter) {
1315
super();
1416
this.log = log;
1517
this.keys = keys;
18+
this.storage = storage;
1619
// There is not need to flush segments cache like splits cache, since resetSegments receives the up-to-date list of active segments
1720
}
1821

1922
protected addSegment(name: string): boolean {
2023
const segmentKey = this.keys.buildSegmentNameKey(name);
2124

2225
try {
23-
if (localStorage.getItem(segmentKey) === DEFINED) return false;
24-
localStorage.setItem(segmentKey, DEFINED);
26+
if (this.storage.getItem(segmentKey) === DEFINED) return false;
27+
this.storage.setItem(segmentKey, DEFINED);
2528
return true;
2629
} catch (e) {
2730
this.log.error(LOG_PREFIX + e);
@@ -33,8 +36,8 @@ export class MySegmentsCacheInLocal extends AbstractMySegmentsCacheSync {
3336
const segmentKey = this.keys.buildSegmentNameKey(name);
3437

3538
try {
36-
if (localStorage.getItem(segmentKey) !== DEFINED) return false;
37-
localStorage.removeItem(segmentKey);
39+
if (this.storage.getItem(segmentKey) !== DEFINED) return false;
40+
this.storage.removeItem(segmentKey);
3841
return true;
3942
} catch (e) {
4043
this.log.error(LOG_PREFIX + e);
@@ -43,18 +46,16 @@ export class MySegmentsCacheInLocal extends AbstractMySegmentsCacheSync {
4346
}
4447

4548
isInSegment(name: string): boolean {
46-
return localStorage.getItem(this.keys.buildSegmentNameKey(name)) === DEFINED;
49+
return this.storage.getItem(this.keys.buildSegmentNameKey(name)) === DEFINED;
4750
}
4851

4952
getRegisteredSegments(): string[] {
50-
// Scan current values from localStorage
51-
return Object.keys(localStorage).reduce((accum, key) => {
52-
let segmentName = this.keys.extractSegmentName(key);
53-
54-
if (segmentName) accum.push(segmentName);
55-
56-
return accum;
57-
}, [] as string[]);
53+
const registeredSegments: string[] = [];
54+
for (let i = 0, len = this.storage.length; i < len; i++) {
55+
const segmentName = this.keys.extractSegmentName(this.storage.key(i)!);
56+
if (segmentName) registeredSegments.push(segmentName);
57+
}
58+
return registeredSegments;
5859
}
5960

6061
getKeysCount() {
@@ -63,16 +64,16 @@ export class MySegmentsCacheInLocal extends AbstractMySegmentsCacheSync {
6364

6465
protected setChangeNumber(changeNumber?: number) {
6566
try {
66-
if (changeNumber) localStorage.setItem(this.keys.buildTillKey(), changeNumber + '');
67-
else localStorage.removeItem(this.keys.buildTillKey());
67+
if (changeNumber) this.storage.setItem(this.keys.buildTillKey(), changeNumber + '');
68+
else this.storage.removeItem(this.keys.buildTillKey());
6869
} catch (e) {
6970
this.log.error(e);
7071
}
7172
}
7273

7374
getChangeNumber() {
7475
const n = -1;
75-
let value: string | number | null = localStorage.getItem(this.keys.buildTillKey());
76+
let value: string | number | null = this.storage.getItem(this.keys.buildTillKey());
7677

7778
if (value !== null) {
7879
value = parseInt(value, 10);

src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,24 @@ import { isFiniteNumber, isNaNNumber, toNumber } from '../../utils/lang';
55
import { setToArray } from '../../utils/lang/sets';
66
import { usesSegments } from '../AbstractSplitsCacheSync';
77
import { KeyBuilderCS } from '../KeyBuilderCS';
8-
import { IRBSegmentsCacheSync } from '../types';
8+
import { IRBSegmentsCacheSync, StorageAdapter } from '../types';
99
import { LOG_PREFIX } from './constants';
1010

1111
export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
1212

1313
private readonly keys: KeyBuilderCS;
1414
private readonly log: ILogger;
15+
private readonly storage: StorageAdapter;
1516

16-
constructor(settings: ISettings, keys: KeyBuilderCS) {
17+
constructor(settings: ISettings, keys: KeyBuilderCS, storage: StorageAdapter) {
1718
this.keys = keys;
1819
this.log = settings.log;
20+
this.storage = storage;
1921
}
2022

2123
clear() {
2224
this.getNames().forEach(name => this.remove(name));
23-
localStorage.removeItem(this.keys.buildRBSegmentsTillKey());
25+
this.storage.removeItem(this.keys.buildRBSegmentsTillKey());
2426
}
2527

2628
update(toAdd: IRBSegment[], toRemove: IRBSegment[], changeNumber: number): boolean {
@@ -31,29 +33,28 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
3133

3234
private setChangeNumber(changeNumber: number) {
3335
try {
34-
localStorage.setItem(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
35-
localStorage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
36+
this.storage.setItem(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
37+
this.storage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
3638
} catch (e) {
3739
this.log.error(LOG_PREFIX + e);
3840
}
3941
}
4042

4143
private updateSegmentCount(diff: number) {
4244
const segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
43-
const count = toNumber(localStorage.getItem(segmentsCountKey)) + diff;
44-
// @ts-expect-error
45-
if (count > 0) localStorage.setItem(segmentsCountKey, count);
46-
else localStorage.removeItem(segmentsCountKey);
45+
const count = toNumber(this.storage.getItem(segmentsCountKey)) + diff;
46+
if (count > 0) this.storage.setItem(segmentsCountKey, count + '');
47+
else this.storage.removeItem(segmentsCountKey);
4748
}
4849

4950
private add(rbSegment: IRBSegment): boolean {
5051
try {
5152
const name = rbSegment.name;
5253
const rbSegmentKey = this.keys.buildRBSegmentKey(name);
53-
const rbSegmentFromLocalStorage = localStorage.getItem(rbSegmentKey);
54-
const previous = rbSegmentFromLocalStorage ? JSON.parse(rbSegmentFromLocalStorage) : null;
54+
const rbSegmentFromStorage = this.storage.getItem(rbSegmentKey);
55+
const previous = rbSegmentFromStorage ? JSON.parse(rbSegmentFromStorage) : null;
5556

56-
localStorage.setItem(rbSegmentKey, JSON.stringify(rbSegment));
57+
this.storage.setItem(rbSegmentKey, JSON.stringify(rbSegment));
5758

5859
let usesSegmentsDiff = 0;
5960
if (previous && usesSegments(previous)) usesSegmentsDiff--;
@@ -72,7 +73,7 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
7273
const rbSegment = this.get(name);
7374
if (!rbSegment) return false;
7475

75-
localStorage.removeItem(this.keys.buildRBSegmentKey(name));
76+
this.storage.removeItem(this.keys.buildRBSegmentKey(name));
7677

7778
if (usesSegments(rbSegment)) this.updateSegmentCount(-1);
7879

@@ -84,13 +85,13 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
8485
}
8586

8687
private getNames(): string[] {
87-
const len = localStorage.length;
88+
const len = this.storage.length;
8889
const accum = [];
8990

9091
let cur = 0;
9192

9293
while (cur < len) {
93-
const key = localStorage.key(cur);
94+
const key = this.storage.key(cur);
9495

9596
if (key != null && this.keys.isRBSegmentKey(key)) accum.push(this.keys.extractKey(key));
9697

@@ -101,7 +102,7 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
101102
}
102103

103104
get(name: string): IRBSegment | null {
104-
const item = localStorage.getItem(this.keys.buildRBSegmentKey(name));
105+
const item = this.storage.getItem(this.keys.buildRBSegmentKey(name));
105106
return item && JSON.parse(item);
106107
}
107108

@@ -113,7 +114,7 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
113114

114115
getChangeNumber(): number {
115116
const n = -1;
116-
let value: string | number | null = localStorage.getItem(this.keys.buildRBSegmentsTillKey());
117+
let value: string | number | null = this.storage.getItem(this.keys.buildRBSegmentsTillKey());
117118

118119
if (value !== null) {
119120
value = parseInt(value, 10);
@@ -125,7 +126,7 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
125126
}
126127

127128
usesSegments(): boolean {
128-
const storedCount = localStorage.getItem(this.keys.buildSplitsWithSegmentCountKey());
129+
const storedCount = this.storage.getItem(this.keys.buildSplitsWithSegmentCountKey());
129130
const splitsWithSegmentsCount = storedCount === null ? 0 : toNumber(storedCount);
130131

131132
return isFiniteNumber(splitsWithSegmentsCount) ?

0 commit comments

Comments
 (0)