Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support comparison operations for Guid #342

Merged
merged 3 commits into from
Mar 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions net/DevExtreme.AspNet.Data.Tests.Xpo/Bug339.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using DevExpress.Xpo;
using System;
using Xunit;

namespace DevExtreme.AspNet.Data.Tests.Xpo {

public class Bug339 {

[Persistent(nameof(Bug339) + "_" + nameof(DataItem))]
public class DataItem {
[Key]
public Guid ID { get; set; }
}

[Fact]
public void Scenario() {
var guid1 = "".PadLeft(32, '1');
var guid2 = "".PadLeft(32, '2');

UnitOfWorkHelper.Exec(uow => {
uow.Save(new DataItem { ID = new Guid(guid1) });
uow.Save(new DataItem { ID = new Guid(guid2) });

uow.CommitChanges();

var loadResult = DataSourceLoader.Load(uow.Query<DataItem>(), new SampleLoadOptions {
Filter = new[] { "ID", "<", guid2 },
RequireTotalCount = true
});

Assert.Equal(1, loadResult.totalCount);
});

}

}

}
3 changes: 2 additions & 1 deletion net/DevExtreme.AspNet.Data.Tests.Xpo/UnitOfWorkHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public static void Exec(Action<UnitOfWork> action) {
dict.GetDataStoreSchema(
typeof(DefaultSort.DataItem),
typeof(RemoteGroupingStress.DataItem),
typeof(Summary.DataItem)
typeof(Summary.DataItem),
typeof(Bug339.DataItem)
);

var provider = XpoDefault.GetConnectionProvider(
Expand Down
27 changes: 27 additions & 0 deletions net/DevExtreme.AspNet.Data.Tests/FilterExpressionCompilerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,33 @@ string CompileOperation(string op) {
Assert.Equal("False", CompileOperation("<="));
}

[Fact]
public void GuidComparison() {
// https://github.com/DevExpress/DevExtreme.AspNet.Data/issues/339

var sampleGuid = Guid.Empty.ToString();

Assert.Equal(
$"(obj.CompareTo({sampleGuid}) > 0)",
Compile<Guid>(new[] { "this", ">", sampleGuid }).Body.ToString()
);

Assert.Equal(
$"(obj.Value.CompareTo({sampleGuid}) < 0)",
Compile<Guid?>(new[] { "this", "<", sampleGuid }).Body.ToString()
);

Assert.Equal(
$"IIF((obj == null), False, (obj.Value.CompareTo({sampleGuid}) >= 0))",
Compile<Guid?>(new[] { "this", ">=", sampleGuid }, true).Body.ToString()
);

Assert.Equal(
"False",
Compile<Guid?>(new[] { "this", "<=", null }).Body.ToString()
);
}

}

}
47 changes: 42 additions & 5 deletions net/DevExtreme.AspNet.Data/FilterExpressionCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,27 @@ Expression CompileBinary(ParameterExpression dataItemExpr, IList criteriaJson) {
if(_stringToLower && clientValue is String)
clientValue = ((string)clientValue).ToLower();

if((accessorExpr.Type == typeof(Guid) || accessorExpr.Type == typeof(Guid?)) && IsInequality(expressionType))
return CompileGuidComparison(accessorExpr, expressionType, clientValue);

Expression valueExpr = Expression.Constant(clientValue, accessorExpr.Type);

if(accessorExpr.Type == typeof(String) && IsInequality(expressionType)) {
var compareMethod = typeof(String).GetMethod(nameof(String.Compare), new[] { typeof(String), typeof(String) });
accessorExpr = Expression.Call(null, compareMethod, accessorExpr, valueExpr);
valueExpr = Expression.Constant(0);
} else if(useDynamicBinding) {
accessorExpr = Expression.Call(typeof(Utils).GetMethod(nameof(Utils.DynamicCompare)), accessorExpr, valueExpr);
valueExpr = Expression.Constant(0);
return Expression.MakeBinary(
expressionType,
Expression.Call(compareMethod, accessorExpr, valueExpr),
Expression.Constant(0)
);
}

if(useDynamicBinding) {
var compareMethod = typeof(Utils).GetMethod(nameof(Utils.DynamicCompare));
return Expression.MakeBinary(
expressionType,
Expression.Call(compareMethod, accessorExpr, valueExpr),
Expression.Constant(0)
);
}

return Expression.MakeBinary(expressionType, accessorExpr, valueExpr);
Expand All @@ -108,6 +120,31 @@ bool IsInequality(ExpressionType type) {
return type == ExpressionType.LessThan || type == ExpressionType.LessThanOrEqual || type == ExpressionType.GreaterThanOrEqual || type == ExpressionType.GreaterThan;
}

Expression CompileGuidComparison(Expression accessorExpr, ExpressionType expressionType, object clientValue) {
if(clientValue == null)
return Expression.Constant(false);

var result = Expression.MakeBinary(
expressionType,
Expression.Call(
Utils.IsNullable(accessorExpr.Type) ? Expression.Property(accessorExpr, "Value") : accessorExpr,
typeof(Guid).GetMethod(nameof(Guid.CompareTo), new[] { typeof(Guid) }),
Expression.Constant(clientValue, typeof(Guid))
),
Expression.Constant(0)
);

if(GuardNulls) {
return Expression.Condition(
Expression.MakeBinary(ExpressionType.Equal, accessorExpr, Expression.Constant(null)),
Expression.Constant(false),
result
);
}

return result;
}

Expression CompileStringFunction(Expression accessorExpr, string clientOperation, string value) {
if(_stringToLower && value != null)
value = value.ToLower();
Expand Down