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 Guid and Nullable Guid Data Types #80

Merged
merged 8 commits into from
Mar 7, 2022
Merged

Support Guid and Nullable Guid Data Types #80

merged 8 commits into from
Mar 7, 2022

Conversation

Ibrahemkhalil
Copy link
Contributor

Support GUID data type.

@tghamm
Copy link
Owner

tghamm commented Mar 3, 2022

Hi @Ibrahemkhalil thank you for the PR. Can you add supporting test cases for the changes you made? Thank you!

@Ibrahemkhalil
Copy link
Contributor Author

Ibrahemkhalil commented Mar 4, 2022

Hi @tghamm
Tests have been updated along with support for [Contains / EndsWith / BeginsWith / Equals]

@tghamm
Copy link
Owner

tghamm commented Mar 4, 2022

@Ibrahemkhalil awesome thank you. It looks like you've addressed the previous issue that Guid inclusion caused (a regression where ToString was executed on all types, preventing linq-to-sql from translating properly). I'll give it a whirl in the next day or two and if all checks out I'll put out a new release. Thanks again for the effort, very cool!

@Ibrahemkhalil Ibrahemkhalil changed the title Support guid data type Support Guid and Nullable Guid Data Types Mar 4, 2022
@tghamm tghamm self-assigned this Mar 5, 2022
@tghamm
Copy link
Owner

tghamm commented Mar 5, 2022

@Ibrahemkhalil I just made a very minor commit to master that will ensure that when code coverage is run against a PR it's assessed against the PR and not against master. The version of coveralls.net I was using was VERY old so I bumped it to a version that will tag your PR as a PR. As a favor, if you don't mind, pull the latest from my master into your branch and update the PR, it'll give accurate code coverage and a passing build in the checks for the PR. Apologies for the inconvenience! I'm reviewing over the weekend - very much appreciate the contribution!

@tghamm
Copy link
Owner

tghamm commented Mar 6, 2022

@Ibrahemkhalil sorry for the back and forth. I've updated CI to properly reflect that there are a couple of test case failures in the PR. Basically the custom operator Guid work I added needs to be removed and the tests need to be corrected in a couple of cases. You can remove the code associated with them here:

