Browse Source

Merge 0bd5e361c6 into 8c80086da1

pull/5843/merge
Laksh sadhwani 2 days ago
committed by GitHub
parent
commit
b1c6e47c07
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 139
      apps/api/src/helper/object.helper.ts

139
apps/api/src/helper/object.helper.ts

@ -31,6 +31,44 @@ export function nullifyValuesInObjects<T>(aObjects: T[], keys: string[]): T[] {
});
}
// Helper: Custom fast clone (faster than structuredClone for our use case)
function fastClone(obj: any, seen = new WeakMap()): any {
// Handle primitives and null
if (obj === null || typeof obj !== 'object') {
return obj;
}
// Don't clone Big.js instances
if (obj instanceof Big) {
return obj;
}
// Handle circular references
if (seen.has(obj)) {
return seen.get(obj);
}
// Handle arrays
if (isArray(obj)) {
const arr: any[] = [];
seen.set(obj, arr);
for (let i = 0; i < obj.length; i++) {
arr[i] = fastClone(obj[i], seen);
}
return arr;
}
// Handle objects
const cloned: any = {};
seen.set(obj, cloned);
const keys = Object.keys(obj);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
cloned[key] = fastClone(obj[key], seen);
}
return cloned;
}
export function redactAttributes({
isFirstRun = true,
object,
@ -44,44 +82,75 @@ export function redactAttributes({
return object;
}
// Create deep clone
const redactedObject = isFirstRun
? JSON.parse(JSON.stringify(object))
: object;
for (const option of options) {
if (redactedObject.hasOwnProperty(option.attribute)) {
if (option.valueMap['*'] || option.valueMap['*'] === null) {
redactedObject[option.attribute] = option.valueMap['*'];
} else if (option.valueMap[redactedObject[option.attribute]]) {
redactedObject[option.attribute] =
option.valueMap[redactedObject[option.attribute]];
}
// Optimization 1: Use custom fast clone instead of structuredClone
const redactedObject = isFirstRun ? fastClone(object) : object;
// Optimization 2: Pre-process options and separate wildcards from conditional mappings
const wildcardAttrs = new Map<string, any>();
const conditionalAttrs = new Map<string, { [key: string]: any }>();
for (const opt of options) {
if ('*' in opt.valueMap) {
wildcardAttrs.set(opt.attribute, opt.valueMap['*']);
} else {
// If the attribute is not present on the current object,
// check if it exists on any nested objects
for (const property in redactedObject) {
if (isArray(redactedObject[property])) {
redactedObject[property] = redactedObject[property].map(
(currentObject) => {
return redactAttributes({
options,
isFirstRun: false,
object: currentObject
});
conditionalAttrs.set(opt.attribute, opt.valueMap);
}
}
// Optimization 3: Use iterative traversal with pointer-based queue
const workQueue: any[] = [redactedObject];
let queueIndex = 0;
while (queueIndex < workQueue.length) {
const current = workQueue[queueIndex++];
// Skip null/undefined
if (current == null) {
continue;
}
// Process wildcard attributes first (most common case)
for (const [attribute, replacementValue] of wildcardAttrs) {
if (attribute in current) {
current[attribute] = replacementValue;
}
}
// Process conditional attributes
for (const [attribute, valueMap] of conditionalAttrs) {
if (attribute in current) {
const currentValue = current[attribute];
if (currentValue in valueMap) {
current[attribute] = valueMap[currentValue];
}
}
}
// Optimization 4: Use Object.keys() instead of for...in (faster, no inherited props)
const keys = Object.keys(current);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const value = current[key];
// Optimization 5: Cache type check
const valueType = typeof value;
if (valueType !== 'object' || value === null) {
continue;
}
if (isArray(value)) {
// Optimization 6: Batch array processing
if (value.length > 0) {
for (let j = 0; j < value.length; j++) {
const item = value[j];
if (item != null && typeof item === 'object') {
workQueue.push(item);
}
);
} else if (
isObject(redactedObject[property]) &&
!(redactedObject[property] instanceof Big)
) {
// Recursively call the function on the nested object
redactedObject[property] = redactAttributes({
options,
isFirstRun: false,
object: redactedObject[property]
});
}
}
} else if (!(value instanceof Big)) {
// Push object to queue (Big.js instances excluded)
workQueue.push(value);
}
}
}

Loading…
Cancel
Save