91 lines
2.5 KiB
JavaScript
91 lines
2.5 KiB
JavaScript
import { Aggregator } from "../../aggregator";
|
|
import {
|
|
ComputeOptions,
|
|
computeValue
|
|
} from "../../core";
|
|
import {
|
|
assert,
|
|
hashCode,
|
|
isArray,
|
|
isString,
|
|
MingoError,
|
|
resolve,
|
|
ValueMap
|
|
} from "../../util";
|
|
import { $mergeObjects } from "../expression";
|
|
const $merge = (collection, expr, options) => {
|
|
const output = isString(expr.into) ? options?.collectionResolver(expr.into) : expr.into;
|
|
assert(isArray(output), `$merge: option 'into' must resolve to an array`);
|
|
const onField = expr.on || options.idKey;
|
|
const getHash = isString(onField) ? (o) => hashCode(resolve(o, onField), options.hashFunction) : (o) => hashCode(onField.map((s) => resolve(o, s), options.hashFunction));
|
|
const map = ValueMap.init();
|
|
for (let i = 0; i < output.length; i++) {
|
|
const obj = output[i];
|
|
const k = getHash(obj);
|
|
assert(
|
|
!map.has(k),
|
|
"$merge: 'into' collection must have unique entries for the 'on' field."
|
|
);
|
|
map.set(k, [obj, i]);
|
|
}
|
|
const copts = ComputeOptions.init(options);
|
|
return collection.map((o) => {
|
|
const k = getHash(o);
|
|
if (map.has(k)) {
|
|
const [target, i] = map.get(k);
|
|
const variables = computeValue(
|
|
target,
|
|
expr.let || { new: "$$ROOT" },
|
|
null,
|
|
// 'root' is the item from the iteration.
|
|
copts.update(o)
|
|
);
|
|
if (isArray(expr.whenMatched)) {
|
|
const aggregator = new Aggregator(expr.whenMatched, {
|
|
...options,
|
|
variables
|
|
});
|
|
output[i] = aggregator.run([target])[0];
|
|
} else {
|
|
switch (expr.whenMatched) {
|
|
case "replace":
|
|
output[i] = o;
|
|
break;
|
|
case "fail":
|
|
throw new MingoError(
|
|
"$merge: failed due to matching as specified by 'whenMatched' option."
|
|
);
|
|
case "keepExisting":
|
|
break;
|
|
case "merge":
|
|
default:
|
|
output[i] = $mergeObjects(
|
|
target,
|
|
[target, o],
|
|
// 'root' is the item from the iteration.
|
|
copts.update(o, { variables })
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
switch (expr.whenNotMatched) {
|
|
case "discard":
|
|
break;
|
|
case "fail":
|
|
throw new MingoError(
|
|
"$merge: failed due to matching as specified by 'whenMatched' option."
|
|
);
|
|
case "insert":
|
|
default:
|
|
output.push(o);
|
|
break;
|
|
}
|
|
}
|
|
return o;
|
|
});
|
|
};
|
|
export {
|
|
$merge
|
|
};
|