Skip to content

Commit

Permalink
Fixed lokiClientCache export issue in production build
Browse files Browse the repository at this point in the history
  • Loading branch information
my7h3le committed Aug 19, 2021
1 parent 2d37f86 commit a60a535
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 88 deletions.
10 changes: 7 additions & 3 deletions demo/client/src/containers/Demo.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,19 @@ import { CreateQueryStr, CreateMutationStr, updateProtoWithFragment } from '../h
import Header from '../images/headers/QUELL-headers-demo w lines.svg';
import DropDown from '../images/buttons/dropdown-button.svg';
import DropDownHover from '../images/buttons/dropdown-button-hover.svg';
import QuellModule from '@quell/client';
import QuellDev from '../../../../quell-client/src/Quellify';
import { lokiClientCache } from "../../../../quell-client/src/helpers/normalizeForLokiCache";
import {Quellify as QuellModule, lokiClientCache as lokiClientCacheModule } from '@quell/client';
import { Quellify as QuellDev, lokiClientCache as lokiClientCacheDev } from '../../../../quell-client/src/Quellify';

const Quell =
process.env.NODE_ENV === "development"
? QuellDev
: QuellModule;

const lokiClientCache =
process.env.NODE_ENV === "development"
? lokiClientCacheDev
: lokiClientCacheModule;

