|
@@ -0,0 +1,192 @@
|
|
|
|
|
+"use strict";
|
|
|
|
|
+
|
|
|
|
|
+var WhereMatchExpression = module.exports = function WhereMatchExpression( txn ){
|
|
|
|
|
+ this._txn = txn;
|
|
|
|
|
+ this._matchType = 'MATCH_WHERE';
|
|
|
|
|
+}, klass = WhereMatchExpression, base = Object, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
|
|
|
|
|
+
|
|
|
|
|
+// DEPENDENCIES
|
|
|
|
|
+var errors = require("../../Errors.js"),
|
|
|
|
|
+ ErrorCodes = errors.ErrorCodes,
|
|
|
|
|
+ MatchExpression = require("./MatchExpression.js"),
|
|
|
|
|
+ MatchExpressionParser = require("./MatchExpressionParser.js");
|
|
|
|
|
+
|
|
|
|
|
+proto._txn = undefined;
|
|
|
|
|
+proto._func = 0;
|
|
|
|
|
+proto._dbName = undefined;
|
|
|
|
|
+proto._ns = undefined;
|
|
|
|
|
+proto._code = undefined;
|
|
|
|
|
+proto._userScope = undefined;
|
|
|
|
|
+proto._scope = undefined;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ *
|
|
|
|
|
+ * Initialize the necessary items
|
|
|
|
|
+ * @method init
|
|
|
|
|
+ * @param dbName
|
|
|
|
|
+ * @param theCode
|
|
|
|
|
+ * @param scope
|
|
|
|
|
+ *
|
|
|
|
|
+ */
|
|
|
|
|
+proto.init = function init(dbName, theCode, scope) {
|
|
|
|
|
+ if ( dbName === undefined ) {
|
|
|
|
|
+ return {'code':'BAD_VALUE', 'description':'ns for $where cannot be empty'};
|
|
|
|
|
+ }
|
|
|
|
|
+ if ( theCode === undefined ) {
|
|
|
|
|
+ return {'code':'BAD_VALUE', 'description':'code for $where cannot be empty'};
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this._dbName = dbName;
|
|
|
|
|
+ this._code = theCode;
|
|
|
|
|
+
|
|
|
|
|
+ // TODO: Not implementing for now.
|
|
|
|
|
+
|
|
|
|
|
+ this._userScope = scope.getOwned();
|
|
|
|
|
+ var userToken = this.getAuthorizationSession().getAuthenticatedUserNamesToken();
|
|
|
|
|
+ this._scope = this.globalScriptEngine.getPooledScope(this._txn, this._dbName, "where" + userToken);
|
|
|
|
|
+ this._func = this._scope.createFunction( this._code.c_str() );
|
|
|
|
|
+ if ( !this._func) {
|
|
|
|
|
+ return {'code':'BAD_VALUE', 'description':'$where compile error'};
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return {'code':'OK'};
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ *
|
|
|
|
|
+ * Matches the necessary items
|
|
|
|
|
+ * @method matches
|
|
|
|
|
+ * @param doc
|
|
|
|
|
+ * @param details
|
|
|
|
|
+ *
|
|
|
|
|
+ */
|
|
|
|
|
+proto.matches = function matches(doc, details) {
|
|
|
|
|
+ var obj = JSON.stringify(doc);
|
|
|
|
|
+
|
|
|
|
|
+ if ( this._userScope === undefined ){
|
|
|
|
|
+ this._scope.init( this._userScope);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this._scope.obj = obj;
|
|
|
|
|
+ this._scope.fullObject = true;
|
|
|
|
|
+
|
|
|
|
|
+ var err = this._scope.invoke( this._func, 0, obj, 1000 * 60, false);
|
|
|
|
|
+ if ( err == -3) { // INVOKE_ERROR
|
|
|
|
|
+ var ss = "error on invocation of $where funciton:\n" + this._scope.getError();
|
|
|
|
|
+ throw new Error(ss);
|
|
|
|
|
+ } else if ( err !== 0 ) {
|
|
|
|
|
+ throw new Error("unknown error in invocation of $where function")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return this._scope.__returnValue !== 0;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ *
|
|
|
|
|
+ * Call the debugString method
|
|
|
|
|
+ * @method toString
|
|
|
|
|
+ *
|
|
|
|
|
+ */
|
|
|
|
|
+proto.debugString = function debugString(level){
|
|
|
|
|
+ return this._debugAddSpace( level ) + "$where\n"
|
|
|
|
|
+ + this._debugAddSpace( level + 1 ) + "dbName: " + this._dbName + "\n"
|
|
|
|
|
+ + this._debugAddSpace( level + 1 ) + "code: " + this._code + "\n"
|
|
|
|
|
+ + this._debugAddSpace( level + 1 ) + "scope: " + this._userScope + "\n";
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ *
|
|
|
|
|
+ * Return evaluation of comparison result of equivalence.
|
|
|
|
|
+ * @method equivalent
|
|
|
|
|
+ * @param level
|
|
|
|
|
+ *
|
|
|
|
|
+ */
|
|
|
|
|
+proto.equivalent = function equivalent(other){
|
|
|
|
|
+
|
|
|
|
|
+ if ( other._matchType != 'MATCH_WHERE' ) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ return this._ns === other._ns &&
|
|
|
|
|
+ this._code === other._code &&
|
|
|
|
|
+ this._userScope === other._userScope;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+proto.expressionParserWhereCallbackReal = function expressionParserWhereCallbackReal(where){
|
|
|
|
|
+ if ( !this.haveClient() ){
|
|
|
|
|
+ return {'code':'NO_CLIENT_CONTEXT', 'description':'no context in $where parsing'};
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var context = this.cc().getContext();
|
|
|
|
|
+ if ( !context ) {
|
|
|
|
|
+ return {'code':'BAD_VALUE', 'description':'no ns in $where parsing'};
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ( !this.globalScrioptEngine ) {
|
|
|
|
|
+ return {'code':'BAD_VALUE', 'description':'no globalScriptEngine in $where parsing'};
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var exp = new WhereMatchExpression();
|
|
|
|
|
+ if ( typeof where === 'string' || typeof where === 'code' ){
|
|
|
|
|
+ var s = this.exp.init( ns, where, {} );
|
|
|
|
|
+ if ( !s.isOK() ) {
|
|
|
|
|
+ return this.StatusWithMatchExpression( s );
|
|
|
|
|
+ }
|
|
|
|
|
+ return this.StatusWithMatchExpression( this.exp.release() );
|
|
|
|
|
+ }
|
|
|
|
|
+ return this.StatusWithMatchExpression( {'code':'BAD_VALUE', 'description':'$where got bad type'} );
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ *
|
|
|
|
|
+ * Writes a debug string for this object
|
|
|
|
|
+ * @method debugString
|
|
|
|
|
+ * @param level
|
|
|
|
|
+ *
|
|
|
|
|
+ */
|
|
|
|
|
+proto._debugAddSpace = function _debugAddSpace(level){
|
|
|
|
|
+ return new Array( level + 1).join(" ");
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ *
|
|
|
|
|
+ * Reset and return the _tagData property
|
|
|
|
|
+ * @method resetTag
|
|
|
|
|
+ *
|
|
|
|
|
+ */
|
|
|
|
|
+proto.resetTag = function resetTag(){
|
|
|
|
|
+ this.setTag(null);
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ *
|
|
|
|
|
+ * Check if the input element matches
|
|
|
|
|
+ * @method matchesSingleElement
|
|
|
|
|
+ * @param e
|
|
|
|
|
+ *
|
|
|
|
|
+ */
|
|
|
|
|
+proto.matchesSingleElement = function matchesSingleElement(e) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ *
|
|
|
|
|
+ * clone this instance to a new one
|
|
|
|
|
+ * @method shallowClone
|
|
|
|
|
+ *
|
|
|
|
|
+ */
|
|
|
|
|
+proto.shallowClone = function shallowClone(){
|
|
|
|
|
+ var e = new WhereMatchExpression(this._txn);
|
|
|
|
|
+ e.init(this._dbName, this._code, this._userScope);
|
|
|
|
|
+ if ( this.getTag() ){
|
|
|
|
|
+ e.setTag(this.getTag().clone());
|
|
|
|
|
+ }
|
|
|
|
|
+ return e;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+TODO: MONGO_INITIALIZER is not impelemented.
|
|
|
|
|
+*/
|