52 lines
1.4 KiB
JavaScript
52 lines
1.4 KiB
JavaScript
import { get } from 'lodash';
|
|
|
|
export default function applyFnToKey(doc, key, fn){
|
|
if (key.includes('.$')){
|
|
applyToArrayKey(doc, key, fn);
|
|
} else {
|
|
applyToSingleKey(doc, key, fn);
|
|
}
|
|
}
|
|
|
|
function applyToSingleKey(doc, key, fn){
|
|
// call the function with the current value and document for context
|
|
fn(doc, key);
|
|
}
|
|
|
|
/**
|
|
* Applies the given function to all instances in a document key
|
|
* key.$.with.$.subdocs will apply to all key[i...n].with[j...m].subdocs
|
|
* Warning: Order might be confusing, it will traverse the deepest array in order
|
|
* but the shallower arrays in reverse order
|
|
*/
|
|
function applyToArrayKey(doc, key, fn){
|
|
const keySplit = key.split('.$');
|
|
// Stack based depth first traversal of arrays
|
|
const array = get(doc, keySplit[0]);
|
|
if (!array) return;
|
|
const stack = [{
|
|
array,
|
|
paths: keySplit.slice(1),
|
|
currentPath: keySplit[0],
|
|
indices: [],
|
|
}];
|
|
while(stack.length){
|
|
const state = stack.pop();
|
|
for (let index in state.array){
|
|
const currentPath = `${state.currentPath}[${index}]${state.paths[0]}`
|
|
if (state.paths.length == 1){
|
|
applyToSingleKey(doc, currentPath, fn);
|
|
} else {
|
|
const array = get(doc, currentPath);
|
|
if (!array) return;
|
|
stack.push({
|
|
array,
|
|
paths: state.paths.slice(1),
|
|
currentPath,
|
|
indices: [...state.indices, index],
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|