4

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?

tamacun
  • 421
  • 1
  • 4
  • 9

0 Answers0