QueryExpressionBuilder

Library for building Predicate Expression from query models
git clone git://185.198.27.126/QueryExpressionBuilder.git
Log | Files | Refs | README

commit 3400be98ae7ae670646c7e501ca2f592fcbb4903
parent c7692bb523fad5cdfc35c972d415d240d941266d
Author: sergik776 <sergik776@yandex.com>
Date:   Sat, 11 May 2024 09:37:23 +0300

New version after publish

Diffstat:
M.gitignore | 6+++---
M.nuspec | 25++++++++++++-------------
MQueryExpressionBuilder.sln | 50+++++++++++++++++++++++++-------------------------
MQueryExpressionBuilder/Attributes.cs | 200++++++++++++++++++++++++++++++++++++++++----------------------------------------
MQueryExpressionBuilder/ExpressionBuilder.cs | 336++++++++++++++++++++++++++++++++++++++++----------------------------------------
MQueryExpressionBuilder/QueryExpressionBuilder.csproj | 37+++++++++++++++++++++++++++----------
MQueryExpressionBuilder/QueryExpressionBuilder.csproj.user | 10+++++-----
MREADME.md | 444++++++++++++++++++++++++++++++++++++++++----------------------------------------
8 files changed, 562 insertions(+), 546 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,4 +1,4 @@ -.vs/* -QueryExpressionBuilder/bin/* -QueryExpressionBuilder/obj/* +.vs/* +QueryExpressionBuilder/bin/* +QueryExpressionBuilder/obj/* QueryExpressionBuilder/Properties/* \ No newline at end of file diff --git a/.nuspec b/.nuspec @@ -1,14 +1,13 @@ -<?xml version="1.0" encoding="utf-8"?> -<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> - <metadata> - <!-- Required elements--> - <id>QueryExpressionBuilder</id> - <version>1.0.0.0</version> - <description>This library helps create a predicate function for filtering database queries based on a model.</description> - <authors>Created by Taogar. </authors> - <licenseUrl>This project is distributed under the [MIT](https://opensource.org/licenses/MIT) license, which allows free use, modification, and distribution of the code in accordance with the terms of the MIT license.</licenseUrl> - <!-- Optional elements --> - <!-- ... --> - </metadata> - <!-- Optional 'files' node --> +<?xml version="1.0" encoding="utf-8"?> +<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> + <metadata> + <!-- Required elements--> + <id>QueryExpressionBuilder</id> + <version>1.1.0.2904</version> + <description>This library helps create a predicate function for filtering database queries based on a model.</description> + <authors>Created by Taogar. </authors> + <licenseUrl>This project is distributed under the [MIT](https://opensource.org/licenses/MIT) license, which allows free use, modification, and distribution of the code in accordance with the terms of the MIT license.</licenseUrl> + <projectUrl>Link on [GitHub](https://github.com/sergik776/QueryExpressionBuilder)</projectUrl> + </metadata> + <!-- Optional 'files' node --> </package> \ No newline at end of file diff --git a/QueryExpressionBuilder.sln b/QueryExpressionBuilder.sln @@ -1,25 +1,25 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.9.34511.98 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QueryExpressionBuilder", "QueryExpressionBuilder\QueryExpressionBuilder.csproj", "{C6B925B3-E450-4830-9B40-305102A14309}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C6B925B3-E450-4830-9B40-305102A14309}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C6B925B3-E450-4830-9B40-305102A14309}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C6B925B3-E450-4830-9B40-305102A14309}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C6B925B3-E450-4830-9B40-305102A14309}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {7E174301-9FE3-4552-830F-D0AEB96012A0} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34511.98 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QueryExpressionBuilder", "QueryExpressionBuilder\QueryExpressionBuilder.csproj", "{C6B925B3-E450-4830-9B40-305102A14309}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C6B925B3-E450-4830-9B40-305102A14309}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6B925B3-E450-4830-9B40-305102A14309}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6B925B3-E450-4830-9B40-305102A14309}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6B925B3-E450-4830-9B40-305102A14309}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {7E174301-9FE3-4552-830F-D0AEB96012A0} + EndGlobalSection +EndGlobal diff --git a/QueryExpressionBuilder/Attributes.cs b/QueryExpressionBuilder/Attributes.cs @@ -1,100 +1,100 @@ -namespace QueryExpressionBuilder.Attributes -{ - /// <summary> - /// Attribute to filtration strings - /// </summary> - public class String - { - - /// <summary> - /// Filtration func StartWith - /// </summary> - [AttributeUsage(AttributeTargets.Property)] - public class StartWithAttribute : BasePredicateAttribute - { - /// <summary> - /// Add attribute func StartWith - /// </summary> - /// <param name="propertyName">Name of property in DB</param> - public StartWithAttribute(string propertyName) : base(propertyName) - { - } - } - - /// <summary> - /// Filtration by contains function - /// </summary> - public class ContainsAttribute : BasePredicateAttribute - { - public ContainsAttribute(string propertyName) : base (propertyName) - { - } - } - } - - /// <summary> - /// Attribute to filtration numbers and DateTime - /// </summary> - public class Numbers - { - /// <summary> - /// Filtration func GreaterOrEqual - /// </summary> - [AttributeUsage(AttributeTargets.Property)] - public class GreaterOrEqualAttribute : BasePredicateAttribute - { - /// <summary> - /// Add attribute func >= - /// </summary> - public GreaterOrEqualAttribute(string propertyName) : base(propertyName) - { - } - } - - /// <summary> - /// Filtration func LessOrEqual - /// </summary> - [AttributeUsage(AttributeTargets.Property)] - public class LessOrEqualAttribute : BasePredicateAttribute - { - /// <summary> - /// Add attribute func <= - /// </summary> - public LessOrEqualAttribute(string propertyName) : base(propertyName) - { - } - } - - /// <summary> - /// Filtration by equals function - /// </summary> - public class EqualsAttribute : BasePredicateAttribute - { - public EqualsAttribute(string propertyName) : base(propertyName) - { - - } - } - } - - /// <summary> - /// Base filtration class - /// </summary> - [AttributeUsage(AttributeTargets.Property)] - public class BasePredicateAttribute : Attribute - { - /// <summary> - /// Name of property in DB - /// </summary> - public string PropertyName { get; set; } - - /// <summary> - /// Constructor with name of property in DB - /// </summary> - /// <param name="propertyName"></param> - public BasePredicateAttribute(string propertyName) - { - PropertyName = propertyName; - } - } -} +namespace QueryExpressionBuilder.Attributes +{ + /// <summary> + /// Attribute to filtration strings + /// </summary> + public class String + { + + /// <summary> + /// Filtration func StartWith + /// </summary> + [AttributeUsage(AttributeTargets.Property)] + public class StartWithAttribute : BasePredicateAttribute + { + /// <summary> + /// Add attribute func StartWith + /// </summary> + /// <param name="propertyName">Name of property in DB</param> + public StartWithAttribute(string propertyName) : base(propertyName) + { + } + } + + /// <summary> + /// Filtration by contains function + /// </summary> + public class ContainsAttribute : BasePredicateAttribute + { + public ContainsAttribute(string propertyName) : base (propertyName) + { + } + } + } + + /// <summary> + /// Attribute to filtration numbers and DateTime + /// </summary> + public class Numbers + { + /// <summary> + /// Filtration func GreaterOrEqual + /// </summary> + [AttributeUsage(AttributeTargets.Property)] + public class GreaterOrEqualAttribute : BasePredicateAttribute + { + /// <summary> + /// Add attribute func >= + /// </summary> + public GreaterOrEqualAttribute(string propertyName) : base(propertyName) + { + } + } + + /// <summary> + /// Filtration func LessOrEqual + /// </summary> + [AttributeUsage(AttributeTargets.Property)] + public class LessOrEqualAttribute : BasePredicateAttribute + { + /// <summary> + /// Add attribute func <= + /// </summary> + public LessOrEqualAttribute(string propertyName) : base(propertyName) + { + } + } + + /// <summary> + /// Filtration by equals function + /// </summary> + public class EqualsAttribute : BasePredicateAttribute + { + public EqualsAttribute(string propertyName) : base(propertyName) + { + + } + } + } + + /// <summary> + /// Base filtration class + /// </summary> + [AttributeUsage(AttributeTargets.Property)] + public class BasePredicateAttribute : Attribute + { + /// <summary> + /// Name of property in DB + /// </summary> + public string PropertyName { get; set; } + + /// <summary> + /// Constructor with name of property in DB + /// </summary> + /// <param name="propertyName"></param> + public BasePredicateAttribute(string propertyName) + { + PropertyName = propertyName; + } + } +} diff --git a/QueryExpressionBuilder/ExpressionBuilder.cs b/QueryExpressionBuilder/ExpressionBuilder.cs @@ -1,168 +1,168 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using static QueryExpressionBuilder.Attributes.Numbers; -using static QueryExpressionBuilder.Attributes.String; - -namespace QueryExpressionBuilder -{ - /// <summary> - /// Class converter from Query model with attributes to predicate func - /// </summary> - public static class ExpressionBuilder - { - /// <summary> - /// Extension method - /// </summary> - /// <typeparam name="TDB">Type in DB</typeparam> - /// <typeparam name="TQE">Type of Query object</typeparam> - /// <param name="queryParams">Dictionary</param> - /// <returns>Predicate func</returns> - public static Expression<Func<TDB, bool>>? ToPredicate<TDB, TQE>(this Dictionary<string, string> queryParams) - { - return GetPredicateFromDictionary<TDB, TQE>(queryParams); - } - - /// <summary> - /// Make predicate from dictionary - /// </summary> - /// <typeparam name="TDB">Type in DB</typeparam> - /// <typeparam name="TQE">Type of Query object</typeparam> - /// <param name="queryParams">Dictionary</param> - /// <returns>Predicate func</returns> - public static Expression<Func<TDB, bool>>? GetPredicateFromDictionary<TDB, TQE>(Dictionary<string, string> queryParams) - { - var query = GetQueryObject<TQE>(queryParams); - return GetPredicate<TDB, TQE>(query); - } - - /// <summary> - /// Make Query instance - /// </summary> - /// <typeparam name="T">Type of Query</typeparam> - /// <param name="queryParams">Dictionary</param> - /// <returns>Instance</returns> - public static T GetQueryObject<T>(Dictionary<string, string> queryParams) - { - Type type = typeof(T); - T queryObject = Activator.CreateInstance<T>(); - - foreach (var property in type.GetProperties()) - { - if (queryParams.ContainsKey(property.Name)) - { - object value; - Type propertyType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType; - - if (propertyType == typeof(string) && string.IsNullOrEmpty(queryParams[property.Name])) - { - value = null; - } - else - { - value = Convert.ChangeType(queryParams[property.Name], propertyType); - } - - property.SetValue(queryObject, value); - } - } - - return queryObject; - } - - /// <summary> - /// Make new predicate func - /// </summary> - /// <typeparam name="TDB">Type in DB</typeparam> - /// <typeparam name="TQE">Query type</typeparam> - /// <returns>Predicate func</returns> - public static Expression<Func<TDB, bool>>? GetPredicate<TDB, TQE>(TQE query) - { - var userParameter = Expression.Parameter(typeof(TDB), typeof(TDB).Name.ToLower()); - List<Expression> conditions = new List<Expression>(); - - //Только те свойства которые помечены атрибутами - var T_pr_props = typeof(TQE).GetProperties().Where(prop => prop.GetCustomAttribute<LessOrEqualAttribute>() != null || - prop.GetCustomAttribute<GreaterOrEqualAttribute>() != null || prop.GetCustomAttribute<StartWithAttribute>() != null || - prop.GetCustomAttribute<ContainsAttribute>() != null || prop.GetCustomAttribute<EqualsAttribute>() != null).ToArray(); - - //Проходимся по всем параметрам класса БД - foreach (var p in typeof(TDB).GetProperties()) - { - var yslovia = T_pr_props.Where(x => x.Name.Contains(p.Name)); - foreach (var y in yslovia) - { - if (y.GetCustomAttribute<StartWithAttribute>() != null) - { - var propertyY = Expression.Property(userParameter, p.Name); - var propertyP = Expression.Property(userParameter, p.Name); - var containsCall = Expression.Call(propertyP, "StartsWith", null, Expression.Constant(y.GetValue(query), typeof(string))); - var obj = y.GetValue(query); - if (obj != null) - { - conditions.Add(containsCall); - } - } - else if(y.GetCustomAttribute<ContainsAttribute>() != null) - { - var propertyY = Expression.Property(userParameter, p.Name); - var propertyP = Expression.Property(userParameter, p.Name); - var containsCall = Expression.Call(propertyP, "Contains", null, Expression.Constant(y.GetValue(query), typeof(string))); - var obj = y.GetValue(query); - if (obj != null) - { - conditions.Add(containsCall); - } - } - else if (y.GetCustomAttribute<GreaterOrEqualAttribute>() != null) - { - var propertyName = y.GetCustomAttribute<GreaterOrEqualAttribute>().PropertyName; - var propertyY = Expression.Property(userParameter, propertyName); - var obj = y.GetValue(query); - if (obj != null) - { - var value = Convert.ChangeType(obj, p.PropertyType); - var constantValue = Expression.Constant(value, p.PropertyType); - var condition = Expression.GreaterThanOrEqual(propertyY, constantValue); - conditions.Add(condition); - } - } - else if (y.GetCustomAttribute<LessOrEqualAttribute>() != null) - { - var propertyName = y.GetCustomAttribute<LessOrEqualAttribute>().PropertyName; - var propertyY = Expression.Property(userParameter, propertyName); - var obj = y.GetValue(query); - if (obj != null) - { - var value = Convert.ChangeType(obj, p.PropertyType); - var constantValue = Expression.Constant(value, p.PropertyType); - var condition = Expression.LessThanOrEqual(propertyY, constantValue); - conditions.Add(condition); - } - } - else if(y.GetCustomAttribute<EqualsAttribute>() != null) - { - var propertyName = y.GetCustomAttribute<EqualsAttribute>().PropertyName; - var propertyY = Expression.Property(userParameter, propertyName); - var obj = y.GetValue(query); - if (obj != null) - { - var value = Convert.ChangeType(obj, p.PropertyType); - var constantValue = Expression.Constant(value, p.PropertyType); - var condition = Expression.Equal(propertyY, constantValue); - conditions.Add(condition); - } - } - } - } - - var body = conditions.Aggregate(Expression.AndAlso); - var predicate = Expression.Lambda<Func<TDB, bool>>(body, userParameter); - return predicate; - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using static QueryExpressionBuilder.Attributes.Numbers; +using static QueryExpressionBuilder.Attributes.String; + +namespace QueryExpressionBuilder +{ + /// <summary> + /// Class converter from Query model with attributes to predicate func + /// </summary> + public static class ExpressionBuilder + { + /// <summary> + /// Extension method + /// </summary> + /// <typeparam name="TDB">Type in DB</typeparam> + /// <typeparam name="TQE">Type of Query object</typeparam> + /// <param name="queryParams">Dictionary</param> + /// <returns>Predicate func</returns> + public static Expression<Func<TDB, bool>>? ToPredicate<TDB, TQE>(this Dictionary<string, string> queryParams) + { + return GetPredicateFromDictionary<TDB, TQE>(queryParams); + } + + /// <summary> + /// Make predicate from dictionary + /// </summary> + /// <typeparam name="TDB">Type in DB</typeparam> + /// <typeparam name="TQE">Type of Query object</typeparam> + /// <param name="queryParams">Dictionary</param> + /// <returns>Predicate func</returns> + public static Expression<Func<TDB, bool>>? GetPredicateFromDictionary<TDB, TQE>(Dictionary<string, string> queryParams) + { + var query = GetQueryObject<TQE>(queryParams); + return GetPredicate<TDB, TQE>(query); + } + + /// <summary> + /// Make Query instance + /// </summary> + /// <typeparam name="T">Type of Query</typeparam> + /// <param name="queryParams">Dictionary</param> + /// <returns>Instance</returns> + public static T GetQueryObject<T>(Dictionary<string, string> queryParams) + { + Type type = typeof(T); + T queryObject = Activator.CreateInstance<T>(); + + foreach (var property in type.GetProperties()) + { + if (queryParams.ContainsKey(property.Name)) + { + object value; + Type propertyType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType; + + if (propertyType == typeof(string) && string.IsNullOrEmpty(queryParams[property.Name])) + { + value = null; + } + else + { + value = Convert.ChangeType(queryParams[property.Name], propertyType); + } + + property.SetValue(queryObject, value); + } + } + + return queryObject; + } + + /// <summary> + /// Make new predicate func + /// </summary> + /// <typeparam name="TDB">Type in DB</typeparam> + /// <typeparam name="TQE">Query type</typeparam> + /// <returns>Predicate func</returns> + public static Expression<Func<TDB, bool>>? GetPredicate<TDB, TQE>(TQE query) + { + var userParameter = Expression.Parameter(typeof(TDB), typeof(TDB).Name.ToLower()); + List<Expression> conditions = new List<Expression>(); + + //Только те свойства которые помечены атрибутами + var T_pr_props = typeof(TQE).GetProperties().Where(prop => prop.GetCustomAttribute<LessOrEqualAttribute>() != null || + prop.GetCustomAttribute<GreaterOrEqualAttribute>() != null || prop.GetCustomAttribute<StartWithAttribute>() != null || + prop.GetCustomAttribute<ContainsAttribute>() != null || prop.GetCustomAttribute<EqualsAttribute>() != null).ToArray(); + + //Проходимся по всем параметрам класса БД + foreach (var p in typeof(TDB).GetProperties()) + { + var yslovia = T_pr_props.Where(x => x.Name.Contains(p.Name)); + foreach (var y in yslovia) + { + if (y.GetCustomAttribute<StartWithAttribute>() != null) + { + var obj = y.GetValue(query); + if (obj != null) + { + var propertyY = Expression.Property(userParameter, p.Name); + var propertyP = Expression.Property(userParameter, p.Name); + var containsCall = Expression.Call(propertyP, "StartsWith", null, Expression.Constant(y.GetValue(query), typeof(string))); + conditions.Add(containsCall); + } + } + else if(y.GetCustomAttribute<ContainsAttribute>() != null) + { + var obj = y.GetValue(query); + if (obj != null) + { + var propertyY = Expression.Property(userParameter, p.Name); + var propertyP = Expression.Property(userParameter, p.Name); + var containsCall = Expression.Call(propertyP, "Contains", null, Expression.Constant(y.GetValue(query), typeof(string))); + conditions.Add(containsCall); + } + } + else if (y.GetCustomAttribute<GreaterOrEqualAttribute>() != null) + { + var propertyName = y.GetCustomAttribute<GreaterOrEqualAttribute>().PropertyName; + var propertyY = Expression.Property(userParameter, propertyName); + var obj = y.GetValue(query); + if (obj != null) + { + var value = Convert.ChangeType(obj, p.PropertyType); + var constantValue = Expression.Constant(value, p.PropertyType); + var condition = Expression.GreaterThanOrEqual(propertyY, constantValue); + conditions.Add(condition); + } + } + else if (y.GetCustomAttribute<LessOrEqualAttribute>() != null) + { + var propertyName = y.GetCustomAttribute<LessOrEqualAttribute>().PropertyName; + var propertyY = Expression.Property(userParameter, propertyName); + var obj = y.GetValue(query); + if (obj != null) + { + var value = Convert.ChangeType(obj, p.PropertyType); + var constantValue = Expression.Constant(value, p.PropertyType); + var condition = Expression.LessThanOrEqual(propertyY, constantValue); + conditions.Add(condition); + } + } + else if(y.GetCustomAttribute<EqualsAttribute>() != null) + { + var propertyName = y.GetCustomAttribute<EqualsAttribute>().PropertyName; + var propertyY = Expression.Property(userParameter, propertyName); + var obj = y.GetValue(query); + if (obj != null) + { + var value = Convert.ChangeType(obj, p.PropertyType); + var constantValue = Expression.Constant(value, p.PropertyType); + var condition = Expression.Equal(propertyY, constantValue); + conditions.Add(condition); + } + } + } + } + + var body = conditions.Aggregate(Expression.AndAlso); + var predicate = Expression.Lambda<Func<TDB, bool>>(body, userParameter); + return predicate; + } + } +} diff --git a/QueryExpressionBuilder/QueryExpressionBuilder.csproj b/QueryExpressionBuilder/QueryExpressionBuilder.csproj @@ -1,10 +1,27 @@ -<Project Sdk="Microsoft.NET.Sdk"> - - <PropertyGroup> - <TargetFramework>net8.0</TargetFramework> - <ImplicitUsings>enable</ImplicitUsings> - <Nullable>enable</Nullable> - <GenerateDocumentationFile>True</GenerateDocumentationFile> - </PropertyGroup> - -</Project> +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>net8.0</TargetFramework> + <ImplicitUsings>enable</ImplicitUsings> + <Nullable>enable</Nullable> + <GenerateDocumentationFile>True</GenerateDocumentationFile> + <Version>1.1.0.2904</Version> + <SignAssembly>True</SignAssembly> + <Authors>Taogar</Authors> + <PackageProjectUrl></PackageProjectUrl> + <RepositoryUrl>https://github.com/sergik776/QueryExpressionBuilder</RepositoryUrl> + <AssemblyVersion>1.1.0.2904</AssemblyVersion> + <FileVersion>1.1.0.2904</FileVersion> + <PackageLicenseExpression>MIT</PackageLicenseExpression> + <PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance> + <PackageReadmeFile>README.md</PackageReadmeFile> + </PropertyGroup> + + <ItemGroup> + <None Include="..\README.md"> + <Pack>True</Pack> + <PackagePath>\</PackagePath> + </None> + </ItemGroup> + +</Project> diff --git a/QueryExpressionBuilder/QueryExpressionBuilder.csproj.user b/QueryExpressionBuilder/QueryExpressionBuilder.csproj.user @@ -1,6 +1,6 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup> - <_LastSelectedProfileId>P:\MyEcoSpace\Libraries\Helpers\QueryExpressionBuilder\QueryExpressionBuilder\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId> - </PropertyGroup> +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <_LastSelectedProfileId>P:\MyEcoSpace\Libraries\Helpers\QueryExpressionBuilder\QueryExpressionBuilder\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId> + </PropertyGroup> </Project> \ No newline at end of file diff --git a/README.md b/README.md @@ -1,223 +1,223 @@ -# QueryExpressionBuilder -Library for generating predicate functions for filtering database queries. - -## Description -This library helps create a predicate function for filtering database queries based on a model. - -## Instruction -To use the library, you need to create a model with properties for filtering. Properties in the model need to be marked with attributes.<br> - -Currently, there are 3 attributes:<br> - -Namespace QueryExpressionBuilder.Attributes.String - attributes for properties of type String<br> -StartWithAttribute - Indicates that a filter equivalent to the System.String.StartWith() function will be used for the property.<br> -ContainsAttribute - Indicates that a filter equivalent to the System.String.Contains() function will be used for the property.<br> - -Namespace QueryExpressionBuilder.Attributes.Numbers - attribute for all properties that are numeric, including DateTime<br> -GreaterOrEqualAttribute - Indicates that a filter equivalent to the >= conditional expression will be used for the property.<br> -LessOrEqualAttribute - Indicates that a filter equivalent to the <= conditional expression will be used for the property.<br> -EqualsAttribute - Just compares values like in a function Equals.<br> - -You need to pass the property name from the class representing the entity in the database to the attribute constructor. - -## Examples -Suppose we have an entity User, which is an entity in the database. -```csharp - public class User : IEntity - { - public Guid Id { get; set; } - public string Name { get; set; } - public string Surname { get; set; } - public string Email { get; set; } - public DateTime BirthDate { get; set; } - public DateTime RegistrationDate { get; set; } - public string PasswodHash { get; set; } - public float Amount { get; set; } - } -``` -To create a Query filter, we need to create a query model. -```csharp - public class UserQuery - { - [QueryExpressionBuilder.Attributes.String.StartWith("Name")] - public string? Name { get; set; } - - [QueryExpressionBuilder.Attributes.String.StartWith("Surname")] - public string? Surname { get; set; } - - [QueryExpressionBuilder.Attributes.String.StartWith("Email")] - public string? Email { get; set; } - - [QueryExpressionBuilder.Attributes.Numbers.GreaterOrEqual("BirthDate")] - public DateTime? FromBirthDate { get; set; } - - [QueryExpressionBuilder.Attributes.Numbers.LessOrEqual("BirthDate")] - public DateTime? ToBirthDate { get; set; } - - [QueryExpressionBuilder.Attributes.Numbers.GreaterOrEqual("RegistrationDate")] - public DateTime? FromRegistrationDate { get; set; } - - [QueryExpressionBuilder.Attributes.Numbers.LessOrEqual("RegistrationDate")] - public DateTime? ToRegistrationDate { get; set; } - - [QueryExpressionBuilder.Attributes.Numbers.GreaterOrEqual("Amount")] - public float? FromAmount { get; set; } - - [QueryExpressionBuilder.Attributes.Numbers.LessOrEqual("Amount")] - public float? ToAmount { get; set; } - } -``` -And now, in the controller method, which represents the endpoint, simply pass the UserQuery object to the ExpressionBuilder class, which will return the predicate function. -```csharp - [ApiController] - [Route("[controller]")] - public class WeatherForecastController : ControllerBase - { - private readonly ILogger<WeatherForecastController> _logger; - private readonly IUserService userService; - - public WeatherForecastController(ILogger<WeatherForecastController> logger, IUserService _userService) - { - userService = _userService; - _logger = logger; - } - - /// <summary> - /// Method for get users - /// </summary> - /// <param name="queryParams">Object containing filtering parameters</param> - /// <returns>Returns a list of users</returns> - [HttpGet("[controller]/GetUsers")] - public async Task<IEnumerable<User>> GetUsers([FromQuery] UserQuery queryParams) - { - //Generating a predicate based on parameters - var predicate = ExpressionBuilder.GetPredicate<User, UserQuery>(queryParams); - //We pass the predicate to the service and return the result - var result = await userService.GetUsers(predicate); - return result; - } - } -``` -Now, when sending a request to the database<br> -https://localhost:7001/GetUsers?Name=M&FromBirthDate=2000-01-01&ToBirthDate=2040-01-01&FromAmount=1000<br> -We get an SQL query. -```sql -SELECT "u"."Id", "u"."Amount", "u"."BirthDate", "u"."Email", "u"."Name", "u"."PasswodHash", "u"."RegistrationDate", "u"."Surname" - FROM "Users" AS "u" - WHERE instr("u"."Name", 'M') > 0 AND "u"."BirthDate" >= '2000-01-01 00:00:00' AND "u"."BirthDate" <= '2040-01-01 00:00:00' AND "u"."Amount" >= 1000 -``` -## License -This project is distributed under the [MIT](https://opensource.org/licenses/MIT) license, which allows free use, modification, and distribution of the code in accordance with the terms of the MIT license. -<br><br><br> - -# QueryExpressionBuilder -Библиотека для генирации функций-предикатов для фильтрирования запросов в БД. - -## Описание -Данная библиотека помогает создать функцию-предикат для фильтрирования запросов в БД на основе модели. - -## Инструкция -Для работы библиотеки необходимо создать модель с свойствами для фильтрации.<br> -Свойства в модели необходимо пометить атрибутами.<br> - -На данный момент существует 3 атрибута:<br> - -Пространство имен QueryExpressionBuilder.Attributes.String - атрибуты для свойств типа String<br> -StartWithAttribute - Означает, что дял свойства будет использоватся фильтр с аналогом функции System.String.StartWith()<br> -ContainsAttribute - Означает, что дял свойства будет использоватся фильтр с аналогом функции System.String.Contains()<br> - -Пространство имен QueryExpressionBuilder.Attributes.Numbers - атрибут для всех свойств которые ввляются числовыми, в том числе DateTime<br> -GreaterOrEqualAttribute - Означает, что для свойства будет использоваться фильтр с аналогом условного выражения >=<br> -LessOrEqualAttribute - Означает, что для свойства будет использоваться фильтр с аналогом условного выражения <=<br> -EqualsAttribute - Просто то же самое, что и Equals.<br> - -В конструктор атрибута необходимо передать название свойства из класса представляющий сущьность в БД.<br> - -## Примеры -Предположим у нас есть сущьность User, которая являеться сущьностью в БД. -```csharp - public class User : IEntity - { - public Guid Id { get; set; } - public string Name { get; set; } - public string Surname { get; set; } - public string Email { get; set; } - public DateTime BirthDate { get; set; } - public DateTime RegistrationDate { get; set; } - public string PasswodHash { get; set; } - public float Amount { get; set; } - } -``` -Для создания Query фильтра нам необходимо создать query-модель -```csharp - public class UserQuery - { - [QueryExpressionBuilder.Attributes.String.StartWith("Name")] - public string? Name { get; set; } - - [QueryExpressionBuilder.Attributes.String.StartWith("Surname")] - public string? Surname { get; set; } - - [QueryExpressionBuilder.Attributes.String.StartWith("Email")] - public string? Email { get; set; } - - [QueryExpressionBuilder.Attributes.Numbers.GreaterOrEqual("BirthDate")] - public DateTime? FromBirthDate { get; set; } - - [QueryExpressionBuilder.Attributes.Numbers.LessOrEqual("BirthDate")] - public DateTime? ToBirthDate { get; set; } - - [QueryExpressionBuilder.Attributes.Numbers.GreaterOrEqual("RegistrationDate")] - public DateTime? FromRegistrationDate { get; set; } - - [QueryExpressionBuilder.Attributes.Numbers.LessOrEqual("RegistrationDate")] - public DateTime? ToRegistrationDate { get; set; } - - [QueryExpressionBuilder.Attributes.Numbers.GreaterOrEqual("Amount")] - public float? FromAmount { get; set; } - - [QueryExpressionBuilder.Attributes.Numbers.LessOrEqual("Amount")] - public float? ToAmount { get; set; } - } -``` -И теперь в методе контроллера, который представляет конечную точку, нужно просто передать обьект UserQuery в класс ExpressionBuilder, который вернет функцию-предикат. -```csharp - [ApiController] - [Route("[controller]")] - public class WeatherForecastController : ControllerBase - { - private readonly ILogger<WeatherForecastController> _logger; - private readonly IUserService userService; - - public WeatherForecastController(ILogger<WeatherForecastController> logger, IUserService _userService) - { - userService = _userService; - _logger = logger; - } - - /// <summary> - /// Метод получения юзеров - /// </summary> - /// <param name="queryParams">Объект содержащий параметры фильтрации</param> - /// <returns>Возвращает список юзеров</returns> - [HttpGet("[controller]/GetUsers")] - public async Task<IEnumerable<User>> GetUsers([FromQuery] UserQuery queryParams) - { - //Генерируем предикат на основе параметров - var predicate = ExpressionBuilder.GetPredicate<User, UserQuery>(queryParams); - //Передаем предикат в сервис и возвращаем результат - var result = await userService.GetUsers(predicate); - return result; - } - } -``` -Теперь отправляя запрос<br> -https://localhost:7001/GetUsers?Name=M&FromBirthDate=2000-01-01&ToBirthDate=2040-01-01&FromAmount=1000<br> -в БД мы получаем SQL запрос -```sql -SELECT "u"."Id", "u"."Amount", "u"."BirthDate", "u"."Email", "u"."Name", "u"."PasswodHash", "u"."RegistrationDate", "u"."Surname" - FROM "Users" AS "u" - WHERE instr("u"."Name", 'M') > 0 AND "u"."BirthDate" >= '2000-01-01 00:00:00' AND "u"."BirthDate" <= '2040-01-01 00:00:00' AND "u"."Amount" >= 1000 -``` -## Лицензия +# QueryExpressionBuilder +Library for generating predicate functions for filtering database queries. + +## Description +This library helps create a predicate function for filtering database queries based on a model. + +## Instruction +To use the library, you need to create a model with properties for filtering. Properties in the model need to be marked with attributes.<br> + +Currently, there are 3 attributes:<br> + +Namespace QueryExpressionBuilder.Attributes.String - attributes for properties of type String<br> +StartWithAttribute - Indicates that a filter equivalent to the System.String.StartWith() function will be used for the property.<br> +ContainsAttribute - Indicates that a filter equivalent to the System.String.Contains() function will be used for the property.<br> + +Namespace QueryExpressionBuilder.Attributes.Numbers - attribute for all properties that are numeric, including DateTime<br> +GreaterOrEqualAttribute - Indicates that a filter equivalent to the >= conditional expression will be used for the property.<br> +LessOrEqualAttribute - Indicates that a filter equivalent to the <= conditional expression will be used for the property.<br> +EqualsAttribute - Just compares values like in a function Equals.<br> + +You need to pass the property name from the class representing the entity in the database to the attribute constructor. + +## Examples +Suppose we have an entity User, which is an entity in the database. +```csharp + public class User : IEntity + { + public Guid Id { get; set; } + public string Name { get; set; } + public string Surname { get; set; } + public string Email { get; set; } + public DateTime BirthDate { get; set; } + public DateTime RegistrationDate { get; set; } + public string PasswodHash { get; set; } + public float Amount { get; set; } + } +``` +To create a Query filter, we need to create a query model. +```csharp + public class UserQuery + { + [QueryExpressionBuilder.Attributes.String.StartWith("Name")] + public string? Name { get; set; } + + [QueryExpressionBuilder.Attributes.String.StartWith("Surname")] + public string? Surname { get; set; } + + [QueryExpressionBuilder.Attributes.String.StartWith("Email")] + public string? Email { get; set; } + + [QueryExpressionBuilder.Attributes.Numbers.GreaterOrEqual("BirthDate")] + public DateTime? FromBirthDate { get; set; } + + [QueryExpressionBuilder.Attributes.Numbers.LessOrEqual("BirthDate")] + public DateTime? ToBirthDate { get; set; } + + [QueryExpressionBuilder.Attributes.Numbers.GreaterOrEqual("RegistrationDate")] + public DateTime? FromRegistrationDate { get; set; } + + [QueryExpressionBuilder.Attributes.Numbers.LessOrEqual("RegistrationDate")] + public DateTime? ToRegistrationDate { get; set; } + + [QueryExpressionBuilder.Attributes.Numbers.GreaterOrEqual("Amount")] + public float? FromAmount { get; set; } + + [QueryExpressionBuilder.Attributes.Numbers.LessOrEqual("Amount")] + public float? ToAmount { get; set; } + } +``` +And now, in the controller method, which represents the endpoint, simply pass the UserQuery object to the ExpressionBuilder class, which will return the predicate function. +```csharp + [ApiController] + [Route("[controller]")] + public class WeatherForecastController : ControllerBase + { + private readonly ILogger<WeatherForecastController> _logger; + private readonly IUserService userService; + + public WeatherForecastController(ILogger<WeatherForecastController> logger, IUserService _userService) + { + userService = _userService; + _logger = logger; + } + + /// <summary> + /// Method for get users + /// </summary> + /// <param name="queryParams">Object containing filtering parameters</param> + /// <returns>Returns a list of users</returns> + [HttpGet("[controller]/GetUsers")] + public async Task<IEnumerable<User>> GetUsers([FromQuery] UserQuery queryParams) + { + //Generating a predicate based on parameters + var predicate = ExpressionBuilder.GetPredicate<User, UserQuery>(queryParams); + //We pass the predicate to the service and return the result + var result = await userService.GetUsers(predicate); + return result; + } + } +``` +Now, when sending a request to the database<br> +https://localhost:7001/GetUsers?Name=M&FromBirthDate=2000-01-01&ToBirthDate=2040-01-01&FromAmount=1000<br> +We get an SQL query. +```sql +SELECT "u"."Id", "u"."Amount", "u"."BirthDate", "u"."Email", "u"."Name", "u"."PasswodHash", "u"."RegistrationDate", "u"."Surname" + FROM "Users" AS "u" + WHERE instr("u"."Name", 'M') > 0 AND "u"."BirthDate" >= '2000-01-01 00:00:00' AND "u"."BirthDate" <= '2040-01-01 00:00:00' AND "u"."Amount" >= 1000 +``` +## License +This project is distributed under the [MIT](https://opensource.org/licenses/MIT) license, which allows free use, modification, and distribution of the code in accordance with the terms of the MIT license. +<br><br><br> + +# QueryExpressionBuilder +Библиотека для генирации функций-предикатов для фильтрирования запросов в БД. + +## Описание +Данная библиотека помогает создать функцию-предикат для фильтрирования запросов в БД на основе модели. + +## Инструкция +Для работы библиотеки необходимо создать модель с свойствами для фильтрации.<br> +Свойства в модели необходимо пометить атрибутами.<br> + +На данный момент существует 3 атрибута:<br> + +Пространство имен QueryExpressionBuilder.Attributes.String - атрибуты для свойств типа String<br> +StartWithAttribute - Означает, что дял свойства будет использоватся фильтр с аналогом функции System.String.StartWith()<br> +ContainsAttribute - Означает, что дял свойства будет использоватся фильтр с аналогом функции System.String.Contains()<br> + +Пространство имен QueryExpressionBuilder.Attributes.Numbers - атрибут для всех свойств которые ввляются числовыми, в том числе DateTime<br> +GreaterOrEqualAttribute - Означает, что для свойства будет использоваться фильтр с аналогом условного выражения >=<br> +LessOrEqualAttribute - Означает, что для свойства будет использоваться фильтр с аналогом условного выражения <=<br> +EqualsAttribute - Просто то же самое, что и Equals.<br> + +В конструктор атрибута необходимо передать название свойства из класса представляющий сущьность в БД.<br> + +## Примеры +Предположим у нас есть сущьность User, которая являеться сущьностью в БД. +```csharp + public class User : IEntity + { + public Guid Id { get; set; } + public string Name { get; set; } + public string Surname { get; set; } + public string Email { get; set; } + public DateTime BirthDate { get; set; } + public DateTime RegistrationDate { get; set; } + public string PasswodHash { get; set; } + public float Amount { get; set; } + } +``` +Для создания Query фильтра нам необходимо создать query-модель +```csharp + public class UserQuery + { + [QueryExpressionBuilder.Attributes.String.StartWith("Name")] + public string? Name { get; set; } + + [QueryExpressionBuilder.Attributes.String.StartWith("Surname")] + public string? Surname { get; set; } + + [QueryExpressionBuilder.Attributes.String.StartWith("Email")] + public string? Email { get; set; } + + [QueryExpressionBuilder.Attributes.Numbers.GreaterOrEqual("BirthDate")] + public DateTime? FromBirthDate { get; set; } + + [QueryExpressionBuilder.Attributes.Numbers.LessOrEqual("BirthDate")] + public DateTime? ToBirthDate { get; set; } + + [QueryExpressionBuilder.Attributes.Numbers.GreaterOrEqual("RegistrationDate")] + public DateTime? FromRegistrationDate { get; set; } + + [QueryExpressionBuilder.Attributes.Numbers.LessOrEqual("RegistrationDate")] + public DateTime? ToRegistrationDate { get; set; } + + [QueryExpressionBuilder.Attributes.Numbers.GreaterOrEqual("Amount")] + public float? FromAmount { get; set; } + + [QueryExpressionBuilder.Attributes.Numbers.LessOrEqual("Amount")] + public float? ToAmount { get; set; } + } +``` +И теперь в методе контроллера, который представляет конечную точку, нужно просто передать обьект UserQuery в класс ExpressionBuilder, который вернет функцию-предикат. +```csharp + [ApiController] + [Route("[controller]")] + public class WeatherForecastController : ControllerBase + { + private readonly ILogger<WeatherForecastController> _logger; + private readonly IUserService userService; + + public WeatherForecastController(ILogger<WeatherForecastController> logger, IUserService _userService) + { + userService = _userService; + _logger = logger; + } + + /// <summary> + /// Метод получения юзеров + /// </summary> + /// <param name="queryParams">Объект содержащий параметры фильтрации</param> + /// <returns>Возвращает список юзеров</returns> + [HttpGet("[controller]/GetUsers")] + public async Task<IEnumerable<User>> GetUsers([FromQuery] UserQuery queryParams) + { + //Генерируем предикат на основе параметров + var predicate = ExpressionBuilder.GetPredicate<User, UserQuery>(queryParams); + //Передаем предикат в сервис и возвращаем результат + var result = await userService.GetUsers(predicate); + return result; + } + } +``` +Теперь отправляя запрос<br> +https://localhost:7001/GetUsers?Name=M&FromBirthDate=2000-01-01&ToBirthDate=2040-01-01&FromAmount=1000<br> +в БД мы получаем SQL запрос +```sql +SELECT "u"."Id", "u"."Amount", "u"."BirthDate", "u"."Email", "u"."Name", "u"."PasswodHash", "u"."RegistrationDate", "u"."Surname" + FROM "Users" AS "u" + WHERE instr("u"."Name", 'M') > 0 AND "u"."BirthDate" >= '2000-01-01 00:00:00' AND "u"."BirthDate" <= '2040-01-01 00:00:00' AND "u"."Amount" >= 1000 +``` +## Лицензия Этот проект распространяется под лицензией [MIT](https://opensource.org/licenses/MIT), которая разрешает свободное использование, изменение и распространение кода в соответствии с условиями лицензии MIT. \ No newline at end of file