Skip to content

Commit f5f7c86

Browse files
author
Robert Stam
committed
Partial work on CSHARP-431. Allow constant to appear on either side of comparison operator in LINQ queries.
1 parent 1419274 commit f5f7c86

File tree

2 files changed

+334
-96
lines changed

2 files changed

+334
-96
lines changed

Driver/Linq/Translators/SelectQuery.cs

Lines changed: 97 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -240,79 +240,78 @@ private IMongoQuery BuildAnyQuery(MethodCallExpression methodCallExpression)
240240

241241
private IMongoQuery BuildArrayLengthQuery(BinaryExpression binaryExpression)
242242
{
243-
var leftUnaryExpression = binaryExpression.Left as UnaryExpression;
244-
if (leftUnaryExpression != null)
243+
// the constant could be on either side (but only == and != are supported and they don't need to be flipped)
244+
var variableExpression = binaryExpression.Left;
245+
var constantExpression = binaryExpression.Right as ConstantExpression;
246+
if (constantExpression == null)
247+
{
248+
constantExpression = binaryExpression.Left as ConstantExpression;
249+
variableExpression = binaryExpression.Right;
250+
}
251+
252+
if (constantExpression == null || constantExpression.Type != typeof(int))
245253
{
246-
if (leftUnaryExpression.NodeType == ExpressionType.ArrayLength)
254+
return null;
255+
}
256+
257+
BsonSerializationInfo serializationInfo = null;
258+
var value = ToInt32(constantExpression);
259+
260+
var unaryExpression = variableExpression as UnaryExpression;
261+
if (unaryExpression != null)
262+
{
263+
if (unaryExpression.NodeType == ExpressionType.ArrayLength)
247264
{
248-
var memberExpression = leftUnaryExpression.Operand as MemberExpression;
249-
var valueExpression = binaryExpression.Right as ConstantExpression;
250-
if (memberExpression != null && valueExpression != null)
265+
var memberExpression = unaryExpression.Operand as MemberExpression;
266+
if (memberExpression != null)
251267
{
252-
var serializationInfo = GetSerializationInfo(memberExpression);
253-
var value = (int)valueExpression.Value;
254-
if (binaryExpression.NodeType == ExpressionType.Equal)
255-
{
256-
return Query.Size(serializationInfo.ElementName, value);
257-
}
258-
else
259-
{
260-
return Query.Not(serializationInfo.ElementName).Size(value);
261-
}
268+
serializationInfo = GetSerializationInfo(memberExpression);
262269
}
263270
}
264271
}
265272

266-
var leftMemberExpression = binaryExpression.Left as MemberExpression;
267-
if (leftMemberExpression != null)
273+
var countPropertyExpression = variableExpression as MemberExpression;
274+
if (countPropertyExpression != null)
268275
{
269-
if (leftMemberExpression.Member.Name == "Count")
276+
if (countPropertyExpression.Member.Name == "Count")
270277
{
271-
var memberExpression = leftMemberExpression.Expression as MemberExpression;
272-
var valueExpression = binaryExpression.Right as ConstantExpression;
273-
if (memberExpression != null && valueExpression != null)
278+
var memberExpression = countPropertyExpression.Expression as MemberExpression;
279+
if (memberExpression != null)
274280
{
275-
var serializationInfo = GetSerializationInfo(memberExpression);
276-
var value = (int)valueExpression.Value;
277-
if (binaryExpression.NodeType == ExpressionType.Equal)
278-
{
279-
return Query.Size(serializationInfo.ElementName, value);
280-
}
281-
else
282-
{
283-
return Query.Not(serializationInfo.ElementName).Size(value);
284-
}
281+
serializationInfo = GetSerializationInfo(memberExpression);
285282
}
286283
}
287284
}
288285

289-
var leftMethodCallExpression = binaryExpression.Left as MethodCallExpression;
290-
if (leftMethodCallExpression != null)
286+
var countMethodCallExpression = variableExpression as MethodCallExpression;
287+
if (countMethodCallExpression != null)
291288
{
292-
if (leftMethodCallExpression.Method.Name == "Count")
289+
if (countMethodCallExpression.Method.Name == "Count")
293290
{
294-
var arguments = leftMethodCallExpression.Arguments.ToArray();
291+
var arguments = countMethodCallExpression.Arguments.ToArray();
295292
if (arguments.Length == 1)
296293
{
297-
var memberExpression = leftMethodCallExpression.Arguments[0] as MemberExpression;
298-
var valueExpression = binaryExpression.Right as ConstantExpression;
299-
if (memberExpression != null && valueExpression != null)
294+
var memberExpression = countMethodCallExpression.Arguments[0] as MemberExpression;
295+
if (memberExpression != null)
300296
{
301-
var serializationInfo = GetSerializationInfo(memberExpression);
302-
var value = (int)valueExpression.Value;
303-
if (binaryExpression.NodeType == ExpressionType.Equal)
304-
{
305-
return Query.Size(serializationInfo.ElementName, value);
306-
}
307-
else
308-
{
309-
return Query.Not(serializationInfo.ElementName).Size(value);
310-
}
297+
serializationInfo = GetSerializationInfo(memberExpression);
311298
}
312299
}
313300
}
314301
}
315302

303+
if (serializationInfo != null)
304+
{
305+
if (binaryExpression.NodeType == ExpressionType.Equal)
306+
{
307+
return Query.Size(serializationInfo.ElementName, value);
308+
}
309+
else
310+
{
311+
return Query.Not(serializationInfo.ElementName).Size(value);
312+
}
313+
}
314+
316315
return null;
317316
}
318317

