Permalink
Browse files

Implemented support for LINQ queries involving string length.

  • Loading branch information...
1 parent e2e5ecb commit 12f9bfcc97c5f72b535b7832a1e1958db2d6a02f Robert Stam committed Apr 7, 2012
Showing with 178 additions and 2 deletions.
  1. +60 −0 Driver/Linq/Translators/SelectQuery.cs
  2. +118 −2 DriverUnitTests/Linq/SelectQueryTests.cs
@@ -361,6 +361,12 @@ private IMongoQuery BuildComparisonQuery(BinaryExpression binaryExpression)
return query;
}
+ query = BuildStringLengthQuery(variableExpression, operatorType, constantExpression);
+ if (query != null)
+ {
+ return query;
+ }
+
BsonSerializationInfo serializationInfo = null;
var value = constantExpression.Value;
@@ -744,6 +750,60 @@ private IMongoQuery BuildQuery(Expression expression)
return query;
}
+ private IMongoQuery BuildStringLengthQuery(Expression variableExpression, ExpressionType operatorType, ConstantExpression constantExpression)
+ {
+ if (constantExpression.Type != typeof(int))
+ {
+ return null;
+ }
+
+ BsonSerializationInfo serializationInfo = null;
+ var value = ToInt32(constantExpression);
+
+ var lengthPropertyExpression = variableExpression as MemberExpression;
+ if (lengthPropertyExpression != null)
+ {
+ if (lengthPropertyExpression.Member.Name == "Length")
+ {
+ var memberExpression = lengthPropertyExpression.Expression as MemberExpression;
+ if (memberExpression != null)
+ {
+ serializationInfo = GetSerializationInfo(memberExpression);
+ if (serializationInfo != null && serializationInfo.NominalType != typeof(string))
+ {
+ serializationInfo = null;
+ }
+ }
+ }
+ }
+
+ if (serializationInfo != null)
+ {
+ string regex = null;
+ switch (operatorType)
+ {
+ case ExpressionType.NotEqual: case ExpressionType.Equal: regex = @"/^.{" + value.ToString() + "}$/s"; break;
+ case ExpressionType.GreaterThan: regex = @"/^.{" + (value + 1).ToString() + ",}$/s"; break;
+ case ExpressionType.GreaterThanOrEqual: regex = @"/^.{" + value.ToString() + ",}$/s"; break;
+ case ExpressionType.LessThan: regex = @"/^.{0," + (value - 1).ToString() + "}$/s"; break;
+ case ExpressionType.LessThanOrEqual: regex = @"/^.{0," + value.ToString() + "}$/s"; break;
+ }
+ if (regex != null)
+ {
+ if (operatorType == ExpressionType.NotEqual)
+ {
+ return Query.Not(serializationInfo.ElementName).Matches(regex);
+ }
+ else
+ {
+ return Query.Matches(serializationInfo.ElementName, regex);
+ }
+ }
+ }
+
+ return null;
+ }
+
private IMongoQuery BuildStringQuery(MethodCallExpression methodCallExpression)
{
if (methodCallExpression.Method.DeclaringType == typeof(string))
@@ -153,7 +153,7 @@ public void Setup()
_collection.Insert(new C { Id = _id1, X = 1, Y = 11, D = new D { Z = 11 }, S = "abc", SA = new string[] { "Tom", "Dick", "Harry" } });
_collection.Insert(new C { Id = _id3, X = 3, Y = 33, D = new D { Z = 33 }, B = true, BA = new bool[] { true }, E = E.A, EA = new E[] { E.A, E.B } });
_collection.Insert(new C { Id = _id5, X = 5, Y = 44, D = new D { Z = 55 }, DBRef = new MongoDBRef("db", "c", 1) });
- _collection.Insert(new C { Id = _id4, X = 4, Y = 44, D = new D { Z = 44 } });
+ _collection.Insert(new C { Id = _id4, X = 4, Y = 44, D = new D { Z = 44 }, S = " xyz " });
}
[Test]
@@ -517,8 +517,9 @@ public void TestDistinctS()
var query = (from c in _collection.AsQueryable<C>()
select c.S).Distinct();
var results = query.ToList();
- Assert.AreEqual(1, results.Count);
+ Assert.AreEqual(2, results.Count);
Assert.IsTrue(results.Contains("abc"));
+ Assert.IsTrue(results.Contains(" xyz "));
}
[Test]
@@ -4422,6 +4423,121 @@ where Regex.IsMatch(c.S, "^abc", RegexOptions.IgnoreCase)
}
[Test]
+ public void TestWhereSLengthEquals3()
+ {
+ var query = from c in _collection.AsQueryable<C>()
+ where c.S.Length == 3
+ select c;
+
+ var translatedQuery = MongoQueryTranslator.Translate(query);
+ Assert.IsInstanceOf<SelectQuery>(translatedQuery);
+ Assert.AreSame(_collection, translatedQuery.Collection);
+ Assert.AreSame(typeof(C), translatedQuery.DocumentType);
+
+ var selectQuery = (SelectQuery)translatedQuery;
+ Assert.AreEqual("(C c) => (c.S.Length == 3)", ExpressionFormatter.ToString(selectQuery.Where));
+ Assert.IsNull(selectQuery.OrderBy);
+ Assert.IsNull(selectQuery.Projection);
+ Assert.IsNull(selectQuery.Skip);
+ Assert.IsNull(selectQuery.Take);
+
+ Assert.AreEqual("{ \"s\" : /^.{3}$/s }", selectQuery.BuildQuery().ToJson());
+ Assert.AreEqual(1, Consume(query));
+ }
+
+ [Test]
+ public void TestWhereSLengthGreaterThan3()
+ {
+ var query = from c in _collection.AsQueryable<C>()
+ where c.S.Length > 3
+ select c;
+
+ var translatedQuery = MongoQueryTranslator.Translate(query);
+ Assert.IsInstanceOf<SelectQuery>(translatedQuery);
+ Assert.AreSame(_collection, translatedQuery.Collection);
+ Assert.AreSame(typeof(C), translatedQuery.DocumentType);
+
+ var selectQuery = (SelectQuery)translatedQuery;
+ Assert.AreEqual("(C c) => (c.S.Length > 3)", ExpressionFormatter.ToString(selectQuery.Where));
+ Assert.IsNull(selectQuery.OrderBy);
+ Assert.IsNull(selectQuery.Projection);
+ Assert.IsNull(selectQuery.Skip);
+ Assert.IsNull(selectQuery.Take);
+
+ Assert.AreEqual("{ \"s\" : /^.{4,}$/s }", selectQuery.BuildQuery().ToJson());
+ Assert.AreEqual(1, Consume(query));
+ }
+
+ [Test]
+ public void TestWhereSLengthGreaterThanOrEquals3()
+ {
+ var query = from c in _collection.AsQueryable<C>()
+ where c.S.Length >= 3
+ select c;
+
+ var translatedQuery = MongoQueryTranslator.Translate(query);
+ Assert.IsInstanceOf<SelectQuery>(translatedQuery);
+ Assert.AreSame(_collection, translatedQuery.Collection);
+ Assert.AreSame(typeof(C), translatedQuery.DocumentType);
+
+ var selectQuery = (SelectQuery)translatedQuery;
+ Assert.AreEqual("(C c) => (c.S.Length >= 3)", ExpressionFormatter.ToString(selectQuery.Where));
+ Assert.IsNull(selectQuery.OrderBy);
+ Assert.IsNull(selectQuery.Projection);
+ Assert.IsNull(selectQuery.Skip);
+ Assert.IsNull(selectQuery.Take);
+
+ Assert.AreEqual("{ \"s\" : /^.{3,}$/s }", selectQuery.BuildQuery().ToJson());
+ Assert.AreEqual(2, Consume(query));
+ }
+
+ [Test]
+ public void TestWhereSLengthLessThan3()
+ {
+ var query = from c in _collection.AsQueryable<C>()
+ where c.S.Length < 3
+ select c;
+
+ var translatedQuery = MongoQueryTranslator.Translate(query);
+ Assert.IsInstanceOf<SelectQuery>(translatedQuery);
+ Assert.AreSame(_collection, translatedQuery.Collection);
+ Assert.AreSame(typeof(C), translatedQuery.DocumentType);
+
+ var selectQuery = (SelectQuery)translatedQuery;
+ Assert.AreEqual("(C c) => (c.S.Length < 3)", ExpressionFormatter.ToString(selectQuery.Where));
+ Assert.IsNull(selectQuery.OrderBy);
+ Assert.IsNull(selectQuery.Projection);
+ Assert.IsNull(selectQuery.Skip);
+ Assert.IsNull(selectQuery.Take);
+
+ Assert.AreEqual("{ \"s\" : /^.{0,2}$/s }", selectQuery.BuildQuery().ToJson());
+ Assert.AreEqual(0, Consume(query));
+ }
+
+ [Test]
+ public void TestWhereSLengthLessThanOrEquals3()
+ {
+ var query = from c in _collection.AsQueryable<C>()
+ where c.S.Length <= 3
+ select c;
+
+ var translatedQuery = MongoQueryTranslator.Translate(query);
+ Assert.IsInstanceOf<SelectQuery>(translatedQuery);
+ Assert.AreSame(_collection, translatedQuery.Collection);
+ Assert.AreSame(typeof(C), translatedQuery.DocumentType);
+
+ var selectQuery = (SelectQuery)translatedQuery;
+ Assert.AreEqual("(C c) => (c.S.Length <= 3)", ExpressionFormatter.ToString(selectQuery.Where));
+ Assert.IsNull(selectQuery.OrderBy);
+ Assert.IsNull(selectQuery.Projection);
+ Assert.IsNull(selectQuery.Skip);
+ Assert.IsNull(selectQuery.Take);
+
+ Assert.AreEqual("{ \"s\" : /^.{0,3}$/s }", selectQuery.BuildQuery().ToJson());
+ Assert.AreEqual(1, Consume(query));
+ }
+
+ [Test]
public void TestWhereSStartsWithAbc()
{
var query = from c in _collection.AsQueryable<C>()

0 comments on commit 12f9bfc

Please sign in to comment.