gqty
Version:
The No-GraphQL Client for TypeScript
131 lines (126 loc) • 4.03 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
const index = require('../Error/index.js');
require('../Utils/hash.js');
const object = require('../Utils/object.js');
const utils = require('./utils.js');
const refKey = Symbol("__ref");
const isNormalizedObjectShell = (value) => shells.has(value);
const deshell = (input) => isNormalizedObjectShell(input) ? input.toJSON() : input;
const shells = /* @__PURE__ */ new Set();
const normalizeObject = (data, { identity, onConflict = (_, t) => t, store }) => {
if (typeof data !== "object" || Array.isArray(data)) {
throw new index.GQtyError(
`Only objects can be normalized, received ${typeof data}.`
);
}
const id = identity(data);
if (!id) return;
const existing = store.get(id);
data = deshell(data);
if (existing) {
data = object.deepAssign({}, [existing.toJSON(), data], onConflict);
existing.$set(data);
return existing;
} else {
const result = new Proxy(
{ [refKey]: data },
{
ownKeys(target) {
return Reflect.ownKeys(target[refKey]);
},
getOwnPropertyDescriptor(target, key) {
return Reflect.getOwnPropertyDescriptor(target[refKey], key);
},
set(target, key, value) {
return Reflect.set(target[refKey], key, value);
},
get(target, key) {
var _a;
if (key === "$set") {
return (value) => {
target[refKey] = value;
};
}
if (key === "toJSON") {
return () => target[refKey];
}
return (_a = Reflect.get(target, key)) != null ? _a : Reflect.get(target[refKey], key);
}
}
);
shells.add(result);
store.set(id, result, {
// Has to use strong reference as this is usually the only reference,
// the cache is referencing the object via an internal identifier string.
strong: true
});
return result;
}
};
const deepNormalizeObject = (data, options) => {
return walk(data);
function walk(input, depth = 0) {
if (depth < 15 && input && typeof input === "object") {
for (const [key, value] of Object.entries(input)) {
input[key] = walk(value, depth + 1);
}
if (!Array.isArray(input) && utils.isCacheObject(input)) {
const id = options.identity(input);
if (id) {
const norbj = normalizeObject(input, options);
if (norbj) {
return norbj;
}
}
}
}
return input;
}
};
const defaultNormalizationHandler = Object.freeze({
identity(value) {
var _a;
if (!value || typeof value !== "object" || Array.isArray(value)) return;
const identityFields = [value.__typename, (_a = value.id) != null ? _a : value._id];
if (identityFields.some((field) => field === void 0)) return;
return identityFields.join(":");
},
onConflict(existing, incoming) {
const mergeObjects = (a, b) => {
const result = { ...a, ...b };
if (isNormalizedObjectShell(a)) {
a.$set(result);
return a;
} else if (isNormalizedObjectShell(b)) {
b.$set(result);
return b;
}
return result;
};
if (Array.isArray(existing) && Array.isArray(incoming)) {
if (existing.length === incoming.length) {
return;
} else {
existing.splice(0, existing.length, ...incoming);
}
return existing;
} else if (utils.isCacheObject(existing) && utils.isCacheObject(incoming)) {
return mergeObjects(existing, incoming);
}
return;
}
});
const isSubsetOf = (a, b) => {
for (const [key, value] of Object.entries(a)) {
if (value !== b[key]) {
return false;
}
}
return true;
};
exports.deepNormalizeObject = deepNormalizeObject;
exports.defaultNormalizationHandler = defaultNormalizationHandler;
exports.isNormalizedObjectShell = isNormalizedObjectShell;
exports.isSubsetOf = isSubsetOf;
exports.normalizeObject = normalizeObject;