@quell/server
Version:
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 serv
126 lines (125 loc) • 6.46 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createNormalizeForCache = void 0;
/**
* Creates a normalizeForCache function with the provided configuration
* This is the main normalization logic that processes GraphQL responses
* and prepares them for caching
* @param config - Configuration object
* @returns Bound normalizeForCache function
*/
function createNormalizeForCache(config) {
const { writeToCache, updateIdCache } = config;
/**
* Traverses over response data and formats it appropriately so that it can be stored in the cache.
* @param {Object} responseData - Data we received from an external source of data such as a database or API.
* @param {Object} map - Map of queries to their desired data types, used to ensure accurate and consistent caching.
* @param {Object} protoField - Slice of the prototype currently being used as a template and reference for the responseData to send information to the cache.
* @param {string} currName - Parent object name, used to pass into updateIDCache.
*/
function normalizeForCache(responseData, map = {}, protoField, currName) {
return __awaiter(this, void 0, void 0, function* () {
console.log("=== NORMALIZE FOR CACHE ===");
console.log("Response Data:", JSON.stringify(responseData, null, 2));
console.log("Proto Field:", JSON.stringify(protoField, null, 2));
// Add safety check
if (!responseData) {
console.log("ERROR: responseData is undefined or null");
return;
}
for (const resultName in responseData) {
const currField = responseData[resultName];
const currProto = protoField[resultName];
console.log(`Processing field: ${resultName}`);
console.log(`currField:`, currField);
console.log(`currProto:`, currProto);
// Add safety check here too
if (!currProto) {
console.log(`ERROR: currProto is undefined for field ${resultName}`);
continue;
}
if (Array.isArray(currField)) {
yield processArrayData(currField, map, currProto, resultName, currName);
}
else if (typeof currField === "object") {
yield processObjectData(currField, currProto, map, currName, resultName, protoField, responseData);
}
}
});
}
/**
* Helper function to process array data during normalization
*/
function processArrayData(currField, map, currProto, resultName, currName) {
return __awaiter(this, void 0, void 0, function* () {
console.log("=== PROCESSING ARRAY DATA ===");
console.log("Skipping individual array item caching - arrays stored with parent object only");
});
}
/**
* Helper function to process object data during normalization
*/
function processObjectData(currField, currProto, map, currName, resultName, protoField, responseData) {
return __awaiter(this, void 0, void 0, function* () {
// Need to get non-Alias ID for cache
// Temporary store for field properties
const fieldStore = {};
// Create a cacheID based on __type and __id from the prototype
let cacheID = Object.prototype.hasOwnProperty.call(map, currProto.__type)
? map[currProto.__type]
: currProto.__type;
cacheID += currProto.__id ? `--${currProto.__id}` : "";
// Process each key in the object
for (const key in currField) {
// Check for ID fields and update cache accordingly
if (!currProto.__id &&
(key === "id" || key === "_id" || key === "ID" || key === "Id")) {
const updatedCurrName = updateCurrentName(responseData, cacheID, currName);
const cacheIDForIDCache = cacheID;
cacheID += `--${currField[key]}`;
updateIdCache(cacheIDForIDCache, cacheID, updatedCurrName);
}
fieldStore[key] = currField[key];
// Recursively process nested objects
if (typeof currField[key] === "object" &&
protoField[resultName] !== null) {
yield normalizeForCache({ [key]: currField[key] }, map, {
[key]: protoField[resultName][key],
}, currName);
}
}
console.log("=== ABOUT TO WRITE TO CACHE ===");
console.log("Cache ID:", cacheID);
console.log("Field Store (what will be cached):", JSON.stringify(fieldStore, null, 2));
console.log("Current Field (from response):", JSON.stringify(currField, null, 2));
// Store the object in cache
writeToCache(cacheID, fieldStore);
});
}
/**
* Helper function to update the current name based on response data
*/
function updateCurrentName(responseData, cacheID, currName) {
if (responseData[cacheID.toLowerCase()]) {
const responseDataAtCacheID = responseData[cacheID.toLowerCase()];
if (typeof responseDataAtCacheID !== "string" &&
!Array.isArray(responseDataAtCacheID)) {
if (typeof responseDataAtCacheID.name === "string") {
return responseDataAtCacheID.name;
}
}
}
return currName;
}
return normalizeForCache;
}
exports.createNormalizeForCache = createNormalizeForCache;