Skip to content

Commit 72a6214

Browse files
Robert Stamcraiggwilson
authored andcommitted
CSHARP-516: Support Int64 values when using % operator in LINQ queries.
1 parent 3d8d92a commit 72a6214

File tree

5 files changed

+280
-14
lines changed

5 files changed

+280
-14
lines changed

Driver/Builders/QueryBuilder.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,14 +283,23 @@ public static IMongoQuery Matches(string name, BsonRegularExpression regex)
283283
/// <param name="modulus">The modulus.</param>
284284
/// <param name="value">The value.</param>
285285
/// <returns>An IMongoQuery.</returns>
286-
public static IMongoQuery Mod(string name, int modulus, int value)
286+
public static IMongoQuery Mod(string name, long modulus, long value)
287287
{
288288
if (name == null)
289289
{
290290
throw new ArgumentNullException("name");
291291
}
292292

293-
var condition = new BsonDocument("$mod", new BsonArray { modulus, value });
293+
BsonDocument condition;
294+
if (modulus >= int.MinValue && modulus <= int.MaxValue &&
295+
value >= int.MinValue && value <= int.MaxValue)
296+
{
297+
condition = new BsonDocument("$mod", new BsonArray { (int)modulus, (int)value });
298+
}
299+
else
300+
{
301+
condition = new BsonDocument("$mod", new BsonArray { modulus, value });
302+
}
294303
return new QueryDocument(name, condition);
295304
}
296305