@@ -331,7 +330,8 @@ private IMongoQuery BuildBooleanQuery(Expression expression)
331330

332331
private IMongoQuery BuildComparisonQuery(BinaryExpression binaryExpression)
333332
{
334-
if (binaryExpression.NodeType == ExpressionType.Equal || binaryExpression.NodeType == ExpressionType.NotEqual)
333+
var operatorNodeType = binaryExpression.NodeType;
334+
if (operatorNodeType == ExpressionType.Equal || operatorNodeType == ExpressionType.NotEqual)
335335
{
336336
var query = BuildArrayLengthQuery(binaryExpression);
337337
if (query != null)
@@ -346,49 +346,57 @@ private IMongoQuery BuildComparisonQuery(BinaryExpression binaryExpression)
346346
}
347347
}
348348

349-
var valueExpression = binaryExpression.Right as ConstantExpression;
350-
if (valueExpression != null)
349+
// the constant could be on either side
350+
var variableExpression = binaryExpression.Left;
351+
var constantExpression = binaryExpression.Right as ConstantExpression;
352+
if (constantExpression == null)
351353
{
352-
var unaryExpression = binaryExpression.Left as UnaryExpression;
353-
if (unaryExpression != null && unaryExpression.NodeType == ExpressionType.Convert && unaryExpression.Operand.Type.IsEnum)
354+
constantExpression = binaryExpression.Left as ConstantExpression;
355+
variableExpression = binaryExpression.Right;
356+
// if the constant was on the left some operators need to be flipped
357+
switch (operatorNodeType)
354358
{
355-
var enumType = unaryExpression.Operand.Type;
356-
if (unaryExpression.Type == Enum.GetUnderlyingType(enumType))
357-
{
358-
var enumSerializationInfo = GetSerializationInfo(unaryExpression.Operand);
359-
if (enumSerializationInfo != null)
360-
{
361-
var numericValue = valueExpression.Value;
362-
var enumValue = Enum.ToObject(enumType, numericValue);
363-
var serializedValue = SerializeValue(enumSerializationInfo, enumValue);
364-
switch (binaryExpression.NodeType)
365-
{
366-
case ExpressionType.Equal: return Query.EQ(enumSerializationInfo.ElementName, serializedValue);
367-
case ExpressionType.GreaterThan: return Query.GT(enumSerializationInfo.ElementName, serializedValue);
368-
case ExpressionType.GreaterThanOrEqual: return Query.GTE(enumSerializationInfo.ElementName, serializedValue);
369-
case ExpressionType.LessThan: return Query.LT(enumSerializationInfo.ElementName, serializedValue);
370-
case ExpressionType.LessThanOrEqual: return Query.LTE(enumSerializationInfo.ElementName, serializedValue);
371-
case ExpressionType.NotEqual: return Query.NE(enumSerializationInfo.ElementName, serializedValue);
372-
}
373-
}
374-
}
359+
case ExpressionType.LessThan: operatorNodeType = ExpressionType.GreaterThan; break;
360+
case ExpressionType.LessThanOrEqual: operatorNodeType = ExpressionType.GreaterThanOrEqual; break;
361+
case ExpressionType.GreaterThan: operatorNodeType = ExpressionType.LessThan; break;
362+
case ExpressionType.GreaterThanOrEqual: operatorNodeType = ExpressionType.LessThanOrEqual; break;
363+
}
364+
}
375365

