From bfe115013998df16b5f869f1f17eaecf4f6feb7f Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Sun, 7 Dec 2025 20:53:22 +0330 Subject: [PATCH] Last works on Tag Service ... --- Extensions/xTagServiceExtension.cs | 84 +++ Interfaces/IXBaseTagProvider.cs | 237 +++++++ Interfaces/IXTagProvider.cs | 153 +++++ Models/Dtos/XTagDto.cs | 2 +- Providers/XBaseTagProvider.cs | 987 +++++++++++++++++++++++++++++ Providers/XTagProvider.cs | 476 ++++++++++++++ 6 files changed, 1938 insertions(+), 1 deletion(-) create mode 100644 Extensions/xTagServiceExtension.cs create mode 100644 Interfaces/IXBaseTagProvider.cs create mode 100644 Interfaces/IXTagProvider.cs create mode 100644 Providers/XBaseTagProvider.cs create mode 100644 Providers/XTagProvider.cs diff --git a/Extensions/xTagServiceExtension.cs b/Extensions/xTagServiceExtension.cs new file mode 100644 index 0000000..9b2e4d0 --- /dev/null +++ b/Extensions/xTagServiceExtension.cs @@ -0,0 +1,84 @@ +using System.Collections.Generic; +using System.Linq; +using xCommons.Extensions; +using xTagService.Models.Dtos; +using xTagService.Models.Entities; + +namespace xTagService.Extensions +{ + public static class xTagServiceExtension + { + /// + /// Map Global Properties From XFile to XFile Dto ... + /// + /// + /// + public static XTagDto ToDto(this XTag source) + { + // + XTagDto result = null; + + // + if (!source.IsNullOrDefault()) + { + // + result = new XTagDto(); + result = result.UpdateData( + updateWith: source, + propertyBlackList: new List + { + nameof(XTag.Deleted), + nameof(XTag.References), + } + ); + + // + // Preparing List ... + if (!source.References.IsNullOrEmpty()) + { + // + result.References = source.References + .ParseListString() + .ToList(); + } + } + + // + return result; + } + + /// + /// Converts a Dto to Entity Representation ... + /// Ignore ID Property ... + /// + /// + /// + public static XTag FromDto(this XTagDto source) + { + // + var result = new XTag(); + + // + if (!source.IsNull()) + { + // + result = result.UpdateData( + updateWith: source, + propertyBlackList: new List + { + nameof(XTag.Deleted), + nameof(XTag.References), + } + ); + + // + if (!source.References.IsNull() && source.References.HasChild()) { + result.References = source.References.ToListString(); + } + } + + // + return result; + } + } +} \ No newline at end of file diff --git a/Interfaces/IXBaseTagProvider.cs b/Interfaces/IXBaseTagProvider.cs new file mode 100644 index 0000000..97e8a58 --- /dev/null +++ b/Interfaces/IXBaseTagProvider.cs @@ -0,0 +1,237 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Threading.Tasks; +using xModels.Dtos; +using xTagService.Models.Dtos; +using xTagService.Models.Entities; + +namespace xTagService.Interfaces +{ + public interface IXBaseTagProvider + { + // + #region Props ... + /// + /// Specified Provider ... + /// + string ProvideFor { get; } + + /// + /// Specified Provider Repositroy ... + /// + IXTagProvider Provider { get; } + #endregion + + // + #region Helper ... + /// + /// Get Specified Identifier ... + /// + /// + /// + string GetIdentifier(TKey forProvidedId); + #endregion + + // + #region Implementation ... + /// + /// Attach Specified Label to Specified Provided Model ... + /// + /// + /// + /// + Task Attach( + string tag, + TKey forProvidedId + ); + + /// + /// Detach Specified Label From Specified Provided Model ... + /// + /// + /// + /// + Task Detach( + string tag, + TKey forProvidedId + ); + + /// + /// Add Specified Tag ... + /// + /// + /// + /// + Task Add( + XTagDto model, + TKey forProvidedId + ); + + /// + /// Retrieve Specified Item as Dto ... + /// + /// + /// + Task Get(int id); + + /// + /// Retrieve Specified Tag by it's Label ... + /// + /// + /// + Task GetTag(string tag); + + /// + /// Retrieve Specified Tag by it's Label ... + /// + /// + /// + /// + Task GetTagFor( + string tag, + TKey forProvidedId + ); + + /// + /// Retrieve All Items as Dto ... + /// + /// + Task> GetAll(); + + /// + /// Retrieve All Items as Dto ... + /// + /// + /// + Task> GetTags(TKey forProvidedId); + + /// + /// Find Specified Item by Condition ... + /// + /// + /// + Task FindOne(Expression> whereClause); + + /// + /// Find Many Items based on Conditions ... + /// + /// + /// + Task> FindMany(Expression> whereClause); + + /// + /// Find Many Items based on Conditions ... + /// + /// + /// + /// + Task> FindManyFor( + Expression> whereClause, + TKey forProvidedId + ); + + /// + /// Query Model retrieving Dtos ... + /// + /// + /// + Task> Query(XQuery query); + + /// + /// Query Model retrieving Dtos ... + /// + /// + /// + /// + Task> QueryTagsFor( + XQuery query, + TKey forProvidedId + ); + + /// + /// Query Conditional Retrieving Dtos ... + /// + /// + /// + /// + Task> ConditionalQuery( + XQuery query, + Expression> whereClause + ); + + /// + /// Query Conditional Retrieving Dtos ... + /// + /// + /// + /// + /// + Task> ConditionalQueryTagsFor( + XQuery query, + Expression> whereClause, + TKey forProvidedId + ); + + /// + /// Remove Specified Dto ... + /// + /// + /// + Task Remove( + int id + ); + + /// + /// Update Specified Dto ... + /// + /// + /// + /// + /// + Task Update( + int id, + XTagDto model, + TKey forProvidedId + ); + + /// + /// Count Exists Entities ... + /// + /// + Task Count(); + + /// + /// Check Entity Exists or not ... + /// + /// + /// + Task IsExists(int id); + + /// + /// Check Tag Exists by Label ... + /// + /// + /// + Task IsTagExists(string tag); + + /// + /// Check Tag Exists by Label ... + /// + /// + /// + /// + Task IsTagExistsFor( + string tag, + TKey forProvidedId + ); + + /// + /// Check Specified Model has Tag or not ... + /// + /// + /// + Task IsExistsFor(TKey forProvidedId); + #endregion + } +} \ No newline at end of file diff --git a/Interfaces/IXTagProvider.cs b/Interfaces/IXTagProvider.cs new file mode 100644 index 0000000..d66f293 --- /dev/null +++ b/Interfaces/IXTagProvider.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Threading.Tasks; +using Microsoft.AspNetCore.SignalR; +using xDataService.Configuration; +using xIdentityModels.Models; +using xIdentityService.Interfaces; +using xModels.Dtos; +using xTagService.Hubs; +using xTagService.Interfaces.Entities; +using xTagService.Models.Dtos; +using xTagService.Models.Entities; + +namespace xTagService.Interfaces +{ + public interface IXTagProvider + { + // + #region Props ... + IXTagRepository Repository { get; } + IHubContext Hub { get; } + IXIdentityProvider IdentityProvider { get; } + XDataServiceConfiguration DataConfiguration { get; } + #endregion + + // + #region Helpers ... + /// + /// Converts an Entity to Dto ... + /// + /// + /// + XTagDto ToXTagDto(XTag model); + + /// + /// Converts a List of Entitiies to List of Dto's ... + /// + /// + /// + IEnumerable ToXTagDtoList(IEnumerable models); + + /// + /// Converts Query Result of Entities to Dto ... + /// + /// + /// + XQueryResult ToXTagDtoQueryResult(XQueryResult queryResult); + #endregion + + // + #region Tools ... + /// + /// Add Specified Tag ... + /// + /// + /// + Task Add(XTagDto model); + + /// + /// Retrieve Specified Item as Dto ... + /// + /// + /// + Task Get(int id); + + /// + /// Retrieve Specified Tag by it's Label ... + /// + /// + /// + Task GetTag(string tag); + + /// + /// Retrieve All Items as Dto ... + /// + /// + Task> GetAll(); + + /// + /// Find Specified Item by Condition ... + /// + /// + /// + Task FindOne(Expression> whereClause); + + /// + /// Find Many Items based on Conditions ... + /// + /// + /// + Task> FindMany(Expression> whereClause); + + /// + /// Query Model retrieving Dtos ... + /// + /// + /// + Task> Query(XQuery query); + + /// + /// Query Conditional Retrieving Dtos ... + /// + /// + /// + /// + Task> ConditionalQuery( + XQuery query, + Expression> whereClause + ); + + /// + /// Remove Specified Dto ... + /// + /// + /// + Task Remove( + int id + ); + + /// + /// Update Specified Dto ... + /// + /// + /// + /// + Task Update( + int id, + XTagDto model + ); + + /// + /// Count Exists Entities ... + /// + /// + Task Count(); + + /// + /// Check Entity Exists or not ... + /// + /// + /// + Task IsExists(int id); + + /// + /// Check Tag Exists by Label ... + /// + /// + /// + Task IsTagExists(string tag); + #endregion + } +} \ No newline at end of file diff --git a/Models/Dtos/XTagDto.cs b/Models/Dtos/XTagDto.cs index c78dfde..7f62031 100644 --- a/Models/Dtos/XTagDto.cs +++ b/Models/Dtos/XTagDto.cs @@ -7,6 +7,6 @@ namespace xTagService.Models.Dtos { public int Id { get; set; } public string Tag { get; set; } - public IList Reference = new List(); + public IList References = new List(); } } \ No newline at end of file diff --git a/Providers/XBaseTagProvider.cs b/Providers/XBaseTagProvider.cs new file mode 100644 index 0000000..24df0fa --- /dev/null +++ b/Providers/XBaseTagProvider.cs @@ -0,0 +1,987 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; +using xCommons.Extensions; +using xDataService.Extensions; +using xExceptions.Constants; +using xModels.Dtos; +using xTagService.Interfaces; +using xTagService.Models.Dtos; +using xTagService.Models.Entities; + +namespace xTagService.Providers +{ + public abstract class XBaseTagProvider : IXBaseTagProvider + { + // + #region Props ... + /// + /// Specified Provider ... + /// + public string ProvideFor { get; } + + /// + /// Specified Provider Repositroy ... + /// + public IXTagProvider Provider { get; } + #endregion + + // + #region Constructor ... + public XBaseTagProvider( + string providedFor, + IXTagProvider tagProvider + ) + { + // + Provider = tagProvider; + ProvideFor = providedFor; + } + #endregion + + // + #region Helper ... + /// + /// Get Specified Identifier ... + /// + /// + /// + public string GetIdentifier(TKey forProvidedId) + { + // + var result = string.Empty; + + // + result = $"{ProvideFor}_{forProvidedId}"; + + // + return result; + } + #endregion + + // + #region Implementation ... + /// + /// Attach Specified Label to Specified Provided Model ... + /// + /// + /// + /// + public async Task Attach( + string tag, + TKey forProvidedId + ) + { + // + // Validate ... + var isValid = !tag.IsNullOrEmpty() && + !forProvidedId.IsNull(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Generate Identifier ... + var identifier = GetIdentifier(forProvidedId); + + // + // Check Tag Exists or not ... + isValid = await Provider.IsTagExists(tag); + + // + XTagDto result = null; + + // + // Add new XTag Entity ... + if (!isValid) + { + // + result = await Provider.Add(new XTagDto + { + Tag = tag, + References = new List { identifier } + }); + } + // + // Update Exists Tag Enttiy ... + else + { + // + result = await Provider.GetTag(tag); + isValid = !result.IsNullOrDefault(); + if (!isValid) + { + XException.ActionFailed.Throw(); + } + + // + result.References.Add(identifier); + result = await Provider.Update(result.Id, result); + isValid = !result.IsNullOrDefault(); + if (!isValid) + { + XException.ActionFailed.Throw(); + } + } + + // + return result; + } + + /// + /// Detach Specified Label From Specified Provided Model ... + /// + /// + /// + /// + public async Task Detach( + string tag, + TKey forProvidedId + ) + { + // + // Validate ... + var isValid = !tag.IsNullOrEmpty() && + !forProvidedId.IsNull(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Generate Identifier ... + var identifier = GetIdentifier(forProvidedId); + + // + XTagDto result = null; + + // + // Check Tag Exists or not ... + isValid = await IsTagExistsFor( + tag: tag, + forProvidedId: forProvidedId + ); + if (!isValid) + { + return result; + } + + // + // Remove id From XTag References ... + result = await GetTagFor( + tag: tag, + forProvidedId: forProvidedId + ); + isValid = !result.IsNullOrDefault(); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + // Remove identifier ... + result.References = result + .References + .Where(rf => rf.ToNormalString() != identifier.ToNormalString()) + .ToList(); + result = await Provider.Update(result.Id, result); + + // + return result; + } + + /// + /// Add Specified Tag ... + /// + /// + /// + /// + public async Task Add( + XTagDto model, + TKey forProvidedId + ) + { + // + // Validate ... + var isValid = !model.IsNull() && + !forProvidedId.IsNull(); + if (!isValid) + { + return null; + } + + // + // Refrences ... + var identifier = GetIdentifier(forProvidedId); + if (!model.References.IsNull() && model.References.HasChild()) + { + // + isValid = !identifier.IsNullOrEmpty() && + !model.References.Any(r => r.ToNormalString() == identifier.ToNormalString()); + } + if (isValid) + { + model.References.Add(identifier); + } + + // + model = await Provider.Add(model); + + // + return model; + } + + /// + /// Retrieve Specified Item as Dto ... + /// + /// + /// + public async Task Get(int id) + { + // + XTagDto result = null; + + // + var isValid = await Provider.IsExists(id); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + var dto = await Provider.Get(id); + isValid = !dto.IsNullOrDefault(); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + // Validate Dto ... + isValid = dto.References.Any(e => e.ToNormalString() + .Contains(ProvideFor.ToNormalString())); + if (!isValid) + { + XException.NotAllowed.Throw(); + } + + // + result = dto; + + // + return result; + } + + /// + /// Retrieve Specified Tag by it's Label ... + /// + /// + /// + public async Task GetTag(string tag) + { + // + var isValid = !tag.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + var dto = await Provider.GetTag(tag); + isValid = !dto.IsNullOrDefault(); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + // Check Identifier ... + isValid = !dto.References.IsNull() && + !dto.References.HasChild() && + dto.References.Any(e => e.ToNormalString().Contains(ProvideFor.ToNormalString())); + if (!isValid) + { + XException.NotAllowed.Throw(); + } + + // + return dto; + } + + /// + /// Retrieve Specified Tag by it's Label ... + /// + /// + /// + /// + public async Task GetTagFor( + string tag, + TKey forProvidedId + ) + { + // + XTagDto result = null; + + // + var dtos = await GetTags(forProvidedId); + if (!dtos.IsNull() && dtos.HasChild()) + { + // + result = dtos.Where(dto => dto.Tag.ToNormalString() == tag.ToNormalString()) + .FirstOrDefault(); + } + + // + return result; + } + + /// + /// Retrieve All Items as Dto ... + /// + /// + public async Task> GetAll() + { + // + var result = await Provider.GetAll(); + if (!result.IsNull() && result.HasChild()) + { + result = result + .Where(e => e.References.Any(er => er.ToNormalString().Contains(ProvideFor.ToNormalString()))); + } + + // + return result; + } + + /// + /// Retrieve All Items as Dto ... + /// + /// + /// + public async Task> GetTags(TKey forProvidedId) + { + // + var result = new List(); + + // + string identifier = GetIdentifier(forProvidedId); + var tags = await GetAll(); + if (!tags.IsNull() && tags.HasChild()) + { + // + result = + tags.Where(t => t.References.Any(tr => tr.ToNormalString() == identifier.ToNormalString())) + .ToList(); + } + + // + return result; + } + + /// + /// Find Specified Item by Condition ... + /// + /// + /// + public async Task FindOne(Expression> whereClause) + { + // + var dto = await Provider.FindOne(whereClause); + if (dto.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + var isValid = dto.References.Any(dr => dr.ToNormalString().Contains(ProvideFor.ToNormalString())); + if (!isValid) + { + XException.NotAllowed.Throw(); + } + + // + return dto; + } + + /// + /// Find Many Items based on Conditions ... + /// + /// + /// + public async Task> FindMany(Expression> whereClause) + { + // + var result = new List(); + var dtos = await Provider.FindMany(whereClause); + if (!dtos.IsNull() && dtos.HasChild()) + { + // + bool isValid = false; + dtos.ToList() + .ForEach(dto => + { + // + isValid = dto.References.HasChild() && + dto.References.Any(r => r.ToNormalString().Contains(ProvideFor.ToNormalString())); + if (isValid) + { + result.Add(dto); + } + }); + } + + // + return result; + } + + /// + /// Find Many Items based on Conditions ... + /// + /// + /// + /// + public async Task> FindManyFor( + Expression> whereClause, + TKey forProvidedId + ) + { + // + var result = new List(); + var dtos = await Provider.FindMany(whereClause); + if (!dtos.IsNull() && dtos.HasChild()) + { + // + bool isValid = false; + var identifier = GetIdentifier(forProvidedId); + dtos.ToList() + .ForEach(dto => + { + // + isValid = dto.References.HasChild() && + dto.References.Any(r => r.ToNormalString() == identifier.ToNormalString()); + if (isValid) + { + result.Add(dto); + } + }); + } + + // + return result; + } + + /// + /// Query Model retrieving Dtos ... + /// + /// + /// + public async Task> Query(XQuery query) + { + // + // Validate ... + if (query.IsNull()) + { + XException.InvalidArgs.Throw(); + } + + // + // Normalize ... + query = query.NormalizeQuery(Provider.DataConfiguration); + + // + var items = (await GetAll()) + .ToList(); + var totalItemsCount = items.Count(); + + // + // Apply Filter ... + if (!query.Filter.IsNullOrEmpty()) + { + // + items = items + .ApplyFilter(query.Filter) + .ToList(); + } + + // + int filteredItemsCount = items.Count(); + + // + // Count Pages ... + var totalPagesCount = query.CountPages(totalItemsCount); + var filteredPagesCount = query.CountPages(filteredItemsCount); + + // + // Apply Paging and Sorting ... + if (totalItemsCount > 0 && + filteredItemsCount > 0) + { + // + // Apply Sorting ... + items = items + .ToList() + .ApplySorting( + query.SortBy, + query.IsAscending + ) + .ToList(); + + // + // Apply Paging ... + items = items + .ToList() + .ApplyPaging( + query.Page, + query.PageSize + ) + .ToList(); + } + + + // + // Prepare Result ... + var result = new XQueryResult + { + Page = query.Page, + Items = items.ToList(), + PageSize = query.PageSize, + TotalPages = totalPagesCount, + TotalItems = totalItemsCount, + TotalFilteredPages = filteredPagesCount, + TotalFilteredItems = filteredItemsCount + }; + + // + return result; + } + + /// + /// Query Model retrieving Dtos ... + /// + /// + /// + /// + public async Task> QueryTagsFor( + XQuery query, + TKey forProvidedId + ) + { + // + // Validate ... + if (query.IsNull() || forProvidedId.IsNull()) + { + XException.InvalidArgs.Throw(); + } + + // + // Normalize ... + query = query.NormalizeQuery(Provider.DataConfiguration); + + // + var items = (await GetTags(forProvidedId)) + .ToList(); + var totalItemsCount = items.Count(); + + // + // Apply Filter ... + if (!query.Filter.IsNullOrEmpty()) + { + // + items = items + .ApplyFilter(query.Filter) + .ToList(); + } + + // + int filteredItemsCount = items.Count(); + + // + // Count Pages ... + var totalPagesCount = query.CountPages(totalItemsCount); + var filteredPagesCount = query.CountPages(filteredItemsCount); + + // + // Apply Paging and Sorting ... + if (totalItemsCount > 0 && + filteredItemsCount > 0) + { + // + // Apply Sorting ... + items = items + .ToList() + .ApplySorting( + query.SortBy, + query.IsAscending + ) + .ToList(); + + // + // Apply Paging ... + items = items + .ToList() + .ApplyPaging( + query.Page, + query.PageSize + ) + .ToList(); + } + + // + // Prepare Result ... + var result = new XQueryResult + { + Page = query.Page, + Items = items.ToList(), + PageSize = query.PageSize, + TotalPages = totalPagesCount, + TotalItems = totalItemsCount, + TotalFilteredPages = filteredPagesCount, + TotalFilteredItems = filteredItemsCount + }; + + // + return result; + } + + /// + /// Query Conditional Retrieving Dtos ... + /// + /// + /// + /// + public async Task> ConditionalQuery( + XQuery query, + Expression> whereClause + ) + { + // + // Validate ... + if (query.IsNull()) + { + XException.InvalidArgs.Throw(); + } + + // + // Normalize ... + query = query.NormalizeQuery(Provider.DataConfiguration); + + // + var items = (await FindMany(whereClause)) + .ToList(); + var totalItemsCount = items.Count(); + + // + // Apply Filter ... + if (!query.Filter.IsNullOrEmpty()) + { + // + items = items + .ApplyFilter(query.Filter) + .ToList(); + } + + // + int filteredItemsCount = items.Count(); + + // + // Count Pages ... + var totalPagesCount = query.CountPages(totalItemsCount); + var filteredPagesCount = query.CountPages(filteredItemsCount); + + // + // Apply Paging and Sorting ... + if (totalItemsCount > 0 && + filteredItemsCount > 0) + { + // + // Apply Sorting ... + items = items + .ToList() + .ApplySorting( + query.SortBy, + query.IsAscending + ) + .ToList(); + + // + // Apply Paging ... + items = items + .ToList() + .ApplyPaging( + query.Page, + query.PageSize + ) + .ToList(); + } + + + // + // Prepare Result ... + var result = new XQueryResult + { + Page = query.Page, + Items = items.ToList(), + PageSize = query.PageSize, + TotalPages = totalPagesCount, + TotalItems = totalItemsCount, + TotalFilteredPages = filteredPagesCount, + TotalFilteredItems = filteredItemsCount + }; + + // + return result; + } + + /// + /// Query Conditional Retrieving Dtos ... + /// + /// + /// + /// + /// + public async Task> ConditionalQueryTagsFor( + XQuery query, + Expression> whereClause, + TKey forProvidedId + ) + { + // + // Validate ... + if (query.IsNull() || forProvidedId.IsNull()) + { + XException.InvalidArgs.Throw(); + } + + // + // Normalize ... + query = query.NormalizeQuery(Provider.DataConfiguration); + + // + var items = (await FindManyFor( + whereClause: whereClause, + forProvidedId: forProvidedId + )) + .ToList(); + var totalItemsCount = items.Count(); + + // + // Apply Filter ... + if (!query.Filter.IsNullOrEmpty()) + { + // + items = items + .ApplyFilter(query.Filter) + .ToList(); + } + + // + int filteredItemsCount = items.Count(); + + // + // Count Pages ... + var totalPagesCount = query.CountPages(totalItemsCount); + var filteredPagesCount = query.CountPages(filteredItemsCount); + + // + // Apply Paging and Sorting ... + if (totalItemsCount > 0 && + filteredItemsCount > 0) + { + // + // Apply Sorting ... + items = items + .ToList() + .ApplySorting( + query.SortBy, + query.IsAscending + ) + .ToList(); + + // + // Apply Paging ... + items = items + .ToList() + .ApplyPaging( + query.Page, + query.PageSize + ) + .ToList(); + } + + + // + // Prepare Result ... + var result = new XQueryResult + { + Page = query.Page, + Items = items.ToList(), + PageSize = query.PageSize, + TotalPages = totalPagesCount, + TotalItems = totalItemsCount, + TotalFilteredPages = filteredPagesCount, + TotalFilteredItems = filteredItemsCount + }; + + // + return result; + } + + /// + /// Remove Specified Dto ... + /// + /// + /// + public async Task Remove( + int id + ) + { + // + var isValid = id.IsValidIntId(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + isValid = await IsExists(id); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + var result = await Provider.Remove(id); + if (result.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + return result; + } + + /// + /// Update Specified Dto ... + /// + /// + /// + /// + /// + public async Task Update( + int id, + XTagDto model, + TKey forProvidedId + ) + { + // + // Validate ... + var identifier = GetIdentifier(forProvidedId); + bool isValid = id.IsValidIntId() && + !forProvidedId.IsNull() && + !model.IsNullOrDefault() && + !model.References.IsNull() && + !identifier.IsNullOrEmpty() && + model.References.Any(er => er.ToNormalString() == identifier.ToNormalString()); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + var result = await Provider.Update(id, model); + if (result.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + return result; + } + + /// + /// Count Exists Entities ... + /// + /// + public async Task Count() + { + return (await GetAll()).Count(); + } + + /// + /// Check Entity Exists or not ... + /// + /// + /// + public async Task IsExists(int id) + { + // + var result = (await GetAll()).Any(e => e.Id == id); + + // + return result; + } + + /// + /// Check Tag Exists by Label ... + /// + /// + /// + public async Task IsTagExists(string tag) + { + // + var result = !(await GetTag(tag)) + .IsNullOrDefault(); + + // + return result; + } + + /// + /// Check Specified Model has Tag or not ... + /// + /// + /// + public async Task IsExistsFor(TKey forProvidedId) + { + // + // Validate ... + var result = !forProvidedId.IsNull(); + if (!result) + { + return result; + } + + // + result = (await GetTags(forProvidedId)).Count() >= 1; + + // + return result; + } + + /// + /// Check Tag Exists by Label ... + /// + /// + /// + /// + public async Task IsTagExistsFor( + string tag, + TKey forProvidedId + ) + { + // + var result = !(await GetTagFor( + tag: tag, + forProvidedId: forProvidedId + )) + .IsNullOrDefault(); + + // + return result; + } + #endregion + } +} \ No newline at end of file diff --git a/Providers/XTagProvider.cs b/Providers/XTagProvider.cs new file mode 100644 index 0000000..7427645 --- /dev/null +++ b/Providers/XTagProvider.cs @@ -0,0 +1,476 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; +using Microsoft.AspNetCore.SignalR; +using xCommons.Extensions; +using xDataService.Configuration; +using xExceptions.Constants; +using xIdentityService.Interfaces; +using xModels.Dtos; +using xTagService.Extensions; +using xTagService.Hubs; +using xTagService.Interfaces; +using xTagService.Interfaces.Entities; +using xTagService.Models.Dtos; +using xTagService.Models.Entities; + +namespace xTagService.Providers +{ + public class XTagProvider : IXTagProvider + { + // + #region Props ... + public IXTagRepository Repository { get; } + public IHubContext Hub { get; } + public IXIdentityProvider IdentityProvider { get; } + public XDataServiceConfiguration DataConfiguration { get; } + #endregion + + // + #region Constructor ... + public XTagProvider( + IXTagRepository repository, + IXIdentityProvider identityProvider, + XDataServiceConfiguration dataConfiguration, + IHubContext hub = null + ) + { + // + Hub = hub; + Repository = repository; + IdentityProvider = identityProvider; + DataConfiguration = dataConfiguration; + } + #endregion + + // + #region Helpers .... + /// + /// Converts an Entity to Dto ... + /// + /// + /// + public XTagDto ToXTagDto(XTag model) + { + return model.ToDto(); + } + + /// + /// Converts a List of Entitiies to List of Dto's ... + /// + /// + /// + public IEnumerable ToXTagDtoList(IEnumerable models) + { + // + var result = new List(); + + // + if (!models.IsNull() && models.HasChild()) + { + // + foreach (var model in models) + { + // + var dto = ToXTagDto(model); + if (!dto.IsNullOrDefault()) + { + result.Add(dto); + } + } + } + + // + return result; + } + + /// + /// Converts Query Result of Entities to Dto ... + /// + /// + /// + public XQueryResult ToXTagDtoQueryResult(XQueryResult queryResult) + { + // + var result = new XQueryResult(); + + // + if (!queryResult.IsNullOrDefault()) + { + // + result.Page = queryResult.Page; + result.PageSize = queryResult.PageSize; + result.TotalItems = queryResult.TotalItems; + result.TotalPages = queryResult.TotalPages; + result.TotalFilteredItems = queryResult.TotalFilteredItems; + result.TotalFilteredPages = queryResult.TotalFilteredPages; + + // + if (!queryResult.Items.IsNull() && queryResult.Items.HasChild()) + { + result.Items = ToXTagDtoList(queryResult.Items); + } + } + + // + return result; + } + #endregion + + // + #region Tools ... + /// + /// Add Specified Tag ... + /// + /// + /// + public async Task Add(XTagDto model) + { + // + XTagDto result = null; + + // + if (!model.IsNullOrDefault()) + { + // + // Converts to Entity ... + var entitiy = model.FromDto(); + if (entitiy.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + entitiy = await Repository.AddAsync(entitiy); + if (entitiy.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + result = ToXTagDto(entitiy); + } + + // + return result; + } + + /// + /// Retrieve Specified Item as Dto ... + /// + /// + /// + public async Task Get(int id) + { + // + var result = new XTagDto(); + if (!id.IsValidIntId()) + { + XException.InvalidArgs.Throw(); + } + + // + if (id.IsValidIntId()) + { + // + var entity = await Repository.GetAsync(id); + if (entity.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + result = ToXTagDto(entity); + if (result.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + } + + // + return result; + } + + /// + /// Retrieve Specified Tag by it's Label ... + /// + /// + /// + public async Task GetTag(string tag) + { + // + // Validate ... + if (tag.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + var result = await FindOne(e => e.Tag.ToNormalString() == tag.ToNormalString()); + if (result.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + return result; + } + + /// + /// Retrieve All Items as Dto ... + /// + /// + public async Task> GetAll() + { + // + var result = new List(); + + // + var entities = await Repository.GetAllAsync(); + if (!entities.IsNull() && entities.HasChild()) + { + // + result = ToXTagDtoList(entities) + .ToList(); + } + + // + return result; + } + + /// + /// Find Specified Item by Condition ... + /// + /// + /// + public async Task FindOne(Expression> whereClause) + { + // + XTagDto result = null; + + // + var entitiy = await Repository.FindOneAsync(whereClause); + if (!entitiy.IsNullOrDefault()) + { + result = ToXTagDto(entitiy); + } + + // + return result; + } + + /// + /// Find Many Items based on Conditions ... + /// + /// + /// + public async Task> FindMany(Expression> whereClause) + { + // + var result = new List(); + + // + var entities = await Repository.FindManyAsync(whereClause); + if (!entities.IsNull() || entities.HasChild()) + { + // + result = ToXTagDtoList(entities) + .ToList(); + } + + // + return result; + } + + /// + /// Query Model retrieving Dtos ... + /// + /// + /// + public async Task> Query(XQuery query) + { + // + var result = new XQueryResult(); + + // + var queryResult = await Repository.QueryAsync(query); + if (!queryResult.IsNull()) + { + result = ToXTagDtoQueryResult(queryResult); + } + + // + return result; + } + + /// + /// Query Conditional Retrieving Dtos ... + /// + /// + /// + /// + public async Task> ConditionalQuery( + XQuery query, + Expression> whereClause + ) + { + // + var result = new XQueryResult(); + + // + var queryResult = await Repository.ConditionalQueryAsync( + query: query, + whereClause: whereClause + ); + if (!queryResult.IsNull()) + { + result = ToXTagDtoQueryResult(queryResult); + } + + // + return result; + } + + /// + /// Remove Specified Dto ... + /// + /// + /// + public async Task Remove( + int id + ) + { + // + // Validate ... + var isValid = id.IsValidIntId(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Exists ... + isValid = await IsExists(id); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + var entity = await Repository.RemoveAsync(id); + + // + XTagDto result = null; + if (!entity.IsNullOrDefault()) + { + result = ToXTagDto(entity); + } + + // + return result; + } + + /// + /// Update Specified Dto ... + /// + /// + /// + /// + /// + public async Task Update( + int id, + XTagDto model + ) + { + // + // Validate ... + var isValid = id.IsValidIntId(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + XTagDto result = null; + + // + // Check Exists ... + isValid = await IsExists(id); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + var entity = await Repository.GetAsync(id); + if (entity.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + var tagEntity = model.FromDto(); + entity = entity.UpdateData( + updateWith: entity, + propertyBlackList: new List + { + nameof(XTagDto.Id), + nameof(XTagDto.References) + } + ); + entity.References = tagEntity.References; + entity = await Repository.UpdateAsync(id, entity); + if (!entity.IsNullOrDefault()) + { + result = ToXTagDto(entity); + } + + // + return result; + } + + /// + /// Count Exists Entities ... + /// + /// + public async Task Count() + { + return await Repository.CountAsync(); + } + + /// + /// Check Entity Exists or not ... + /// + /// + /// + public async Task IsExists(int id) + { + return await Repository.IsExistsAsync(id); + } + + /// + /// Check Tag Exists by Label ... + /// + /// + /// + public async Task IsTagExists(string tag) + { + // + var result = false; + + // + if (!tag.IsNullOrEmpty()) + { + // + var dto = await FindOne(e => e.Tag.ToNormalString() == tag.ToNormalString()); + result = !dto.IsNullOrDefault(); + } + + // + return result; + } + #endregion + } +} \ No newline at end of file