| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- "use strict";
- /**
- * Generic comparison expression that gets used for $eq, $ne, $lt, $lte, $gt, $gte, and $cmp.
- * @class CompareExpression
- * @namespace mungedb-aggregate.pipeline.expressions
- * @module mungedb-aggregate
- * @constructor
- */
- var CompareExpression = module.exports = function CompareExpression(cmpOp) {
- if (!(arguments.length === 1 && typeof cmpOp === "string")) throw new Error(klass.name + ": args expected: cmpOp");
- this.cmpOp = cmpOp;
- base.call(this);
- }, klass = CompareExpression, base = require("./FixedArityExpressionT")(CompareExpression, 2), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
- var Value = require("../Value"),
- Expression = require("./Expression");
- klass.parse = function parse(jsonExpr, vps, op) {
- var expr = new CompareExpression(op),
- args = base.parseArguments(jsonExpr, vps);
- expr.validateArguments(args);
- expr.operands = args;
- return expr;
- };
- /**
- * Lookup table for truth value returns
- * @param truthValues truth value for -1, 0, 1
- * @param reverse reverse comparison operator
- * @param name string name
- */
- var CmpLookup = function CmpLookup(truthValues, reverse, name) { // emulating a struct
- if (arguments.length !== 3) throw new Error("args expected: truthValues, reverse, name");
- this.truthValues = truthValues;
- this.reverse = reverse;
- this.name = name;
- };
- /**
- * Enumeration of comparison operators. Any changes to these values require adjustment of
- * the lookup table in the implementation.
- */
- var CmpOp = klass.CmpOp = {
- EQ: "$eq",
- NE: "$ne",
- GT: "$gt",
- GTE: "$gte",
- LT: "$lt",
- LTE: "$lte",
- CMP: "$cmp",
- };
- /**
- * a table of cmp type lookups to truth values
- * @private
- */
- var cmpLookupMap = [ //NOTE: converted from this Array to a Dict/Object below using CmpLookup#name as the key
- // -1 0 1 reverse name (taking advantage of the fact that our 'enums' are strings below)
- new CmpLookup([false, true, false], CmpOp.EQ, CmpOp.EQ),
- new CmpLookup([true, false, true], CmpOp.NE, CmpOp.NE),
- new CmpLookup([false, false, true], CmpOp.LT, CmpOp.GT),
- new CmpLookup([false, true, true], CmpOp.LTE, CmpOp.GTE),
- new CmpLookup([true, false, false], CmpOp.GT, CmpOp.LT),
- new CmpLookup([true, true, false], CmpOp.GTE, CmpOp.LTE),
- // CMP is special. Only name is used.
- new CmpLookup([false, false, false], CmpOp.CMP, CmpOp.CMP)
- ].reduce(function(r, o) {
- r[o.name] = o;
- return r;
- }, {});
- proto.evaluateInternal = function evaluateInternal(vars) {
- var left = this.operands[0].evaluateInternal(vars),
- right = this.operands[1].evaluateInternal(vars),
- cmp = Value.compare(left, right);
- // Make cmp one of 1, 0, or -1.
- if (cmp === 0) {
- //leave as 0
- } else if (cmp < 0) {
- cmp = -1;
- } else if (cmp > 0) {
- cmp = 1;
- }
- if (this.cmpOp === CmpOp.CMP)
- return cmp;
- var returnValue = cmpLookupMap[this.cmpOp].truthValues[cmp + 1];
- return returnValue;
- };
- proto.getOpName = function getOpName() {
- return this.cmpOp;
- };
- function bindLast(fn, lastArg) { // similar to the boost::bind used in the mongo code
- return function() {
- return fn.apply(this, Array.prototype.slice.call(arguments).concat([lastArg]));
- };
- }
- Expression.registerExpression("$cmp", bindLast(klass.parse, CmpOp.CMP));
- Expression.registerExpression("$eq", bindLast(klass.parse, CmpOp.EQ));
- Expression.registerExpression("$gt", bindLast(klass.parse, CmpOp.GT));
- Expression.registerExpression("$gte", bindLast(klass.parse, CmpOp.GTE));
- Expression.registerExpression("$lt", bindLast(klass.parse, CmpOp.LT));
- Expression.registerExpression("$lte", bindLast(klass.parse, CmpOp.LTE));
- Expression.registerExpression("$ne", bindLast(klass.parse, CmpOp.NE));
|