Skip to content

Commit d793e7e

Browse files
Merge pull request #34 from matteobortolazzo/ArrayQuerySingleItem
Support querying with single item array
2 parents a10c8c4 + 03fefe3 commit d793e7e

File tree

3 files changed

+61
-67
lines changed

3 files changed

+61
-67
lines changed
Lines changed: 30 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,119 +1,83 @@
11
using Newtonsoft.Json;
22
using System;
3+
using System.Collections;
34
using System.Collections.Generic;
45
using System.Diagnostics;
56
using System.Linq;
67
using System.Linq.Expressions;
78

89
namespace CouchDB.Driver
910
{
10-
#pragma warning disable IDE0058 // Expression value is never used
1111
internal partial class QueryTranslator
1212
{
1313
protected override Expression VisitConstant(ConstantExpression c)
1414
{
15-
if (c.Value is IQueryable)
15+
HandleConstant(c.Value);
16+
17+
return c;
18+
}
19+
20+
private void HandleConstant(object constant)
21+
{
22+
if (constant is IQueryable)
1623
{
1724
// assume constant nodes w/ IQueryables are table references
1825
// q.ElementType.Name
1926
}
20-
else if (c.Value == null)
27+
else if (constant == null)
2128
{
2229
_sb.Append("null");
2330
}
2431
else
2532
{
26-
switch (Type.GetTypeCode(c.Value.GetType()))
33+
switch (Type.GetTypeCode(constant.GetType()))
2734
{
2835
case TypeCode.Boolean:
29-
_sb.Append(((bool)c.Value) ? "true" : "false");
36+
_sb.Append(((bool)constant) ? "true" : "false");
3037
break;
3138
case TypeCode.String:
32-
_sb.Append($"\"{c.Value}\"");
39+
_sb.Append($"\"{constant}\"");
3340
break;
3441
case TypeCode.DateTime:
35-
_sb.Append(JsonConvert.SerializeObject(c.Value));
42+
_sb.Append(JsonConvert.SerializeObject(constant));
3643
break;
3744
case TypeCode.Object:
38-
if (c.Value is IList<bool>)
39-
{
40-
VisitIEnumerable(c.Value as IList<bool>);
41-
}
42-
else if (c.Value is IList<int>)
43-
{
44-
VisitIEnumerable(c.Value as IList<int>);
45-
}
46-
else if (c.Value is IList<long>)
47-
{
48-
VisitIEnumerable(c.Value as IList<long>);
49-
}
50-
else if (c.Value is IList<decimal>)
51-
{
52-
VisitIEnumerable(c.Value as IList<decimal>);
53-
}
54-
else if (c.Value is IList<float>)
55-
{
56-
VisitIEnumerable(c.Value as IList<float>);
57-
}
58-
else if (c.Value is IList<double>)
45+
if (constant is IEnumerable enumerable)
5946
{
60-
VisitIEnumerable(c.Value as IList<double>);
47+
VisitIEnumerable(enumerable);
6148
}
62-
else if (c.Value is IList<string>)
49+
else if (constant is Guid)
6350
{
64-
VisitIEnumerable(c.Value as IList<string>);
65-
}
66-
else if (c.Value is Guid)
67-
{
68-
_sb.Append(JsonConvert.SerializeObject(c.Value));
51+
_sb.Append(JsonConvert.SerializeObject(constant));
6952
}
7053
else
7154
{
72-
Debug.WriteLine($"The constant for '{c.Value}' not ufficially supported.");
73-
_sb.Append(JsonConvert.SerializeObject(c.Value));
55+
Debug.WriteLine($"The constant for '{constant}' not ufficially supported.");
56+
_sb.Append(JsonConvert.SerializeObject(constant));
7457
}
7558
break;
7659
default:
77-
_sb.Append(c.Value);
60+
_sb.Append(constant);
7861
break;
7962
}
8063
}
8164

82-
return c;
8365
}
8466

85-
private void VisitIEnumerable<T>(IList<T> list)
67+
private void VisitIEnumerable(IEnumerable list)
8668
{
87-
if (list.Count < 1)
88-
{
89-
return;
90-
}
91-
if (list.Count == 1)
92-
{
93-
_sb.Append(VisitConst(list[0]));
94-
}
95-
else
69+
_sb.Append("[");
70+
bool needsComma = false;
71+
foreach (var item in list)
9672
{
97-
_sb.Append("[");
98-
_sb.Append(string.Join(",", list.Select(e => VisitConst(e))));
99-
_sb.Append("]");
100-
}
101-
102-
string VisitConst(object o)
103-
{
104-
switch (Type.GetTypeCode(o.GetType()))
73+
if (needsComma)
10574
{
106-
case TypeCode.Boolean:
107-
return (bool)o ? "true" : "false";
108-
case TypeCode.String:
109-
return $"\"{o}\"";
110-
case TypeCode.Object:
111-
throw new NotSupportedException($"The constant for '{o}' is not supported");
112-
default:
113-
return o.ToString();
75+
_sb.Append(",");
11476
}
77+
HandleConstant(item);
78+
needsComma = true;
11579
}
80+
_sb.Append("]");
11681
}
11782
}
118-
#pragma warning restore IDE0058 // Expression value is never used
11983
}

src/CouchDB.Driver/Translators/MethodCallExpressionTranslator.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using CouchDB.Driver.Extensions;
22
using CouchDB.Driver.Types;
3+
using Newtonsoft.Json;
34
using System;
5+
using System.Collections.Generic;
46
using System.Linq;
57
using System.Linq.Expressions;
68

@@ -315,7 +317,29 @@ private Expression VisitUseIndexMethod(MethodCallExpression m)
315317
{
316318
Visit(m.Arguments[0]);
317319
_sb.Append("\"use_index\":");
318-
Visit(m.Arguments[1]);
320+
if (!(m.Arguments[1] is ConstantExpression indexArgsExpression))
321+
{
322+
throw new ArgumentException("UseIndex requires an IList<string> argument");
323+
}
324+
325+
if (!(indexArgsExpression.Value is IList<string> indexArgs))
326+
{
327+
throw new ArgumentException("UseIndex requires an IList<string> argument");
328+
}
329+
else if (indexArgs.Count == 1)
330+
{
331+
// use_index expects the value with [ or ] when it's a single item array
332+
Visit(Expression.Constant(indexArgs[0]));
333+
}
334+
else if (indexArgs.Count == 2)
335+
{
336+
Visit(indexArgsExpression);
337+
}
338+
else
339+
{
340+
throw new ArgumentException("UseIndex requires 1 or 2 strings");
341+
}
342+
319343
_sb.Append(",");
320344
return m;
321345
}

tests/CouchDB.Driver.UnitTests/Find/Find_Selector_Conditions.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ public void Array_In_Guid()
9090
Assert.Equal(@"{""selector"":{""guid"":{""$in"":[""00000000-0000-0000-0000-000000000000"",""11111111-1111-1111-1111-111111111111""]}}}", json);
9191
}
9292
[Fact]
93+
public void Array_InSingleItem()
94+
{
95+
var json = _rebels.Where(r => r.Age.In(new[] { 20 })).ToString();
96+
Assert.Equal(@"{""selector"":{""age"":{""$in"":[20]}}}", json);
97+
}
98+
[Fact]
9399
public void Array_NotIn()
94100
{
95101
var json = _rebels.Where(r => !r.Age.In(new[] { 20, 30 })).ToString();

0 commit comments

Comments
 (0)