Skip to content

Commit fd813c7

Browse files
Allow using query filters for non-string types (#25)
* implement filter support for all known data types
1 parent 1a34fe9 commit fd813c7

File tree

5 files changed

+137
-54
lines changed

5 files changed

+137
-54
lines changed

CoreHelpers.WindowsAzure.Storage.Table.Tests/ITS019QueryFilter.cs

+96
Original file line numberDiff line numberDiff line change
@@ -134,5 +134,101 @@ public async Task VerifyQueryfilterBoolOnly()
134134
await storageContext.DropTableAsync<DemoEntityQuery>();
135135
}
136136
}
137+
138+
[Fact]
139+
public async Task VerifyQueryfilterLongOnly()
140+
{
141+
// Import from Blob
142+
using (var storageContext = new StorageContext(env.ConnectionString))
143+
{
144+
// set the tablename context
145+
storageContext.SetTableContext();
146+
147+
var l = 2910892817298;
148+
149+
// create the model
150+
var models = new List<DemoEntityQuery>()
151+
{
152+
new DemoEntityQuery() {R = "E6", StringField = "Demo03"},
153+
new DemoEntityQuery() {R = "E7", StringField = "Demo03", LongField = l - 1},
154+
new DemoEntityQuery() {R = "E8", StringField = "Demo03", LongField = l + 1}
155+
};
156+
157+
// ensure we are using the attributes
158+
storageContext.AddAttributeMapper(typeof(DemoEntityQuery));
159+
160+
// inser the model
161+
await storageContext.EnableAutoCreateTable().MergeOrInsertAsync<DemoEntityQuery>(models);
162+
163+
// build the basic filter
164+
var filterItem = new QueryFilter()
165+
{
166+
FilterType = QueryFilterType.And,
167+
Property = nameof(DemoEntityQuery.LongField),
168+
Value = l,
169+
Operator = QueryFilterOperator.GreaterEqual
170+
};
171+
172+
// query all elements with empty filter list
173+
var result = (await storageContext.QueryAsync<DemoEntityQuery>(null, new List<QueryFilter>())).ToList();
174+
Assert.Equal(3, result.Count());
175+
176+
result = (await storageContext.QueryAsync<DemoEntityQuery>("P1", new List<QueryFilter>() { filterItem })).ToList();
177+
Assert.Single(result, i => i?.LongField == l + 1);
178+
179+
// Clean up
180+
var all = await storageContext.QueryAsync<DemoEntityQuery>();
181+
await storageContext.DeleteAsync<DemoEntityQuery>(all);
182+
await storageContext.DropTableAsync<DemoEntityQuery>();
183+
}
184+
}
185+
186+
[Fact]
187+
public async Task VerifyQueryfilterDateTimeOnly()
188+
{
189+
// Import from Blob
190+
using (var storageContext = new StorageContext(env.ConnectionString))
191+
{
192+
// set the tablename context
193+
storageContext.SetTableContext();
194+
195+
var now = DateTime.UtcNow;
196+
197+
// create the model
198+
var models = new List<DemoEntityQuery>()
199+
{
200+
new DemoEntityQuery() {R = "E6", StringField = "Demo03"},
201+
new DemoEntityQuery() {R = "E7", StringField = "Demo03", DateTimeField = now.AddDays(-1)},
202+
new DemoEntityQuery() {R = "E8", StringField = "Demo03", DateTimeField = now.AddDays(1)}
203+
};
204+
205+
// ensure we are using the attributes
206+
storageContext.AddAttributeMapper(typeof(DemoEntityQuery));
207+
208+
// inser the model
209+
await storageContext.EnableAutoCreateTable().MergeOrInsertAsync<DemoEntityQuery>(models);
210+
211+
// build the basic filter
212+
var filterItem = new QueryFilter()
213+
{
214+
FilterType = QueryFilterType.And,
215+
Property = nameof(DemoEntityQuery.DateTimeField),
216+
Value = now,
217+
Operator = QueryFilterOperator.GreaterEqual
218+
};
219+
220+
// query all elements with empty filter list
221+
var result = (await storageContext.QueryAsync<DemoEntityQuery>(null, new List<QueryFilter>())).ToList();
222+
Assert.Equal(3, result.Count());
223+
224+
result = (await storageContext.QueryAsync<DemoEntityQuery>("P1", new List<QueryFilter>() { filterItem })).ToList();
225+
Assert.Single(result, i => i?.DateTimeField == now.AddDays(1));
226+
227+
// Clean up
228+
var all = await storageContext.QueryAsync<DemoEntityQuery>();
229+
await storageContext.DeleteAsync<DemoEntityQuery>(all);
230+
await storageContext.DropTableAsync<DemoEntityQuery>();
231+
}
232+
}
137233
}
138234
}

CoreHelpers.WindowsAzure.Storage.Table.Tests/Models/DemoEntityQuery.cs

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ public class DemoEntityQuery
1313
public string StringField { get; set; } = String.Empty;
1414

1515
public bool BoolField { get; set; }
16+
17+
public DateTime? DateTimeField { get; set; }
18+
19+
public long LongField { get; set; }
1620
}
1721
}
1822

Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
1-
using System;
2-
using CoreHelpers.WindowsAzure.Storage.Table.Tests.Contracts;
1+
using CoreHelpers.WindowsAzure.Storage.Table.Tests.Contracts;
32