public class GuidContainsOperator: IFilterOperator
{
public string Operator => "contains_guid";
public Expression GetExpression(Type type, IFilterRule rule, Expression propertyExp, BuildExpressionOptions options)
{
var value = rule.Value;
if (value is Array items) value = items.GetValue(0);
var someValue = Expression.Constant(value.ToString().ToLower(), typeof(string));
var nullCheck = QueryBuilder.GetNullCheckExpression(propertyExp);
var propertyExpString = Expression.Call(propertyExp, propertyExp.Type.GetMethod("ToString", Type.EmptyTypes));
var method = propertyExpString.Type.GetMethod("Contains", new[] { type });
Expression exOut = Expression.Call(propertyExpString, typeof(string).GetMethod("ToLower", Type.EmptyTypes));
exOut = Expression.AndAlso(nullCheck, Expression.Call(exOut, method, someValue));
return exOut;
}
}
public class GuidEndsWithOperator : IFilterOperator
{
public string Operator => "ends_with_guid";
public Expression GetExpression(Type type, IFilterRule rule, Expression propertyExp, BuildExpressionOptions options)
{
var value = rule.Value;
if (value is Array items) value = items.GetValue(0);
var someValue = Expression.Constant(value.ToString().ToLower(), typeof(string));
var nullCheck = QueryBuilder.GetNullCheckExpression(propertyExp);
var propertyExpString = Expression.Call(propertyExp, propertyExp.Type.GetMethod("ToString", Type.EmptyTypes));
var method = propertyExpString.Type.GetMethod("EndsWith", new[] { type });
Expression exOut = Expression.Call(propertyExpString, typeof(string).GetMethod("ToLower", Type.EmptyTypes));
exOut = Expression.AndAlso(nullCheck, Expression.Call(exOut, method, someValue));
return exOut;
}
}
public class GuidBeginsWithOperator : IFilterOperator
{
public string Operator => "begins_with_guid";
public Expression GetExpression(Type type, IFilterRule rule, Expression propertyExp, BuildExpressionOptions options)
{
var value = rule.Value;
if (value is Array items) value = items.GetValue(0);
var someValue = Expression.Constant(value.ToString().ToLower(), typeof(string));
var nullCheck = QueryBuilder.GetNullCheckExpression(propertyExp);
var propertyExpString = Expression.Call(propertyExp, propertyExp.Type.GetMethod("ToString", Type.EmptyTypes));
var method = propertyExpString.Type.GetMethod("StartsWith", new[] { type });
Expression exOut = Expression.Call(propertyExpString, typeof(string).GetMethod("ToLower", Type.EmptyTypes));
exOut = Expression.AndAlso(nullCheck, Expression.Call(exOut, method, someValue));
return exOut;
}
}
public class GuidEqualsOperator : IFilterOperator
{
public string Operator => "equal_guid";
public Expression GetExpression(Type type, IFilterRule rule, Expression propertyExp, BuildExpressionOptions options)
{
var value = rule.Value;
Expression someValue = QueryBuilder.GetConstants(type, value, false, options).First();
Expression exOut;
if (type == typeof(string))
{
var nullCheck = QueryBuilder.GetNullCheckExpression(propertyExp);
var propertyExpString = Expression.Call(propertyExp, propertyExp.Type.GetMethod("ToString", Type.EmptyTypes));
exOut = Expression.Call(propertyExpString, typeof(string).GetMethod("ToLower", Type.EmptyTypes));
var someValueString = Expression.Call(someValue, someValue.Type.GetMethod("ToString", Type.EmptyTypes));
someValue = Expression.Call(someValueString, typeof(string).GetMethod("ToLower", Type.EmptyTypes));
exOut = Expression.AndAlso(nullCheck, Expression.Equal(exOut, someValue));
}
else
{
exOut = Expression.Equal(propertyExp, Expression.Convert(someValue, propertyExp.Type));
}
return exOut;
}
}
public class GuidInOperator : IFilterOperator
{
public string Operator => "in_guid";
public Expression GetExpression(Type type, IFilterRule rule, Expression propertyExp, BuildExpressionOptions options)
{
var value = rule.Value;
var someValues = QueryBuilder.GetConstants(type, value, true, options);
var nullCheck = QueryBuilder.GetNullCheckExpression(propertyExp);
if (QueryBuilder.IsGenericList(propertyExp.Type))
{
var genericType = propertyExp.Type.GetGenericArguments().First();
var method = propertyExp.Type.GetMethod("Contains", new[] { genericType });
Expression exOut;
if (someValues.Count > 1)
{
exOut = Expression.Call(propertyExp, method, Expression.Convert(someValues[0], genericType));
var counter = 1;
while (counter < someValues.Count)
{
exOut = Expression.Or(exOut,
Expression.Call(propertyExp, method, Expression.Convert(someValues[counter], genericType)));
counter++;
}
}
else
{
exOut = Expression.Call(propertyExp, method, Expression.Convert(someValues.First(), genericType));
}
return Expression.AndAlso(nullCheck, exOut);
}
else
{
Expression exOut;
if (someValues.Count > 1)
{
if (type == typeof(string))
{
var propertyExpString = Expression.Call(propertyExp, propertyExp.Type.GetMethod("ToString", Type.EmptyTypes));
exOut = Expression.Call(propertyExpString, typeof(string).GetMethod("ToLower", Type.EmptyTypes));
var someValueString = Expression.Call(someValues[0], someValues[0].Type.GetMethod("ToString", Type.EmptyTypes));
var somevalue = Expression.Call(someValueString, typeof(string).GetMethod("ToLower", Type.EmptyTypes));
exOut = Expression.Equal(exOut, somevalue);
var counter = 1;
while (counter < someValues.Count)
{
var nextvalueString = Expression.Call(someValues[counter], someValues[counter].Type.GetMethod("ToString", Type.EmptyTypes));
var nextvalue = Expression.Call(nextvalueString, typeof(string).GetMethod("ToLower", Type.EmptyTypes));
exOut = Expression.Or(exOut,
Expression.Equal(
Expression.Call(propertyExpString, typeof(string).GetMethod("ToLower", Type.EmptyTypes)),
nextvalue));
counter++;
}
}
else
{
exOut = Expression.Equal(propertyExp, Expression.Convert(someValues[0], propertyExp.Type));
var counter = 1;
while (counter < someValues.Count)
{
exOut = Expression.Or(exOut,
Expression.Equal(propertyExp, Expression.Convert(someValues[counter], propertyExp.Type)));
counter++;
}
}
}
else
{
if (type == typeof(string))
{
var propertyExpString = Expression.Call(propertyExp, propertyExp.Type.GetMethod("ToString", Type.EmptyTypes));
exOut = Expression.Call(propertyExpString, typeof(string).GetMethod("ToLower", Type.EmptyTypes));
var someValueString = Expression.Call(someValues.First(), someValues.First().Type.GetMethod("ToString", Type.EmptyTypes));
var somevalue = Expression.Call(someValueString, typeof(string).GetMethod("ToLower", Type.EmptyTypes));
exOut = Expression.Equal(exOut, somevalue);
}
else
{
exOut = Expression.Equal(propertyExp, Expression.Convert(someValues.First(), propertyExp.Type));
}
}
return Expression.AndAlso(nullCheck, exOut);
}
}
}

@Ibrahemkhalil
Copy link
Contributor Author

Ibrahemkhalil commented Mar 6, 2022

@tghamm no issue.
I wanted to remove the GUID custom operators but I wouldn't do that without your approval, I thought you might want to keep them as sample code, that's why I just wrote a comment of deletion there for your reference.

For datetime, some tests weren't passing because provided values have format d/m/yyyy but being parsed as m/d/yyyy (or vice versa, I don't remember actually). You need to consider documenting the right format to be provided by consumers.

Anyway, now GUID custom operators are deleted completely and all tests passed.

@tghamm
Copy link
Owner

tghamm commented Mar 6, 2022

@Ibrahemkhalil thank you. I'll give it a closer look in a bit but I think this probably rounds it out. Good note on date formatting, that is worth a revisit.

@tghamm tghamm merged commit 56b041c into tghamm:master Mar 7, 2022
@tghamm
Copy link
Owner

tghamm commented Mar 7, 2022

@Ibrahemkhalil new version has been released, thanks again for your contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants