Skip to content

Commit

Permalink
Merge pull request matteobortolazzo#34 from matteobortolazzo/ArrayQue…
Browse files Browse the repository at this point in the history
…rySingleItem

Support querying with single item array
  • Loading branch information
matteobortolazzo authored Apr 25, 2019
2 parents a10c8c4 + 03fefe3 commit d793e7e
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 67 deletions.
96 changes: 30 additions & 66 deletions src/CouchDB.Driver/Translators/ConstantExpressionTranslator.cs
Original file line number Diff line number Diff line change
@@ -1,119 +1,83 @@
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;

namespace CouchDB.Driver
{
#pragma warning disable IDE0058 // Expression value is never used
internal partial class QueryTranslator
{
protected override Expression VisitConstant(ConstantExpression c)
{
if (c.Value is IQueryable)
HandleConstant(c.Value);

return c;
}

private void HandleConstant(object constant)
{
if (constant is IQueryable)
{
// assume constant nodes w/ IQueryables are table references
// q.ElementType.Name
}
else if (c.Value == null)
else if (constant == null)
{
_sb.Append("null");
}
else
{
switch (Type.GetTypeCode(c.Value.GetType()))
switch (Type.GetTypeCode(constant.GetType()))
{
case TypeCode.Boolean:
_sb.Append(((bool)c.Value) ? "true" : "false");
_sb.Append(((bool)constant) ? "true" : "false");
break;
case TypeCode.String:
_sb.Append($"\"{c.Value}\"");
_sb.Append($"\"{constant}\"");
break;
case TypeCode.DateTime:
_sb.Append(JsonConvert.SerializeObject(c.Value));
_sb.Append(JsonConvert.SerializeObject(constant));
break;
case TypeCode.Object:
if (c.Value is IList<bool>)
{
VisitIEnumerable(c.Value as IList<bool>);
}
else if (c.Value is IList<int>)
{
VisitIEnumerable(c.Value as IList<int>);
}
else if (c.Value is IList<long>)
{
VisitIEnumerable(c.Value as IList<long>);
}
else if (c.Value is IList<decimal>)
{
VisitIEnumerable(c.Value as IList<decimal>);
}
else if (c.Value is IList<float>)
{
VisitIEnumerable(c.Value as IList<float>);
}
else if (c.Value is IList<double>)
if (constant is IEnumerable enumerable)
{
VisitIEnumerable(c.Value as IList<double>);
VisitIEnumerable(enumerable);
}
else if (c.Value is IList<string>)
else if (constant is Guid)
{
VisitIEnumerable(c.Value as IList<string>);
}
else if (c.Value is Guid)
{
_sb.Append(JsonConvert.SerializeObject(c.Value));
_sb.Append(JsonConvert.SerializeObject(constant));
}
else
{
Debug.WriteLine($"The constant for '{c.Value}' not ufficially supported.");
_sb.Append(JsonConvert.SerializeObject(c.Value));
Debug.WriteLine($"The constant for '{constant}' not ufficially supported.");
_sb.Append(JsonConvert.SerializeObject(constant));
}
break;
default:
_sb.Append(c.Value);
_sb.Append(constant);
break;
}
}

return c;
}

private void VisitIEnumerable<T>(IList<T> list)
private void VisitIEnumerable(IEnumerable list)
{
if (list.Count < 1)
{
return;
}
if (list.Count == 1)
{
_sb.Append(VisitConst(list[0]));
}
else
_sb.Append("[");
bool needsComma = false;
foreach (var item in list)
{
_sb.Append("[");
_sb.Append(string.Join(",", list.Select(e => VisitConst(e))));
_sb.Append("]");
}

string VisitConst(object o)
{
switch (Type.GetTypeCode(o.GetType()))
if (needsComma)
{
case TypeCode.Boolean:
return (bool)o ? "true" : "false";
case TypeCode.String:
return $"\"{o}\"";
case TypeCode.Object:
throw new NotSupportedException($"The constant for '{o}' is not supported");
default:
return o.ToString();
_sb.Append(",");
}
HandleConstant(item);
needsComma = true;
}
_sb.Append("]");
}
}
#pragma warning restore IDE0058 // Expression value is never used
}
26 changes: 25 additions & 1 deletion src/CouchDB.Driver/Translators/MethodCallExpressionTranslator.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using CouchDB.Driver.Extensions;
using CouchDB.Driver.Types;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

Expand Down Expand Up @@ -315,7 +317,29 @@ private Expression VisitUseIndexMethod(MethodCallExpression m)
{
Visit(m.Arguments[0]);
_sb.Append("\"use_index\":");
Visit(m.Arguments[1]);
if (!(m.Arguments[1] is ConstantExpression indexArgsExpression))
{
throw new ArgumentException("UseIndex requires an IList<string> argument");
}

if (!(indexArgsExpression.Value is IList<string> indexArgs))
{
throw new ArgumentException("UseIndex requires an IList<string> argument");
}
else if (indexArgs.Count == 1)
{
// use_index expects the value with [ or ] when it's a single item array
Visit(Expression.Constant(indexArgs[0]));
}
else if (indexArgs.Count == 2)
{
Visit(indexArgsExpression);
}
else
{
throw new ArgumentException("UseIndex requires 1 or 2 strings");
}

_sb.Append(",");
return m;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ public void Array_In_Guid()
Assert.Equal(@"{""selector"":{""guid"":{""$in"":[""00000000-0000-0000-0000-000000000000"",""11111111-1111-1111-1111-111111111111""]}}}", json);
}
[Fact]
public void Array_InSingleItem()
{
var json = _rebels.Where(r => r.Age.In(new[] { 20 })).ToString();
Assert.Equal(@"{""selector"":{""age"":{""$in"":[20]}}}", json);
}
[Fact]
public void Array_NotIn()
{
var json = _rebels.Where(r => !r.Age.In(new[] { 20, 30 })).ToString();
Expand Down

0 comments on commit d793e7e

Please sign in to comment.