/*
Container that renders the whole demo dashboard
*/
Expand Down
4 changes: 2 additions & 2 deletions demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@
"description": "",
"dependencies": {
"@babel/runtime": "^7.11.2",
"@quell/client": "1.1.1",
"@quell/server": "1.1.1",
"@quell/client": "3.0.1",
"@quell/server": "2.2.1",
"concurrently": "^5.3.0",
"dotenv": "^8.2.0",
"express": "^4.17.1",
Expand Down
2 changes: 1 addition & 1 deletion quell-client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@quell/client",
"version": "3.0.0",
"version": "3.0.1",
"description": "Quell is an open-source NPM package providing a light-weight caching layer implementation and cache invalidation for GraphQL responses on both the client- and server-side. Use Quell to prevent redundant client-side API requests and to minimize costly server-side response latency.",
"main": "src/Quellify.js",
"scripts": {
Expand Down
199 changes: 117 additions & 82 deletions quell-client/src/Quellify.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
const { parse } = require("graphql/language/parser");
const parseAST = require("./helpers/parseAST");
const { parse } = require('graphql/language/parser');
const parseAST = require('./helpers/parseAST');
// const normalizeForSessionCache = require("./helpers/normalizeForSessionCache");
const { lokiClientCache, normalizeForLokiCache } = require("./helpers/normalizeForLokiCache");
const { buildFromCache, generateCacheID } = require("./helpers/buildFromCache");
const {
lokiClientCache,
normalizeForLokiCache,
} = require('./helpers/normalizeForLokiCache');
const { buildFromCache, generateCacheID } = require('./helpers/buildFromCache');
// const createQueryObj = require("./helpers/createQueryObj");
// const createQueryStr = require("./helpers/createQueryStr");
// const createMutationStr = require("./helpers/createMutationStr");
// const joinResponses = require("./helpers/joinResponses");
const updateProtoWithFragment = require("./helpers/updateProtoWithFragments");
const updateProtoWithFragment = require('./helpers/updateProtoWithFragments');

// NOTE:
// options feature is currently EXPERIMENTAL and the intention is to give Quell users the ability to customize cache update policies or to define custom IDs to use as keys when caching data
Expand All @@ -17,12 +20,12 @@ const defaultOptions = {
// default time that data stays in cache before expires
__defaultCacheTime: 600,
// configures type of cache storage used (client-side only)
__cacheType: "session",
__cacheType: 'session',
// custom field that defines the uniqueID used for caching
__userDefinedID: null,
// default fetchHeaders, user can overwrite
headers: {
"Content-Type": "application/json",
'Content-Type': 'application/json',
},
};

Expand All @@ -39,14 +42,20 @@ const defaultOptions = {
* - returns the joined response to the user.
* @param {string} endPoint - The address to where requests are sent and processed. E.g. '/graphql'
* @param {string} query - The graphQL query that is requested from the client
* @param {object} mutationMap - map of mutation that will be used to create mutation object and determine mutation type
* @param {object} mutationMap - map of mutation that will be used to create mutation object and determine mutation type
* @param {object} map - JavaScript object with a key-value pair for every valid root query - type defined in the user's GraphQL schema
* @param {object} queryTypeMap - map of queryType that will be used when caching on client cache storage
* @param {object} userOptions - JavaScript object with customizable properties (note: this feature is still in development, please see defaultOptions for an example)
*/


async function Quellify(endPoint, query, mutationMap, map, queryTypeMap, userOptions) {
async function Quellify(
endPoint,
query,
mutationMap,
map,
queryTypeMap,
userOptions
) {
// merge defaultOptions with userOptions
// defaultOptions will supply any necessary options that the user hasn't specified
const options = { ...defaultOptions, ...userOptions };
Expand All @@ -58,7 +67,7 @@ async function Quellify(endPoint, query, mutationMap, map, queryTypeMap, userOpt
delete map[props]; // avoid duplicate properties
map[key] = value;
}

// Create AST based on the input query using the parse method available in the graphQL library (further reading: https://en.wikipedia.org/wiki/Abstract_syntax_tree)
const AST = parse(query);

Expand All @@ -78,9 +87,9 @@ async function Quellify(endPoint, query, mutationMap, map, queryTypeMap, userOpt
const { proto, operationType, frags } = parseAST(AST, options);

// pass-through for queries and operations that QuellCache cannot handle
if (operationType === "unQuellable") {
if (operationType === 'unQuellable') {
const fetchOptions = {
method: "POST",
method: 'POST',
headers: options.headers,
body: JSON.stringify({ query: query }),
};
Expand All @@ -91,9 +100,9 @@ async function Quellify(endPoint, query, mutationMap, map, queryTypeMap, userOpt

// Return response as a promise
return new Promise((resolve, reject) => resolve(parsedData));
} else if (operationType === 'mutation') {
//if operationType is mutation

} else if (operationType === "mutation") { //if operationType is mutation

//if the mutationQuery is not coming from demo, mutation Query can be created using the code below
//let mutationQuery = createMutationStr(proto);
// create mutation object using mutationMap and proto cretaed from parseAST;
Expand All @@ -103,64 +112,73 @@ async function Quellify(endPoint, query, mutationMap, map, queryTypeMap, userOpt
if (proto.hasOwnProperty(mutation)) mutationObject = proto[mutation];
}

//determine the number of args
//determine the number of args
let argsLen = Object.keys(mutationObject.__args).length;

//if it is add mutation, do below
if (mutationObject.__type.includes("add") ||
mutationObject.__type.includes("new") ||
mutationObject.__type.includes("create") ||
mutationObject.__type.includes("make"))
{

//if it is add mutation, do below
if (
mutationObject.__type.includes('add') ||
mutationObject.__type.includes('new') ||
mutationObject.__type.includes('create') ||
mutationObject.__type.includes('make')
) {
// add mutation
const fetchOptions = {
method: "POST",
headers: options.headers,
body: JSON.stringify({ query: query }),
method: 'POST',
headers: options.headers,
body: JSON.stringify({ query: query }),
};

// Execute fetch request with original query
const serverResponse = await fetch(endPoint, fetchOptions);
const parsedData = await serverResponse.json();

// Normalize returned data into cache
normalizeForLokiCache(parsedData.data, queryTypeMap, isMutation, map, proto); //using lokiJS
normalizeForLokiCache(
parsedData.data,
queryTypeMap,
isMutation,
map,
proto
); //using lokiJS
// normalizeForCache(parsedData.data, map, proto); //using sessionStorage - old client cache storage

console.log(lokiClientCache); // to be deleted

// Return response as a promise
return new Promise((resolve, reject) => resolve({ data: parsedData }));

}else{ //update or delete mutation
let fetchOptions;
if(argsLen === 1) { //delete mutation if the number of args is one
fetchOptions = {
method: 'DELETE',
headers: options.headers,
body: JSON.stringify({ query: query }),
};
}else if(argsLen > 1) { //update mutation if the number of args is more than one
fetchOptions = {
method: "POST",
headers: options.headers,
body: JSON.stringify({ query: query }),
};
}
//regardless of update or delete, clear lokiJS
lokiClientCache.clear();
console.log(lokiClientCache);
// Execute fetch request with original query
const serverResponse = await fetch(endPoint, fetchOptions);
const parsedData = await serverResponse.json();
// no nomarlizeForLokiCache as query will pull out updated cache from server cache;
// Return response as a promise
return new Promise((resolve, reject) => resolve({ data: parsedData }));
} else {
//update or delete mutation
let fetchOptions;
if (argsLen === 1) {
//delete mutation if the number of args is one
fetchOptions = {
method: 'DELETE',
headers: options.headers,
body: JSON.stringify({ query: query }),
};
} else if (argsLen > 1) {
//update mutation if the number of args is more than one
fetchOptions = {
method: 'POST',
headers: options.headers,
body: JSON.stringify({ query: query }),
};
}
//regardless of update or delete, clear lokiJS
lokiClientCache.clear();
console.log(lokiClientCache);
// Execute fetch request with original query
const serverResponse = await fetch(endPoint, fetchOptions);
const parsedData = await serverResponse.json();
// no nomarlizeForLokiCache as query will pull out updated cache from server cache;
// Return response as a promise
return new Promise((resolve, reject) => resolve({ data: parsedData }));
}
} else { // if the request is query
} else {
// if the request is query

/*
/*
const fetchOptions = {
method: "POST",
headers: options.headers,
Expand All @@ -181,14 +199,14 @@ async function Quellify(endPoint, query, mutationMap, map, queryTypeMap, userOpt
* @param {object} frags - JavaScript object with a key of the fragment name defined by the user, and properties for each field requested on that fragment
* check if the user's request included fragments before invoking updateProtoWithFragment
*/

const prototype =
Object.keys(frags).length > 0
? updateProtoWithFragment(proto, frags)
: proto;
// create an array of root queries on the prototype object so that we can differentiate between root queries and fields nested in a root query
const prototypeKeys = Object.keys(prototype);

/**
* buildFromCache searches the cache for data requested from the user and builds cacheResponse based on data in the cache. Fields that are available in the cache will remain true on the prototype object and fields that are not in the cache and therefore need to be fetched from the server, will be toggled to false.
* @param {object} prototype - JavaScript object generated by parseAST (or updateProtoWithFragment if the user request included fragments)
Expand All @@ -197,7 +215,7 @@ async function Quellify(endPoint, query, mutationMap, map, queryTypeMap, userOpt

// store data in client cache to cacheResponse using buildFromCache
// const cacheResponse = buildFromCache(prototype, prototypeKeys);

// initialize a cacheHasData to false
let cacheHasData = false;
/*
Expand All @@ -209,57 +227,75 @@ async function Quellify(endPoint, query, mutationMap, map, queryTypeMap, userOpt
}
}
*/

let cacheID;
for (const typeKey in proto) {
if (prototypeKeys.includes(typeKey)) cacheID = generateCacheID(prototype[typeKey]);
if (prototypeKeys.includes(typeKey))
cacheID = generateCacheID(prototype[typeKey]);
}

let lokiJS = lokiClientCache.data;
const cacheIDArr= [], cacheArr = [], tempArr = [];
const cacheIDArr = [],
cacheArr = [],
tempArr = [];
let prevProperty;
lokiJS.forEach(cachedData => {
for(const property in cachedData) {
if(property === "queryType" && prevProperty === "cacheKey" && cachedData[property] === cacheID){
lokiJS.forEach((cachedData) => {
for (const property in cachedData) {
if (
property === 'queryType' &&
prevProperty === 'cacheKey' &&
cachedData[property] === cacheID
) {
cacheIDArr.push(cachedData[prevProperty]);
}else if(property === "queryType" && prevProperty === "cacheID" && cachedData[property] && cachedData[property] === cacheID ) {
} else if (
property === 'queryType' &&
prevProperty === 'cacheID' &&
cachedData[property] &&
cachedData[property] === cacheID
) {
cacheArr.push(cachedData);
}else{
} else {
prevProperty = property;
}
}
})
if(cacheIDArr.length > 0) cacheHasData = true;
});
if (cacheIDArr.length > 0) cacheHasData = true;

const fetchOptions = {
method: "POST",
method: 'POST',
headers: options.headers,
body: JSON.stringify({ query: query }),
};
// Execute fetch request with original query
const serverResponse = await fetch(endPoint, fetchOptions);
const parsedData = await serverResponse.json();
normalizeForLokiCache(parsedData.data, queryTypeMap, isMutation, map, proto);
normalizeForLokiCache(
parsedData.data,
queryTypeMap,
isMutation,
map,
proto
);

if (!cacheHasData) {
console.log(lokiClientCache);
// Return response as a promise
return new Promise((resolve, reject) => resolve({ data: parsedData }));
}


cacheIDArr.forEach(ID => {
cacheIDArr.forEach((ID) => {
let idx = 0;
cacheArr.forEach(cached => {
for(const property in cached) {
if (property === "id" && cached[property] === ID[idx]) tempArr.push(cached);
cacheArr.forEach((cached) => {
for (const property in cached) {
if (property === 'id' && cached[property] === ID[idx])
tempArr.push(cached);
}
idx += 1
idx += 1;
});
})
});

const cacheResponse = Object.assign({}, tempArr, parsedData);
console.log("cacheResp: ", cacheResponse);
console.log('cacheResp: ', cacheResponse);
//const finalResponse = {data: cacheResponse};

/*
Expand Down Expand Up @@ -295,9 +331,8 @@ async function Quellify(endPoint, query, mutationMap, map, queryTypeMap, userOpt
mergedResponse = { data: cacheResponse };
}
*/
return new Promise((resolve, reject) => resolve(cacheResponse));

return new Promise((resolve, reject) => resolve(cacheResponse));
}
}

module.exports = Quellify;
module.exports = { Quellify, lokiClientCache };

0 comments on commit a60a535

Please sign in to comment.