Skip to content

Commit

Permalink
Merge pull request #33 from Alonsog66/master
Browse files Browse the repository at this point in the history
Added session storage and clear cache functionality
  • Loading branch information
travismfrank authored Sep 19, 2020
2 parents dda95be + ad2ec34 commit 517425b
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 75 deletions.
83 changes: 52 additions & 31 deletions ObsidianWrapper/ObsidianWrapper.jsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
import React from 'https://dev.jspm.io/[email protected]'; // from deps
// import clientStorage from 'https://deno.land/x/[email protected]/ObsidianWrapper/clientStorage.js';
import React from 'https://dev.jspm.io/[email protected]';

import normalizeResult from '../src/normalize.js';
import destructureQueries from '../src/destructureQueries.js';

// Context will be used to create a custom provider for the application
export const cacheContext = React.createContext();
// Declaration of custom Obsidian Wrapper
function ObsidianWrapper(props) {
const [cache, setCache] = React.useState({});

// Primary function, provides access to fetching and caching capabilities
async function fetcher(query, options = {}) {

console.log(cache);

// Desctructuring of optional parameters, default values are defined and may be over written
const {
endpoint = '/graphql',
pollInterval = null,
destructure = true,
sessionStore = false,
} = options;
if (destructure) {
const obsidianSchema = window.__INITIAL_STATE__.obsidianSchema;
/* COMMENT OUT THESE LINES FOR SERVER CACHE */
const deepCache = Object.assign({}, cache);
const obsidianReturn = await destructureQueries(query, obsidianSchema, deepCache);
const deepCache = sessionStore ? localStorage : Object.assign({}, cache);
const obsidianReturn = await destructureQueries(
query,
obsidianSchema,
deepCache
);
// // Conditional to check if query is stored in global cache
if (obsidianReturn) {
console.log('--------------');
Expand All @@ -36,11 +40,14 @@ function ObsidianWrapper(props) {
);
}
} else {
if (cache[query]) {
const checkStorage = sessionStore
? JSON.parse(sessionStorage.getItem(query))
: cache[query];
if (checkStorage) {
console.log('--------------');
console.log('Found it in the cache!!');
console.log('--------------');
return new Promise((resolve, reject) => resolve(cache[query]));
return new Promise((resolve, reject) => resolve(checkStorage));
}
}
// If not found in cache, query is excecuted
Expand All @@ -56,27 +63,33 @@ function ObsidianWrapper(props) {
setInterval(() => {
console.log('--------------');
console.log('Fetching query with poll interval');
fetchData(query, endpoint);
fetchData(query, endpoint, destructure, sessionStore);
}, pollInterval);
}
console.log('--------------');
console.log('Fetching Data');
// Excection of fetch
return await fetchData(query, endpoint, destructure);
/* COMMENT OUT THESE LINES FOR SERVER CACHE */
/* COMMENT OUT THESE LINES FOR SERVER CACHE */
return new Promise((resolve, reject) =>
resolve(fetchData(query, endpoint, destructure, sessionStore))
);
}
// Function to update the global cache with new response data
function updateCache(query, response) {
function updateCache(query, response, sessionStore) {
// Declaring new object with new data to store in cache
const newObj = Object.assign(cache, { [query]: response });

// React hook to update global cache object
setCache(newObj);
// Can be uncommeted to store data in session storage
// sessionStorage.setItem(query, JSON.stringify(response));
sessionStore
? sessionStorage.setItem(query, JSON.stringify(response))
: setCache(newObj);
}
function clearCache() {
sessionStorage.clear();
setCache({});
}

// Excecutes graphql fetch request
async function fetchData(query, endpoint, destructure) {
async function fetchData(query, endpoint, destructure, sessionStore) {
try {
const respJSON = await fetch(endpoint, {
method: 'POST',
Expand All @@ -90,28 +103,36 @@ function ObsidianWrapper(props) {
// Excecute function to update the cache with new response
if (destructure) {
const obsidianSchema = window.__INITIAL_STATE__.obsidianSchema;
/* COMMENT OUT THESE LINES FOR SERVER CACHE */

const deepCache = Object.assign({}, cache);
normalizeResult(query, resp, obsidianSchema, deepCache)
.then(updatedCache => {
for (let key in updatedCache) {
for (let hash in updatedCache[key]) {
updateCache(hash, updatedCache[key][hash]);
}
}
return resp;

return new Promise((resolve, reject) => {
resolve(
normalizeResult(query, resp, obsidianSchema, deepCache).then(
(updatedCache) => {
for (let key in updatedCache) {
for (let hash in updatedCache[key]) {
updateCache(hash, updatedCache[key][hash], sessionStore);
}
}
return resp;
}
)
);
});
/* COMMENT OUT THESE LINES FOR SERVER CACHE */
} else {
updateCache(query, resp);
updateCache(query, resp, sessionStore);
return resp;
}
return resp;
} catch (e) {
console.log(e);
}
}

// Returning Provider React component that allows consuming components to subscribe to context changes
return <cacheContext.Provider value={{ cache, fetcher }} {...props} />;
return (
<cacheContext.Provider value={{ cache, fetcher, clearCache }} {...props} />
);
}
// Declaration of custom hook to allow access to provider
function useObsidian() {
Expand Down
Binary file added demo/.DS_Store
Binary file not shown.
6 changes: 4 additions & 2 deletions demo/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ const App = () => {
const [page, setPage] = (React as any).useState(1);
const { fetcher } = useObsidian();


(React as any).useEffect(() => {
fetcher(`{ getEightBooks(id: 1) { id title author } }`)
.then((resp: any) => setBooks([...resp.data.getEightBooks]));
fetcher(`{ getEightBooks(id: 1) { id title author } }`).then((resp: any) =>
setBooks([...resp.data.getEightBooks])
);
}, []);

const pageTurn = (id: any) => {
Expand Down
77 changes: 35 additions & 42 deletions demo/deno.test.ts
Original file line number Diff line number Diff line change
@@ -1,88 +1,81 @@
import { superoak } from "https://deno.land/x/[email protected]/mod.ts";
import { describe, it } from "https://deno.land/x/[email protected]/test/utils.ts";
import { expect } from "https://deno.land/x/[email protected]/test/deps.ts";
import { superoak } from 'https://deno.land/x/[email protected]/mod.ts';
import { describe, it } from 'https://deno.land/x/[email protected]/test/utils.ts';
import { expect } from 'https://deno.land/x/[email protected]/test/deps.ts';

import { app } from './server.tsx';

describe('GET request to root url', () => {
it('Sends 200 Status and Content Type text/html', async ( done ) => {
(await superoak(app))
.get("/")
.end((err, res) => {
expect(res.status).toEqual(200);
expect(res.type).toEqual('text/html');
done();
});
it('Sends 200 Status and Content Type text/html', async (done) => {
(await superoak(app)).get('/').end((err, res) => {
expect(res.status).toEqual(200);
expect(res.type).toEqual('text/html');
done();
});
});

})
});

describe('GraphQL query response testing', () => {
it('getBook query succeeds', async (done:any) => {
it('getBook query succeeds', async (done: any) => {
(await superoak(app))
.post('/graphql')
.send({query: '{getBook(id:1){ id title author }}'})
.end((err:any, res:any) => {
.send({ query: '{getBook(id:1){ id title author }}' })
.end((err: any, res: any) => {
console.log(res);
expect(res.status).toEqual(200);
expect(res.body.data.getBook.id).toEqual('1');
expect(res.body.data.getBook.title).toEqual('Lets Go');
expect(res.body.data.getBook.author).toEqual('Jeho');
setTimeout(done, 500);
})
})
});
});

it('Invalid getBook query fails', async (done) => {
(await superoak(app))
.post('/graphql')
.send({query:'{getBook{ id title author }}'})
.send({ query: '{getBook{ id title author }}' })
.end((err, res) => {
console.log('error', err)
console.log('error', err);
console.log(res);
expect(res.status).toEqual(200);
expect(res.body.errors).toBeTruthy();
done();
})
})
});
});

it('getEightBooks succeeds', async (done) => {
(await superoak(app))
.post('/graphql')
.send({query:'{getEightBooks(id:1){ id title author }}'})
.send({ query: '{getEightBooks(id:1){ id title author }}' })
.end((err, res) => {
console.log(res);
expect(res.status).toEqual(200);
expect(res.body.data.getEightBooks).toHaveLength(8);
setTimeout(done, 500);
})
})
})
});
});
});

describe('Redis cache testing', () => {
it('second query takes less than half time of first', async (done) => {
let firstResTime : number;
(await superoak(app))
let firstResTime: number;
(await superoak(app))
.post('/graphql')
.send({query: '{getBook(id:2){ id title author }}'})
.send({ query: '{getBook(id:2){ id title author }}' })
.end((err, res) => {
console.log(res);
firstResTime = Number(res.header['x-response-time'].slice(0, -2));
})
});

setTimeout(async () => {(await superoak(app))
setTimeout(async () => {
(await superoak(app))
.post('/graphql')
.send({query: '{getBook(id:2){ id title author }}'})
.send({ query: '{getBook(id:2){ id title author }}' })
.end((err, res) => {
const newTime: number = res.header['x-response-time'].slice(0, -2);

expect(newTime < (0.5 * firstResTime)).toBeTruthy();
expect(newTime < 0.5 * firstResTime).toBeTruthy();
setTimeout(done, 500);
})}, 500)
})
})






});
}, 500);
});
});
Binary file added demo/dump.rdb
Binary file not shown.

0 comments on commit 517425b

Please sign in to comment.