diff --git a/ReleaseNotes.md b/ReleaseNotes.md
index 1d4c6e0..d3abab5 100644
--- a/ReleaseNotes.md
+++ b/ReleaseNotes.md
@@ -1,3 +1,7 @@
+# 2.0.2
+- Support for datatypes DateOnly, TimeOnly and UInt128
+- Unit test code coverage at 95%
+
# 2.0.1
- Change ServiceQueryServiceFilter.FilterType enum to a string for easier serialization
diff --git a/ServiceQueryV2.sln b/ServiceQueryV2.sln
new file mode 100644
index 0000000..b6d24b2
--- /dev/null
+++ b/ServiceQueryV2.sln
@@ -0,0 +1,70 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.2.32616.157
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceQuery", "src\ServiceQueryV2\ServiceQuery.csproj", "{C8EC306E-305E-4977-A8AD-324F28A18DB2}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceQuery.AzureDataTables", "src\ServiceQuery.AzureDataTablesV2\ServiceQuery.AzureDataTables.csproj", "{38933403-A973-4B9F-AB6C-8A0B37D4DB0F}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{CDCE8DCF-CCAE-4110-A51E-4DD07BF24885}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceQueryV2Net8.Integration.Xunit", "src\Tests\ServiceQueryV2Net8.Integration.Xunit\ServiceQueryV2Net8.Integration.Xunit.csproj", "{F13E1A15-CE47-4A04-A508-9AE0DDC0DFCE}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceQueryV2Net8.Xunit", "src\Tests\ServiceQueryV2Net8.Xunit\ServiceQueryV2Net8.Xunit.csproj", "{9538825C-8868-45F5-B3F8-54C6000176C6}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceQuery.AzureDataTablesV2Net8.Integration.Xunit", "src\Tests\ServiceQuery.AzureDataTablesV2Net8.Integration.Xunit\ServiceQuery.AzureDataTablesV2Net8.Integration.Xunit.csproj", "{90E31385-8FD8-4940-ADDC-D24FA284D44F}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceQueryV2Net6.Xunit", "src\Tests\ServiceQueryV2Net6.Xunit\ServiceQueryV2Net6.Xunit.csproj", "{605277F0-8655-434E-B2FA-C86D3D62F4F7}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceQueryV2Net7.Xunit", "src\Tests\ServiceQueryV2Net7.Xunit\ServiceQueryV2Net7.Xunit.csproj", "{32110F60-13E5-43A3-AA8D-A75F1AD24AA3}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C8EC306E-305E-4977-A8AD-324F28A18DB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C8EC306E-305E-4977-A8AD-324F28A18DB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C8EC306E-305E-4977-A8AD-324F28A18DB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C8EC306E-305E-4977-A8AD-324F28A18DB2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {38933403-A973-4B9F-AB6C-8A0B37D4DB0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {38933403-A973-4B9F-AB6C-8A0B37D4DB0F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {38933403-A973-4B9F-AB6C-8A0B37D4DB0F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {38933403-A973-4B9F-AB6C-8A0B37D4DB0F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F13E1A15-CE47-4A04-A508-9AE0DDC0DFCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F13E1A15-CE47-4A04-A508-9AE0DDC0DFCE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F13E1A15-CE47-4A04-A508-9AE0DDC0DFCE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F13E1A15-CE47-4A04-A508-9AE0DDC0DFCE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9538825C-8868-45F5-B3F8-54C6000176C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9538825C-8868-45F5-B3F8-54C6000176C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9538825C-8868-45F5-B3F8-54C6000176C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9538825C-8868-45F5-B3F8-54C6000176C6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {90E31385-8FD8-4940-ADDC-D24FA284D44F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {90E31385-8FD8-4940-ADDC-D24FA284D44F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {90E31385-8FD8-4940-ADDC-D24FA284D44F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {90E31385-8FD8-4940-ADDC-D24FA284D44F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {605277F0-8655-434E-B2FA-C86D3D62F4F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {605277F0-8655-434E-B2FA-C86D3D62F4F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {605277F0-8655-434E-B2FA-C86D3D62F4F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {605277F0-8655-434E-B2FA-C86D3D62F4F7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {32110F60-13E5-43A3-AA8D-A75F1AD24AA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {32110F60-13E5-43A3-AA8D-A75F1AD24AA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {32110F60-13E5-43A3-AA8D-A75F1AD24AA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {32110F60-13E5-43A3-AA8D-A75F1AD24AA3}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {F13E1A15-CE47-4A04-A508-9AE0DDC0DFCE} = {CDCE8DCF-CCAE-4110-A51E-4DD07BF24885}
+ {9538825C-8868-45F5-B3F8-54C6000176C6} = {CDCE8DCF-CCAE-4110-A51E-4DD07BF24885}
+ {90E31385-8FD8-4940-ADDC-D24FA284D44F} = {CDCE8DCF-CCAE-4110-A51E-4DD07BF24885}
+ {605277F0-8655-434E-B2FA-C86D3D62F4F7} = {CDCE8DCF-CCAE-4110-A51E-4DD07BF24885}
+ {32110F60-13E5-43A3-AA8D-A75F1AD24AA3} = {CDCE8DCF-CCAE-4110-A51E-4DD07BF24885}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {F708D827-C6F0-4D56-A3C1-F45D8B98F897}
+ EndGlobalSection
+EndGlobal
diff --git a/src/ServiceQuery.AzureDataTablesV2/ServiceQuery.AzureDataTables.csproj b/src/ServiceQuery.AzureDataTablesV2/ServiceQuery.AzureDataTables.csproj
index df0d799..0b615ad 100644
--- a/src/ServiceQuery.AzureDataTablesV2/ServiceQuery.AzureDataTables.csproj
+++ b/src/ServiceQuery.AzureDataTablesV2/ServiceQuery.AzureDataTables.csproj
@@ -1,7 +1,7 @@
- 2.0.1
+ 2.1.0
ServiceQuery allows dynamic querying of data over service boundaries. Visit http://ServiceQuery.com to learn more.
ServiceQuery.AzureDataTables
holomodular
@@ -32,7 +32,7 @@
12.8.3
-
+
diff --git a/src/ServiceQueryV2/Extensions/ServiceQueryExtensions.cs b/src/ServiceQueryV2/Extensions/ServiceQueryExtensions.cs
index 4518218..ef5a39f 100644
--- a/src/ServiceQueryV2/Extensions/ServiceQueryExtensions.cs
+++ b/src/ServiceQueryV2/Extensions/ServiceQueryExtensions.cs
@@ -22,9 +22,6 @@ public static partial class ServiceQueryExtensions
///
public static IQueryable Apply(this IServiceQuery query, IQueryable queryable, ServiceQueryOptions serviceQueryOptions = null)
{
- //Get the filters back in grouped sets
- ServiceQueryFilterSet filterSet = GetFilterSet(query);
-
//Get type and property info of the base type
Type entityType = typeof(T);
var properties = entityType.GetProperties();
@@ -42,6 +39,9 @@ public static IQueryable Apply(this IServiceQuery query, IQueryable que
options.PropertyNameMappings = mappings;
}
+ //Get the filters back in grouped sets
+ ServiceQueryFilterSet filterSet = GetFilterSet(query, options);
+
//Build "where" clause
queryable = BuildWhere(queryable, filterSet, entityType, properties, options);
@@ -71,26 +71,26 @@ private static IQueryable BuildWhere(this IQueryable queryable, Service
///
public static Expression> BuildWhereExpression(this IServiceQuery query, ServiceQueryOptions serviceQueryOptions = null)
{
- //Get the filters back in grouped sets
- ServiceQueryFilterSet filterSet = GetFilterSet(query);
-
//Get type and property info of the base type
Type entityType = typeof(T);
var properties = entityType.GetProperties();
- //Get column name mappings (in case storage object name is different than mapped object name)
+ //Get name mappings (in case storage object name is different than mapped object name)
ServiceQueryOptions options = new ServiceQueryOptions();
if (serviceQueryOptions != null)
options = serviceQueryOptions;
Dictionary mappings = options.PropertyNameMappings;
if (mappings == null || mappings.Count == 0)
{
- //Use same property name (will be case-insensitive)
+ // Use all existing property names
mappings = new Dictionary();
properties.ToList().ForEach(x => mappings.Add(x.Name, x.Name));
options.PropertyNameMappings = mappings;
}
+ //Get the filters back in grouped sets
+ ServiceQueryFilterSet filterSet = GetFilterSet(query, options);
+
//Build "where" clause
return BuildWhereExpression(filterSet, entityType, properties, options);
}
@@ -179,9 +179,6 @@ private static Expression> BuildWhereExpression(this ServiceQue
///
public static List GetSelectProperties(this IServiceQuery queryable, ServiceQueryOptions serviceQueryOptions = null)
{
- //Get the filters back in grouped sets
- ServiceQueryFilterSet filterSet = GetFilterSet(queryable);
-
//Get type and property info of the base type
Type entityType = typeof(T);
var properties = entityType.GetProperties();
@@ -199,6 +196,9 @@ public static List GetSelectProperties(this IServiceQuery queryable,
options.PropertyNameMappings = mappings;
}
+ //Get the filters back in grouped sets
+ ServiceQueryFilterSet filterSet = GetFilterSet(queryable, options);
+
List selectFilters = new List();
if (filterSet.SelectFilters != null && filterSet.SelectFilters.Count > 0)
{
@@ -232,9 +232,6 @@ public static List GetSelectProperties(this IServiceQuery queryable,
///
public static Expression> BuildSelectExpression(this IServiceQuery queryable, ServiceQueryOptions serviceQueryOptions = null)
{
- //Get the filters back in grouped sets
- ServiceQueryFilterSet filterSet = GetFilterSet(queryable);
-
//Get type and property info of the base type
Type entityType = typeof(T);
var properties = entityType.GetProperties();
@@ -252,6 +249,9 @@ public static Expression> BuildSelectExpression(this IServiceQuery
options.PropertyNameMappings = mappings;
}
+ //Get the filters back in grouped sets
+ ServiceQueryFilterSet filterSet = GetFilterSet(queryable, options);
+
//Build "where" clause
return BuildSelectExpressionEx(filterSet, entityType, properties, options);
}
@@ -361,30 +361,27 @@ private static Expression> BuildExpresion(this IServiceQueryFil
{
switch (filter.FilterType)
{
- case ServiceQueryFilterType.Aggregate:
- break; //TODO
+ //case ServiceQueryFilterType.Aggregate:
+ // break;
case ServiceQueryFilterType.Between:
return GetBetweenExpression(filter, t, props, serviceQueryOptions);
case ServiceQueryFilterType.Compare:
return GetCompareExpression(filter, t, props, serviceQueryOptions);
-
- case ServiceQueryFilterType.Distinct:
- break; //No expression (handled in buildselect)
- case ServiceQueryFilterType.Expression:
- break; //No expression (handled in buildwhere)
+ //case ServiceQueryFilterType.Distinct:
+ // break; //No expression (handled in buildselect)
+ //case ServiceQueryFilterType.Expression:
+ // break; //No expression (handled in buildwhere)
case ServiceQueryFilterType.Null:
return GetNullExpression(filter, t, props, serviceQueryOptions);
-
- case ServiceQueryFilterType.PropertyCompare:
- break; //TODO
- case ServiceQueryFilterType.Select:
- break; //No expression (handled in buildselect)
+ //case ServiceQueryFilterType.PropertyCompare:
+ // break;
+ //case ServiceQueryFilterType.Select:
+ // break; //No expression (handled in buildselect)
case ServiceQueryFilterType.Set:
return GetSetExpression(filter, t, props, serviceQueryOptions);
-
- case ServiceQueryFilterType.Sort:
- break; //No expression (handled by buildorderby)
+ //case ServiceQueryFilterType.Sort:
+ // break; //No expression (handled by buildorderby)
}
return null;
}
@@ -567,13 +564,7 @@ private static Expression> GetCompareExpression(IServiceQueryFi
member = Expression.MakeMemberAccess(arg, p);
BinaryExpression exp = Expression.NotEqual(member, Expression.Constant(null, p.PropertyType));
var first = Expression.Lambda>(exp, arg);
-
-#if NET35
-
- return Expression.Lambda>(Expression.AndAlso(first.Body, second), first.Parameters);
-#else
return Expression.Lambda>(Expression.AndAlso(first.Body, new ExpressionParameterReplacer(second.Parameters, first.Parameters).Visit(second.Body)), first.Parameters);
-#endif
}
return Expression.Lambda(startsWithCall, typeParam) as Expression>;
@@ -594,12 +585,7 @@ private static Expression> GetCompareExpression(IServiceQueryFi
member = Expression.MakeMemberAccess(arg, p);
BinaryExpression exp = Expression.NotEqual(member, Expression.Constant(null, p.PropertyType));
var first = Expression.Lambda>(exp, arg);
-#if NET35
-
- return Expression.Lambda>(Expression.AndAlso(first.Body, second), first.Parameters);
-#else
return Expression.Lambda>(Expression.AndAlso(first.Body, new ExpressionParameterReplacer(second.Parameters, first.Parameters).Visit(second.Body)), first.Parameters);
-#endif
}
return Expression.Lambda(containsCall, typeParam) as Expression>;
@@ -703,9 +689,6 @@ private static Expression> GetCompareExpression(IServiceQueryFi
///
public static Expression> BuildOrderByExpression(this IServiceQuery serviceQuery, IQueryable queryable, ServiceQueryOptions serviceQueryOptions = null)
{
- //Get the filters back in grouped sets
- ServiceQueryFilterSet filterSet = GetFilterSet(serviceQuery);
-
//Get type and property info of the base type
Type entityType = typeof(T);
var properties = entityType.GetProperties();
@@ -723,6 +706,9 @@ public static Expression> BuildOrderByExpression(this IServic
options.PropertyNameMappings = mappings;
}
+ //Get the filters back in grouped sets
+ ServiceQueryFilterSet filterSet = GetFilterSet(serviceQuery, options);
+
//Build "where" clause
return BuildOrderByExpression(filterSet, entityType, properties, options);
}
@@ -788,6 +774,15 @@ private static IQueryable BuildOrderBy(this IQueryable queryable, Servi
else
queryable = queryable.OrderByDescending(Expression.Lambda>(Expression.Property(param, p), param));
}
+#if NET6_0_OR_GREATER
+ if (p.PropertyType == typeof(DateOnly))
+ {
+ if (filterSet.SortFilters[i].SortType == ServiceQuerySortType.Ascending)
+ queryable = queryable.OrderBy(Expression.Lambda>(Expression.Property(param, p), param));
+ else
+ queryable = queryable.OrderByDescending(Expression.Lambda>(Expression.Property(param, p), param));
+ }
+#endif
if (p.PropertyType == typeof(DateTime))
{
if (filterSet.SortFilters[i].SortType == ServiceQuerySortType.Ascending)
@@ -865,6 +860,15 @@ private static IQueryable BuildOrderBy(this IQueryable queryable, Servi
else
queryable = queryable.OrderByDescending(Expression.Lambda>(Expression.Property(param, p), param));
}
+#if NET6_0_OR_GREATER
+ if (p.PropertyType == typeof(TimeOnly))
+ {
+ if (filterSet.SortFilters[i].SortType == ServiceQuerySortType.Ascending)
+ queryable = queryable.OrderBy(Expression.Lambda>(Expression.Property(param, p), param));
+ else
+ queryable = queryable.OrderByDescending(Expression.Lambda>(Expression.Property(param, p), param));
+ }
+#endif
if (p.PropertyType == typeof(TimeSpan))
{
if (filterSet.SortFilters[i].SortType == ServiceQuerySortType.Ascending)
@@ -893,6 +897,15 @@ private static IQueryable BuildOrderBy(this IQueryable queryable, Servi
else
queryable = queryable.OrderByDescending(Expression.Lambda>(Expression.Property(param, p), param));
}
+#if NET7_0_OR_GREATER
+ if (p.PropertyType == typeof(UInt128))
+ {
+ if (filterSet.SortFilters[i].SortType == ServiceQuerySortType.Ascending)
+ queryable = queryable.OrderBy(Expression.Lambda>(Expression.Property(param, p), param));
+ else
+ queryable = queryable.OrderByDescending(Expression.Lambda>(Expression.Property(param, p), param));
+ }
+#endif
}
}
return queryable;
@@ -903,8 +916,11 @@ private static IQueryable BuildOrderBy(this IQueryable queryable, Servi
}
}
- private static ServiceQueryFilterSet GetFilterSet(this IServiceQuery query)
+ private static ServiceQueryFilterSet GetFilterSet(this IServiceQuery query, ServiceQueryOptions options)
{
+ if (query.Filters != null && options != null && !options.AllowMissingExpressions)
+ ValidateQuery(query);
+
ServiceQueryFilterSet filterSet = new ServiceQueryFilterSet();
List currentWhereFilters = new List();
bool nestedExpression = false;
@@ -965,9 +981,9 @@ private static ServiceQueryFilterSet GetFilterSet(this IServiceQuery query)
currentWhereFilters.Add(filter);
break;
- case ServiceQueryFilterType.PropertyCompare:
- currentWhereFilters.Add(filter);
- break;
+ //case ServiceQueryFilterType.PropertyCompare:
+ // currentWhereFilters.Add(filter);
+ // break;
case ServiceQueryFilterType.Select:
filterSet.SelectFilters.Add(filter);
@@ -988,6 +1004,91 @@ private static ServiceQueryFilterSet GetFilterSet(this IServiceQuery query)
return filterSet;
}
+ private static void ValidateQuery(IServiceQuery query)
+ {
+ var beginCount = query.Filters.Where(x => x.ExpressionType == ServiceQueryExpressionType.Begin).Count();
+ var endCount = query.Filters.Where(x => x.ExpressionType == ServiceQueryExpressionType.End).Count();
+ if (beginCount != endCount)
+ throw new ServiceQueryException("Begin and End expression counts do not match");
+
+ // Make sure all filters have an associated expression (if needed)
+ bool anyWhereExpressionFound = false;
+ bool isAndOrExpressionNeeded = false;
+ Stack beginendstack = new Stack();
+ foreach (var item in query.Filters)
+ {
+ switch (item.FilterType)
+ {
+ case ServiceQueryFilterType.Between:
+ if (isAndOrExpressionNeeded)
+ throw new ServiceQueryException("Expression is needed before Between filter");
+ isAndOrExpressionNeeded = true;
+ anyWhereExpressionFound = true;
+ continue;
+
+ case ServiceQueryFilterType.Compare:
+ if (isAndOrExpressionNeeded)
+ throw new ServiceQueryException("Expression is needed before Compare filter");
+ isAndOrExpressionNeeded = true;
+ anyWhereExpressionFound = true;
+ continue;
+
+ case ServiceQueryFilterType.Null:
+ if (isAndOrExpressionNeeded)
+ throw new ServiceQueryException("Expression is needed before Compare filter");
+ isAndOrExpressionNeeded = true;
+ anyWhereExpressionFound = true;
+ continue;
+
+ case ServiceQueryFilterType.Set:
+ if (isAndOrExpressionNeeded)
+ throw new ServiceQueryException("Expression is needed before Compare filter");
+ isAndOrExpressionNeeded = true;
+ anyWhereExpressionFound = true;
+ continue;
+
+ case ServiceQueryFilterType.Expression:
+ switch (item.ExpressionType)
+ {
+ case ServiceQueryExpressionType.Begin:
+ beginendstack.Push(ServiceQueryExpressionType.Begin);
+ if (isAndOrExpressionNeeded)
+ isAndOrExpressionNeeded = false;
+ continue;
+
+ case ServiceQueryExpressionType.End:
+ if (beginendstack.Count == 0)
+ throw new ServiceQueryException("End Expression is before Begin");
+ beginendstack.Pop();
+ if (isAndOrExpressionNeeded)
+ isAndOrExpressionNeeded = false;
+ isAndOrExpressionNeeded = true;
+ continue;
+
+ case ServiceQueryExpressionType.And:
+ if (isAndOrExpressionNeeded)
+ isAndOrExpressionNeeded = false;
+ else
+ throw new ServiceQueryException("And Expression is not needed");
+ continue;
+
+ case ServiceQueryExpressionType.Or:
+ if (isAndOrExpressionNeeded)
+ isAndOrExpressionNeeded = false;
+ else
+ throw new ServiceQueryException("Or Expression is not needed");
+ continue;
+ }
+ continue;
+ // ALl others don't matter
+ }
+ }
+ if (anyWhereExpressionFound && !isAndOrExpressionNeeded)
+ throw new Exception("Ending expression is missing");
+ if (beginendstack.Count > 0)
+ throw new ServiceQueryException("Begin and End expression counts do not match");
+ }
+
private static object GetParsedPropertyType(PropertyInfo prop, string value)
{
if (prop.PropertyType == typeof(bool))
@@ -1021,6 +1122,16 @@ private static object GetParsedPropertyType(PropertyInfo prop, string value)
return new char?();
return new char?(char.Parse(value));
}
+#if NET6_0_OR_GREATER
+ if (prop.PropertyType == typeof(DateOnly))
+ return DateOnly.Parse(value);
+ if (prop.PropertyType == typeof(DateOnly?))
+ {
+ if (string.IsNullOrEmpty(value))
+ return new DateOnly?();
+ return new DateOnly?(DateOnly.Parse(value));
+ }
+#endif
if (prop.PropertyType == typeof(DateTime))
return DateTime.Parse(value, null, System.Globalization.DateTimeStyles.RoundtripKind);
if (prop.PropertyType == typeof(DateTime?))
@@ -1105,6 +1216,16 @@ private static object GetParsedPropertyType(PropertyInfo prop, string value)
}
if (prop.PropertyType == typeof(string))
return value;
+#if NET6_0_OR_GREATER
+ if (prop.PropertyType == typeof(TimeOnly))
+ return TimeOnly.Parse(value);
+ if (prop.PropertyType == typeof(TimeOnly?))
+ {
+ if (string.IsNullOrEmpty(value))
+ return new TimeOnly?();
+ return new TimeOnly?(TimeOnly.Parse(value));
+ }
+#endif
if (prop.PropertyType == typeof(TimeSpan))
return TimeSpan.Parse(value);
if (prop.PropertyType == typeof(TimeSpan?))
@@ -1239,9 +1360,6 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
if (filter == null)
return null;
- //Get the filters back in grouped sets
- ServiceQueryFilterSet filterSet = GetFilterSet(serviceQuery);
-
//Get type and property info of the base type
Type entityType = typeof(T);
var properties = entityType.GetProperties();
@@ -1263,6 +1381,9 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
if (filter.AggregateType == ServiceQueryAggregateType.Count)
return query.Count();
+ //Get the filters back in grouped sets
+ ServiceQueryFilterSet filterSet = GetFilterSet(serviceQuery, options);
+
var param = Expression.Parameter(entityType, "x");
PropertyInfo prop = null;
if (filter.Properties == null || filter.Properties.Count == 0)
@@ -1285,6 +1406,13 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
throw new ServiceQueryException("aggregate functions not supported on char");
if (prop.PropertyType == typeof(char?))
throw new ServiceQueryException("aggregate functions not supported on char?");
+#if NET6_0_OR_GREATER
+ if (prop.PropertyType == typeof(DateOnly))
+ throw new ServiceQueryException("aggregate functions not supported on DateOnly");
+ if (prop.PropertyType == typeof(DateOnly?))
+ throw new ServiceQueryException("aggregate functions not supported on DateOnly?");
+#endif
+
if (prop.PropertyType == typeof(DateTime))
throw new ServiceQueryException("aggregate functions not supported on DateTime");
if (prop.PropertyType == typeof(DateTime?))
@@ -1293,6 +1421,12 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
throw new ServiceQueryException("aggregate functions not supported on DateTimeOffset");
if (prop.PropertyType == typeof(DateTimeOffset?))
throw new ServiceQueryException("aggregate functions not supported on DateTimeOffset?");
+#if NET6_0_OR_GREATER
+ if (prop.PropertyType == typeof(TimeOnly))
+ throw new ServiceQueryException("aggregate functions not supported on TimeOnly");
+ if (prop.PropertyType == typeof(TimeOnly?))
+ throw new ServiceQueryException("aggregate functions not supported on TimeOnly?");
+#endif
if (prop.PropertyType == typeof(TimeSpan))
throw new ServiceQueryException("aggregate functions not supported on TimeSpan");
if (prop.PropertyType == typeof(TimeSpan?))
@@ -1313,9 +1447,6 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
case ServiceQueryAggregateType.Sum:
return Convert.ToDouble(query.Sum(decimalSelector));
-
- default:
- throw new ServiceQueryException("aggregate not defined");
}
}
if (prop.PropertyType == typeof(decimal?))
@@ -1346,9 +1477,6 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
if (sval.HasValue)
return Convert.ToDouble(sval.Value);
return null;
-
- default:
- throw new ServiceQueryException("aggregate not defined");
}
}
if (prop.PropertyType == typeof(double))
@@ -1367,9 +1495,6 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
case ServiceQueryAggregateType.Sum:
return query.Sum(doubleSelector);
-
- default:
- throw new ServiceQueryException("aggregate not defined");
}
}
if (prop.PropertyType == typeof(double?))
@@ -1388,9 +1513,6 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
case ServiceQueryAggregateType.Sum:
return query.Sum(doubleNSelector);
-
- default:
- throw new ServiceQueryException("aggregate not defined");
}
}
if (prop.PropertyType == typeof(Guid))
@@ -1413,9 +1535,6 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
case ServiceQueryAggregateType.Sum:
throw new ServiceQueryException("sum not supported on short");
-
- default:
- throw new ServiceQueryException("aggregate not defined");
}
}
if (prop.PropertyType == typeof(short?))
@@ -1434,9 +1553,6 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
case ServiceQueryAggregateType.Sum:
throw new ServiceQueryException("sum not supported on short?");
-
- default:
- throw new ServiceQueryException("aggregate not defined");
}
}
if (prop.PropertyType == typeof(int))
@@ -1455,9 +1571,6 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
case ServiceQueryAggregateType.Sum:
return query.Sum(intSelector);
-
- default:
- throw new ServiceQueryException("aggregate not defined");
}
}
if (prop.PropertyType == typeof(int?))
@@ -1476,9 +1589,6 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
case ServiceQueryAggregateType.Sum:
return query.Sum(intNSelector);
-
- default:
- throw new ServiceQueryException("aggregate not defined");
}
}
if (prop.PropertyType == typeof(long))
@@ -1497,9 +1607,6 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
case ServiceQueryAggregateType.Sum:
return query.Sum(longSelector);
-
- default:
- throw new ServiceQueryException("aggregate not defined");
}
}
if (prop.PropertyType == typeof(long?))
@@ -1518,9 +1625,6 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
case ServiceQueryAggregateType.Sum:
return query.Sum(longNSelector);
-
- default:
- throw new ServiceQueryException("aggregate not defined");
}
}
if (prop.PropertyType == typeof(sbyte))
@@ -1539,9 +1643,6 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
case ServiceQueryAggregateType.Sum:
throw new ServiceQueryException("sum not supported on sbyte");
-
- default:
- throw new ServiceQueryException("aggregate not defined");
}
}
if (prop.PropertyType == typeof(sbyte?))
@@ -1560,9 +1661,6 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
case ServiceQueryAggregateType.Sum:
throw new ServiceQueryException("sum not supported on sbyte?");
-
- default:
- throw new ServiceQueryException("aggregate not defined");
}
}
if (prop.PropertyType == typeof(Single))
@@ -1581,9 +1679,6 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
case ServiceQueryAggregateType.Sum:
return query.Sum(singleSelector);
-
- default:
- throw new ServiceQueryException("aggregate not defined");
}
}
if (prop.PropertyType == typeof(Single?))
@@ -1602,24 +1697,17 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
case ServiceQueryAggregateType.Sum:
return query.Sum(singleNSelector);
-
- default:
- throw new ServiceQueryException("aggregate not defined");
}
}
if (prop.PropertyType == typeof(string))
throw new ServiceQueryException("aggregate functions not supported on string");
- if (prop.PropertyType == typeof(TimeSpan))
- throw new ServiceQueryException("aggregate functions not supported on TimeSpan");
- if (prop.PropertyType == typeof(TimeSpan?))
- throw new ServiceQueryException("aggregate functions not supported on TimeSpan?");
if (prop.PropertyType == typeof(UInt16))
{
var uint16Selector = Expression.Lambda>(Expression.Property(param, prop), param);
switch (filter.AggregateType)
{
case ServiceQueryAggregateType.Average:
- throw new ServiceQueryException("average not supported on UInt32");
+ throw new ServiceQueryException("average not supported on UInt16");
case ServiceQueryAggregateType.Maximum:
return query.Max(uint16Selector);
@@ -1628,10 +1716,7 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
return query.Min(uint16Selector);
case ServiceQueryAggregateType.Sum:
- throw new ServiceQueryException("sum not supported on UInt32");
-
- default:
- throw new ServiceQueryException("aggregate not defined");
+ throw new ServiceQueryException("sum not supported on UInt16");
}
}
if (prop.PropertyType == typeof(UInt16?))
@@ -1640,7 +1725,7 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
switch (filter.AggregateType)
{
case ServiceQueryAggregateType.Average:
- throw new ServiceQueryException("average not supported on UInt32?");
+ throw new ServiceQueryException("average not supported on UInt16?");
case ServiceQueryAggregateType.Maximum:
return query.Max(uint16NSelector);
@@ -1649,10 +1734,7 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
return query.Min(uint16NSelector);
case ServiceQueryAggregateType.Sum:
- throw new ServiceQueryException("sum not supported on UInt32?");
-
- default:
- throw new ServiceQueryException("aggregate not defined");
+ throw new ServiceQueryException("sum not supported on UInt16?");
}
}
if (prop.PropertyType == typeof(UInt32))
@@ -1671,9 +1753,6 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
case ServiceQueryAggregateType.Sum:
throw new ServiceQueryException("sum not supported on UInt32");
-
- default:
- throw new ServiceQueryException("aggregate not defined");
}
}
if (prop.PropertyType == typeof(UInt32?))
@@ -1692,9 +1771,6 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
case ServiceQueryAggregateType.Sum:
throw new ServiceQueryException("sum not supported on UInt32?");
-
- default:
- throw new ServiceQueryException("aggregate not defined");
}
}
if (prop.PropertyType == typeof(UInt64))
@@ -1724,7 +1800,7 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
switch (filter.AggregateType)
{
case ServiceQueryAggregateType.Average:
- throw new ServiceQueryException("average not supported on UInt32?");
+ throw new ServiceQueryException("average not supported on UInt64?");
case ServiceQueryAggregateType.Maximum:
return query.Max(uint64NSelector);
@@ -1733,10 +1809,7 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
return query.Min(uint64NSelector);
case ServiceQueryAggregateType.Sum:
- throw new ServiceQueryException("sum not supported on UInt32?");
-
- default:
- throw new ServiceQueryException("aggregate not defined");
+ throw new ServiceQueryException("sum not supported on UInt64?");
}
}
#if NET7_0_OR_GREATER
@@ -1749,43 +1822,37 @@ public static ServiceQueryResponse Execute(this IServiceQuery serviceQuery
throw new ServiceQueryException("average not supported on UInt128");
case ServiceQueryAggregateType.Maximum:
- return Convert.ToDouble(query.Max(uint128Selector));
+ return (double)query.Max(uint128Selector);
case ServiceQueryAggregateType.Minimum:
- return Convert.ToDouble(query.Min(uint128Selector));
+ return (double)query.Min(uint128Selector);
case ServiceQueryAggregateType.Sum:
throw new ServiceQueryException("sum not supported on UInt128");
-
- default:
- throw new ServiceQueryException("aggregate not defined");
}
}
if (prop.PropertyType == typeof(UInt128?))
{
- var uint128NSelector = Expression.Lambda>(Expression.Property(param, prop), param);
+ var uint128NSelector = Expression.Lambda>(Expression.Property(param, prop), param);
switch (filter.AggregateType)
{
case ServiceQueryAggregateType.Average:
throw new ServiceQueryException("average not supported on UInt128?");
case ServiceQueryAggregateType.Maximum:
- var mauint128Nval = query.Max(uint128NSelector);
- if (mauint128Nval.HasValue)
- return Convert.ToDouble(mauint128Nval.Value);
+ var val = query.Max(uint128NSelector);
+ if (val.HasValue)
+ return (double)val.Value;
return null;
case ServiceQueryAggregateType.Minimum:
- var miuint128Nval = query.Min(uint128NSelector);
- if (miuint128Nval.HasValue)
- return Convert.ToDouble(miuint128Nval.Value);
+ var val2 = query.Min(uint128NSelector);
+ if (val2.HasValue)
+ return (double)val2.Value;
return null;
case ServiceQueryAggregateType.Sum:
throw new ServiceQueryException("sum not supported on UInt128?");
-
- default:
- throw new ServiceQueryException("aggregate not defined");
}
}
#endif
diff --git a/src/ServiceQueryV2/Extensions/ServiceQueryRequestExtensions.cs b/src/ServiceQueryV2/Extensions/ServiceQueryRequestExtensions.cs
index 3f07416..91c7479 100644
--- a/src/ServiceQueryV2/Extensions/ServiceQueryRequestExtensions.cs
+++ b/src/ServiceQueryV2/Extensions/ServiceQueryRequestExtensions.cs
@@ -1,4 +1,5 @@
-using System.Dynamic;
+using System;
+using System.Dynamic;
using System.Linq;
using System.Threading.Tasks;
@@ -226,6 +227,7 @@ public static ServiceQuery GetServiceQuery(this IServiceQueryRequest request)
builder.Sum(filter.Properties?.FirstOrDefault());
continue;
}
+ throw new ServiceQueryException($"filterType {filter.FilterType} not found");
}
return builder.Build();
diff --git a/src/ServiceQueryV2/Model/ServiceQueryOptions.cs b/src/ServiceQueryV2/Model/ServiceQueryOptions.cs
index 25d3d0a..da9f853 100644
--- a/src/ServiceQueryV2/Model/ServiceQueryOptions.cs
+++ b/src/ServiceQueryV2/Model/ServiceQueryOptions.cs
@@ -19,5 +19,11 @@ public class ServiceQueryOptions
/// Default is false.
///
public bool PropertyNameCaseSensitive { get; set; }
+
+ ///
+ /// Determine if missing BEGIN/END/AND/OR expressions throw an exception
+ /// or try to add them missing ones automatiically.
+ ///
+ public bool AllowMissingExpressions { get; set; }
}
}
\ No newline at end of file
diff --git a/src/ServiceQueryV2/ServiceQuery.csproj b/src/ServiceQueryV2/ServiceQuery.csproj
index ba0adba..f2065cc 100644
--- a/src/ServiceQueryV2/ServiceQuery.csproj
+++ b/src/ServiceQueryV2/ServiceQuery.csproj
@@ -1,7 +1,7 @@
- 2.0.1
+ 2.1.0
ServiceQuery allows dynamic querying of data over service boundaries. Visit http://ServiceQuery.com to learn more.
ServiceQuery
holomodular
diff --git a/src/Tests/ServiceQueryV2Net6.Xunit/ServiceQueryV2Net6.Xunit.csproj b/src/Tests/ServiceQueryV2Net6.Xunit/ServiceQueryV2Net6.Xunit.csproj
index 4cb08f4..be9735a 100644
--- a/src/Tests/ServiceQueryV2Net6.Xunit/ServiceQueryV2Net6.Xunit.csproj
+++ b/src/Tests/ServiceQueryV2Net6.Xunit/ServiceQueryV2Net6.Xunit.csproj
@@ -12,36 +12,38 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Tests/ServiceQueryV2Net7.Xunit/ServiceQueryV2Net7.Xunit.csproj b/src/Tests/ServiceQueryV2Net7.Xunit/ServiceQueryV2Net7.Xunit.csproj
index b10f515..e091a99 100644
--- a/src/Tests/ServiceQueryV2Net7.Xunit/ServiceQueryV2Net7.Xunit.csproj
+++ b/src/Tests/ServiceQueryV2Net7.Xunit/ServiceQueryV2Net7.Xunit.csproj
@@ -13,35 +13,38 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Tests/ServiceQueryV2Net8.Xunit/ServiceQueryV2Net8.Xunit.csproj b/src/Tests/ServiceQueryV2Net8.Xunit/ServiceQueryV2Net8.Xunit.csproj
index faa802f..0208006 100644
--- a/src/Tests/ServiceQueryV2Net8.Xunit/ServiceQueryV2Net8.Xunit.csproj
+++ b/src/Tests/ServiceQueryV2Net8.Xunit/ServiceQueryV2Net8.Xunit.csproj
@@ -10,37 +10,36 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Tests/TestFiles/V2/AggregateAverageTests.cs b/src/Tests/TestFiles/V2/AggregateAverageTests.cs
new file mode 100644
index 0000000..79210c4
--- /dev/null
+++ b/src/Tests/TestFiles/V2/AggregateAverageTests.cs
@@ -0,0 +1,933 @@
+namespace ServiceQuery.Xunit
+{
+ public class AggregateAverageTests : AggregateAverageTests
+ {
+ public override IQueryable GetTestList()
+ {
+ return new TestClass().GetDefaultList().AsQueryable();
+ }
+
+ public override IQueryable GetTestNullCopyList()
+ {
+ var list = new TestClass().GetDefaultList();
+ foreach (var item in list)
+ item.CopyToNullVals();
+ return list.AsQueryable();
+ }
+ }
+
+ public abstract class AggregateAverageTests : BaseTest where T : class
+ {
+ public bool ValidateNullLong = true;
+
+ public bool CosmosIntLongRounding = false;
+
+ [Fact]
+ public void AverageStandardTest()
+ {
+ var sourceQueryable = GetTestList();
+ IServiceQuery serviceQuery;
+ double? result;
+
+ // Boolean
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.BoolVal)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+
+ // ByteArray
+ var tempbyteArray = new byte[1] { 1 };
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.ByteArrayVal)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+
+ // Byte
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.ByteVal)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+
+ // Char
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.CharVal)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+
+ if (ValidateDateTimeOffset)
+ {
+ // DateTimeOffset
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.DateTimeOffsetVal)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ }
+
+#if NET6_0_OR_GREATER
+ // DateOnly
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.DateOnlyVal)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+#endif
+
+ // DateTime
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.DateTimeVal)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+
+ // Decimal
+ if (ValidateDecimal)
+ {
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.DecimalVal)).Build();
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ Assert.True(result == (double)6 / 4);
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ Assert.True(result == (double)6 / 4);
+ }
+
+ // Double
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.DoubleVal)).Build();
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ Assert.True(result == (double)6 / 4);
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.DoubleVal)).Build();
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ Assert.True(result == (double)6 / 4);
+
+ // Float
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.FloatVal)).Build();
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ Assert.True(result == (double)6 / 4);
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ Assert.True(result == (double)6 / 4);
+
+ // Guid
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.GuidVal)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+
+ if (CosmosIntLongRounding)
+ {
+ // Int
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.IntVal)).Build();
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ Assert.True(result == Math.Round((double)6 / 4));
+
+ // Long
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.LongVal)).Build();
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ Assert.True(result == Math.Round((double)6 / 4));
+ }
+ else
+ {
+ // Int
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.IntVal)).Build();
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ Assert.True(result == (double)6 / 4);
+
+ // Long
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.LongVal)).Build();
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ Assert.True(result == (double)6 / 4);
+ }
+
+ // SByte
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.SByteVal)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+
+ // Short
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.ShortVal)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+
+ // Single
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.SingleVal)).Build();
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ Assert.True(result == (double)6 / 4);
+
+ // String
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.StringVal)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+
+#if NET6_0_OR_GREATER
+ // TimeOnly
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.TimeOnlyVal)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+#endif
+
+ if (ValidateTimeSpan)
+ {
+ // TimeSpan
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.TimeSpanVal)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ }
+
+#if NET7_0_OR_GREATER
+ if (ValidateUInt128)
+ {
+ // UInt128
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.UInt128Val)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ }
+#endif
+
+ if (ValidateUInt64)
+ {
+ // UInt64
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.UInt64Val)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ }
+
+ // UInt32
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.UInt32Val)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+
+ // UInt16
+ serviceQuery = ServiceQueryBuilder.New().Average(nameof(TestClass.UInt16Val)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.ExecuteAggregate(sourceQueryable);
+ });
+ }
+
+ [Fact]
+ public void AverageRequestTest()
+ {
+ var sourceQueryable = GetTestList();
+ IServiceQueryRequest serviceQuery;
+ double? result;
+
+ // Boolean
+ serviceQuery = ServiceQueryRequestBuilder.New().Average(nameof(TestClass.BoolVal)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.GetServiceQuery().ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.GetServiceQuery().ExecuteAggregate(sourceQueryable);
+ });
+
+ // ByteArray
+ var tempbyteArray = new byte[1] { 1 };
+ serviceQuery = ServiceQueryRequestBuilder.New().Average(nameof(TestClass.ByteArrayVal)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.GetServiceQuery().ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.GetServiceQuery().ExecuteAggregate(sourceQueryable);
+ });
+
+ // Byte
+ serviceQuery = ServiceQueryRequestBuilder.New().Average(nameof(TestClass.ByteVal)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.GetServiceQuery().ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.GetServiceQuery().ExecuteAggregate(sourceQueryable);
+ });
+
+ // Char
+ serviceQuery = ServiceQueryRequestBuilder.New().Average(nameof(TestClass.CharVal)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.GetServiceQuery().ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.GetServiceQuery().ExecuteAggregate(sourceQueryable);
+ });
+
+ if (ValidateDateTimeOffset)
+ {
+ // DateTimeOffset
+ serviceQuery = ServiceQueryRequestBuilder.New().Average(nameof(TestClass.DateTimeOffsetVal)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.GetServiceQuery().ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.GetServiceQuery().ExecuteAggregate(sourceQueryable);
+ });
+ }
+
+#if NET6_0_OR_GREATER
+
+ // DateOnly
+ serviceQuery = ServiceQueryRequestBuilder.New().Average(nameof(TestClass.DateOnlyVal)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.GetServiceQuery().ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.GetServiceQuery().ExecuteAggregate(sourceQueryable);
+ });
+#endif
+
+ // DateTime
+ serviceQuery = ServiceQueryRequestBuilder.New().Average(nameof(TestClass.DateTimeVal)).Build();
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.GetServiceQuery().ExecuteAggregate(sourceQueryable);
+ });
+ Assert.Throws(() =>
+ {
+ result = serviceQuery.GetServiceQuery().ExecuteAggregate(sourceQueryable);
+ });
+
+ // Decimal
+ if (ValidateDecimal)
+ {
+ serviceQuery = ServiceQueryRequestBuilder.New().Average(nameof(TestClass.DecimalVal)).Build();
+ result = serviceQuery.GetServiceQuery().ExecuteAggregate(sourceQueryable);
+ Assert.True(result == (double)6 / 4);
+ }
+
+ // Double
+ serviceQuery = ServiceQueryRequestBuilder.New().Average(nameof(TestClass.DoubleVal)).Build();
+ result = serviceQuery.GetServiceQuery().ExecuteAggregate(sourceQueryable);
+ Assert.True(result == (double)6 / 4);
+ result = serviceQuery.GetServiceQuery().ExecuteAggregate(sourceQueryable);
+ Assert.True(result == (double)6 / 4);
+
+ // Float
+ serviceQuery = ServiceQueryRequestBuilder.New().Average(nameof(TestClass.FloatVal)).Build();
+ result = serviceQuery.GetServiceQuery().ExecuteAggregate(sourceQueryable);
+ Assert.True(result == (double)6 / 4);
+
+ // Guid
+ serviceQuery = ServiceQueryRequestBuilder.New().Average(nameof(TestClass.GuidVal)).Build();
+ Assert.Throws