|
|
@@ -20,6 +20,39 @@ var SetIsSubsetExpression = module.exports = function SetIsSubsetExpression() {
|
|
|
}
|
|
|
});
|
|
|
|
|
|
+
|
|
|
+var Optimized = function Optimized(cachedRhsSet, operands) {
|
|
|
+ this.operands = operands;
|
|
|
+}
|
|
|
+
|
|
|
+Optimized.prototype = Object.create(SetIsSubsetExpression.prototype, {
|
|
|
+ constructor: {
|
|
|
+ value: Optimized
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+Optimized.prototype.setIsSubsetHelper = function setIsSubsetHelper(vars){
|
|
|
+ // do not shortcircuit when lhs.size() > rhs.size()
|
|
|
+ // because lhs can have redundant entries
|
|
|
+ lhs.forEach(function (item){
|
|
|
+ if (! rhs.contains(item)){
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return true;
|
|
|
+};
|
|
|
+
|
|
|
+Optimized.prototype.evaluateInternal = function evaluateInternal(vars){
|
|
|
+ lhs = operands[0].evaluateInternal(vars);
|
|
|
+ rhs = operands[1].evaluateInternal(vars);
|
|
|
+
|
|
|
+ if (!(lhs instanceof Array)) throw new Error("uassert 17046: both operands of " + this.getOpName() + " must be arrays. Second argument is of type " + typeof lhs);
|
|
|
+ if (!(rhs instanceof Array)) throw new Error("uassert 17042: both operands of " + this.getOpName() + " must be arrays. Second argument is of type " + typeof rhs);
|
|
|
+
|
|
|
+ return setIsSubsetHelper(lhs, arrayToSet(rhs));
|
|
|
+};
|
|
|
+
|
|
|
// DEPENDENCIES
|
|
|
var Value = require("../Value"),
|
|
|
Expression = require("./Expression");
|
|
|
@@ -29,39 +62,51 @@ proto.getOpName = function getOpName() {
|
|
|
return "$setissubset";
|
|
|
};
|
|
|
|
|
|
+//Returns an object containing unique values. All keys are the same as the corresponding value.
|
|
|
+proto.arrayToSet = function arrayToSet(array){
|
|
|
+ var set = {};
|
|
|
+
|
|
|
+ // This ensures no duplicates.
|
|
|
+ array.forEach(function (element) {
|
|
|
+ var elementString = JSON.stringify(element);
|
|
|
+ set[elementString] = element;
|
|
|
+ });
|
|
|
+
|
|
|
+ return set;
|
|
|
+};
|
|
|
+
|
|
|
proto.optimize = function optimize(cachedRhsSet, operands) {
|
|
|
|
|
|
-// This optimize needs to be done, eventually
|
|
|
+ // perform basic optimizations
|
|
|
+ var optimized = this.optimize();
|
|
|
|
|
|
-// // perfore basic optimizations
|
|
|
-// intrusive_ptr<Expression> optimized = ExpressionNary::optimize();
|
|
|
+ // if NaryExoressuib.optimize() created a new value, return it directly
|
|
|
+ if(optimized != this){
|
|
|
+ return optimized;
|
|
|
+ }
|
|
|
|
|
|
-// // if ExpressionNary::optimize() created a new value, return it directly
|
|
|
-// if (optimized.get() != this)
|
|
|
-// return optimized;
|
|
|
+ if (operands[1] instanceof ConstantExpression){
|
|
|
+ var ce = operands[1],
|
|
|
+ rhs = ce.getValue();
|
|
|
|
|
|
-// if (ExpressionConstant* ec = dynamic_cast<ExpressionConstant*>(vpOperand[1].get())) {
|
|
|
-// const Value rhs = ec->getValue();
|
|
|
-// uassert(17311, str::stream() << "both operands of $setIsSubset must be arrays. Second "
|
|
|
-// << "argument is of type: " << typeName(rhs.getType()),
|
|
|
-// rhs.getType() == Array);
|
|
|
+ if (!(rhs instanceof Array)) throw new Error("uassert 17311: both operands of " + this.getOpName() + " must be arrays. Second argument is of type " + typeof rhs);
|
|
|
|
|
|
-// return new Optimized(arrayToSet(rhs), vpOperand);
|
|
|
-// }
|
|
|
+ return new Optimized(proto.arrayToSet(rhs), operands);
|
|
|
+ }
|
|
|
|
|
|
-// return optimized;
|
|
|
+ return optimized;
|
|
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
- * Takes 2 arrays. Assigns the second array to the first array.
|
|
|
+ * Takes 2 arrays. Returns true if the second is a subset of the first. Returns false otherwise.
|
|
|
* @method evaluateInternal
|
|
|
**/
|
|
|
proto.evaluateInternal = function evaluateInternal(vars) {
|
|
|
var array1 = this.operands[0].evaluateInternal(vars),
|
|
|
array2 = this.operands[1].evaluateInternal(vars);
|
|
|
- if (array1 instanceof Array) throw new Error(this.getOpName() + ": object 1 must be an array");
|
|
|
- if (array2 instanceof Array) throw new Error(this.getOpName() + ": object 2 must be an array");
|
|
|
+ if (!(array1 instanceof Array)) throw new Error(this.getOpName() + ": object 1 must be an array. Got a(n) " + typeof array1);
|
|
|
+ if (!(array2 instanceof Array)) throw new Error(this.getOpName() + ": object 2 must be an array. Got a(n) " + typeof array1);
|
|
|
|
|
|
var sizeOfArray1 = array1.length;
|
|
|
var sizeOfArray2 = array2.length;
|