I'm using a generic map function in a MongoDB MapReduce operation where the map itself is kind of a meta-algorithm that runs certain functions passed to it though the scope
. This works fine for normal JS functions, but I also want to pass in partially applied functions, which is where I've ran into problems.
I fill mrScope
with various configuration, including the function I need partially applied like this:
mrScope.operator = operators.getOperator(opSettings.arg1);
I call the (promisified) mapReduce:
conn.mongoClient.collection(input.collection).mapReduceAsync(map, reduce, {
query : input.rawQuery,
scope : {
fScope: mrScope
},
jsMode : true,
out : 'testMe'
})
getOperator
is supposed to return a partially applied function. The last argument to the function is always passed in map
, like this:
fScope.operator.call(null, operatorInput);
At this point I can get various errors from MongoDB, depending on how I try to create the partial application in getOperator
. The relevant parts here are (it has typescript typedefs just for clarity):
export function getOperator(arg: number): OperatorFunction {
if (arg === 0) {
throw 'arg must not be 0';
} else {
return op.bind(null, arg);
}
}
function op(arg: number, values: number[]): number {
var result = 0;
// do something
return result;
}
If I use the native bind()
like this, MongoDB throws this error:
{ [MongoError: exception: Error: 16722 SyntaxError: Unexpected identifier
at fuzzyMap (_funcs9:4:26)
at fuzzyMap (_funcs9:4:26) near 'e.operator);
function computeTa' (line 4)]
cause:
{ [MongoError: exception: Error: 16722 SyntaxError: Unexpected identifier
at fuzzyMap (_funcs9:4:26)
at fuzzyMap (_funcs9:4:26) near 'e.operator);
function computeTa' (line 4)]
name: 'MongoError',
errmsg: 'exception: Error: 16722 SyntaxError: Unexpected identifier\n at fuzzyMap (_funcs9:4:26)\n at fuzzyMap (_funcs9:4:26) near \'e.operator);\r function computeTa\' (line 4)',
code: 16722,
ok: 0 },
isOperational: true,
errmsg: 'exception: Error: 16722 SyntaxError: Unexpected identifier\n at fuzzyMap (_funcs9:4:26)\n at fuzzyMap (_funcs9:4:26) near \'e.operator);\r function computeTa\' (line 4)',
code: 16722,
ok: 0 }
I have no idea about this error. I can call the bound function outside MapReduce no problem. I guess it has to do something with bind
being a native code function, but not sure.
If I use a simple non-native bind like this (for a modified op
):
function partial(fn: Function, ...others: any[]) {
var slice = Array.prototype.slice;
var args = slice.call(arguments, 1);
return function() {
return fn.apply(this, args.concat(slice.call(arguments, 0)));
};
}
and in getOperator
:
return partial(op, arg);
In this case it has no actual reference to op
so the errors are understandable.
Now I understand that I could easily do this without partial application and just pass in op
directly, but I find this approach elegant and I'm curious if it can be done and if so, how would you do it?