diff --git a/Directory.Build.props b/Directory.Build.props index fb81732..26d29ca 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ - 2.0.0 + 2.0.1 Exprelsior Alexandre Murari Junior (alexmurari) @@ -12,8 +12,7 @@ https://github.com/alexmurari/Exprelsior/ -- Assemblies are strong-name signed -- Other minor code improvements + - Fixed query parser not working with short name properties. \ No newline at end of file diff --git a/Exprelsior.Shared/Exprelsior.Shared.csproj b/Exprelsior.Shared/Exprelsior.Shared.csproj index 6cbb362..8a493d3 100644 --- a/Exprelsior.Shared/Exprelsior.Shared.csproj +++ b/Exprelsior.Shared/Exprelsior.Shared.csproj @@ -8,7 +8,7 @@ bin\$(Configuration)\Package Shared functions library for Exprelsior, a .NET Standard lambda expression generator for creating dynamic predicates. icon.png - C# .NET .netstandard + C# .NET .netstandard expression predicate expression-builder predicate-builder dynamic-predicate false LICENSE true diff --git a/Exprelsior.Shared/Extensions/TypeExtensions.cs b/Exprelsior.Shared/Extensions/TypeExtensions.cs index b1cbac2..8a8d4b2 100644 --- a/Exprelsior.Shared/Extensions/TypeExtensions.cs +++ b/Exprelsior.Shared/Extensions/TypeExtensions.cs @@ -13,7 +13,7 @@ public static class TypeExtensions { /// - /// The numeric types. + /// The numeric types. /// public static readonly Type[] NumericTypes = { @@ -24,11 +24,10 @@ public static class TypeExtensions /// Returns a value indicating whether the provided type is a collection type. /// /// - /// Although implements , it is not considered a collection type by - /// this method. + /// Although implements , it is not considered a collection type by this method. /// /// The type to be checked. - /// True if it is a collection type; otherwise, false. + /// True if it is a collection type; otherwise, false. public static bool IsCollection(this Type type) { if (type.IsString()) @@ -45,7 +44,7 @@ public static bool IsCollection(this Type type) /// The type to be checked. /// /// - /// True if the type is a type; otherwise, false. + /// True if the type is a type; otherwise, false. /// public static bool IsDateTime(this Type type) { @@ -64,7 +63,7 @@ public static bool IsDateTime(this Type type) /// The type to be checked. /// /// - /// True if the type is a type; otherwise, false. + /// True if the type is a type; otherwise, false. /// public static bool IsTimeSpan(this Type type) { @@ -86,10 +85,10 @@ public static bool IsTimeSpan(this Type type) /// The type to be checked. /// /// - /// Informs whether objects should be considered generic collection types by this method. + /// The value that indicates whether objects should be considered generic collection types by this method. /// /// - /// True if the type is a generic collection; otherwise, false. + /// True if the type is a generic collection; otherwise, false. /// public static bool IsGenericCollection(this Type type, bool includeArrays = true) { @@ -101,8 +100,7 @@ public static bool IsGenericCollection(this Type type, bool includeArrays = true } /// - /// Returns a value indicating whether the provided type is a generic collection and the generic type parameter is the - /// same as the provided type. + /// Returns a value indicating whether the provided type is a generic collection and the generic type parameter is the same as the provided type. /// /// /// Although implements , it is not considered a collection type by this method. @@ -114,10 +112,10 @@ public static bool IsGenericCollection(this Type type, bool includeArrays = true /// The generic type argument of the collection. /// /// - /// Informs whether objects should be considered generic collection types by this method. + /// The value that indicates whether objects should be considered generic collection types by this method. /// /// - /// True if the type is a generic collection of the provided generic type argument; otherwise, false. + /// True if the type is a generic collection of the provided generic type argument; otherwise, false. /// public static bool IsGenericCollection(this Type type, Type genericTypeArgument, bool includeArrays = true) { @@ -132,8 +130,7 @@ public static bool IsGenericCollection(this Type type, Type genericTypeArgument, /// Returns a value indicating whether the provided type is a generic collection and the generic type parameter is included in he specified type list. /// /// - /// Although implements , it is not considered a collection type by - /// this method. + /// Although implements , it is not considered a collection type by this method. /// /// /// The type to be checked. @@ -142,10 +139,10 @@ public static bool IsGenericCollection(this Type type, Type genericTypeArgument, /// The collection of generic type arguments of the collection. /// /// - /// Informs whether objects should be considered generic collection types by this method. + /// The value that indicates whether objects should be considered generic collection types by this method. /// /// - /// True if the type is a generic collection of the provided generic type argument; otherwise, false. + /// True if the type is a generic collection of the provided generic type argument; otherwise, false. /// public static bool IsGenericCollection(this Type type, Type[] genericTypeArguments, bool includeArrays = true) { @@ -163,7 +160,7 @@ public static bool IsGenericCollection(this Type type, Type[] genericTypeArgumen /// The type to be checked. /// /// - /// True if the type is a non-generic ; otherwise, false. + /// True if the type is a non-generic ; otherwise, false. /// public static bool IsNonGenericIList(this Type type) { @@ -177,7 +174,7 @@ public static bool IsNonGenericIList(this Type type) /// The type to be checked. /// /// - /// True if the type is a numeric type; otherwise, false. + /// True if the type is a numeric type; otherwise, false. /// public static bool IsNumeric(this Type type) { @@ -196,7 +193,7 @@ public static bool IsNumeric(this Type type) /// The type to be checked. /// /// - /// True if the type is a type; otherwise, false. + /// True if the type is a type; otherwise, false. /// public static bool IsString(this Type type) { @@ -210,7 +207,7 @@ public static bool IsString(this Type type) /// The type to be checked. /// /// - /// True if the type is a type; otherwise, false. + /// True if the type is a type; otherwise, false. /// public static bool IsChar(this Type type) { @@ -229,7 +226,7 @@ public static bool IsChar(this Type type) /// The type to be checked. /// /// - /// True if the type is a type; otherwise, false. + /// True if the type is a type; otherwise, false. /// public static bool IsBoolean(this Type type) { @@ -248,7 +245,7 @@ public static bool IsBoolean(this Type type) /// The type to be checked. /// /// - /// True if the type is a type; otherwise, false. + /// True if the type is a type; otherwise, false. /// public static bool IsGuid(this Type type) { @@ -267,7 +264,8 @@ public static bool IsGuid(this Type type) /// The type to be checked. /// /// - /// True if the type is a type; otherwise, false. + /// A tuple consisting of a value indicating whether the provided type is a type + /// and the type argument of the representing the underlying type. /// public static (bool IsNullable, Type UnderlyingType) IsNullableType(this Type type) { diff --git a/Exprelsior.Tests/Exprelsior.Tests.csproj b/Exprelsior.Tests/Exprelsior.Tests.csproj index c705f03..954d881 100644 --- a/Exprelsior.Tests/Exprelsior.Tests.csproj +++ b/Exprelsior.Tests/Exprelsior.Tests.csproj @@ -2,12 +2,12 @@ netcoreapp3.1 - false - 1.0.0.0 - 1.0.0.0 + true + false + ..\ExprelsiorKey.pfx @@ -35,10 +35,10 @@ - - + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Exprelsior.Tests/QueryParser/QueryParserTests.cs b/Exprelsior.Tests/QueryParser/QueryParserTests.cs new file mode 100644 index 0000000..567139c --- /dev/null +++ b/Exprelsior.Tests/QueryParser/QueryParserTests.cs @@ -0,0 +1,32 @@ +namespace Exprelsior.Tests.QueryParser +{ + using System.Linq; + using Xunit; + + /// + /// Unit tests for the query parser. + /// + public class QueryParserTests + { + /// + /// Asserts that short name properties are correctly parsed by the query parser. + /// + /// The property name to test. + [Theory] + [InlineData("F")] + [InlineData("Fo")] + [InlineData("Foo")] + public void Assert_Short_Name_Properties_Are_Parsed_Correctly(string propertyName) + { + // Arrange + var query = $"eq('{propertyName}', '1')"; + + // Act + var queryElements = Exprelsior.DynamicQuery.Parser.QueryParser.ParseQuery(query).ToList(); + + // Assert + Assert.NotEmpty(queryElements); + Assert.Contains(queryElements, t => t.PropertyName == propertyName); + } + } +} diff --git a/Exprelsior.sln b/Exprelsior.sln index c9d7b58..91a623e 100644 --- a/Exprelsior.sln +++ b/Exprelsior.sln @@ -15,7 +15,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Directory.Build.props = Directory.Build.props ExprelsiorKey.pfx = ExprelsiorKey.pfx icon.png = icon.png - Import-PfxCertificate.psm1 = Import-PfxCertificate.psm1 README.md = README.md EndProjectSection EndProject diff --git a/Exprelsior/DynamicQuery/Parser/QueryParser.cs b/Exprelsior/DynamicQuery/Parser/QueryParser.cs index f468f47..440234e 100644 --- a/Exprelsior/DynamicQuery/Parser/QueryParser.cs +++ b/Exprelsior/DynamicQuery/Parser/QueryParser.cs @@ -48,7 +48,7 @@ internal static class QueryParser /// private static readonly Regex QueryElementsRegex = new Regex( - @"((?[A-Za-z]{2,3})(?=(\s*\(\s*))|(?<=^[A-Za-z]{2,3}\s*\(\s*)'(?(?!\.).[a-zA-Z][a-zA-Z0-9._]+)(?.+?)'\s*(?=\))|((?:\[\s*|\G(?!\A))('(?.+?)')(?:(?:\s*,\s*(?=[^\]]*?\]))|\s*\]))", + @"((?[A-Za-z]{2,3})(?=(\s*\(\s*))|(?<=^[A-Za-z]{2,3}\s*\(\s*)'(?(?!\.).[a-zA-Z0-9._]*)(?.+?)'\s*(?=\))|((?:\[\s*|\G(?!\A))('(?.+?)')(?:(?:\s*,\s*(?=[^\]]*?\]))|\s*\]))", RegexOptions.Compiled & RegexOptions.ExplicitCapture); /// diff --git a/Exprelsior/Exprelsior.csproj b/Exprelsior/Exprelsior.csproj index 9fa2fb5..9917f63 100644 --- a/Exprelsior/Exprelsior.csproj +++ b/Exprelsior/Exprelsior.csproj @@ -8,7 +8,7 @@ bin\$(Configuration)\Package A .NET Standard lambda expression generator for creating dynamic predicates. icon.png - C# .NET .netstandard expression predicate dynamicpredicates + C# .NET .netstandard expression predicate expression-builder predicate-builder dynamic-predicate false LICENSE true @@ -25,6 +25,14 @@ + + + <_Parameter1> + Exprelsior.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100ed6ebae92a81ca8042974fc0424b278c77e37027c44a3093ba08da000462165d7d1f9f2cf6619d592af4c66f925f9a143395f8ddd981cbaeaeb2775db782b10c94fd77cb47da9bb488528fc24889eddd653bdf6d6a732a3629e388361e84a31fcf059dd1b7826433c49f69ff080f18cad84506fbffe50502e3d1786903f5f5b6 + + + + diff --git a/Exprelsior/ExpressionBuilder/ExpressionBuilder.cs b/Exprelsior/ExpressionBuilder/ExpressionBuilder.cs index d545ad3..bac2f4d 100644 --- a/Exprelsior/ExpressionBuilder/ExpressionBuilder.cs +++ b/Exprelsior/ExpressionBuilder/ExpressionBuilder.cs @@ -10,24 +10,24 @@ using Exprelsior.Shared.Extensions; /// - /// Provides static methods to create instances. + /// Provides static methods to create instances representing comparison operations and property accessors. /// public static class ExpressionBuilder { /// - /// Creates a lambda expression that represents an accessor to a property from an object of type . + /// Creates a lambda expression that represents accessing a property of an object of type . /// - /// - /// The name or the path to the property to be accessed composed of simple dot-separated property access expressions. - /// /// /// The type that contains the property to be accessed. /// + /// + /// The name or the path to the property. + /// /// /// The type of the accessed property used as the delegate return type. /// /// - /// The built instance representing the property accessor. + /// A representing the property accessor. /// public static Expression> CreateAccessor(string propertyNameOrPath) { @@ -40,15 +40,14 @@ public static Expression> CreateAccessor(string pro } /// - /// Creates a binary lambda expression that compares the value of an property from an object of - /// type with the provided value using the specified comparison operator. + /// Creates a binary lambda expression that represents a comparison operation between a property + /// of and the provided value using the specified comparison operator. /// /// /// The type that contains the property to be compared. /// /// - /// The name or the path to access the property to be compared composed of simple dot-separated property access - /// expressions. + /// The name or the path to the property. /// /// /// The value to compare the property. @@ -56,15 +55,15 @@ public static Expression> CreateAccessor(string pro /// /// The comparison operator. /// - /// The built instance representing the binary operation. + /// A representing the comparison operation. public static Expression> CreateBinary(string propertyNameOrPath, object value, ExpressionOperator @operator) { return BuildBinaryExpression(propertyNameOrPath, value, @operator); } /// - /// Creates a binary lambda expression that compares the value of an property from an object of - /// type with the provided value using the specified comparison operator. + /// Creates a binary lambda expression that represents a comparison operation between a property + /// of and the provided value using the specified comparison operator. /// /// /// The type that contains the property to be compared. @@ -78,24 +77,22 @@ public static Expression> CreateBinary(string propertyNameOrPat /// /// The comparison operator. /// - /// The built instance representing the binary operation. + /// A representing the comparison operation. public static Expression> CreateBinary(PropertyInfo propertyInfo, object value, ExpressionOperator @operator) { return BuildBinaryExpression(propertyInfo.Name, value, @operator); } /// - /// Creates an from the provided object representing an query. + /// Creates a binary lambda expression that represents a comparison operation from the provided textual representation of the operation. /// /// - /// The type being queried. + /// The type that contains the property to be compared. /// /// - /// The string representing the query. + /// The textual representation of the comparison operation. /// - /// - /// The object representing the query. - /// + /// A representing the comparison operation. public static Expression> CreateBinaryFromQuery(string query) { query.ThrowIfNullOrWhitespace(nameof(query)); @@ -130,18 +127,17 @@ public static Expression> CreateBinaryFromQuery(string query) } /// - /// Creates a that represents accessing a property from an object of type - /// . + /// Creates a that represents accessing a property of an object of type . /// /// - /// The name or the path to the property to be accessed composed of simple dot-separated property access expressions. + /// The name or the path to the property. /// /// /// The type that contains the property to be accessed. /// /// /// The representing a parameter of the type that contains - /// the accessed property and the representing the accessor to the property. + /// the accessed property and the representing the property accessor. /// private static (ParameterExpression Parameter, MemberExpression Accessor) BuildAccessor(string propertyNameOrPath) { @@ -156,15 +152,14 @@ private static (ParameterExpression Parameter, MemberExpression Accessor) BuildA } /// - /// Creates a binary lambda expression that compares the value of an property from an object of - /// type with the provided value using the specified comparison operator. + /// Creates a binary lambda expression that represents a comparison operation between a property + /// of and the provided value using the specified comparison operator. /// /// /// The type with the property to be compared. /// /// - /// The name or the path to access the property to be compared composed of simple dot-separated property access - /// expressions. + /// The name or the path to the property. /// /// /// The value to compare the property. @@ -172,7 +167,7 @@ private static (ParameterExpression Parameter, MemberExpression Accessor) BuildA /// /// The comparison operator. /// - /// The built instance representing the binary operation. + /// A representing the comparison operation. private static Expression> BuildBinaryExpression(string propertyNameOrPath, object value, ExpressionOperator @operator) { propertyNameOrPath.ThrowIfNullOrWhitespace(nameof(propertyNameOrPath)); diff --git a/Exprelsior/ExpressionBuilder/Parser/ExpressionTypeParser.cs b/Exprelsior/ExpressionBuilder/Parser/ExpressionTypeParser.cs index 55761de..56f6a94 100644 --- a/Exprelsior/ExpressionBuilder/Parser/ExpressionTypeParser.cs +++ b/Exprelsior/ExpressionBuilder/Parser/ExpressionTypeParser.cs @@ -34,25 +34,25 @@ internal static (Expression property, Expression value) BuildAccessorAndValue(Ex Expression resultValue; var propertyType = property.Type; - var propertyTypeNullable = propertyType.IsNullableType(); - var propertyUnderlyingType = propertyType.IsGenericCollection() ? propertyType.IsArray ? propertyType.GetElementType() : propertyType.GetGenericArguments()[0] : propertyType; - var propertyUnderlyingTypeNullable = propertyUnderlyingType.IsNullableType(); + var (isNullableType, _) = propertyType.IsNullableType(); + var propertyUnderlyingType = propertyType.IsGenericCollection() ? ExtractGenericCollectionType(propertyType) : propertyType; + var (isNullableUnderlyingType, underlyingType) = propertyUnderlyingType.IsNullableType(); if (propertyUnderlyingType == null) throw new InvalidOperationException(); - var propertyAbsoluteType = propertyUnderlyingTypeNullable.IsNullable ? propertyUnderlyingTypeNullable.UnderlyingType : propertyUnderlyingType; + var propertyAbsoluteType = isNullableUnderlyingType ? underlyingType : propertyUnderlyingType; var valueType = value?.GetType(); switch (value) { - case null when propertyType.IsValueType && !propertyTypeNullable.IsNullable: + case null when propertyType.IsValueType && !isNullableType: throw new InvalidOperationException($"Invalid comparison: provided a null value for comparing with a non-nullable type. Type: {propertyType.Name}."); case null: return (resultProperty, Expression.Convert(Expression.Constant(null), propertyUnderlyingType)); case IEnumerable valueCollection: { - if (propertyUnderlyingType.IsValueType && !propertyUnderlyingTypeNullable.IsNullable && valueCollection.Cast().Any(t => t == null)) + if (propertyUnderlyingType.IsValueType && !isNullableUnderlyingType && valueCollection.Cast().Any(t => t == null)) { throw new InvalidOperationException($"Invalid comparison: provided a null value for comparing with a non-nullable type. Type: {propertyType.Name}."); } @@ -63,7 +63,7 @@ internal static (Expression property, Expression value) BuildAccessorAndValue(Ex if (@operator == ExpressionOperator.ContainsOnValue) { - resultValue = Expression.Constant(ParseCollectionValues(value, propertyType, propertyAbsoluteType, propertyTypeNullable.IsNullable)); + resultValue = Expression.Constant(ParseCollectionValues(value, propertyType, propertyAbsoluteType, isNullableType)); } else { @@ -88,14 +88,13 @@ internal static (Expression property, Expression value) BuildAccessorAndValue(Ex value = ParseStringToGuid(value); } else - value = ParseCollectionValues(value, propertyUnderlyingType, propertyAbsoluteType, propertyUnderlyingTypeNullable.IsNullable); + value = ParseCollectionValues(value, propertyUnderlyingType, propertyAbsoluteType, isNullableUnderlyingType); valueType = value?.GetType(); - if (!valueType.IsGenericCollection(propertyUnderlyingType) && propertyUnderlyingTypeNullable.IsNullable) - resultValue = Expression.Convert(Expression.Constant(value), propertyUnderlyingType); - else - resultValue = Expression.Constant(value); + resultValue = !valueType.IsGenericCollection(propertyUnderlyingType) && isNullableUnderlyingType + ? (Expression)Expression.Convert(Expression.Constant(value), propertyUnderlyingType) + : Expression.Constant(value); } else resultValue = Expression.Constant(value); @@ -109,42 +108,42 @@ internal static (Expression property, Expression value) BuildAccessorAndValue(Ex { resultValue = valueType.IsChar() ? Expression.Constant(value) : Expression.Constant(ParseStringToChar(value)); - if (propertyTypeNullable.IsNullable) + if (isNullableType) resultValue = Expression.Convert(resultValue, propertyType); } else if (propertyType.IsNumeric()) { resultValue = valueType.IsNumeric() ? Expression.Constant(value) : Expression.Constant(ParseObjectToNumber(value, propertyAbsoluteType)); - if (propertyTypeNullable.IsNullable) + if (isNullableType) resultValue = Expression.Convert(resultValue, propertyType); } else if (propertyType.IsDateTime()) { resultValue = valueType.IsDateTime() ? Expression.Constant(value) : Expression.Constant(ParseStringToDateTime(value)); - if (propertyTypeNullable.IsNullable) + if (isNullableType) resultValue = Expression.Convert(resultValue, propertyType); } else if (propertyType.IsTimeSpan()) { resultValue = valueType.IsTimeSpan() ? Expression.Constant(value) : Expression.Constant(ParseStringToTimeSpan(value)); - if (propertyTypeNullable.IsNullable) + if (isNullableType) resultValue = Expression.Convert(resultValue, propertyType); } else if (propertyType.IsBoolean()) { resultValue = valueType.IsBoolean() ? Expression.Constant(value) : Expression.Constant(ConvertToBoolean(value)); - if (propertyTypeNullable.IsNullable) + if (isNullableType) resultValue = Expression.Convert(resultValue, propertyType); } else if (propertyType.IsGuid()) { resultValue = valueType.IsGuid() ? Expression.Constant(value) : Expression.Constant(ParseStringToGuid(value)); - if (propertyTypeNullable.IsNullable) + if (isNullableType) resultValue = Expression.Convert(resultValue, propertyType); } else @@ -152,6 +151,11 @@ internal static (Expression property, Expression value) BuildAccessorAndValue(Ex } return (resultProperty, resultValue); + + Type ExtractGenericCollectionType(Type genericCollectionType) + { + return genericCollectionType.IsArray ? genericCollectionType.GetElementType() : genericCollectionType.GetGenericArguments()[0]; + } } /// @@ -225,12 +229,14 @@ private static object ParseCollectionValues(object value, Type propertyType, Typ /// private static object ConvertCollectionToBoolean(object value, bool isNullable = false) { - if (value is IEnumerable collection) + switch (value) { - return isNullable ? (object)collection.Select(ConvertToBoolean).ToList() : collection.Select(t => ConvertToBoolean(t).GetValueOrDefault()).ToList(); - } + case IEnumerable collection: + return isNullable ? (object)collection.Select(ConvertToBoolean).ToList() : collection.Select(t => ConvertToBoolean(t).GetValueOrDefault()).ToList(); - return value; + default: + return value; + } } /// @@ -342,12 +348,14 @@ private static object ParseObjectCollectionToNumber(object value, Type propertyT /// private static object ParseStringCollectionToDateTime(object value, bool isNullable = false) { - if (value is IEnumerable collection) + switch (value) { - return isNullable ? (object)collection.Select(ParseStringToDateTime).ToList() : collection.Select(t => ParseStringToDateTime(t).GetValueOrDefault()).ToList(); - } + case IEnumerable collection: + return isNullable ? (object)collection.Select(ParseStringToDateTime).ToList() : collection.Select(t => ParseStringToDateTime(t).GetValueOrDefault()).ToList(); - return null; + default: + return null; + } } /// @@ -390,12 +398,14 @@ private static object ParseStringCollectionToDateTime(object value, bool isNulla /// private static object ParseStringCollectionToTimeSpan(object value, bool isNullable = false) { - if (value is IEnumerable collection) + switch (value) { - return isNullable ? (object)collection.Select(ParseStringToTimeSpan).ToList() : collection.Select(t => ParseStringToTimeSpan(t).GetValueOrDefault()).ToList(); - } + case IEnumerable collection: + return isNullable ? (object)collection.Select(ParseStringToTimeSpan).ToList() : collection.Select(t => ParseStringToTimeSpan(t).GetValueOrDefault()).ToList(); - return null; + default: + return null; + } } /// @@ -438,12 +448,14 @@ private static object ParseStringCollectionToTimeSpan(object value, bool isNulla /// private static object ParseStringCollectionToGuid(object value, bool isNullable = false) { - if (value is IEnumerable collection) + switch (value) { - return isNullable ? (object)collection.Select(ParseStringToGuid).ToList() : collection.Select(t => ParseStringToGuid(t).GetValueOrDefault()).ToList(); - } + case IEnumerable collection: + return isNullable ? (object)collection.Select(ParseStringToGuid).ToList() : collection.Select(t => ParseStringToGuid(t).GetValueOrDefault()).ToList(); - return null; + default: + return null; + } } /// @@ -486,12 +498,14 @@ private static object ParseStringCollectionToGuid(object value, bool isNullable /// private static object ParseStringCollectionToChar(object value, bool isNullable = false) { - if (value is IEnumerable collection) + switch (value) { - return isNullable ? (object)collection.Select(ParseStringToChar).ToList() : collection.Select(t => ParseStringToChar(t).GetValueOrDefault()).ToList(); - } + case IEnumerable collection: + return isNullable ? (object)collection.Select(ParseStringToChar).ToList() : collection.Select(t => ParseStringToChar(t).GetValueOrDefault()).ToList(); - return null; + default: + return null; + } } } } diff --git a/Import-PfxCertificate.psm1 b/Import-PfxCertificate.psm1 deleted file mode 100644 index 0ce403b..0000000 --- a/Import-PfxCertificate.psm1 +++ /dev/null @@ -1,31 +0,0 @@ -function Import-PfxCertificate { - Param ( - [string] $pfx, - [string] $password, - [string] $containerName - ); - process { - if(!(Test-Path -Path $pfx)) { - Write-Warning "Unable to locate PFX file: $pfx"; - return; - } - - $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2; - $cert.Import($pfx, $password, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable); - $exportPrivateKeyInformation = $true; - $certXml = $cert.PrivateKey.ToXmlString($exportPrivateKeyInformation); - - $csp = New-Object System.Security.Cryptography.CspParameters; - $csp.KeyContainerName = $containerName; - $csp.Flags = [System.Security.Cryptography.CspProviderFlags]::UseMachineKeyStore -bor [System.Security.Cryptography.CspProviderFlags]::NoPrompt; # -bor is bitwise or - $csp.KeyNumber = [System.Security.Cryptography.KeyNumber]::Signature; - - $rsa = New-Object System.Security.Cryptography.RSACryptoServiceProvider $csp; - $rsa.FromXmlString($certXml); - $rsa.Clear(); - - "Sucesfully imported $pfx into StrongName CSP store"; - } -} - -Export-ModuleMember -Function Import-PfxCertificate; \ No newline at end of file diff --git a/README.md b/README.md index 42fd509..d845119 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,10 @@ Exprelsior

