diff --git a/Controllers/XBaseProvidedController.cs b/Controllers/XBaseProvidedController.cs new file mode 100644 index 0000000..e5bc37f --- /dev/null +++ b/Controllers/XBaseProvidedController.cs @@ -0,0 +1,514 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.Extensions.Logging; +using xCommons.Configurations; +using xCommons.Extensions; +using xCommons.Providers; +using xExceptions.Constants; +using xIdentityService.Controllers; +using xIdentityService.Interfaces; +using xModels.Base; +using xModels.Dtos; +using xPushService.Base; +using xPushService.Interfaces; + +namespace xPushService.Controllers +{ + [AllowAnonymous] + public abstract class XBaseProvidedController : XBaseIdentityApiV1Controller, IXBaseProvidedController + where TEntity : XBaseEntity + where TDto : XBaseEntityDto + where THub : XBaseDtoHub + { + private readonly IXBaseProvided provider; + private readonly Func, IOrderedQueryable> defaultOrderBuilder; + private readonly Func, IIncludableQueryable> defaultIncludeBuilder; + + protected XBaseProvidedController( + ILogger> logger, + XAppConfiguration appConfiguration, + IXIdentityProvider identityProvider, + XValidationProvider validationProvider, + IXBaseProvided provider, + Func, IOrderedQueryable> defaultOrderBuilder = null, + Func, IIncludableQueryable> defaultIncludeBuilder = null + ) : base( + logger, + appConfiguration, + identityProvider, + validationProvider + ) + { + this.provider = provider; + this.defaultOrderBuilder = defaultOrderBuilder; + this.defaultIncludeBuilder = defaultIncludeBuilder; + } + + // + #region Retrieve ... + /// + /// Get Specified Item by ID ... + /// + /// + /// + /// + /// + [HttpGet("{id}")] + public virtual async Task> Get( + [FromRoute] TKey id, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + ValidationProvider.NotNull(id); + + // + var result = await provider.Get( + id: id, + includeBuilder: !useDefaultIncludes + ? null + : defaultIncludeBuilder, + cancellationToken: cancellationToken + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// Get All Exists Items ... + /// + /// + /// + /// + /// + [HttpGet("")] + public virtual async Task>> GetAll( + [FromQuery] bool useDefaultOrders = false, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + + // + var result = await provider.GetAll( + orderBuilder: !useDefaultOrders + ? null + : defaultOrderBuilder, + includeBuilder: !useDefaultIncludes + ? null + : defaultIncludeBuilder, + cancellationToken: cancellationToken + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// Find an item by providing a Conditional Expression ... + /// + /// + /// + /// + /// + [HttpGet("Find/One")] + public virtual async Task> FindOne( + [FromRoute] string query, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + await ValidationProvider + .GroupValidationBuilder() + .AddNotEmpty(query) + .ValidateGroupAsync(); + + // + var result = await provider.FindOne( + includeBuilder: !useDefaultIncludes + ? null + : defaultIncludeBuilder, + cancellationToken: cancellationToken, + predicate: x => x.PropValuesContains(query) + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// Find a collection of Items by proving a Query Search ... + /// + /// + /// + /// + /// + /// + [HttpGet("Find/Many")] + public virtual async Task>> FindMany( + [FromRoute] string query, + [FromQuery] bool useDefaultOrders = false, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + await ValidationProvider + .GroupValidationBuilder() + .AddNotEmpty(query) + .ValidateGroupAsync(); + + // + var result = await provider.FindMany( + orderBuilder: !useDefaultOrders + ? null + : defaultOrderBuilder, + includeBuilder: !useDefaultIncludes + ? null + : defaultIncludeBuilder, + cancellationToken: cancellationToken, + predicate: x => x.PropValuesContains(query) + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// Retrieve Items based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + [HttpGet("Query")] + public virtual async Task>> Query( + [FromQuery] XQuery query, + [FromQuery] bool useDefaultOrders = false, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + await ValidationProvider + .GroupValidationBuilder() + .AddNotNull(query) + .ValidateGroupAsync(); + + // + var result = await provider.Query( + query: query, + predicate: null, + orderBuilder: !useDefaultOrders + ? null + : defaultOrderBuilder, + includeBuilder: !useDefaultIncludes + ? null + : defaultIncludeBuilder, + cancellationToken: cancellationToken + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// Retrieve Owned Items based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + [HttpGet("Query/Owned")] + public virtual async Task>> QueryOwned( + [FromQuery] XQuery query, + [FromQuery] bool useDefaultOrders = false, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + await ValidationProvider + .GroupValidationBuilder() + .AddNotNull(query) + .ValidateGroupAsync(); + + // + var userInfo = await GetUserInfo(); + + // + var result = await provider.QueryOwned( + query: query, + predicate: null, + userInfo: userInfo, + orderBuilder: !useDefaultOrders + ? null + : defaultOrderBuilder, + includeBuilder: !useDefaultIncludes + ? null + : defaultIncludeBuilder, + cancellationToken: cancellationToken + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + #endregion + + // + #region Add/Update/Remove ... + /// + /// Add an item ... + /// + /// + /// + /// + [HttpPost("")] + public virtual async Task> Add( + [FromBody] TDto item, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + await ValidationProvider + .GroupValidationBuilder() + .AddNotNull(item) + .ValidateGroupAsync(); + + // + var userInfo = await GetUserInfo(); + var connectionId = GetConnectionId(); + + // + var result = await provider.Add( + item: item, + userInfo: userInfo, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// Update an item values ... + /// + /// + /// + /// + /// + [HttpPut("{id}")] + public virtual async Task> Update( + [FromRoute] TKey id, + [FromBody] TDto item, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + await ValidationProvider + .GroupValidationBuilder() + .AddNotNull(id) + .AddNotNull(item) + .ValidateGroupAsync(); + + // + var userInfo = await GetUserInfo(); + var connectionId = GetConnectionId(); + + // + var result = await provider.Update( + id: id, + item: item, + userInfo: userInfo, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// Remove an Item ... + /// + /// + /// + /// + [HttpDelete("{id}")] + public virtual async Task> Remove( + [FromRoute] TKey id, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + await ValidationProvider + .GroupValidationBuilder() + .AddNotNull(id) + .ValidateGroupAsync(); + + // + var userInfo = await GetUserInfo(); + var connectionId = GetConnectionId(); + + // + var result = await provider.Remove( + id: id, + userInfo: userInfo, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + #endregion + } +} \ No newline at end of file diff --git a/Controllers/XBaseRepositoryProviderController.cs b/Controllers/XBaseRepositoryProviderController.cs index d697fbe..2dbf79e 100644 --- a/Controllers/XBaseRepositoryProviderController.cs +++ b/Controllers/XBaseRepositoryProviderController.cs @@ -429,7 +429,7 @@ namespace xPushService.Controllers } /// - /// find a collection of Items by proving a Conditional Expression ... + /// find a collection of Items by proving a Query Search ... /// /// /// @@ -482,7 +482,7 @@ namespace xPushService.Controllers } /// - /// retrieve Items based on XQuery Pagination structure ... + /// Retrieve Items based on XQuery Pagination structure ... /// /// /// diff --git a/Interfaces/IXBaseProvided.cs b/Interfaces/IXBaseProvided.cs new file mode 100644 index 0000000..a956b7d --- /dev/null +++ b/Interfaces/IXBaseProvided.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using xIdentityModels.Models; +using xModels.Base; +using xModels.Dtos; +using xPushService.Base; + +namespace xPushService.Interfaces +{ + /// + /// a Provided Service Used for Providing Data Based on Validations of Users ... + /// + /// + /// + /// + /// + public interface IXBaseProvided + where TEntity : XBaseEntity + where TDto : XBaseEntityDto + where THub : XBaseDtoHub + { + /// + /// Get Specified Item by ID ... + /// + /// + /// + /// + /// + Task Get( + TKey id, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ); + + /// + /// Get All Exists Items ... + /// + /// + /// + /// + /// + Task> GetAll( + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ); + + /// + /// Find an item by providing a Conditional Expression ... + /// + /// + /// + /// + /// + Task FindOne( + Expression> predicate, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ); + + /// + /// Find a collection of Items by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + Task> FindMany( + Expression> predicate, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ); + + /// + /// Retrieve Items based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + Task> Query( + XQuery query, + Expression> predicate = null, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ); + + /// + /// Retrieve Owned Items based on XQuery Pagination structure ... + /// if supported ... + /// + /// + /// + /// + /// + /// + /// + /// + Task> QueryOwned( + XQuery query, + XUserClaimsInfoDto userInfo = null, + Expression> predicate = null, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ); + + /// + /// Add an item values ... + /// + /// + /// + /// + /// + /// + Task Add( + TDto item, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Update an item values ... + /// + /// + /// + /// + /// + /// + /// + Task Update( + TKey id, + TDto item, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// remove an Item ... + /// + /// + /// + /// + /// + /// + Task Remove( + TKey id, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// count all exists Items ... + /// + /// + /// + Task Count( + CancellationToken cancellationToken = default + ); + + /// + /// Check an Item exists or not ... + /// + /// + /// + /// + Task IsExists( + TKey id, + CancellationToken cancellationToken = default + ); + } +} \ No newline at end of file diff --git a/Interfaces/IXBaseProvidedController.cs b/Interfaces/IXBaseProvidedController.cs new file mode 100644 index 0000000..8a31716 --- /dev/null +++ b/Interfaces/IXBaseProvidedController.cs @@ -0,0 +1,157 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using xModels.Base; +using xModels.Dtos; +using xPushService.Base; + +namespace xPushService.Interfaces +{ + /// + /// a Provided Controller Used for Providing a Provided Service Actions ... + /// + /// + /// + /// + /// + public interface IXBaseProvidedController + where TEntity : XBaseEntity + where TDto : XBaseEntityDto + where THub : XBaseDtoHub + { + // + #region Retrieve ... + /// + /// Get Specified Item by ID ... + /// + /// + /// + /// + /// + [HttpGet("{id}")] + Task> Get( + [FromRoute] TKey id, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ); + + /// + /// Get All Exists Items ... + /// + /// + /// + /// + /// + [HttpGet("")] + Task>> GetAll( + [FromQuery] bool useDefaultOrders = false, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ); + + /// + /// Find an item by providing a Conditional Expression ... + /// + /// + /// + /// + /// + [HttpGet("Find/One")] + Task> FindOne( + [FromRoute] string query, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ); + + /// + /// Find a collection of Items by proving a Query Search ... + /// + /// + /// + /// + /// + /// + [HttpGet("Find/Many")] + Task>> FindMany( + [FromRoute] string query, + [FromQuery] bool useDefaultOrders = false, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ); + + /// + /// Retrieve Items based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + [HttpGet("Query")] + Task>> Query( + [FromQuery] XQuery query, + [FromQuery] bool useDefaultOrders = false, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ); + + /// + /// Retrieve Owned Items based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + [HttpGet("Query/Owned")] + Task>> QueryOwned( + [FromQuery] XQuery query, + [FromQuery] bool useDefaultOrders = false, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Add/Update/Remove ... + /// + /// Add an item ... + /// + /// + /// + /// + [HttpPost("")] + Task> Add( + [FromBody] TDto item, + CancellationToken cancellationToken = default + ); + + /// + /// Update an item values ... + /// + /// + /// + /// + /// + [HttpPut("{id}")] + Task> Update( + [FromRoute] TKey id, + [FromBody] TDto item, + CancellationToken cancellationToken = default + ); + + /// + /// Remove an Item ... + /// + /// + /// + /// + [HttpDelete("{id}")] + Task> Remove( + [FromRoute] TKey id, + CancellationToken cancellationToken = default + ); + #endregion + } +} \ No newline at end of file diff --git a/Providers/XBaseProvided.cs b/Providers/XBaseProvided.cs new file mode 100644 index 0000000..459997a --- /dev/null +++ b/Providers/XBaseProvided.cs @@ -0,0 +1,417 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using xCommons.Extensions; +using xExceptions.Constants; +using xIdentityModels.Extensions; +using xIdentityModels.Models; +using xModels.Base; +using xModels.Dtos; +using xPushService.Base; +using xPushService.Interfaces; + +namespace xPushService.Providers +{ + /// + /// a Provided Service Used for Providing Data Based on Validations of Users ... + /// + /// + /// + /// + /// + public abstract class XBaseProvided : IXBaseProvided + where TEntity : XBaseEntity + where TDto : XBaseEntityDto + where THub : XBaseDtoHub + { + // + #region Props ... + private readonly string[] permittedRoles; + private readonly IXBaseDtoProvider provider; + #endregion + + // + #region Constructor ... + protected XBaseProvided( + IXBaseDtoProvider provider, + string[] permittedRoles = null + ) + { + this.provider = provider; + this.permittedRoles = permittedRoles; + } + #endregion + + /// + /// Check an Items is Owned for User or not ... + /// + /// + /// + /// + public abstract bool IsOwned( + TDto item, + XUserClaimsInfoDto userInfo + ); + public abstract bool IsOwned( + TEntity item, + XUserClaimsInfoDto userInfo + ); + + /// + /// Check User Has Permission for Manipulate Data or not ... + /// + /// + /// + public bool HasPermision( + XUserClaimsInfoDto userInfo + ) + { + // + var result = + !userInfo.IsNullOrDefault() && + userInfo.HasAccess(permittedRoles); + + // + return result; + } + + // + #region Provided Actions ... + /// + /// Get Specified Item by ID ... + /// + /// + /// + /// + /// + public virtual async Task Get( + TKey id, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await provider.GetAsync( + id: id, + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Get All Exists Items ... + /// + /// + /// + /// + /// + public virtual async Task> GetAll( + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await provider.GetAllAsync( + ignoreSoftDeleteds: true, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// find an item by providing a Conditional Expression ... + /// + /// + /// + /// + /// + public virtual async Task FindOne( + Expression> predicate, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await provider.FindOneAsync( + predicate: predicate, + ignoreSoftDeleteds: true, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// find a collection of Items by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + public virtual async Task> FindMany( + Expression> predicate, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await provider.FindManyAsync( + predicate: predicate, + ignoreSoftDeleteds: true, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// retrieve Items based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task> Query( + XQuery query, + Expression> predicate = null, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await provider.QueryAsync( + query: query, + predicate: predicate, + ignoreSoftDeleteds: true, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// retrieve Owned Items based on XQuery Pagination structure ... + /// if supported ... + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task> QueryOwned( + XQuery query, + XUserClaimsInfoDto userInfo = null, + Expression> predicate = null, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + Expression> predicateor = null; + if (!predicate.IsNull()) + { + // + var predicateFnc = predicate.Compile(); + predicateor = x => + predicateFnc(x) && + IsOwned(x, userInfo); + } + else + { + predicateor = x => IsOwned(x, userInfo); + } + + // + var result = await provider.QueryAsync( + query: query, + predicate: predicateor, + ignoreSoftDeleteds: true, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Add an item values ... + /// + /// + /// + /// + /// + /// + public virtual async Task Add( + TDto item, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await provider.AddAsync( + item: item, + saveChanges: true, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Update an item values ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task Update( + TKey id, + TDto item, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Check Permission ... + var hasPermission = + IsOwned(item, userInfo) || + HasPermision(userInfo); + if (!hasPermission) + { + XException.NotAllowed.Throw(); + } + + // + var result = await provider.UpdateAsync( + id: id, + item: item, + saveChanges: true, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// remove an Item ... + /// + /// + /// + /// + /// + /// + public virtual async Task Remove( + TKey id, + XUserClaimsInfoDto userInfo = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Check Permission ... + var item = await Get( + id: id, + cancellationToken: cancellationToken + ); + var hasPermission = + IsOwned(item, userInfo) || + HasPermision(userInfo); + if (!hasPermission) + { + XException.NotAllowed.Throw(); + } + + // + var result = await provider.RemoveAsync( + id: id, + saveChanges: true, + softDelete: false, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// count all exists Items ... + /// + /// + /// + public virtual async Task Count( + CancellationToken cancellationToken = default + ) + { + // + var result = await provider.CountAsync( + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Check an Item exists or not ... + /// + /// + /// + /// + public virtual async Task IsExists( + TKey id, + CancellationToken cancellationToken = default + ) + { + // + var result = await provider.IsExistsAsync( + id: id, + cancellationToken: cancellationToken + ); + + // + return result; + } + #endregion + } +} \ No newline at end of file