43
namespace CoreHelpers.WindowsAzure.Storage.Table.Tests.TestEnvironments
54
{
65
public class UnittestStorageEnvironment : ITestEnvironment
7-
{
8-
public string ConnectionString {
9-
get {
10-
6+
{
7+
public string ConnectionString
8+
{
9+
get
10+
{
1111
var connectionString = Environment.GetEnvironmentVariable("STORAGE");
12-
if (!String.IsNullOrEmpty(connectionString))
12+
if (!string.IsNullOrEmpty(connectionString))
1313
{
1414
Console.WriteLine("Using environment credentials");
1515
return connectionString;
1616
}
1717

18-
var filePath = Environment.ExpandEnvironmentVariables(Path.Combine("%HOME%", ".corehelpers.credentials.txt"));
18+
var filePath = Environment.ExpandEnvironmentVariables(Path.Combine(
19+
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".corehelpers.credentials.txt"));
1920
Console.WriteLine("Using filesystem credentials");
21+
2022
return File.ReadLines(filePath).First();
2123
}
2224
}
2325
}
24-
}
25-
26+
}

CoreHelpers.WindowsAzure.Storage.Table/CoreHelpers.WindowsAzure.Storage.Table.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
<PackageReference Include="System.Linq.Queryable" Version="4.3.0" />
3535
<PackageReference Include="Handlebars.Net" Version="2.1.2" />
3636
<PackageReference Include="System.Linq.Parallel" Version="4.3.0" />
37-
<PackageReference Include="Azure.Data.Tables" Version="12.6.1" />
37+
<PackageReference Include="Azure.Data.Tables" Version="12.8.0" />
3838
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
3939
</ItemGroup>
4040
<ItemGroup>

CoreHelpers.WindowsAzure.Storage.Table/Extensions/QueryFilterExtensions.cs

+25-43
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,37 @@
11
using System;
2-
using CoreHelpers.WindowsAzure.Storage.Table.Serialization;
2+
using System.Globalization;
33

44
namespace CoreHelpers.WindowsAzure.Storage.Table.Extensions
55
{
66
public static class QueryFilterExtensions
7-
{
7+
{
88
public static string ToFilterString(this QueryFilter filter)
99
{
10-
var filterOperation = "eq";
11-
switch (filter.Operator)
10+
var filterOperation = filter.Operator switch
1211
{
13-
case QueryFilterOperator.Equal:
14-
filterOperation = "eq";
15-
break;
16-
case QueryFilterOperator.NotEqual:
17-
filterOperation = "ne";
18-
break;
19-
case QueryFilterOperator.Lower:
20-
filterOperation = "lt";
21-
break;
22-
case QueryFilterOperator.Greater:
23-
filterOperation = "gt";
24-
break;
25-
case QueryFilterOperator.LowerEqual:
26-
filterOperation = "le";
27-
break;
28-
case QueryFilterOperator.GreaterEqual:
29-
filterOperation = "ge";
30-
break;
31-
}
12+
QueryFilterOperator.Equal => "eq",
13+
QueryFilterOperator.NotEqual => "ne",
14+
QueryFilterOperator.Lower => "lt",
15+
QueryFilterOperator.Greater => "gt",
16+
QueryFilterOperator.LowerEqual => "le",
17+
QueryFilterOperator.GreaterEqual => "ge",
18+
_ => "eq"
19+
};
3220

33-
var filterValueString = default(string);
34-
35-
if (filter.Value is string)
36-
filterValueString = $"'{(string)filter.Value}'";
37-
else if (filter.Value is bool)
38-
filterValueString = ((bool)filter.Value) ? "true" : "false";
39-
else if (filter.Value is byte[])
40-
filterValueString = Convert.ToString((byte[]) filter.Value);
41-
else if (filter.Value is DateTimeOffset)
42-
filterValueString = Convert.ToString((DateTimeOffset) filter.Value);
43-
else if (filter.Value is double)
44-
filterValueString = Convert.ToString((double) filter.Value);
45-
else if (filter.Value is Guid)
46-
filterValueString = ((Guid) filter.Value).ToString();
47-
else if (filter.Value is int)
48-
filterValueString = Convert.ToString((int) filter.Value);
49-
else if (filter.Value is long)
50-
filterValueString = Convert.ToString((long) filter.Value);
51-
else
52-
throw new NotSupportedException($"QueryFilter of Type \"{filter.Value?.GetType().FullName}\" is not supported.");
21+
var filterValueString = filter.Value switch
22+
{
23+
string value => $"'{value}'",
24+
bool b => b.ToString().ToLower(),
25+
byte[] bytes => $"binary'{Convert.ToBase64String(bytes)}'",
26+
DateTimeOffset offset => $"datetime'{offset.ToUniversalTime():s}Z'",
27+
DateTime offset => $"datetime'{offset.ToUniversalTime():s}Z'",
28+
double d => d.ToString(CultureInfo.InvariantCulture),
29+
Guid guid => $"guid'{guid}'",
30+
int i => i.ToString(),
31+
long l => $"{l}L",
32+
_ => throw new NotSupportedException(
33+
$"QueryFilter of Type \"{filter.Value?.GetType().FullName}\" is not supported.")
34+
};
5335

5436
return $"{filter.Property} {filterOperation} {filterValueString}";
5537
}

0 commit comments

Comments
 (0)