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