376-
return null;
377-
}
378-
379-
var serializationInfo = GetSerializationInfo(binaryExpression.Left);
380-
if (serializationInfo != null)
366+
if (constantExpression == null)
367+
{
368+
return null;
369+
}
370+
371+
BsonSerializationInfo serializationInfo = null;
372+
var value = constantExpression.Value;
373+
374+
var unaryExpression = variableExpression as UnaryExpression;
375+
if (unaryExpression != null && unaryExpression.NodeType == ExpressionType.Convert && unaryExpression.Operand.Type.IsEnum)
376+
{
377+
var enumType = unaryExpression.Operand.Type;
378+
if (unaryExpression.Type == Enum.GetUnderlyingType(enumType))
381379
{
382-
var serializedValue = SerializeValue(serializationInfo, valueExpression.Value);
383-
switch (binaryExpression.NodeType)
384-
{
385-
case ExpressionType.Equal: return Query.EQ(serializationInfo.ElementName, serializedValue);
386-
case ExpressionType.GreaterThan: return Query.GT(serializationInfo.ElementName, serializedValue);
387-
case ExpressionType.GreaterThanOrEqual: return Query.GTE(serializationInfo.ElementName, serializedValue);
388-
case ExpressionType.LessThan: return Query.LT(serializationInfo.ElementName, serializedValue);
389-
case ExpressionType.LessThanOrEqual: return Query.LTE(serializationInfo.ElementName, serializedValue);
390-
case ExpressionType.NotEqual: return Query.NE(serializationInfo.ElementName, serializedValue);
391-
}
380+
serializationInfo = GetSerializationInfo(unaryExpression.Operand);
381+
value = Enum.ToObject(enumType, value); // serialize enum instead of underlying integer
382+
}
383+
}
384+
else
385+
{
386+
serializationInfo = GetSerializationInfo(variableExpression);
387+
}
388+
389+
if (serializationInfo != null)
390+
{
391+
var serializedValue = SerializeValue(serializationInfo, value);
392+
switch (operatorNodeType)
393+
{
394+
case ExpressionType.Equal: return Query.EQ(serializationInfo.ElementName, serializedValue);
395+
case ExpressionType.GreaterThan: return Query.GT(serializationInfo.ElementName, serializedValue);
396+
case ExpressionType.GreaterThanOrEqual: return Query.GTE(serializationInfo.ElementName, serializedValue);
397+
case ExpressionType.LessThan: return Query.LT(serializationInfo.ElementName, serializedValue);
398+
case ExpressionType.LessThanOrEqual: return Query.LTE(serializationInfo.ElementName, serializedValue);
399+
case ExpressionType.NotEqual: return Query.NE(serializationInfo.ElementName, serializedValue);
392400
}
393401
}
394402

0 commit comments

Comments
 (0)