- A .NET Standard lambda expression generator for creating dynamic predicates. + A .NET Standard lambda expression generator for building dynamic predicates.

- + Nuget @@ -23,7 +23,7 @@

- + Nuget (with prereleases) @@ -40,8 +40,8 @@ ## What is Exprelsior? -Exprelsior is a .NET Standard library that enables .NET developers to create strongly-typed -binary lambda expressions from pure text using it's own query syntax or from the expression builder method. +Exprelsior is a .NET Standard library that enables .NET developers to dynamically create strongly-typed +binary lambda expressions from pure text using it's own query syntax. With support to all major .NET data types, including nullable types, nested properties and it's own query syntax, Exprelsior brings the creation of dynamic predicates to a whole new level. @@ -54,6 +54,7 @@ brings the creation of dynamic predicates to a whole new level. 2. [Usage](#2-usage) 1. [Query Syntax Example](#query-syntax-example) 2. [Expression Builder Example](#expression-builder-example) + 3. [Property Accessor Example](#property-accessor-example) 3. [The Query Syntax](#3-the-query-syntax) 1. [Query Elements](#query-elements) 2. [Creating Simple Queries](#simple-queries) @@ -71,7 +72,7 @@ brings the creation of dynamic predicates to a whole new level. ## 1. Overview -The objective of this library is to build binary lambda expressions in an dynamic manner. +The objective of this library is to build binary lambda expressions in a dynamic manner. Example: @@ -132,6 +133,23 @@ public async Task Get([FromQuery] int @operator, [FromQuery] stri return result; } ``` + +### Property Accessor Example + +```csharp +[HttpGet] +public async Task Get() +{ + var accessor = ExpressionBuilder.CreateAccessor("DateOfBirth.Date"); + + // accessor = (Expression>) t => t.DateOfBirth.Date + + var result = await FooRepository.Query.OrderBy(accessor).ToList(); + + return result; +} +``` + --- ## 3. The Query Syntax diff --git a/SnInstallPfx.exe b/SnInstallPfx.exe new file mode 100644 index 0000000..683d922 Binary files /dev/null and b/SnInstallPfx.exe differ diff --git a/appveyor.yml b/appveyor.yml index 3a2bff7..daaec3a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -42,8 +42,7 @@ before_build: # Import PFX file for strong naming assemblies. - ps: | - Import-Module "$env:APPVEYOR_BUILD_FOLDER\Import-PfxCertificate.psm1"; - Import-PfxCertificate -pfx "$env:APPVEYOR_BUILD_FOLDER\ExprelsiorKey.pfx" -password $env:certificate_pass -containerName $env:certificate_container_name; + Start-Process -FilePath "$env:APPVEYOR_BUILD_FOLDER\SnInstallPfx.exe" -ArgumentList "$env:APPVEYOR_BUILD_FOLDER\ExprelsiorKey.pfx $env:certificate_pass" -NoNewWindow - ps: dotnet restore