map-transform
Version:
Map and transform objects with mapping definitions
86 lines • 3.3 kB
JavaScript
import { pathGetter, pathSetter } from '../operations/getSet.js';
import { defToDataMapper } from '../utils/definitionHelpers.js';
import { revFromState, isNonvalue } from '../utils/stateHelpers.js';
import { ensureArray } from '../utils/array.js';
import { isObject } from '../utils/is.js';
function addToBucket(value, buckets, key) {
const bucket = buckets.get(key);
if (bucket) {
bucket.push(value);
}
else {
buckets.set(key, [value]);
}
}
async function sortIntoBuckets(getFn, pipelines, getGroupFn, data, state, nonvalues) {
const arr = ensureArray(getFn(data, state));
const retBucket = new Map();
if (pipelines.length > 0) {
for (const value of arr) {
for (const [pipeline, key] of pipelines) {
const result = await pipeline(value, state);
if (result) {
addToBucket(value, retBucket, key);
break;
}
}
}
}
else if (getGroupFn) {
for (const value of arr) {
const key = await getGroupFn(value, state);
if (!isNonvalue(key, nonvalues)) {
addToBucket(value, retBucket, String(key));
}
}
}
return Object.fromEntries(retBucket.entries());
}
function shouldGoInBucket(options, condition, size) {
let inBucket = 0;
const mapper = condition ? defToDataMapper(condition, options) : undefined;
return async function considerItemForBucket(item, state) {
if (size === undefined || inBucket < size) {
if (!mapper || (await mapper(item, state))) {
inBucket++;
return true;
}
}
return false;
};
}
const extractArrayFromBuckets = (buckets, keys, nonvalues) => isObject(buckets)
? (keys || Object.keys(buckets))
.flatMap((key) => buckets[key])
.filter((key) => !isNonvalue(key, nonvalues))
: [];
const prepareGroupByPathFn = (pipeline, options) => typeof pipeline === 'string'
? pathGetter(pipeline)
: pipeline === undefined
? undefined
: defToDataMapper(pipeline, options);
const extractBucketKeys = (buckets, hasGroupFn) => buckets.length === 0 && hasGroupFn ? undefined : buckets.map(({ key }) => key);
const transformer = function bucket({ path = '.', buckets = [], groupByPath, }) {
return (options) => {
const getFn = pathGetter(path);
const setFn = pathSetter(path, options);
const getGroupByPathFn = prepareGroupByPathFn(groupByPath, options);
const pipelines = buckets
.filter(({ key }) => typeof key === 'string')
.map((bucket) => [
shouldGoInBucket(options, bucket.condition ?? bucket.pipeline, bucket.size),
bucket.key,
]);
const keys = extractBucketKeys(buckets, !!getGroupByPathFn);
return async (data, state) => {
if (revFromState(state)) {
return setFn(extractArrayFromBuckets(data, keys, options.nonvalues), state);
}
else {
return sortIntoBuckets(getFn, pipelines, getGroupByPathFn, data, state, options.nonvalues);
}
};
};
};
export default transformer;
//# sourceMappingURL=bucket.js.map