summaryrefslogtreecommitdiff
path: root/src/mongo/scripting/bson_template_evaluator.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/scripting/bson_template_evaluator.h')
-rw-r--r--src/mongo/scripting/bson_template_evaluator.h152
1 files changed, 152 insertions, 0 deletions
diff --git a/src/mongo/scripting/bson_template_evaluator.h b/src/mongo/scripting/bson_template_evaluator.h
new file mode 100644
index 00000000000..2c60df73514
--- /dev/null
+++ b/src/mongo/scripting/bson_template_evaluator.h
@@ -0,0 +1,152 @@
+/** @file templateevaluator.h */
+
+/*
+ * Copyright (C) 2012 10gen Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This library supports a templating language that helps in generating BSON documents from a
+ * template. The language supports the following template:
+ * #RAND_INT, #RAND_STRING and #CONCAT.
+ *
+ * The language will help in quickly expressing richer documents for use in benchRun.
+ * Ex. : { key : { #RAND_INT: [10, 20] } } or { key : { #CONCAT: ["hello", " ", "world"] } }
+ *
+ * Where possible, the templates can also be combined together and evaluated. For eg.
+ * { key : { #CONCAT: [{ #RAND_INT: [10, 20] }, " ", "world"] } }
+ *
+ * This library DOES NOT support combining or nesting the templates in an arbitrary fashion.
+ * eg. { key : { #RAND_INT: [{ #RAND_INT: [10, 15] }, 20] } } is not supported.
+ *
+ */
+#pragma once
+
+#include <map>
+#include <string>
+
+#include <boost/function.hpp>
+#include <boost/noncopyable.hpp>
+
+#include "mongo/db/jsobj.h"
+
+namespace mongo {
+
+ /*
+ * BsonTemplateEvaluator Object for evaluating the templates. The Object exposes
+ * methods to evaluate existing template operators (#RAND_INT) and add new template operators.
+ *
+ * To evaluate a template, call the object's 'evaluate' method and pass it as arguments, the
+ * template object that you want to evaluate and a BSONObjBuilder object that will contain the
+ * resultant BSON object. Eg.
+ *
+ * Status st = bsonTemplEvalObj->evaluate(inputTemplateObj, outputBSONObjBuilder)
+ *
+ * The 'evaluate' method will never throw an exception and will return an appropriate Status
+ * code on success/error scenario.
+ *
+ * High level working : The evaluate() method takes in a BSONObj as input, iterates over the
+ * BSON elements in the input BSONObj, and calls _evalElem() method. The _evalElem() method
+ * figures out the specific template and then calls the corresponding template function.
+ * The evaluated result is added to the BSONObjBuilder object and is returned to the evaluate()
+ * method.
+ *
+ */
+ class BsonTemplateEvaluator : private boost::noncopyable {
+ public:
+ /* Status of template evaluation. Logically the the status are "success", "bad operator"
+ * and "operation evaluation error." */
+ enum Status {
+ StatusSuccess = 0,
+ StatusBadOperator,
+ StatusOpEvaluationError
+ };
+
+ /*
+ * OperatorFn : function object wrappers that define a call interface.
+ * All template operators have this signature.
+ * @params btl : pointer to the BsonTemplateEvaluator Object
+ * fieldName : key of the object being evaluated
+ * in : the embedded BSONObj
+ * builder : the output BSONObj
+ * Eg. for object { key : { #RAND_INT: [10, 20] } }
+ * fieldName : key
+ * in : { #RAND_INT: [10, 20] }
+ */
+ typedef boost::function< Status (BsonTemplateEvaluator* btl, const char* fieldName,
+ const BSONObj& in, BSONObjBuilder& builder) > OperatorFn;
+
+ BsonTemplateEvaluator();
+ ~BsonTemplateEvaluator();
+
+ /*
+ * "Add a new operator, "name" with behavior "op" to this evaluator.
+ */
+ void addOperator(const std::string& name, const OperatorFn& op);
+
+ /*
+ * Returns the OperatorFn registered for the operator named "op", or
+ * OperatorFn() if there is no such operator.
+ */
+ OperatorFn operatorEvaluator(const std::string& op) const;
+
+ /* This is the top level method for using this library. It takes a BSON Object as input,
+ * evaluates the templates and saves the result in the builder object.
+ * The method returns a status code on success/error condition.
+ * The templates cannot be used at the top level.
+ * So this is okay as an input { key : {#RAND_INT: [10, 20]} }
+ * but not this { {#RAND_INT : [10, 20]} : some_value }
+ */
+ Status evaluate(const BSONObj& src, BSONObjBuilder& builder);
+
+ private:
+ void initializeEvaluator();
+ // map that holds operators along with their respective function pointers
+ typedef std::map< std::string, OperatorFn > OperatorMap;
+ OperatorMap _operatorFunctions;
+
+ // evaluates a BSON element. This is internally called by the top level evaluate method.
+ Status _evalElem(BSONElement in, BSONObjBuilder& out);
+
+ /*
+ * Operator method to support #RAND_INT : { key : { #RAND_INT: [10, 20] } }
+ * The array arguments to #RAND_INT are the min and mix range between which a random number
+ * will be chosen. The chosen random number is inclusive at the lower end but not at the
+ * upper end.
+ * This will evaluate to something like { key : 14 }
+ * #RAND_INT also supports a third optional argument which is a multiplier.
+ * Thus for an input { key : { #RAND_INT: [10, 20, 4] } }, the method will
+ * choose a random number between 10 and 20 and then multiple the chosen value with 4.
+ */
+ static Status evalRandInt(BsonTemplateEvaluator* btl, const char* fieldName,
+ const BSONObj in, BSONObjBuilder& out);
+ /*
+ * Operator method to support #RAND_STRING : { key : { #RAND_STRING: [12] } }
+ * The array argument to RAND_STRING is the length of the string that is desired.
+ * This will evaluate to something like { key : "randomstring" }
+ */
+ static Status evalRandString(BsonTemplateEvaluator* btl, const char* fieldName,
+ const BSONObj in, BSONObjBuilder& out);
+ /*
+ * Operator method to support #CONCAT : { key : { #CONCAT: ["hello", " ", "world", 2012] } }
+ * The array argument to CONCAT are the strings to be concatenated. If the argument is not
+ * a string it will be stringified and concatendated.
+ * This will evaluate to { key : "hello world2012" }
+ */
+ static Status evalConcat(BsonTemplateEvaluator* btl, const char* fieldName,
+ const BSONObj in, BSONObjBuilder& out);
+
+ };
+
+} // end namespace