Driver/Builders/QueryBuilderTyped.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ public static IMongoQuery Matches(Expression<Func<TDocument, IEnumerable<string>
241241
/// <param name="modulus">The modulus.</param>
242242
/// <param name="value">The value.</param>
243243
/// <returns>An IMongoQuery.</returns>
244-
public static IMongoQuery Mod(Expression<Func<TDocument, int>> memberExpression, int modulus, int value)
244+
public static IMongoQuery Mod(Expression<Func<TDocument, int>> memberExpression, long modulus, long value)
245245
{
246246
return new QueryBuilder<TDocument>().Mod(memberExpression, modulus, value);
247247
}
@@ -253,7 +253,7 @@ public static IMongoQuery Mod(Expression<Func<TDocument, int>> memberExpression,
253253
/// <param name="modulus">The modulus.</param>
254254
/// <param name="value">The value.</param>
255255
/// <returns>An IMongoQuery.</returns>
256-
public static IMongoQuery Mod(Expression<Func<TDocument, IEnumerable<int>>> memberExpression, int modulus, int value)
256+
public static IMongoQuery Mod(Expression<Func<TDocument, IEnumerable<int>>> memberExpression, long modulus, long value)
257257
{
258258
return new QueryBuilder<TDocument>().Mod(memberExpression, modulus, value);
259259
}
@@ -873,7 +873,7 @@ public IMongoQuery Matches(Expression<Func<TDocument, IEnumerable<string>>> memb
873873
/// <param name="modulus">The modulus.</param>
874874
/// <param name="value">The value.</param>
875875
/// <returns>An IMongoQuery.</returns>
876-
public IMongoQuery Mod(Expression<Func<TDocument, int>> memberExpression, int modulus, int value)
876+
public IMongoQuery Mod(Expression<Func<TDocument, int>> memberExpression, long modulus, long value)
877877
{
878878
if (memberExpression == null)
879879
{
@@ -891,7 +891,7 @@ public IMongoQuery Mod(Expression<Func<TDocument, int>> memberExpression, int mo
891891
/// <param name="modulus">The modulus.</param>
892892
/// <param name="value">The value.</param>
893893
/// <returns>An IMongoQuery.</returns>
894-
public IMongoQuery Mod(Expression<Func<TDocument, IEnumerable<int>>> memberExpression, int modulus, int value)
894+
public IMongoQuery Mod(Expression<Func<TDocument, IEnumerable<int>>> memberExpression, long modulus, long value)
895895
{
896896
if (memberExpression == null)
897897
{

Driver/Linq/Translators/PredicateTranslator.cs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -755,11 +755,11 @@ private IMongoQuery BuildModQuery(Expression variableExpression, ExpressionType
755755
return null;
756756
}
757757

758-
if (constantExpression.Type != typeof(int))
758+
if (constantExpression.Type != typeof(int) && constantExpression.Type != typeof(long))
759759
{
760760
return null;
761761
}
762-
var value = ToInt32(constantExpression);
762+
var value = ToInt64(constantExpression);
763763

764764
var modBinaryExpression = variableExpression as BinaryExpression;
765765
if (modBinaryExpression != null && modBinaryExpression.NodeType == ExpressionType.Modulo)
@@ -768,7 +768,7 @@ private IMongoQuery BuildModQuery(Expression variableExpression, ExpressionType
768768
var modulusExpression = modBinaryExpression.Right as ConstantExpression;
769769
if (modulusExpression != null)
770770
{
771-
var modulus = ToInt32(modulusExpression);
771+
var modulus = ToInt64(modulusExpression);
772772
if (operatorType == ExpressionType.Equal)
773773
{
774774
return Query.Mod(serializationInfo.ElementName, modulus, value);
@@ -1390,5 +1390,28 @@ private int ToInt32(Expression expression)
13901390

13911391
return (int)constantExpression.Value;
13921392
}
1393+
1394+
private long ToInt64(Expression expression)
1395+
{
1396+
if (expression.Type != typeof(int) && expression.Type != typeof(long))
1397+
{
1398+
throw new ArgumentOutOfRangeException("expression", "Expected an Expression of Type Int32 or Int64.");
1399+
}
1400+
1401+
var constantExpression = expression as ConstantExpression;
1402+
if (constantExpression == null)
1403+
{
1404+
throw new ArgumentOutOfRangeException("expression", "Expected a ConstantExpression.");
1405+
}
1406+
1407+
if (expression.Type == typeof(int))
1408+
{
1409+
return (long)(int)constantExpression.Value;
1410+
}
1411+
else
1412+
{
1413+
return (long)constantExpression.Value;
1414+
}
1415+
}
13931416
}
13941417
}

DriverUnitTests/Linq/SelectQueryTests.cs

Lines changed: 122 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ public class C
4343
public ObjectId Id { get; set; }
4444
[BsonElement("x")]
4545
public int X { get; set; }
46+
[BsonElement("lx")]
47+
public long LX { get; set; }
4648
[BsonElement("y")]
4749
public int Y { get; set; }
4850
[BsonElement("d")]
@@ -150,11 +152,11 @@ public void Setup()
150152

151153
// documents inserted deliberately out of order to test sorting
152154
_collection.Drop();
153-
_collection.Insert(new C { Id = _id2, X = 2, Y = 11, D = new D { Z = 22 }, A = new [] { 2, 3, 4 }, DA = new List<D> { new D { Z = 111 }, new D { Z = 222 } }, L = new List<int> { 2, 3, 4 } });
154-
_collection.Insert(new C { Id = _id1, X = 1, Y = 11, D = new D { Z = 11 }, S = "abc", SA = new string[] { "Tom", "Dick", "Harry" } });
155-
_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 } });
156-
_collection.Insert(new C { Id = _id5, X = 5, Y = 44, D = new D { Z = 55 }, DBRef = new MongoDBRef("db", "c", 1) });
157-
_collection.Insert(new C { Id = _id4, X = 4, Y = 44, D = new D { Z = 44 }, S = " xyz ", DA = new List<D> { new D { Z = 333 }, new D { Z = 444 } } });
155+
_collection.Insert(new C { Id = _id2, X = 2, LX = 2, Y = 11, D = new D { Z = 22 }, A = new[] { 2, 3, 4 }, DA = new List<D> { new D { Z = 111 }, new D { Z = 222 } }, L = new List<int> { 2, 3, 4 } });
156+
_collection.Insert(new C { Id = _id1, X = 1, LX = 1, Y = 11, D = new D { Z = 11 }, S = "abc", SA = new string[] { "Tom", "Dick", "Harry" } });
157+
_collection.Insert(new C { Id = _id3, X = 3, LX = 3, Y = 33, D = new D { Z = 33 }, B = true, BA = new bool[] { true }, E = E.A, EA = new E[] { E.A, E.B } });
158+
_collection.Insert(new C { Id = _id5, X = 5, LX = 5, Y = 44, D = new D { Z = 55 }, DBRef = new MongoDBRef("db", "c", 1) });
159+
_collection.Insert(new C { Id = _id4, X = 4, LX = 4, Y = 44, D = new D { Z = 44 }, S = " xyz ", DA = new List<D> { new D { Z = 333 }, new D { Z = 444 } } });
158160
}
159161

160162
[Test]
@@ -4046,6 +4048,121 @@ public void TestWhereLSub1NotEquals3Not()
40464048
Assert.AreEqual(1, Consume(query));
40474049
}
40484050

4051+
[Test]
4052+
public void TestWhereLXModTwoEquals1()
4053+
{
4054+
var query = from c in _collection.AsQueryable<C>()
4055+
where c.LX % 2 == 1
4056+
select c;
4057+
4058+
var translatedQuery = MongoQueryTranslator.Translate(query);
4059+
Assert.IsInstanceOf<SelectQuery>(translatedQuery);
4060+
Assert.AreSame(_collection, translatedQuery.Collection);
4061+
Assert.AreSame(typeof(C), translatedQuery.DocumentType);
4062+
4063+
var selectQuery = (SelectQuery)translatedQuery;
4064+
Assert.AreEqual("(C c) => ((c.LX % 2) == 1)", ExpressionFormatter.ToString(selectQuery.Where));
4065+
Assert.IsNull(selectQuery.OrderBy);
4066+
Assert.IsNull(selectQuery.Projection);
4067+
Assert.IsNull(selectQuery.Skip);
4068+
Assert.IsNull(selectQuery.Take);
4069+
4070+
Assert.AreEqual("{ \"lx\" : { \"$mod\" : [2, 1] } }", selectQuery.BuildQuery().ToJson());
4071+
Assert.AreEqual(3, Consume(query));
4072+
}
4073+
4074+
[Test]
4075+
public void TestWhereLXModTwoEquals1Not()
4076+
{
4077+
var query = from c in _collection.AsQueryable<C>()
4078+
where !(c.LX % 2 == 1)
4079+
select c;
4080+
4081+
var translatedQuery = MongoQueryTranslator.Translate(query);
4082+
Assert.IsInstanceOf<SelectQuery>(translatedQuery);
4083+
Assert.AreSame(_collection, translatedQuery.Collection);
4084+
Assert.AreSame(typeof(C), translatedQuery.DocumentType);
4085+
4086+
var selectQuery = (SelectQuery)translatedQuery;
4087+
Assert.AreEqual("(C c) => !((c.LX % 2) == 1)", ExpressionFormatter.ToString(selectQuery.Where));
4088+
Assert.IsNull(selectQuery.OrderBy);
4089+
Assert.IsNull(selectQuery.Projection);
4090+
Assert.IsNull(selectQuery.Skip);
4091+
Assert.IsNull(selectQuery.Take);
4092+
4093+
Assert.AreEqual("{ \"lx\" : { \"$not\" : { \"$mod\" : [2, 1] } } }", selectQuery.BuildQuery().ToJson());
4094+
Assert.AreEqual(2, Consume(query));
4095+
}
4096+
4097+
[Test]
4098+
public void TestWhereLXModTwoEquals1Reversed()
4099+
{
4100+
var query = from c in _collection.AsQueryable<C>()
4101+
where 1 == c.LX % 2
4102+
select c;
4103+
4104+
var translatedQuery = MongoQueryTranslator.Translate(query);
4105+
Assert.IsInstanceOf<SelectQuery>(translatedQuery);
4106+
Assert.AreSame(_collection, translatedQuery.Collection);
4107+
Assert.AreSame(typeof(C), translatedQuery.DocumentType);
4108+
4109+
var selectQuery = (SelectQuery)translatedQuery;
4110+
Assert.AreEqual("(C c) => ((c.LX % 2) == 1)", ExpressionFormatter.ToString(selectQuery.Where));
4111+
Assert.IsNull(selectQuery.OrderBy);
4112+
Assert.IsNull(selectQuery.Projection);
4113+
Assert.IsNull(selectQuery.Skip);
4114+
Assert.IsNull(selectQuery.Take);
4115+
4116+
Assert.AreEqual("{ \"lx\" : { \"$mod\" : [2, 1] } }", selectQuery.BuildQuery().ToJson());
4117+
Assert.AreEqual(3, Consume(query));
4118+
}
4119+
4120+
[Test]
4121+
public void TestWhereLXModTwoNotEquals1()
4122+
{
4123+
var query = from c in _collection.AsQueryable<C>()
4124+
where c.LX % 2 != 1
4125+
select c;
4126+
4127+
var translatedQuery = MongoQueryTranslator.Translate(query);
4128+
Assert.IsInstanceOf<SelectQuery>(translatedQuery);
4129+
Assert.AreSame(_collection, translatedQuery.Collection);
4130+
Assert.AreSame(typeof(C), translatedQuery.DocumentType);
4131+
4132+
var selectQuery = (SelectQuery)translatedQuery;
4133+
Assert.AreEqual("(C c) => ((c.LX % 2) != 1)", ExpressionFormatter.ToString(selectQuery.Where));
4134+
Assert.IsNull(selectQuery.OrderBy);
4135+
Assert.IsNull(selectQuery.Projection);
4136+
Assert.IsNull(selectQuery.Skip);
4137+
Assert.IsNull(selectQuery.Take);
4138+
4139+
Assert.AreEqual("{ \"lx\" : { \"$not\" : { \"$mod\" : [2, 1] } } }", selectQuery.BuildQuery().ToJson());
4140+
Assert.AreEqual(2, Consume(query));
4141+
}
4142+
4143+
[Test]
4144+
public void TestWhereLXModTwoNotEquals1Not()
4145+
{
4146+
var query = from c in _collection.AsQueryable<C>()
4147+
where !(c.LX % 2 != 1)
4148+
select c;
4149+
4150+
var translatedQuery = MongoQueryTranslator.Translate(query);
4151+
Assert.IsInstanceOf<SelectQuery>(translatedQuery);
4152+
Assert.AreSame(_collection, translatedQuery.Collection);
4153+
Assert.AreSame(typeof(C), translatedQuery.DocumentType);
4154+
4155+
var selectQuery = (SelectQuery)translatedQuery;
4156+
Assert.AreEqual("(C c) => !((c.LX % 2) != 1)", ExpressionFormatter.ToString(selectQuery.Where));
4157+
Assert.IsNull(selectQuery.OrderBy);
4158+
Assert.IsNull(selectQuery.Projection);
4159+
Assert.IsNull(selectQuery.Skip);
4160+
Assert.IsNull(selectQuery.Take);
4161+
4162+
Assert.AreEqual("{ \"lx\" : { \"$mod\" : [2, 1] } }", selectQuery.BuildQuery().ToJson());
4163+
Assert.AreEqual(3, Consume(query));
4164+
}
4165+
40494166
[Test]
40504167
public void TestWhereSASub0ContainsO()
40514168
{

0 commit comments

Comments
 (0)