react-native-storage
Advanced tools
Comparing version 0.0.16 to 0.1.0
@@ -6,238 +6,289 @@ jest.dontMock('../storage.js'); | ||
DEFAULTEXPIRES = 1000 * 3600; | ||
let storage = new Storage({ | ||
let localStorage = new Storage({ | ||
size: SIZE, | ||
defaultExpires: DEFAULTEXPIRES | ||
}); | ||
let asyncStorage = new Storage({ | ||
size: SIZE, | ||
defaultExpires: DEFAULTEXPIRES, | ||
storageBackend: window.asyncStorage, | ||
isPromise: true | ||
}); | ||
let stores = { localStorage, asyncStorage }; | ||
describe('react-native-storage: basic function', () => { | ||
it('accepts parameters in constructor', () => { | ||
expect(storage._SIZE).toBe(SIZE); | ||
expect(storage.defaultExpires).toBe(DEFAULTEXPIRES); | ||
}); | ||
pit('saves and loads any type of data', () => { | ||
let testCases = { | ||
testNumber: 11221, | ||
testString: 'testString', | ||
testObject: { | ||
fname: 'foo', | ||
lname: 'bar' | ||
}, | ||
testArray: [ 'one', 'two', 'three' ], | ||
testBoolean: false, | ||
testNull: null, | ||
complexObject: { | ||
complexArray : [ 1, 2, 3, 'test', { a: 'b' } ] | ||
} | ||
}; | ||
let returnCases = {}, returnCasesWithId = {}; | ||
let tasks = []; | ||
for(let key in testCases) { | ||
tasks.push( | ||
storage.save({ | ||
key, | ||
rawData: testCases[key] | ||
}).then(() => | ||
Object.keys(stores).map(storageKey => { | ||
let storage = stores[storageKey]; | ||
it('accepts parameters in constructor' + `(${storageKey})`, () => { | ||
expect(storage._SIZE).toBe(SIZE); | ||
expect(storage.defaultExpires).toBe(DEFAULTEXPIRES); | ||
}); | ||
pit('saves and loads any type of data' + `(${storageKey})`, () => { | ||
let testCases = { | ||
testNumber: 11221, | ||
testString: 'testString', | ||
testObject: { | ||
fname: 'foo', | ||
lname: 'bar' | ||
}, | ||
testArray: [ 'one', 'two', 'three' ], | ||
testBoolean: false, | ||
testNull: null, | ||
complexObject: { | ||
complexArray : [ 1, 2, 3, 'test', { a: 'b' } ] | ||
} | ||
}; | ||
let returnCases = {}, returnCasesWithId = {}; | ||
let tasks = []; | ||
for(let key in testCases) { | ||
tasks.push( | ||
storage.save({ | ||
key, | ||
rawData: testCases[key] | ||
}).then(() => | ||
storage.load({ | ||
key | ||
}).then( ret => { | ||
}).then(ret => { | ||
returnCases[key] = ret; | ||
}) | ||
) | ||
); | ||
tasks.push( | ||
storage.save({ | ||
key, | ||
id: 1, | ||
rawData: testCases[key] | ||
}).then(() => | ||
) | ||
); | ||
tasks.push( | ||
storage.save({ | ||
key, | ||
id: 1, | ||
rawData: testCases[key] | ||
}).then(() => | ||
storage.load({ | ||
key, | ||
id: 1 | ||
}).then( ret => { | ||
}).then(ret => { | ||
returnCasesWithId[key] = ret; | ||
}) | ||
) | ||
); | ||
} | ||
return Promise.all(tasks).then(() => { | ||
for(let key in testCases) { | ||
expect(JSON.stringify(testCases[key])).toBe(JSON.stringify(returnCases[key])); | ||
expect(JSON.stringify(testCases[key])).toBe(JSON.stringify(returnCasesWithId[key])); | ||
) | ||
); | ||
} | ||
return Promise.all(tasks).then(() => { | ||
for(let key in testCases) { | ||
expect(JSON.stringify(testCases[key])).toBe(JSON.stringify(returnCases[key])); | ||
expect(JSON.stringify(testCases[key])).toBe(JSON.stringify(returnCasesWithId[key])); | ||
} | ||
}); | ||
}); | ||
}); | ||
pit('rejects when no data found and no sync method', () => { | ||
let testKey1 = 'testKey' + Math.random(), | ||
testKey2 = 'testKey' + Math.random(), | ||
testId2 = 'testId' + Math.random(); | ||
let ret1, ret2, reject1, reject2; | ||
let tasks = [ | ||
storage.load({ | ||
key: testKey1 | ||
}).then( ret => { | ||
ret1 = ret; | ||
}).catch( () => { | ||
reject1 = true; | ||
}), | ||
storage.load({ | ||
key: testKey2, | ||
id: testId2 | ||
}).then( ret => { | ||
ret2 = ret; | ||
}).catch( () => { | ||
reject2 = true; | ||
pit('rejects when no data found and no sync method' + `(${storageKey})`, () => { | ||
let testKey1 = 'testKey' + Math.random(), | ||
testKey2 = 'testKey' + Math.random(), | ||
testId2 = 'testId' + Math.random(); | ||
let ret1, ret2, reject1, reject2; | ||
let tasks = [ | ||
storage.load({ | ||
key: testKey1 | ||
}).then(ret => { | ||
ret1 = ret; | ||
}).catch(() => { | ||
reject1 = true; | ||
}), | ||
storage.load({ | ||
key: testKey2, | ||
id: testId2 | ||
}).then(ret => { | ||
ret2 = ret; | ||
}).catch(() => { | ||
reject2 = true; | ||
}) | ||
]; | ||
return Promise.all(tasks).then(() => { | ||
expect(ret1).toBeUndefined(); | ||
expect(ret2).toBeUndefined(); | ||
expect(reject1 && reject2).toBe(true); | ||
}); | ||
}); | ||
pit('rejects when data expired and no sync method' + `(${storageKey})`, () => { | ||
let originGetTime = Date.prototype.getTime; | ||
let starttime = 0; | ||
Date.prototype.getTime = jest.genMockFn().mockImpl(() => { | ||
return starttime += 100; | ||
}); | ||
let testKey1 = 'testKey' + Math.random(), | ||
testKey2 = 'testKey' + Math.random(), | ||
testId2 = 'testId' + Math.random(), | ||
testData1 = 'testData1' + Math.random(), | ||
testData2 = 'testData2' + Math.random(); | ||
let ret1, ret2, reject1, reject2; | ||
let tasks = [ | ||
storage.save({ | ||
key: testKey1, | ||
rawData: testData1, | ||
expires: 1, | ||
}).then(() => | ||
storage.load({ | ||
key: testKey1 | ||
}) | ||
).then(ret => { | ||
ret1 = ret; | ||
}).catch(() => { | ||
reject1 = true; | ||
}), | ||
storage.save({ | ||
key: testKey2, | ||
id: testId2, | ||
rawData: testData2, | ||
expires: 1, | ||
}).then(() => | ||
storage.load({ | ||
key: testKey2, | ||
id: testId2, | ||
}) | ||
).then(ret => { | ||
ret2 = ret; | ||
}).catch(() => { | ||
reject2 = true; | ||
}), | ||
]; | ||
return Promise.all(tasks).then(() => { | ||
expect(ret1).toBeUndefined(); | ||
expect(ret2).toBeUndefined(); | ||
expect(reject1 && reject2).toBe(true); | ||
Date.prototype.getTime = originGetTime; | ||
}); | ||
}); | ||
//it('overwrites "key+id" data when loops over(exceeds SIZE)', () => { | ||
// let testKey = 'testKey' + Math.random(), | ||
// testId = 'testId' + Math.random(), | ||
// testData = 'testData' + Math.random(); | ||
// let ret1, ret2, done1, done2, tmpIndex1, tmpIndex2; | ||
// runs(() => { | ||
// storage.save({ | ||
// key: testKey, | ||
// id: testId, | ||
// rawData: testData | ||
// }); | ||
// tmpIndex1 = storage._m.index; | ||
// for (let i = 0; i < SIZE - 1; i++) { | ||
// storage.save({ | ||
// key: 'testKey' + Math.random(), | ||
// id: 'testId' + Math.random(), | ||
// rawData: 'testData' + Math.random() | ||
// }); | ||
// } | ||
// | ||
// //not overwrited yet | ||
// storage.load({ | ||
// key: testKey, | ||
// id: testId | ||
// }).then( ret => { | ||
// ret1 = ret; | ||
// done1 = true; | ||
// }).catch(() => { | ||
// done1 = true; | ||
// }); | ||
// | ||
// //overwrite | ||
// storage.save({ | ||
// key: 'testKey' + Math.random(), | ||
// id: 'testId' + Math.random(), | ||
// rawData: 'testData' + Math.random() | ||
// }); | ||
// tmpIndex2 = storage._m.index; | ||
// storage.load({ | ||
// key: testKey, | ||
// id: testId | ||
// }).then( ret => { | ||
// ret2 = ret; | ||
// done2 = true; | ||
// }).catch(() => { | ||
// done2 = true; | ||
// }); | ||
// }); | ||
// waitsFor(() => { | ||
// return done1 && done2; | ||
// }, 'Values should be loaded', 1000); | ||
// | ||
// runs(() => { | ||
// expect(tmpIndex1).toBe(tmpIndex2); | ||
// expect(ret1).toBe(testData); | ||
// expect(ret2).toNotBe(testData); | ||
// }); | ||
//}); | ||
pit('removes data correctly' + `(${storageKey})`, () => { | ||
let testKey1 = 'testKey1' + Math.random(), | ||
testKey2 = 'testKey2' + Math.random(), | ||
testId2 = 'testId2' + Math.random(), | ||
testData1 = 'testData1' + Math.random(), | ||
testData2 = 'testData2' + Math.random(); | ||
let ret1 = [undefined, undefined], ret2 = [undefined, undefined]; | ||
let task = (key, id, rawData, retArray) => { | ||
return storage.save({ | ||
key, | ||
id, | ||
rawData | ||
}).then(() => { | ||
return storage.load({ | ||
key, | ||
id | ||
}); | ||
}).then(ret => { | ||
retArray[0] = ret; | ||
return storage.remove({ key, id }); | ||
}).then(() => { | ||
return storage.load({ key, id }); | ||
}).then(ret => { | ||
retArray[1] = ret; | ||
}).catch(() => { | ||
retArray[1] = 'catched'; | ||
}); | ||
}; | ||
return Promise.all([ | ||
task(testKey1, undefined, testData1, ret1), | ||
task(testKey2, testId2, testData2, ret2) | ||
]).then(() => { | ||
expect(ret1[0]).toBe(testData1); | ||
expect(ret1[1]).toBe('catched'); | ||
expect(ret2[0]).toBe(testData2); | ||
expect(ret2[1]).toBe('catched'); | ||
}); | ||
}); | ||
pit('get all data for key correctly' + `(${storageKey})`, () =>{ | ||
let key = 'testKey' + Math.random(), | ||
testIds = [Math.random(), Math.random(), Math.random()], | ||
testDatas = [Math.random(), Math.random(), Math.random()]; | ||
return Promise.all( | ||
testIds.map((id, i) => storage.save({ | ||
key, | ||
id, | ||
rawData: testDatas[i] | ||
})) | ||
) | ||
.then(() => { | ||
return storage.getAllDataForKey(key); | ||
}) | ||
]; | ||
return Promise.all(tasks).then(() => { | ||
expect(ret1).toBeUndefined(); | ||
expect(ret2).toBeUndefined(); | ||
expect(reject1 && reject2).toBe(true); | ||
.then(realRet => { | ||
expect(realRet).toEqual(testDatas); | ||
}); | ||
}); | ||
}); | ||
//it('overwrites "key+id" data when loops over(exceeds SIZE)', () => { | ||
// let testKey = 'testKey' + Math.random(), | ||
// testId = 'testId' + Math.random(), | ||
// testData = 'testData' + Math.random(); | ||
// let ret1, ret2, done1, done2, tmpIndex1, tmpIndex2; | ||
// runs(() => { | ||
// storage.save({ | ||
// key: testKey, | ||
// id: testId, | ||
// rawData: testData | ||
// }); | ||
// tmpIndex1 = storage._m.index; | ||
// for (let i = 0; i < SIZE - 1; i++) { | ||
// storage.save({ | ||
// key: 'testKey' + Math.random(), | ||
// id: 'testId' + Math.random(), | ||
// rawData: 'testData' + Math.random() | ||
// }); | ||
// } | ||
// | ||
// //not overwrited yet | ||
// storage.load({ | ||
// key: testKey, | ||
// id: testId | ||
// }).then( ret => { | ||
// ret1 = ret; | ||
// done1 = true; | ||
// }).catch(() => { | ||
// done1 = true; | ||
// }); | ||
// | ||
// //overwrite | ||
// storage.save({ | ||
// key: 'testKey' + Math.random(), | ||
// id: 'testId' + Math.random(), | ||
// rawData: 'testData' + Math.random() | ||
// }); | ||
// tmpIndex2 = storage._m.index; | ||
// storage.load({ | ||
// key: testKey, | ||
// id: testId | ||
// }).then( ret => { | ||
// ret2 = ret; | ||
// done2 = true; | ||
// }).catch(() => { | ||
// done2 = true; | ||
// }); | ||
// }); | ||
// waitsFor(() => { | ||
// return done1 && done2; | ||
// }, 'Values should be loaded', 1000); | ||
// | ||
// runs(() => { | ||
// expect(tmpIndex1).toBe(tmpIndex2); | ||
// expect(ret1).toBe(testData); | ||
// expect(ret2).toNotBe(testData); | ||
// }); | ||
//}); | ||
//it('ignores all "key+id" data when innerVersion mismatched', () => { | ||
// let testKey = 'testKey' + Math.random(), | ||
// testId = 'testId' + Math.random(), | ||
// testData = 'testData' + Math.random(); | ||
// let ret1, ret2, done1, done2, tmpVersion; | ||
// runs(() => { | ||
// storage.save({ | ||
// key: testKey, | ||
// id: testId, | ||
// rawData: testData | ||
// }); | ||
// storage.load({ | ||
// key: testKey, | ||
// id: testId | ||
// }).then( ret => { | ||
// ret1 = ret; | ||
// done1 = true; | ||
// }).catch(() => { | ||
// done1 = true; | ||
// }); | ||
// | ||
// let map = JSON.parse(storage._s.getItem('map')); | ||
// tmpVersion = map.innerVersion; | ||
// map.innerVersion = -1; | ||
// storage._s.setItem('map', JSON.stringify(map)); | ||
// | ||
// let newStorage = new Storage(); | ||
// newStorage.load({ | ||
// key: testKey, | ||
// id: testId | ||
// }).then(ret => { | ||
// ret2 = ret; | ||
// done2 = true; | ||
// }).catch(() => { | ||
// done2 = true; | ||
// }); | ||
// }); | ||
// waitsFor(() => { | ||
// return done1 && done2; | ||
// }, 'Values should be loaded', 1000); | ||
// runs(() => { | ||
// expect(ret1).toBe(testData); | ||
// expect(ret2).toBeUndefined(); | ||
// | ||
// let newMap = JSON.parse(storage._s.getItem('map')); | ||
// newMap.innerVersion = tmpVersion; | ||
// storage._s.setItem('map', JSON.stringify(newMap)); | ||
// }); | ||
//}); | ||
pit('removes data correctly', () => { | ||
let testKey1 = 'testKey1' + Math.random(), | ||
testKey2 = 'testKey2' + Math.random(), | ||
testId2 = 'testId2' + Math.random(), | ||
testData1 = 'testData1' + Math.random(), | ||
testData2 = 'testData2' + Math.random(); | ||
let ret1 = [undefined, undefined], ret2 = [undefined, undefined]; | ||
let task = (key, id, rawData, retArray) => { | ||
return storage.save({ | ||
key, | ||
id, | ||
rawData | ||
}).then(() => { | ||
return storage.load({ | ||
pit('load ids by key correctly' + `(${storageKey})`, () => { | ||
let key = 'testKey' + Math.random(), | ||
testIds = [Math.random(), Math.random(), Math.random()], | ||
rawData = 'testData' + Math.random(); | ||
let ret = []; | ||
let tasks = testIds.map(id => | ||
storage.save({ | ||
key, | ||
id | ||
id, | ||
rawData | ||
}) | ||
); | ||
return Promise.all(tasks).then(() => { | ||
storage.getIdsForKey(key).then(rets => { | ||
expect(rets).toEqual(testIds); | ||
}); | ||
}).then( ret => { | ||
retArray[0] = ret; | ||
return storage.remove({ key, id }); | ||
}).then( () => { | ||
return storage.load({ key, id }); | ||
}).then( ret => { | ||
retArray[1] = ret; | ||
}).catch( () => { | ||
retArray[1] = 'catched'; | ||
});; | ||
}; | ||
return Promise.all([ | ||
task(testKey1, undefined, testData1, ret1), | ||
task(testKey2, testId2, testData2, ret2) | ||
]).then(() => { | ||
expect(ret1[0]).toBe(testData1); | ||
expect(ret1[1]).toBe('catched'); | ||
expect(ret2[0]).toBe(testData2); | ||
expect(ret2[1]).toBe('catched'); | ||
}) | ||
}); | ||
}); | ||
}); |
@@ -8,347 +8,356 @@ /** | ||
let storage = new Storage(); | ||
let localStorage = new Storage(); | ||
let asyncStorage = new Storage({ | ||
storageBackend: window.asyncStorage, | ||
isPromise: true | ||
}); | ||
let stores = { localStorage, asyncStorage }; | ||
describe('react-native-storage: batch and sync test', () => { | ||
it('triggers sync when no data found', () => { | ||
let testKey1 = 'testKey1' + Math.random(), | ||
testKey2 = 'testKey2' + Math.random(), | ||
testId2 = 'testId2' + Math.random(), | ||
syncData = 'syncData'; | ||
let ret1, ret2, | ||
done1, done2; | ||
let sync1 = jest.genMockFn().mockImpl( params => { | ||
let { resolve } = params; | ||
resolve && resolve(syncData); | ||
}); | ||
let sync2 = jest.genMockFn().mockImpl( params => { | ||
let { id, resolve } = params; | ||
resolve && resolve(syncData + id); | ||
}); | ||
storage.sync[testKey1] = sync1; | ||
storage.sync[testKey2] = sync2; | ||
Object.keys(stores).map(storageKey => { | ||
let storage = stores[storageKey]; | ||
it('triggers sync when no data found' + `(${storageKey})`, () => { | ||
let testKey1 = 'testKey1' + Math.random(), | ||
testKey2 = 'testKey2' + Math.random(), | ||
testId2 = 'testId2' + Math.random(), | ||
syncData = 'syncData'; | ||
let ret1, ret2, | ||
done1, done2; | ||
let sync1 = jest.genMockFn().mockImpl(params => { | ||
let {resolve} = params; | ||
resolve && resolve(syncData); | ||
}); | ||
let sync2 = jest.genMockFn().mockImpl(params => { | ||
let {id, resolve} = params; | ||
resolve && resolve(syncData + id); | ||
}); | ||
storage.sync[testKey1] = sync1; | ||
storage.sync[testKey2] = sync2; | ||
runs(() => { | ||
//key not found | ||
storage.load({ | ||
key: testKey1 | ||
}).then( ret => { | ||
ret1 = ret; | ||
done1 = true; | ||
}).catch( () => { | ||
done1 = true; | ||
runs(() => { | ||
//key not found | ||
storage.load({ | ||
key: testKey1 | ||
}).then(ret => { | ||
ret1 = ret; | ||
done1 = true; | ||
}).catch(() => { | ||
done1 = true; | ||
}); | ||
//key and id not found | ||
storage.load({ | ||
key: testKey2, | ||
id: testId2 | ||
}).then(ret => { | ||
ret2 = ret; | ||
done2 = true; | ||
}).catch(() => { | ||
done2 = true; | ||
}); | ||
}); | ||
//key and id not found | ||
storage.load({ | ||
key: testKey2, | ||
id: testId2 | ||
}).then( ret => { | ||
ret2 = ret; | ||
done2 = true; | ||
}).catch( () => { | ||
done2 = true; | ||
waitsFor(() => { | ||
return done1 && done2; | ||
}, 'Values should be loaded', 1000); | ||
runs(() => { | ||
expect(ret1).toBe(syncData); | ||
expect(sync1.mock.calls.length).toBe(1); | ||
expect(sync2.mock.calls.length).toBe(1); | ||
expect(ret2).toBe(syncData + testId2); | ||
}); | ||
}); | ||
waitsFor(() => { | ||
return done1 && done2; | ||
}, 'Values should be loaded', 1000); | ||
runs(() => { | ||
expect(ret1).toBe(syncData); | ||
expect(sync1.mock.calls.length).toBe(1); | ||
expect(sync2.mock.calls.length).toBe(1); | ||
expect(ret2).toBe(syncData + testId2); | ||
}); | ||
}); | ||
it('does not trigger sync when data found and do not expire', () => { | ||
let testKey1 = 'testKey1' + Math.random(), | ||
testKey2 = 'testKey2' + Math.random(), | ||
testId2 = 'testId2' + Math.random(), | ||
testData1 = 'testData1', | ||
testData2 = 'testData2', | ||
syncData = 'syncData'; | ||
let ret1, ret2, | ||
done1, done2; | ||
let sync1 = jest.genMockFn().mockImpl( params => { | ||
let { resolve } = params; | ||
resolve && resolve(syncData); | ||
}); | ||
let sync2 = jest.genMockFn().mockImpl( params => { | ||
let { id, resolve } = params; | ||
resolve && resolve(syncData + id); | ||
}); | ||
storage.sync[testKey1] = sync1; | ||
storage.sync[testKey2] = sync2; | ||
runs(() => { | ||
//save data, expires in long time | ||
storage.save({ | ||
key: testKey1, | ||
rawData: testData1, | ||
expires: 10000 | ||
it('does not trigger sync when data found and do not expire' + `(${storageKey})`, () => { | ||
let testKey1 = 'testKey1' + Math.random(), | ||
testKey2 = 'testKey2' + Math.random(), | ||
testId2 = 'testId2' + Math.random(), | ||
testData1 = 'testData1', | ||
testData2 = 'testData2', | ||
syncData = 'syncData'; | ||
let ret1, ret2, | ||
done1, done2; | ||
let sync1 = jest.genMockFn().mockImpl(params => { | ||
let {resolve} = params; | ||
resolve && resolve(syncData); | ||
}); | ||
storage.save({ | ||
key: testKey2, | ||
id: testId2, | ||
rawData: testData2, | ||
expires: 10000 | ||
let sync2 = jest.genMockFn().mockImpl(params => { | ||
let {id, resolve} = params; | ||
resolve && resolve(syncData + id); | ||
}); | ||
storage.sync[testKey1] = sync1; | ||
storage.sync[testKey2] = sync2; | ||
//instantly load | ||
storage.load({ | ||
key: testKey1 | ||
}).then( ret => { | ||
ret1 = ret; | ||
done1 = true; | ||
}).catch( () => { | ||
done1 = true; | ||
runs(() => { | ||
//save data, expires in long time | ||
storage.save({ | ||
key: testKey1, | ||
rawData: testData1, | ||
expires: 10000 | ||
}); | ||
storage.save({ | ||
key: testKey2, | ||
id: testId2, | ||
rawData: testData2, | ||
expires: 10000 | ||
}); | ||
//instantly load | ||
storage.load({ | ||
key: testKey1 | ||
}).then(ret => { | ||
ret1 = ret; | ||
done1 = true; | ||
}).catch(() => { | ||
done1 = true; | ||
}); | ||
storage.load({ | ||
key: testKey2, | ||
id: testId2 | ||
}).then(ret => { | ||
ret2 = ret; | ||
done2 = true; | ||
}).catch(() => { | ||
done2 = true; | ||
}); | ||
}); | ||
storage.load({ | ||
key: testKey2, | ||
id: testId2 | ||
}).then( ret => { | ||
ret2 = ret; | ||
done2 = true; | ||
}).catch( () => { | ||
done2 = true; | ||
waitsFor(() => { | ||
return done1 && done2; | ||
}, 'Values should be loaded', 1000); | ||
runs(() => { | ||
expect(ret1).toBe(testData1); | ||
expect(sync1.mock.calls.length).toBe(0); | ||
expect(sync2.mock.calls.length).toBe(0); | ||
expect(ret2).toBe(testData2); | ||
}); | ||
}); | ||
waitsFor(() => { | ||
return done1 && done2; | ||
}, 'Values should be loaded', 1000); | ||
runs(() => { | ||
expect(ret1).toBe(testData1); | ||
expect(sync1.mock.calls.length).toBe(0); | ||
expect(sync2.mock.calls.length).toBe(0); | ||
expect(ret2).toBe(testData2); | ||
}); | ||
}); | ||
it('triggers sync when data expires but still returns outdated data(syncInBackground: true)', () => { | ||
let testKey1 = 'testKey1' + Math.random(), | ||
testKey2 = 'testKey2' + Math.random(), | ||
testId2 = 'testId2' + Math.random(), | ||
testData1 = 'testData1', | ||
testData2 = 'testData2', | ||
syncData = 'syncData'; | ||
let ret1, ret2, | ||
done1, done2; | ||
let sync1 = jest.genMockFn().mockImpl( params => { | ||
let { resolve } = params; | ||
resolve && resolve(syncData); | ||
}); | ||
let sync2 = jest.genMockFn().mockImpl( params => { | ||
let { id, resolve } = params; | ||
resolve && resolve(syncData + id); | ||
}); | ||
storage.sync[testKey1] = sync1; | ||
storage.sync[testKey2] = sync2; | ||
runs(() => { | ||
//save data, expires in no time | ||
storage.save({ | ||
key: testKey1, | ||
rawData: testData1, | ||
expires: -1 | ||
it('triggers sync when data expires but still returns outdated data(syncInBackground: true)' + `(${storageKey})`, () => { | ||
let testKey1 = 'testKey1' + Math.random(), | ||
testKey2 = 'testKey2' + Math.random(), | ||
testId2 = 'testId2' + Math.random(), | ||
testData1 = 'testData1', | ||
testData2 = 'testData2', | ||
syncData = 'syncData'; | ||
let ret1, ret2, | ||
done1, done2; | ||
let sync1 = jest.genMockFn().mockImpl(params => { | ||
let {resolve} = params; | ||
resolve && resolve(syncData); | ||
}); | ||
storage.save({ | ||
key: testKey2, | ||
id: testId2, | ||
rawData: testData2, | ||
expires: -1 | ||
let sync2 = jest.genMockFn().mockImpl(params => { | ||
let {id, resolve} = params; | ||
resolve && resolve(syncData + id); | ||
}); | ||
storage.sync[testKey1] = sync1; | ||
storage.sync[testKey2] = sync2; | ||
//instantly load | ||
storage.load({ | ||
key: testKey1 | ||
}).then( ret => { | ||
ret1 = ret; | ||
done1 = true; | ||
}).catch( () => { | ||
done1 = true; | ||
runs(() => { | ||
//save data, expires in no time | ||
storage.save({ | ||
key: testKey1, | ||
rawData: testData1, | ||
expires: -1 | ||
}); | ||
storage.save({ | ||
key: testKey2, | ||
id: testId2, | ||
rawData: testData2, | ||
expires: -1 | ||
}); | ||
//instantly load | ||
storage.load({ | ||
key: testKey1 | ||
}).then(ret => { | ||
ret1 = ret; | ||
done1 = true; | ||
}).catch(() => { | ||
done1 = true; | ||
}); | ||
storage.load({ | ||
key: testKey2, | ||
id: testId2 | ||
}).then(ret => { | ||
ret2 = ret; | ||
done2 = true; | ||
}).catch(() => { | ||
done2 = true; | ||
}); | ||
}); | ||
storage.load({ | ||
key: testKey2, | ||
id: testId2 | ||
}).then( ret => { | ||
ret2 = ret; | ||
done2 = true; | ||
}).catch( () => { | ||
done2 = true; | ||
}); | ||
}); | ||
waitsFor(() => { | ||
return done1 && done2; | ||
}, 'Values should be loaded', 1000); | ||
runs(() => { | ||
expect(ret1).toBe(testData1); | ||
expect(sync1.mock.calls.length).toBe(1); | ||
waitsFor(() => { | ||
return done1 && done2; | ||
}, 'Values should be loaded', 1000); | ||
runs(() => { | ||
expect(ret1).toBe(testData1); | ||
expect(sync1.mock.calls.length).toBe(1); | ||
expect(ret2).toBe(testData2); | ||
expect(sync2.mock.calls.length).toBe(1); | ||
expect(ret2).toBe(testData2); | ||
expect(sync2.mock.calls.length).toBe(1); | ||
}); | ||
}); | ||
}); | ||
it('triggers sync when data expires and returns latest data(syncInBackground: false)', () => { | ||
let testKey1 = 'testKey1' + Math.random(), | ||
testKey2 = 'testKey2' + Math.random(), | ||
testId2 = 'testId2' + Math.random(), | ||
testData1 = 'testData1', | ||
testData2 = 'testData2', | ||
syncData = 'syncData'; | ||
let ret1, ret2, | ||
done1, done2; | ||
let sync1 = jest.genMockFn().mockImpl( params => { | ||
let { resolve } = params; | ||
resolve && resolve(syncData); | ||
}); | ||
let sync2 = jest.genMockFn().mockImpl( params => { | ||
let { id, resolve } = params; | ||
resolve && resolve(syncData + id); | ||
}); | ||
storage.sync[testKey1] = sync1; | ||
storage.sync[testKey2] = sync2; | ||
runs(() => { | ||
//save data, expires in no time | ||
storage.save({ | ||
key: testKey1, | ||
rawData: testData1, | ||
expires: -1 | ||
it('triggers sync when data expires and returns latest data(syncInBackground: false)' + `(${storageKey})`, () => { | ||
let testKey1 = 'testKey1' + Math.random(), | ||
testKey2 = 'testKey2' + Math.random(), | ||
testId2 = 'testId2' + Math.random(), | ||
testData1 = 'testData1', | ||
testData2 = 'testData2', | ||
syncData = 'syncData'; | ||
let ret1, ret2, | ||
done1, done2; | ||
let sync1 = jest.genMockFn().mockImpl(params => { | ||
let {resolve} = params; | ||
resolve && resolve(syncData); | ||
}); | ||
storage.save({ | ||
key: testKey2, | ||
id: testId2, | ||
rawData: testData2, | ||
expires: -1 | ||
let sync2 = jest.genMockFn().mockImpl(params => { | ||
let {id, resolve} = params; | ||
resolve && resolve(syncData + id); | ||
}); | ||
storage.sync[testKey1] = sync1; | ||
storage.sync[testKey2] = sync2; | ||
//instantly load | ||
storage.load({ | ||
key: testKey1, | ||
syncInBackground: false | ||
}).then( ret => { | ||
ret1 = ret; | ||
done1 = true; | ||
}).catch( () => { | ||
done1 = true; | ||
runs(() => { | ||
//save data, expires in no time | ||
storage.save({ | ||
key: testKey1, | ||
rawData: testData1, | ||
expires: -1 | ||
}); | ||
storage.save({ | ||
key: testKey2, | ||
id: testId2, | ||
rawData: testData2, | ||
expires: -1 | ||
}); | ||
//instantly load | ||
storage.load({ | ||
key: testKey1, | ||
syncInBackground: false | ||
}).then(ret => { | ||
ret1 = ret; | ||
done1 = true; | ||
}).catch(() => { | ||
done1 = true; | ||
}); | ||
storage.load({ | ||
key: testKey2, | ||
id: testId2, | ||
syncInBackground: false | ||
}).then(ret => { | ||
ret2 = ret; | ||
done2 = true; | ||
}).catch(() => { | ||
done2 = true; | ||
}); | ||
}); | ||
storage.load({ | ||
key: testKey2, | ||
id: testId2, | ||
syncInBackground: false | ||
}).then( ret => { | ||
ret2 = ret; | ||
done2 = true; | ||
}).catch( () => { | ||
done2 = true; | ||
waitsFor(() => { | ||
return done1 && done2; | ||
}, 'Values should be loaded', 1000); | ||
runs(() => { | ||
expect(ret1).toBe(syncData); | ||
expect(sync1.mock.calls.length).toBe(1); | ||
expect(ret2).toBe(syncData + testId2); | ||
expect(sync2.mock.calls.length).toBe(1); | ||
}); | ||
}); | ||
it('returns batch data with batch keys' + `(${storageKey})`, () => { | ||
let testKey1 = 'testKey1' + Math.random(), | ||
testKey2 = 'testKey2' + Math.random(), | ||
testKey3 = 'testKey3' + Math.random(), | ||
testData1 = 'testData1', | ||
testData2 = 'testData2', | ||
testData3 = 'testData3'; | ||
let ret, | ||
done; | ||
let sync3 = jest.genMockFn().mockImpl(params => { | ||
let {resolve} = params; | ||
resolve && resolve(testData3); | ||
}); | ||
storage.sync[testKey3] = sync3; | ||
waitsFor(() => { | ||
return done1 && done2; | ||
}, 'Values should be loaded', 1000); | ||
runs(() => { | ||
expect(ret1).toBe(syncData); | ||
expect(sync1.mock.calls.length).toBe(1); | ||
runs(() => { | ||
//save key1 and key2 | ||
storage.save({ | ||
key: testKey1, | ||
rawData: testData1 | ||
}); | ||
storage.save({ | ||
key: testKey2, | ||
rawData: testData2 | ||
}); | ||
expect(ret2).toBe(syncData + testId2); | ||
expect(sync2.mock.calls.length).toBe(1); | ||
}); | ||
}); | ||
it('returns batch data with batch keys', () => { | ||
let testKey1 = 'testKey1' + Math.random(), | ||
testKey2 = 'testKey2' + Math.random(), | ||
testKey3 = 'testKey3' + Math.random(), | ||
testData1 = 'testData1', | ||
testData2 = 'testData2', | ||
testData3 = 'testData3'; | ||
let ret, | ||
done; | ||
let sync3 = jest.genMockFn().mockImpl( params => { | ||
let { resolve } = params; | ||
resolve && resolve(testData3); | ||
}); | ||
storage.sync[testKey3] = sync3; | ||
runs(() => { | ||
//save key1 and key2 | ||
storage.save({ | ||
key: testKey1, | ||
rawData: testData1 | ||
//instantly load | ||
storage.getBatchData([ | ||
{key: testKey1}, | ||
{key: testKey2}, | ||
{key: testKey3} | ||
]).then(results => { | ||
ret = results; | ||
done = true; | ||
}).catch(() => { | ||
done = true; | ||
}) | ||
}); | ||
storage.save({ | ||
key: testKey2, | ||
rawData: testData2 | ||
waitsFor(() => { | ||
return done; | ||
}, 'Values should be loaded', 1000); | ||
runs(() => { | ||
expect(ret[0]).toBe(testData1); | ||
expect(ret[1]).toBe(testData2); | ||
expect(ret[2]).toBe(testData3); | ||
expect(sync3.mock.calls.length).toBe(1); | ||
}); | ||
//instantly load | ||
storage.getBatchData([ | ||
{ key: testKey1 }, | ||
{ key: testKey2 }, | ||
{ key: testKey3 } | ||
]).then( results => { | ||
ret = results; | ||
done = true; | ||
}).catch( () => { | ||
done = true; | ||
}) | ||
}); | ||
waitsFor(() => { | ||
return done; | ||
}, 'Values should be loaded', 1000); | ||
runs(() => { | ||
expect(ret[0]).toBe(testData1); | ||
expect(ret[1]).toBe(testData2); | ||
expect(ret[2]).toBe(testData3); | ||
expect(sync3.mock.calls.length).toBe(1); | ||
}); | ||
}); | ||
it('returns batch data with batch ids', () => { | ||
let testKey = 'testKey' + Math.random(), | ||
testId1 = 'testId1' + Math.random(), | ||
testId2 = 'testId2' + Math.random(), | ||
testId3 = 'testId3' + Math.random(), | ||
testData1 = 'testData1', | ||
testData2 = 'testData2', | ||
testData3 = 'testData3'; | ||
let ret, | ||
done; | ||
let sync = jest.genMockFn().mockImpl( params => { | ||
let { resolve } = params; | ||
// when id is an array, the return value should be an ordered array too | ||
resolve && resolve([testData3]); | ||
}); | ||
storage.sync[testKey] = sync; | ||
it('returns batch data with batch ids' + `(${storageKey})`, () => { | ||
let testKey = 'testKey' + Math.random(), | ||
testId1 = 'testId1' + Math.random(), | ||
testId2 = 'testId2' + Math.random(), | ||
testId3 = 'testId3' + Math.random(), | ||
testData1 = 'testData1', | ||
testData2 = 'testData2', | ||
testData3 = 'testData3'; | ||
let ret, | ||
done; | ||
let sync = jest.genMockFn().mockImpl(params => { | ||
let {resolve} = params; | ||
// when id is an array, the return value should be an ordered array too | ||
resolve && resolve([testData3]); | ||
}); | ||
storage.sync[testKey] = sync; | ||
runs(() => { | ||
//save id1 and id2 | ||
storage.save({ | ||
key: testKey, | ||
id: testId1, | ||
rawData: testData1 | ||
runs(() => { | ||
//save id1 and id2 | ||
storage.save({ | ||
key: testKey, | ||
id: testId1, | ||
rawData: testData1 | ||
}); | ||
storage.save({ | ||
key: testKey, | ||
id: testId2, | ||
rawData: testData2 | ||
}); | ||
//instantly load | ||
storage.getBatchDataWithIds({ | ||
key: testKey, | ||
ids: [testId1, testId2, testId3] | ||
}).then(results => { | ||
ret = results; | ||
done = true; | ||
}).catch(() => { | ||
done = true; | ||
}) | ||
}); | ||
storage.save({ | ||
key: testKey, | ||
id: testId2, | ||
rawData: testData2 | ||
waitsFor(() => { | ||
return done; | ||
}, 'Values should be loaded', 1000); | ||
runs(() => { | ||
expect(ret[0]).toBe(testData1); | ||
expect(ret[1]).toBe(testData2); | ||
expect(ret[2]).toBe(testData3); | ||
expect(JSON.stringify(sync.mock.calls[0][0].id)).toBe(JSON.stringify([testId3])); | ||
}); | ||
//instantly load | ||
storage.getBatchDataWithIds({ | ||
key: testKey, | ||
ids: [ testId1, testId2, testId3 ] | ||
}).then( results => { | ||
ret = results; | ||
done = true; | ||
}).catch( () => { | ||
done = true; | ||
}) | ||
}); | ||
waitsFor(() => { | ||
return done; | ||
}, 'Values should be loaded', 1000); | ||
runs(() => { | ||
expect(ret[0]).toBe(testData1); | ||
expect(ret[1]).toBe(testData2); | ||
expect(ret[2]).toBe(testData3); | ||
expect(JSON.stringify(sync.mock.calls[0][0].id)).toBe(JSON.stringify([testId3])); | ||
}); | ||
}); | ||
}) | ||
}); |
{ | ||
"name": "react-native-storage", | ||
"version": "0.0.16", | ||
"description": "This is a local storage wrapper for both react-native(AsyncStorage) and browser(localStorage). ES6/babel is needed.", | ||
"version": "0.1.0", | ||
"description": "A local storage wrapper for both react-native(AsyncStorage) and browser(localStorage). Support size controlling, auto expiring, remote data auto syncing and getting batch data in one query.", | ||
"main": "storage.js", | ||
"scripts": { | ||
"test": "jest --verbose" | ||
"test": "jest" | ||
}, | ||
"jest": { | ||
"verbose": true, | ||
"bail": true, | ||
"scriptPreprocessor": "node_modules/babel-jest", | ||
@@ -11,0 +13,0 @@ "setupEnvScriptFile": "jestSupport/mockStorage.js" |
@@ -5,3 +5,3 @@ # react-native-storage [![Build Status](https://travis-ci.org/sunnylqm/react-native-storage.svg)](https://travis-ci.org/sunnylqm/react-native-storage) [![npm version](https://badge.fury.io/js/react-native-storage.svg)](http://badge.fury.io/js/react-native-storage) | ||
这是一个本地持久存储的封装,可以同时支持react-native(AsyncStorage)和浏览器(localStorage)。ES6语法,promise异步读取,使用jest进行了完整的单元测试。由于代码使用ES6语法编写,因而需要[babel库](http://babeljs.io/docs/setup/#browserify)的支持。 | ||
这是一个本地持久存储的封装,可以同时支持react-native(AsyncStorage)和浏览器(localStorage)。ES6语法,promise异步读取,使用jest进行了完整的单元测试。 | ||
@@ -29,4 +29,4 @@ ## 安装 | ||
include: [ | ||
//path.join(__dirname, '你自己的js文件路径'), | ||
//path.join(__dirname, 'node_modules/其他需要babel的第三方库'), | ||
// path.join(__dirname, '你自己的js文件路径'), | ||
// path.join(__dirname, 'node_modules/其他需要babel的第三方库'), | ||
path.join(__dirname, 'node_modules/react-native-storage') | ||
@@ -55,3 +55,3 @@ ], | ||
请勿使用`require('react-native-storage')`语法, 否则在react native 0.16版本中会报错. | ||
请勿使用`require('react-native-storage')`语法, 否则在react native 0.16之后的版本中会报错. | ||
@@ -61,25 +61,27 @@ ### 初始化 | ||
var storage = new Storage({ | ||
//最大容量,默认值1000条数据循环存储 | ||
// 最大容量,默认值1000条数据循环存储 | ||
size: 1000, | ||
//数据过期时间,默认一整天(1000 * 3600 * 24秒) | ||
// 数据过期时间,默认一整天(1000 * 3600 * 24秒) | ||
defaultExpires: 1000 * 3600 * 24, | ||
//读写时在内存中缓存数据。默认启用。 | ||
// 读写时在内存中缓存数据。默认启用。 | ||
enableCache: true, | ||
//如果storage中没有相应数据,或数据已过期, | ||
//则会调用相应的sync同步方法,无缝返回最新数据。 | ||
// 如果storage中没有相应数据,或数据已过期, | ||
// 则会调用相应的sync同步方法,无缝返回最新数据。 | ||
sync : { | ||
//同步方法的具体说明会在后文提到 | ||
// 同步方法的具体说明会在后文提到 | ||
} | ||
}) | ||
//最好在全局范围内创建一个(且只有一个)storage实例,方便使用 | ||
// 最好在全局范围内创建一个(且只有一个)storage实例,方便直接调用 | ||
//对于web | ||
//window.storage = storage; | ||
// 对于web | ||
// window.storage = storage; | ||
//对于react native | ||
//global.storage = storage; | ||
// 对于react native | ||
// global.storage = storage; | ||
// 这样在之后的任意位置即可以直接调用storage | ||
``` | ||
@@ -89,5 +91,4 @@ | ||
```javascript | ||
//使用key来保存数据。这些数据一般是全局独有的,常常需要调用的。 | ||
//除非你手动移除,这些数据会被永久保存,而且默认不会过期。 | ||
//即便指定了且达到了过期时间,数据也不会被删除,而只是触发调用同步方法。 | ||
// 使用key来保存数据。这些数据一般是全局独有的,常常需要调用的。 | ||
// 除非你手动移除,这些数据会被永久保存,而且默认不会过期。 | ||
storage.save({ | ||
@@ -101,4 +102,4 @@ key: 'loginState', //注意:请不要在key中使用_下划线符号! | ||
//如果不指定过期时间,则会使用defaultExpires参数 | ||
//如果设为null,则永不过期 | ||
// 如果不指定过期时间,则会使用defaultExpires参数 | ||
// 如果设为null,则永不过期 | ||
expires: 1000 * 3600 | ||
@@ -111,13 +112,13 @@ }); | ||
//autoSync(默认为true)意味着在没有找到数据或数据过期时自动调用相应的同步方法 | ||
// autoSync(默认为true)意味着在没有找到数据或数据过期时自动调用相应的同步方法 | ||
autoSync: true, | ||
//syncInBackground(默认为true)意味着如果数据过期, | ||
//在调用同步方法的同时先返回已经过期的数据。 | ||
//设置为false的话,则始终强制返回同步方法提供的最新数据(当然会需要更多等待时间)。 | ||
// syncInBackground(默认为true)意味着如果数据过期, | ||
// 在调用同步方法的同时先返回已经过期的数据。 | ||
// 设置为false的话,则始终强制返回同步方法提供的最新数据(当然会需要更多等待时间)。 | ||
syncInBackground: true | ||
}).then( ret => { | ||
}).then(ret => { | ||
//如果找到数据,则在then方法中返回 | ||
console.log(ret.userid); | ||
}).catch( err => { | ||
}).catch(err => { | ||
//如果没有找到数据且没有同步方法, | ||
@@ -132,6 +133,6 @@ //或者有其他异常,则在catch中返回 | ||
```javascript | ||
//使用key和id来保存数据,一般是保存同类别(key)的大量数据。 | ||
//这些"key-id"数据有一个保存上限,即在初始化storage时传入的size参数。 | ||
//在默认上限参数下,第1001个数据会覆盖第1个数据。 | ||
//覆盖之后,再读取第1个数据,会返回catch或是相应的同步方法。 | ||
// 使用key和id来保存数据,一般是保存同类别(key)的大量数据。 | ||
// 这些"key-id"数据有一个保存上限,即在初始化storage时传入的size参数。 | ||
// 在默认上限参数下,第1001个数据会覆盖第1个数据。 | ||
// 覆盖之后,再读取第1个数据,会返回catch或是相应的同步方法。 | ||
var userA = { | ||
@@ -148,4 +149,4 @@ name: 'A', | ||
storage.save({ | ||
key: 'user', //注意:请不要在key中使用_下划线符号! | ||
id: '1001', //注意:请不要在id中使用_下划线符号! | ||
key: 'user', // 注意:请不要在key中使用_下划线符号! | ||
id: '1001', // 注意:请不要在id中使用_下划线符号! | ||
rawData: userA, | ||
@@ -159,14 +160,29 @@ expires: 1000 * 60 | ||
id: '1001' | ||
}).then( ret => { | ||
//如果找到数据,则在then方法中返回 | ||
}).then(ret => { | ||
// 如果找到数据,则在then方法中返回 | ||
console.log(ret.userid); | ||
}).catch( err => { | ||
//如果没有找到数据且没有同步方法, | ||
//或者有其他异常,则在catch中返回 | ||
}).catch(err => { | ||
// 如果没有找到数据且没有同步方法, | ||
// 或者有其他异常,则在catch中返回 | ||
console.warn(err); | ||
}) | ||
// -------------------------------------------------- | ||
// 获取某个key下的所有id | ||
storage.getIdsForKey('user').then(ids => { | ||
console.log(ids); | ||
}); | ||
// 获取某个key下的所有数据 | ||
storage.getAllDataForKey('user').then(users => { | ||
console.log(users); | ||
}); | ||
// !! 清除某个key下的所有数据 | ||
storage.clearMapForKey('user'); | ||
// -------------------------------------------------- | ||
//删除单个数据 | ||
// 删除单个数据 | ||
storage.remove({ | ||
@@ -180,3 +196,3 @@ key: 'lastPage' | ||
//!! 清空map,移除所有"key-id"数据(但会保留只有key的数据) | ||
// !! 清空map,移除所有"key-id"数据(但会保留只有key的数据) | ||
storage.clearMap(); | ||
@@ -196,5 +212,5 @@ ``` | ||
body: 'id=' + id | ||
}).then( response => { | ||
}).then(response => { | ||
return response.json(); | ||
}).then( json => { | ||
}).then(json => { | ||
//console.log(json); | ||
@@ -214,3 +230,3 @@ if(json && json.user){ | ||
} | ||
}).catch( err => { | ||
}).catch(err => { | ||
console.warn(err); | ||
@@ -235,4 +251,4 @@ reject && reject(err); | ||
```javascript | ||
//使用和load方法一样的参数读取批量数据,但是参数是以数组的方式提供。 | ||
//会在需要时分别调用相应的同步方法,最后统一返回一个有序数组。 | ||
// 使用和load方法一样的参数读取批量数据,但是参数是以数组的方式提供。 | ||
// 会在需要时分别调用相应的同步方法,最后统一返回一个有序数组。 | ||
storage.getBatchData([ | ||
@@ -244,3 +260,3 @@ { key: 'loginState' }, | ||
]) | ||
.then( results => { | ||
.then(results => { | ||
results.forEach( result => { | ||
@@ -261,3 +277,3 @@ console.log(result); | ||
####如有任何问题,欢迎在[issues](https://github.com/sunnylqm/react-native-storage/issues)页面中提出。 | ||
#### 如有任何问题,欢迎在[issues](https://github.com/sunnylqm/react-native-storage/issues)页面中提出。 | ||
@@ -267,2 +283,7 @@ | ||
#### 0.1.0 | ||
1. 添加getIdsForKey、getAllDataForKey、clearMapForKey方法 | ||
2、修复了一些过期的逻辑 | ||
3、重构了单元测试代码 | ||
#### 0.0.16 | ||
@@ -269,0 +290,0 @@ 1. getBatchDataWithIds现在不会在本地数据齐全的情况下触发sync方法了 |
@@ -29,4 +29,4 @@ # react-native-storage [![Build Status](https://travis-ci.org/sunnylqm/react-native-storage.svg)](https://travis-ci.org/sunnylqm/react-native-storage) [![npm version](https://badge.fury.io/js/react-native-storage.svg)](http://badge.fury.io/js/react-native-storage) | ||
include: [ | ||
//path.join(__dirname, 'your-own-js-files'), | ||
//path.join(__dirname, 'node_modules/some-other-lib-that-needs-babel'), | ||
// path.join(__dirname, 'your-own-js-files'), | ||
// path.join(__dirname, 'node_modules/some-other-lib-that-needs-babel'), | ||
path.join(__dirname, 'node_modules/react-native-storage') | ||
@@ -56,3 +56,3 @@ ], | ||
Do not use `require('react-native-storage')`, which would cause error in version 0.16. | ||
Do not use `require('react-native-storage')`, which would cause error in react native version >= 0.16. | ||
@@ -95,3 +95,2 @@ ### Init | ||
// They are perminently stored unless you remove. | ||
// Even expires, the data won't be removed. Only sync method would be invoked. | ||
storage.save({ | ||
@@ -122,6 +121,6 @@ key: 'loginState', // Note: Do not use underscore("_") in key! | ||
syncInBackground: true | ||
}).then( ret => { | ||
}).then(ret => { | ||
// found data goes to then() | ||
console.log(ret.userid); | ||
}).catch( err => { | ||
}).catch(err => { | ||
// any exception including data not found | ||
@@ -159,14 +158,30 @@ // goes to catch() | ||
id: '1001' | ||
}).then( ret => { | ||
}).then(ret => { | ||
// found data goes to then() | ||
console.log(ret.userid); | ||
}).catch( err => { | ||
}).catch(err => { | ||
// any exception including data not found | ||
// goes to catch() | ||
console.warn(err); | ||
}) | ||
}); | ||
// -------------------------------------------------- | ||
// getIdsForKey | ||
storage.getIdsForKey('user').then(ids => { | ||
console.log(ids); | ||
}); | ||
// getAllDataForKey | ||
storage.getAllDataForKey('user').then(users => { | ||
console.log(users); | ||
}); | ||
// !! clear all data under a key | ||
storage.clearMapForKey('user'); | ||
// -------------------------------------------------- | ||
//remove single record | ||
// remove single record | ||
storage.remove({ | ||
@@ -180,3 +195,3 @@ key: 'lastPage' | ||
//!! clear map and remove all key-id data (but keep the key-only data) | ||
// !! clear map and remove all key-id data (but keep the key-only data) | ||
storage.clearMap(); | ||
@@ -200,5 +215,5 @@ ``` | ||
body: 'id=' + id | ||
}).then( response => { | ||
}).then(response => { | ||
return response.json(); | ||
}).then( json => { | ||
}).then(json => { | ||
// console.log(json); | ||
@@ -218,3 +233,3 @@ if(json && json.user){ | ||
} | ||
}).catch( err => { | ||
}).catch(err => { | ||
console.warn(err); | ||
@@ -251,4 +266,4 @@ reject && reject(err); | ||
]) | ||
.then( results => { | ||
results.forEach( result => { | ||
.then(results => { | ||
results.forEach(result => { | ||
console.log(result); | ||
@@ -266,8 +281,14 @@ }) | ||
There is a notable difference between the two methods except the arguments. **getBatchData** will invoke different sync methods(since the keys may be different) one by one when corresponding data is missing. However, **getBatchDataWithIds** will collect missing data, push their ids to an array, then pass the array to the corresponding sync method(to avoid too many requests) once, so you need to implement array query on server end and handle the parameters of sync method properly(cause the id parameter can be a single string or an array of strings). | ||
There is a notable difference between the two methods except the arguments. **getBatchData** will invoke different sync methods(since the keys may be different) one by one when corresponding data is missing. However, **getBatchDataWithIds** will collect missing data, push their ids to an array, then pass the array to the corresponding sync method(to avoid too many requests) once, so you need to implement array query on server end and handle the parameters of sync method properly(cause the id parameter can be a single string or an array of strings). | ||
####You are welcome to ask any question in the [issues](https://github.com/sunnylqm/react-native-storage/issues) page. | ||
#### You are welcome to ask any question in the [issues](https://github.com/sunnylqm/react-native-storage/issues) page. | ||
### Changelog | ||
#### 0.1.0 | ||
1. add getIdsForKey, getAllDataForKey, clearMapForKey methods | ||
2、fix some expires logic | ||
3、refactor unit tests | ||
#### 0.0.16 | ||
@@ -274,0 +295,0 @@ 1. getBatchDataWithIds now won't invoke sync if everything is ready in storage. |
/* | ||
* local storage(web/react native) wrapper | ||
* sunnylqm 2016-03-03 | ||
* version 0.0.16 | ||
* sunnylqm 2016-05-27 | ||
* version 0.1.0 | ||
*/ | ||
@@ -17,7 +17,7 @@ | ||
me.isPromise = options.isPromise || true; | ||
me._innerVersion = 10; | ||
me._innerVersion = 11; | ||
me.cache = {}; | ||
if(!me._s) { | ||
if(window && window.localStorage) { | ||
if(typeof window !== 'undefined' && window.localStorage) { | ||
try { | ||
@@ -74,3 +74,4 @@ // avoid key conflict | ||
innerVersion: me._innerVersion, | ||
index: 0 | ||
index: 0, | ||
__keys__: {} | ||
}; | ||
@@ -94,3 +95,5 @@ } | ||
let oldId = m[m.index]; | ||
let splitOldId = oldId.split('_') | ||
delete m[oldId]; | ||
this._removeIdInKey(splitOldId[0], splitOldId[1]) | ||
if(this.enableCache) { | ||
@@ -102,2 +105,6 @@ delete this.cache[oldId]; | ||
m[m.index] = newId; | ||
m.__keys__[key] = m.__keys__[key] || []; | ||
m.__keys__[key].push(id); | ||
if(this.enableCache) { | ||
@@ -204,8 +211,11 @@ const cacheData = JSON.parse(data); | ||
let now = new Date().getTime(); | ||
if(autoSync && ret.expires < now && me.sync[key]) { | ||
if(syncInBackground) { | ||
me.sync[key]({}); | ||
return Promise.resolve(ret.rawData); | ||
if(autoSync && ret.expires < now) { | ||
if (me.sync[key]){ | ||
if(syncInBackground) { | ||
me.sync[key]({}); | ||
return Promise.resolve(ret.rawData); | ||
} | ||
return new Promise((resolve, reject) => me.sync[key]({resolve, reject})); | ||
} | ||
return new Promise((resolve, reject) => me.sync[key]({resolve, reject})); | ||
return Promise.reject(); | ||
} | ||
@@ -246,2 +256,3 @@ return Promise.resolve(ret.rawData); | ||
} | ||
return Promise.reject(); | ||
} | ||
@@ -284,2 +295,3 @@ return Promise.resolve(ret.rawData); | ||
} | ||
me._removeIdInKey(key, id); | ||
let idTobeDeleted = m[newId]; | ||
@@ -292,2 +304,8 @@ delete m[newId]; | ||
} | ||
_removeIdInKey(key, id) { | ||
let indexTobeRemoved = this._m.__keys__[key].indexOf(id); | ||
if(indexTobeRemoved !== -1) { | ||
this._m.__keys__[key].splice(indexTobeRemoved, 1); | ||
} | ||
} | ||
load(params) { | ||
@@ -317,2 +335,21 @@ let me = this; | ||
} | ||
clearMapForKey(key) { | ||
return this._mapPromise.then(() => { | ||
let tasks = this._m.__keys__[key].map(id => this.remove({ key, id })); | ||
return Promise.all(tasks); | ||
}); | ||
} | ||
getIdsForKey(key) { | ||
return this._mapPromise.then(() => { | ||
return this._m.__keys__[key] || []; | ||
}); | ||
} | ||
getAllDataForKey(key, options) { | ||
options = Object.assign({ syncInBackground: true }, options); | ||
return this.getIdsForKey(key).then(ids => { | ||
let querys = ids.map(id => ({ key, id, syncInBackground: options.syncInBackground })); | ||
return this.getBatchData(querys); | ||
}); | ||
} | ||
} | ||
@@ -319,0 +356,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
105862
22
295
1051