瀏覽代碼

Merge pull request #55 from RiveraGroup/feature/mongo_2.6.5_matcher_TextMatchExpression

EAGLESIX-3004: Ported code; wrote text cases.
Chris Sexton 11 年之前
父節點
當前提交
dff560dc55

+ 9 - 3
lib/pipeline/matcher/MatchExpressionParser.js

@@ -32,6 +32,8 @@ var errors = require("../../Errors.js"),
 	AllElemMatchOp = require("./AllElemMatchOp.js"),
 	AtomicMatchExpression = require("./AtomicMatchExpression.js");
 
+proto.expressionParserTextCallback = require('./TextMatchExpressionParser').expressionParserTextCallbackReal;
+
 // The maximum allowed depth of a query tree. Just to guard against stack overflow.
 var MAXIMUM_TREE_DEPTH = 100;
 
@@ -149,10 +151,14 @@ proto._parse = function _parse(obj, level){
 				if (status.code != ErrorCodes.OK)
 					return status;
 				root.add(status.result);*/
+			} else if ('text' === rest) {
+				if (typeof currval !== 'object') {
+					return {code: ErrorCodes.BAD_VALUE, description: '$text expects an object'};
+				}
+
+				return this.expressionTextCallback(currval);
 			}
-			else if ("comment" == rest) {
-				1+1;
-			}
+			else if ("comment" == rest) {}
 			else {
 				return {code:ErrorCodes.BAD_VALUE, description:"unknown top level operator: " + currname};
 			}

+ 112 - 0
lib/pipeline/matcher/TextMatchExpression.js

@@ -0,0 +1,112 @@
+"use strict";
+
+var LeafMatchExpression = require('./LeafMatchExpression.js');
+
+var TextMatchExpression = module.exports = function TextMatchExpression() {
+	base.call(this, 'TEXT');
+}, klass = TextMatchExpression, base = LeafMatchExpression, proto = klass.prototype = Object.create(base.prototype, {constructor: {value: klass}});
+
+/**
+ *
+ * Initializes the class object.
+ *
+ * @param query
+ * @param language
+ * @returns {*}
+ */
+proto.init = function init(query, language) {
+	this._query = query;
+	this._language = language;
+
+	return this.initPath('_fts');
+};
+
+/**
+ * Gets the query.
+ *
+ * @returns {*}
+ */
+proto.getQuery = function getQuery() {
+	return this._query;
+};
+
+/**
+ * Gets the language.
+ *
+ * @returns {*}
+ */
+proto.getLanguage = function getLanguage() {
+	return this._language;
+};
+
+/**
+ * Check if the input element matches.
+ *
+ * @param e
+ * @returns {boolean}
+ */
+proto.matchesSingleElement = function matchesSingleElement(e) {
+	return true;
+};
+
+/**
+ * Debug a string.
+ *
+ * @param level
+ * @returns {string}
+ */
+proto.debugString = function debugString(level) {
+	var rtn = this._debugAddSpace(level);
+
+	rtn += 'TEXT : query=' + ', language=' + this._language + ', tag=';
+
+	var tagData = this.getTag();
+
+	if (tagData !== null) {
+		tagData.debugString(level);
+	} else {
+		rtn += 'NULL';
+	}
+
+	return rtn + '\n';
+};
+
+/**
+ * Verifies the equivalency of two operands.
+ *
+ * @param other
+ * @returns {boolean}
+ */
+proto.equivalent = function equivalent(other) {
+	if (this.matchType() !== other.matchType()) {
+		return false;
+	}
+
+	if (other.getQuery() !== this._query) {
+		return false;
+	}
+
+	if (other.getLanguage() !== this._language) {
+		return false;
+	}
+
+	return true;
+};
+
+/**
+ * Clone this instance into a new one.
+ *
+ * @returns {TextMatchExpression}
+ */
+proto.shallowClone = function shallowClone() {
+	var next = new TextMatchExpression();
+
+	next.init(this._query, this._language);
+
+	if (this.getTag()) {
+		next.getTag(this.getTag().clone());
+	}
+
+	return next;
+};
+

+ 25 - 0
lib/pipeline/matcher/TextMatchExpressionParser.js

@@ -0,0 +1,25 @@
+/**
+ * Expression parser's text callback function.
+ *
+ * @param queryObj
+ * @returns {*}
+ * @private
+ */
+var _expressionParserTextCallbackReal = function _expressionParserTextCallbackReal(queryObj) {
+	if (queryObj.$search._type !== 'string') {
+		return {code: ErrorCodes.BadValue, description: '$search needs a String'};
+	}
+
+	var e = new TextMatchExpression(),
+		s = e.init(query, language);
+
+	if (s.code !== 'OK') {
+		return s;
+	}
+
+	return e.release();
+};
+
+module.exports = {
+	expressionParserTextCallbackReal: _expressionParserTextCallbackReal
+};

+ 59 - 0
test/lib/pipeline/matcher/TextMatchExpression_test.js

@@ -0,0 +1,59 @@
+"use strict";
+
+var assert = require('assert'),
+	TextMatchExpression = require('../../../../lib/pipeline/matcher/TextMatchExpression.js'),
+	MatchDetails = require('../../../../lib/pipeline/matcher/MatchDetails.js');
+
+module.exports = {
+	'TextMatchExpression': {
+		'Should match an element, regardless of what is provided.': function() {
+			var text = new TextMatchExpression(),
+				text2 = new TextMatchExpression();
+
+			assert.strictEqual(text.init('query', 'language').code, 'OK');
+			assert.strictEqual(text2.init('query2', 'language2').code, 'OK');
+
+			assert.ok(text.matchesSingleElement(text2)); // It'll always work. Just the way it is in source.
+		},
+
+		'Should return the query provided in the init.': function() {
+			var text = new TextMatchExpression();
+
+			text.init('query', 'language');
+
+			assert.strictEqual(text.getQuery(), 'query');
+		},
+
+		'Should return the language provided in the init.': function() {
+			var text = new TextMatchExpression();
+
+			text.init('query', 'language');
+
+			assert.strictEqual(text.getLanguage(), 'language');
+		},
+
+		'Should return equivalency.': function() {
+			var text1 = new TextMatchExpression(),
+				text2 = new TextMatchExpression(),
+				text3 = new TextMatchExpression();
+
+			text1.init('query', 'language');
+			text2.init('query', 'language');
+			text3.init('query2', 'language2');
+
+			assert.ok(text1.equivalent(text1));
+			assert.ok(text1.equivalent(text2));
+			assert.ok(!text1.equivalent(text3));
+		},
+
+		'Should return a shallow copy of the original text match expression.': function() {
+			var text1 = new TextMatchExpression(),
+				status = text1.init('query', 'language'),
+				text2 = text1.shallowClone();
+
+			assert.ok(text1.equivalent(text2));
+		}
+	}
+};
+
+if (!module.parent)(new(require("mocha"))()).ui("exports").reporter("spec").addFile(__filename).run(process.exit);