Skip to content

Commit

Permalink
v1.2.0-beta.0 - support both LocalStorage and Async Storage via DI
Browse files Browse the repository at this point in the history
  • Loading branch information
kosiakMD committed Jul 13, 2019
1 parent 8ccb5ea commit af897e0
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 62 deletions.
16 changes: 15 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,28 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## RoadMap

### Add
- tests
- *finish support for LocalStorage (e.g. add multiSet)!*
- *rewrite EnchantedInMemoryCache into `class`!*
- add tests
- ability for 2-ways updating linked/nested queries as optional
- migration support
- support Fragments
- support/restoring storing Queries with IDs

## Unreleased

## v1.2.0-beta.0
### Changed
**Breaking changes*
- *added as 3rd EnchantedInMemoryCache param `AppStorage`* - support of both `AsyncStorage` and `LocalStorage` via Dependency Injection as `GraphQLStorage` (previous `storage`)
- EnchantedInMemoryCache 3rd param `logs` became 4th
- `AppStorage` and `GQLStorage` are not more available directly and as set of static only methods - they are created with dependencies provided as params in `enchantInMemoryCache` and set as properties to the new "enchanted" cache:
```javascript
const cache = createEnchantedInMemoryCache(...);
const GQLStorage = cache.GQLStorage; // to get `GQLStorage`
const AppStorage = cache.AppStorage; // to get `AppStorage`
```

## v1.1.3
### Changed
- _Readme.md_ - fixed definitions, improved by new changes
Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,13 @@ import { InMemoryCache } from 'apollo-cache-inmemory';
import ApolloClient from 'apollo-client';
import { withClientState } from 'apollo-link-state';
import { ApolloLink } from 'apollo-link';
// ...
// if React Native
// up to RN v0.58
// import { AsyncStorage } from 'react-native';
// since RN v0.59
import AsyncStorage from '@react-native-community/async-storage';
// if Web just use window.LocalStorage

