8000 feat: Key Value cache implementation for React Native (#426) · github/optimizely-javascript-sdk@08deb5c · GitHub
[go: up one dir, main page]

Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Commit 08deb5c

Browse files
authored
feat: Key Value cache implementation for React Native (optimizely#426)
Summary: This is a Key Value Pair cache implementation for react native. This will be used when developing a Separate Datafile Manager for React native which will support datafile caching. Test plan: Added Unit Tests
1 parent 1e00509 commit 08deb5c

File tree

6 files changed

+225
-2
lines changed

6 files changed

+225
-2
lines changed

.travis.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,11 @@ jobs:
8282
- &packagetest
8383
stage: 'Test sub packages'
8484
node_js: '12'
85-
before_install: cd packages/datafile-manager
85+
before_install: cd packages/utils
8686
- <<: *packagetest
8787
before_install: cd packages/event-processor
8888
- <<: *packagetest
8989
before_install: cd packages/logging
9090
- <<: *packagetest
91-
before_install: cd packages/utils
91+
before_script: npm install "@react-native-community/async-storage"
92+
before_install: cd packages/datafile-manager
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* Copyright 2020, Optimizely
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
export default class AsyncStorage {
18+
static getItem(key: string, callback?: (error?: Error, result?: string) => void): Promise<string | null> {
19+
return new Promise((resolve, reject) => {
20+
switch (key) {
21+
case 'keyThatExists':
22+
resolve('{ "name": "Awesome Object" }')
23+
break
24+
case 'keyThatDoesNotExist':
25+
resolve(null)
26+
break
27+
case 'keyWithInvalidJsonObject':
28+
resolve('bad json }')
29+
break
30+
}
31+
})
32+
}
33+
34+
static setItem(key: string, value: string, callback?: (error?: Error) => void): Promise<void> {
35+
return Promise.resolve()
36+
}
37+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* Copyright 2020, Optimizely
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import ReactNativeAsyncStorageCache from '../src/reactNativeAsyncStorageCache'
18+
19+
describe('reactNativeAsyncStorageCache', () => {
20+
let cacheInstance: ReactNativeAsyncStorageCache
21+
22+
beforeEach(() => {
23+
cacheInstance = new ReactNativeAsyncStorageCache()
24+
})
25+
26+
describe('get', function() {
27+
it('should return correct object when item is found in cache', function() {
28+
return cacheInstance.get('keyThatExists')
29+
.then(v => expect(v).toEqual({ name: "Awesome Object" }))
30+
})
31+
32+
it('should return null if item is not found in cache', function() {
33+
return cacheInstance.get('keyThatDoesNotExist').then(v => expect(v).toBeNull())
34+
})
35+
36+
it('should reject promise error if string has an incorrect JSON format', function() {
37+
return cacheInstance.get('keyWithInvalidJsonObject')
38+
.catch(() => 'exception caught').then(v => { expect(v).toEqual('exception caught') })
39+
})
40+
})
41+
42+
describe('set', function() {
43+
it('should resolve promise if item was successfully set in the cache', function() {
44+
const testObj = { name: "Awesome Object" }
45+
return cacheInstance.set('testKey', testObj)
46+
})
47+
48+
it('should reject promise if item was not set in the cache because of json stringifying error', function() {
49+
const testObj: any = { name: "Awesome Object" }
50+
testObj.myOwnReference = testObj
51+
return cacheInstance.set('testKey', testObj)
52+
.catch(() => 'exception caught').then(v => expect(v).toEqual('exception caught'))
53+
})
54+
})
55+
56+
describe('contains', function() {
57+
it('should return true if object with key exists', function() {
58+
return cacheInstance.contains('keyThatExists').then(v => expect(v).toBeTruthy())
59+
})
60+
61+
it('should return false if object with key does not exist', function() {
62+
return cacheInstance.contains('keyThatDoesNotExist').then(v => expect(v).toBeFalsy())
63+
})
64+
})
65+
})

packages/datafile-manager/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@
3838
"@optimizely/js-sdk-logging": "^0.1.0",
3939
"@optimizely/js-sdk-utils": "^0.1.0"
4040
},
41+
"peerDependencies": {
42+
"@react-native-community/async-storage": "^1.2.0"
43+
},
4144
"scripts": {
4245
"test": "jest",
4346
"tsc": "rm -rf lib && tsc",
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* Copyright 2020, Optimizely
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/**
18+
* An Interface to implement a persistent key value cache which supports strings as keys
19+
* and JSON Object as value.
20+
*/
21+
export default interface PersistentKeyValueCache {
22+
23+
/**
24+
* Returns value stored against a key or null if not found.
25+
* @param key
26+
* @returns
27+
* Resolves promise with
28+
* 1. Object if value found was stored as a JSON Object.
29+
* 2. null if the key does not exist in the cache.
30+
* Rejects the promise in case of an error
31+
*/
32+
get(key: string): Promise<any | null>
33+
34+
/**
35+
* Stores Object in the persistent cache against a key
36+
* @param key
37+
* @param val
38+
* @returns
39+
* Resolves promise without a value if successful
40+
* Rejects the promise in case of an error
41+
*/
42+
set(key: string, val: any): Promise<void>
43+
44+
/**
45+
* Checks if a key exists in the cache
46+
* @param key
47+
* Resolves promise with
48+
* 1. true if the key exists
49+
* 2. false if the key does not exist
50+
* Rejects the promise in case of an error
51+
*/
52+
contains(key: string): Promise<Boolean>
53+
54+
/**
55+
* Removes the key value pair from cache.
56+
* @param key
57+
* Resolves promise without a value if successful
58+
* Rejects the promise in case of an error
59+
*/
60+
remove(key: string): Promise<void>
61+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
* Copyright 2020, Optimizely
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { getLogger } from '@optimizely/js-sdk-logging'
18+
import AsyncStorage from '@react-native-community/async-storage'
19+
20+
import PersistentKeyValueCache from './persistentKeyValueCache'
21+
22+
const logger = getLogger('DatafileManager')
23+
24+
export default class ReactNativeAsyncStorageCache implements PersistentKeyValueCache {
25+
get(key: string): Promise<any | null> {
26+
return AsyncStorage.getItem(key)
27+
.then((val: string | null) => {
28+
if (!val) {
29+
return null
30+
}
31+
try {
32+
return JSON.parse(val);
33+
} catch (ex) {
34+
logger.error('Error Parsing Object from cache - %s', ex)
35+
throw ex
36+
}
37+
})
38+
}
39+
40+
set(key: string, val: any): Promise<void> {
41+
try {
42+
return AsyncStorage.setItem(key, JSON.stringify(val))
43+
} catch (ex) {
44+
logger.error('Error stringifying Object to Json - %s', ex)
45+
return Promise.reject(ex)
46+
}
47+
}
48+
49+
contains(key: string): Promise<Boolean> {
50+
return AsyncStorage.getItem(key).then((val: string | null) => (val !== null))
51+
}
52+
53+
remove(key: string): Promise<void> {
54+
return AsyncStorage.removeItem(key)
55+
}
56+
}

0 commit comments

Comments
 (0)
0