const inMemoryCache = new InMemoryCache({
// ...
});
Expand All @@ -190,8 +196,12 @@ const logs = {
const cache = createEnchantedInMemoryCache(
inMemoryCache,
subscribedQueries,
AsyncStorage, // or LocalStorage
logs,
// alternative to `GraphQLStorage` class, eg for wrapper Realm
);
const GQLStorage = cache.GQLStorage; // to get `GQLStorage`
const AppStorage = cache.AppStorage; // to get `AppStorage` - AsyncStorage or LocalStorage
// ...
const stateLink = withClientState({
cache,
Expand Down
13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apollo-enchanted-cache-inmemory",
"version": "1.1.3",
"version": "1.2.0-beta.0",
"description": "Apollo InMemoryCache wrapper for storing selected only queries and for updating linked/nested without IDs",
"main": "src/index.js",
"scripts": {
Expand Down Expand Up @@ -29,15 +29,16 @@
"keywords": [
"apollo",
"cache",
"store",
"save",
"queries",
"query",
"storage",
"selected",
"restore",
"store",
"update",
"nest",
"bind",
"query",
"queries",
"selected"
"bind"
],
"author": "Kosiak MD",
"license": "MIT",
Expand Down
98 changes: 80 additions & 18 deletions src/AppStorage/AppStorage.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,68 @@
import { AsyncStorage } from 'react-native';
/**
* @typedef {{
* getItem: Function,
* setItem: Function,
* removeItem: Function,
* clear: Function,
* getAllKeys: Function,
* multiGet?: Function,
* multiRemove?: Function,
* mergeItem?: Function,
* }} AnyStorage
* */

class AppStorage {
/** @type AnyStorage || null */
storage = null;

constructor(storage) {
if (storage) {
this.storage = storage;
if (!this.storage.multiGet || !this.storage.multiRemove) {
this.enchantLocalStorage(this.storage);
}
} else {
throw new Error('No Storage provided');
}
}

enchantLocalStorage(localStorage) {
/** add multiGet */
localStorage.multiGet = async (keys, callback) => {
const errors = [];
const results = [];
const interCallback = (error, result) => {
if (error) errors.push(error);
if (result) results.push(result);
};
try {
return await Promise.all(keys.map(key => this.get(key, interCallback)));
} catch (e) {
throw e;
} finally {
if (callback) callback(errors, results);
}
};
/** add multiRemove */
localStorage.multiRemove = async (keys, callback) => {
const errors = [];
const results = [];
const interCallback = (error, result) => {
if (error) errors.push(error);
if (result) results.push(result);
};
try {
return await Promise.all(
keys.map(key => this.remove(key, interCallback)),
);
} catch (e) {
throw e;
} finally {
if (callback) callback(errors, results);
}
};
}

/**
* @callback storageCallback
* @param {Error|null} error
Expand All @@ -23,8 +85,8 @@ class AppStorage {
* @param {getCallback?} callback
* @return {Promise}
* */
static async get(key, callback) {
return AsyncStorage.getItem(key, callback);
async get(key, callback) {
return this.storage.getItem(key, callback);
}

/**
Expand All @@ -34,64 +96,64 @@ class AppStorage {
* @return void
*/
/**
* @param {Query | String} key
* @param {Array<Query | String>} keys
* @param {multiActionCallback?} callback
* @return {Promise}
* */
static async multiGet(key, callback) {
return AsyncStorage.multiGet(key, callback);
async multiGet(keys, callback) {
return this.storage.multiGet(keys, callback);
}

/**
* @param {Query | String} key
* @param {multiActionCallback?} callback
* @return {Promise}
* */
static async multiRemove(key, callback) {
return AsyncStorage.multiRemove(key, callback);
async multiRemove(key, callback) {
return this.storage.multiRemove(key, callback);
}

/**
* @param {String} key
* @param {String} data
* @param {storageCallback?} callback
* */
static async set(key, data, callback) {
return AsyncStorage.setItem(key, data, callback);
async set(key, data, callback) {
return this.storage.setItem(key, data, callback);
}

/**
* @param {String} key
* @param {String} data
* @param {storageCallback?} callback
* */
static async merge(key, data, callback) {
return AsyncStorage.mergeItem(key, data, callback);
async merge(key, data, callback) {
return this.storage.mergeItem(key, data, callback);
}

/**
* @param {Query | String} key
* @param {storageCallback?} callback
* @return {Promise}
* */
static async remove(key, callback) {
return AsyncStorage.removeItem(key, callback);
async remove(key, callback) {
return this.storage.removeItem(key, callback);
}

/**
* @param {storageCallback?} callback
* @return {Promise}
* */
static async reset(callback) {
return AsyncStorage.clear(callback);
async reset(callback) {
return this.storage.clear(callback);
}

/**
* @param {keysCallback?} callback
* @return {Promise}
* */
static async getKeys(callback) {
return AsyncStorage.getAllKeys(callback);
async getKeys(callback) {
return this.storage.getAllKeys(callback);
}
}

Expand Down
24 changes: 14 additions & 10 deletions src/GQLStorage/GQLStorage.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,20 @@ class GQLStorage {
return `${GQLStorage.queryMark}:${queryName}`;
}

constructor(appStorage) {
this.appStorage = new AppStorage(appStorage);
}

/**
* @static
* @async
* @param {Query | String} query
* @param {Object | String} storeData
* @return {Promise}
* */
static async saveQuery(query, storeData) {
async saveQuery(query, storeData) {
const queryName = GQLStorage.getQueryName(query);
return AppStorage.set(queryName, JSON.stringify(storeData));
return this.appStorage.set(queryName, JSON.stringify(storeData));
}

/**
Expand All @@ -45,9 +49,9 @@ class GQLStorage {
* @param {getCallback?} callback
* @return {Promise}
* */
static async getQuery(query, callback) {
async getQuery(query, callback) {
const queryName = GQLStorage.getQueryName(query);
const result = await AppStorage.get(queryName, callback);
const result = await this.appStorage.get(queryName, callback);
return JSON.parse(result);
}

Expand All @@ -64,9 +68,9 @@ class GQLStorage {
* @param {multiActionCallback?} callback
* @return {Promise}
* */
static async multiGet(queries, callback) {
async multiGet(queries, callback) {
const keys = queries.map(GQLStorage.getQueryName);
const results = await AppStorage.multiGet(keys, callback);
const results = await this.appStorage.multiGet(keys, callback);
return results.map(keyValueArray => JSON.parse(keyValueArray[1]));
}

Expand All @@ -77,9 +81,9 @@ class GQLStorage {
* @param {multiActionCallback?} callback
* @return {Promise}
* */
static async multiRemove(queries, callback) {
async multiRemove(queries, callback) {
const keys = queries.map(GQLStorage.getQueryName);
await AppStorage.multiRemove(keys, callback);
await this.appStorage.multiRemove(keys, callback);
return true;
}

Expand All @@ -96,9 +100,9 @@ class GQLStorage {
* @param {removeCallback?} callback
* @return {Promise}
* */
static async removeQuery(query, callback) {
async removeQuery(query, callback) {
const queryName = GQLStorage.getQueryName(query);
return AppStorage.remove(queryName, callback);
return this.appStorage.remove(queryName, callback);
}
}

Expand Down
1 change: 0 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export GQLStorage from './GQLStorage';
export EnchantedPromise from './helpers/EnchantedPromise';
export * from './helpers';
export * from './utils';
Expand Down
Loading

0 comments on commit af897e0

Please sign in to comment.