diff --git a/DI/XDIHelperExtension.cs b/DI/XDIHelperExtension.cs index 8e561d0..965c7f5 100644 --- a/DI/XDIHelperExtension.cs +++ b/DI/XDIHelperExtension.cs @@ -1,3 +1,83 @@ -namespace xStringService.DI { - public static class XDIHelperExtension { } +using System; +using Microsoft.Extensions.DependencyInjection; +using xExceptions.Constants; +using xCommons.Extensions; +using xStringService.Interfaces; +using xStringService.Providers; + +namespace xStringService.DI +{ + public static class XDIHelperExtension + { + /// + /// Register Module Provided Service on DI + /// + /// + /// + public static void AddXStringService( + this IServiceCollection services, + ServiceLifetime lifeTime + ) + { + AddStringService( + services, + lifeTime + ); + } + + // + #region Private ... + /// + /// a LogTag for XStringService ... + /// + private static string XLogTag = "XStringService"; + + /// + /// print a log in Console ... + /// + /// + private static void Log(string message) + { + Console.WriteLine($"{XLogTag} => {message}"); + } + + /// + /// Register Push Service ... + /// + /// + /// + private static void AddStringService( + IServiceCollection services, + ServiceLifetime lifeTime + ) + { + // + var exception = XException.InvalidArgs.ToException(); ; + + // + // Services ... + var isServicesExists = !services.IsNull(); + if (!isServicesExists) + { + // + Log("AddStringService failed, services not provided ..."); + throw exception; + } + + // + // Lifetime ... + var isLifetimeExists = !lifeTime.IsNull(); + if (!isLifetimeExists) + { + // + Log("AddStringService failed, lifetime not provided ..."); + throw exception; + } + + // + services.Add(new ServiceDescriptor(typeof(IXStringProvider), typeof(XStringProvider), lifeTime)); + Log("AddStringService Succeed ..."); + } + #endregion + } } \ No newline at end of file diff --git a/DataHelper/Events/XStringEvents.cs b/DataHelper/Events/XStringEvents.cs new file mode 100644 index 0000000..a56db2c --- /dev/null +++ b/DataHelper/Events/XStringEvents.cs @@ -0,0 +1,9 @@ +using xDataService.Events; +using xStringService.Interfaces.Entities; +using xStringService.Models.Entities; + +namespace xStringService.DataHelper.Events +{ + public class XStringEvents : XBaseRepositoryEvents, IXStringEvents + {} +} \ No newline at end of file diff --git a/DataHelper/GraphQL/XStringGraphQLTypeHelper.cs b/DataHelper/GraphQL/XStringGraphQLTypeHelper.cs new file mode 100644 index 0000000..3ede619 --- /dev/null +++ b/DataHelper/GraphQL/XStringGraphQLTypeHelper.cs @@ -0,0 +1,25 @@ +using xDataService.Configuration; +using xDataService.GraphQL; +using xStringService.Interfaces.Entities; +using xStringService.Models.Entities; + +namespace xStringService.DataHelper.GraphQL +{ + public class XStringGraphQLTypeHelper : XBaseGraphQLTypeHelper, IXStringGraphQLTypeHelper + { + public XStringGraphQLTypeHelper( + XDataServiceConfiguration configuration + ) : base(configuration) + { } + + public override string GetInQueryCollectionName() + { + return "strings"; + } + + public override string GetInQuerySingleName() + { + return "string"; + } + } +} \ No newline at end of file diff --git a/DataHelper/GraphQL/XStringGraphQuery.cs b/DataHelper/GraphQL/XStringGraphQuery.cs new file mode 100644 index 0000000..fb6a1ba --- /dev/null +++ b/DataHelper/GraphQL/XStringGraphQuery.cs @@ -0,0 +1,22 @@ +using GraphQL.Types; +using xDataService.Configuration; +using xDataService.GraphQL; +using xStringService.Interfaces.Entities; +using xStringService.Models.Entities; + +namespace xDataHelper.GraphQL +{ + public class XStringGraphQuery : XBaseGraphQLQuery + { + public XStringGraphQuery( + XDataServiceConfiguration configuration, + IXStringRepository repository, + IXStringGraphQLTypeHelper helper + ) : base( + configuration, + repository, + helper + ) + { } + } +} \ No newline at end of file diff --git a/DataHelper/GraphQL/XStringGraphSchema.cs b/DataHelper/GraphQL/XStringGraphSchema.cs new file mode 100644 index 0000000..f28d89e --- /dev/null +++ b/DataHelper/GraphQL/XStringGraphSchema.cs @@ -0,0 +1,13 @@ +using System; +using GraphQL.Types; + +namespace xDataHelper.GraphQL +{ + public class XStringGraphSchema : Schema + { + public XStringGraphSchema(IServiceProvider services) : base(services) + { + Query = (XStringGraphQuery)services.GetService(typeof(XStringGraphQuery)); + } + } +} \ No newline at end of file diff --git a/DataHelper/GraphQL/XStringGraphType.cs b/DataHelper/GraphQL/XStringGraphType.cs new file mode 100644 index 0000000..54e9bbc --- /dev/null +++ b/DataHelper/GraphQL/XStringGraphType.cs @@ -0,0 +1,15 @@ +using xDataService.GraphQL; +using xStringService.Models.Entities; + +namespace xDataHelper.GraphQL +{ + public class XStringGraphType : XBaseGraphObjectType + { + public XStringGraphType() : base() + { + Field(x => x.Language); + Field(x => x.ResourceTitle); + Field(x => x.TranslatedValue); + } + } +} \ No newline at end of file diff --git a/Extensions/XModelExtensions.cs b/Extensions/XModelExtensions.cs new file mode 100644 index 0000000..9198007 --- /dev/null +++ b/Extensions/XModelExtensions.cs @@ -0,0 +1,118 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using xCommons.Extensions; +using xModels.Dtos; +using xStringService.Models.Dtos; +using xStringService.Models.Entities; + +namespace xStringService.Extensions +{ + public static class XModelExtensions + { + /// + /// Converts an Entity to Dto Representation ... + /// + /// + /// + public static XStringDto ToXStringDto(this XString source) + { + // + XStringDto result = new XStringDto(); + + // + result.Id = source.Id; + result.Language = source.Language; + result.ResourceTitle = source.ResourceTitle; + result.TranslatedValue = source.TranslatedValue; + + // + return result; + } + + /// + /// Converts a Collection of Entities to Dto ... + /// + /// + /// + public static IEnumerable ToXStringDtos(this IEnumerable source) + { + // + var list = new List(); + + // + // Validate ... + bool isValid = source.HasChild(); + if (!isValid) + { + return list.AsEnumerable(); + } + + // + var result = source.Select(e => ToXStringDto(e)); + + // + return result; + } + + /// + /// Converts an Entity to LocaleResource Dto ... + /// + /// + /// + public static XLocaleResourceDto ToXLocaleResourceDto(this XString source) + { + // + var result = new XLocaleResourceDto + { + Language = source.IsNull() ? "" : source.Language, + Value = source.IsNull() ? "" : source.TranslatedValue, + }; + + // + return result; + } + + /// + /// Converts an Dto to LocaleResource Dto ... + /// + /// + /// + public static XLocaleResourceDto ToXLocaleResourceDto(this XStringDto source) + { + // + var result = new XLocaleResourceDto + { + Language = source.IsNull() ? "" : source.Language, + Value = source.IsNull() ? "" : source.TranslatedValue, + }; + + // + return result; + } + + /// + /// Converts a Collection of Entities to Locale Resource Presentation ... + /// + /// + /// + public static IEnumerable ToXLocaleResourceDtos(this IEnumerable source) + { + // + var result = source.Select(e => ToXLocaleResourceDto(e)); + return result; + } + + /// + /// Converts a Collection of Dtos to Locale Resource Presentation ... + /// + /// + /// + public static IEnumerable ToXLocaleResourceDtos(this IEnumerable source) + { + // + var result = source.Select(e => ToXLocaleResourceDto(e)); + return result; + } + } +} \ No newline at end of file diff --git a/Interfaces/Entities/IXStringEvents.cs b/Interfaces/Entities/IXStringEvents.cs new file mode 100644 index 0000000..4f6b4da --- /dev/null +++ b/Interfaces/Entities/IXStringEvents.cs @@ -0,0 +1,8 @@ +using xDataService.Interfaces; +using xStringService.Models.Entities; + +namespace xStringService.Interfaces.Entities +{ + public interface IXStringEvents : IXBaseRepositoryEvents + { } +} \ No newline at end of file diff --git a/Interfaces/Entities/IXStringGraphQLTypeHelper.cs b/Interfaces/Entities/IXStringGraphQLTypeHelper.cs new file mode 100644 index 0000000..8d10308 --- /dev/null +++ b/Interfaces/Entities/IXStringGraphQLTypeHelper.cs @@ -0,0 +1,8 @@ +using xDataService.Interfaces; +using xStringService.Models.Entities; + +namespace xStringService.Interfaces.Entities +{ + public interface IXStringGraphQLTypeHelper : IXBaseGraphQLTypeHelper + { } +} \ No newline at end of file diff --git a/Interfaces/Entities/IXStringRepository.cs b/Interfaces/Entities/IXStringRepository.cs new file mode 100644 index 0000000..01b921e --- /dev/null +++ b/Interfaces/Entities/IXStringRepository.cs @@ -0,0 +1,8 @@ +using xDataService.Interfaces; +using xStringService.Models.Entities; + +namespace xStringService.Interfaces.Entities +{ + public interface IXStringRepository : IXBaseRepository + { } +} \ No newline at end of file diff --git a/Interfaces/IXStringProvider.cs b/Interfaces/IXStringProvider.cs new file mode 100644 index 0000000..32d3cc8 --- /dev/null +++ b/Interfaces/IXStringProvider.cs @@ -0,0 +1,251 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Threading.Tasks; +using xCommons.Configurations; +using xDataService.Configuration; +using xModels.Dtos; +using xStringService.Interfaces.Entities; +using xStringService.Models.Dtos; +using xStringService.Models.Entities; + +namespace xStringService.Interfaces +{ + public interface IXStringProvider + { + // + #region Props ... + IXStringRepository Repository { get; } + XAppConfiguration AppConfiguration { get; } + XDataServiceConfiguration DataConfiguration { get; } + #endregion + + // + #region Retrievers ... + /// + /// Retrieve all Exists Languages ... + /// + /// + Task> GetLanguages(); + + /// + /// Check Specified Resource Exists or not ... + /// + /// + /// + /// + Task IsResourceExists( + string resource, + string language = null + ); + + /// + /// Retrieve Specified Translation of Specified Resource ... + /// + /// + /// + /// + Task GetResourceValue( + string resource, + string language = null + ); + + /// + /// Retrieve an Specified Resource Items ... + /// + /// + /// + Task> GetResources(string resource); + + /// + /// Retrieve Specified Resource Items as XResourceDto Presentation ... + /// + /// + /// + Task GetResource(string resource); + #endregion + + // + #region Query ... + /// + /// Query Resource IDs ... + /// + /// + /// + Task> QueryResourceIds(XQuery query); + + /// + /// Query Specified Language Resources ... + /// + /// + /// + /// + Task> QueryLanguageResources( + XQuery query, + string language = null // + ); + + /// + /// Query Locale Resources ... + /// + /// + /// + /// + Task> QueryLocaleResources( + XQuery query, + string language = null // + ); + + /// + /// Conditional Query Resources ... + /// + /// + /// + /// + /// + Task> ConditionalQueryResources( + XQuery query, + Expression> condition, + string language = null + ); + #endregion + + // + #region Add/Update Actions ... + /// + /// Add Specified Resource ... + /// + /// + /// + /// + /// + Task Add( + string resource, + string value, + string language = null + ); + + /// + /// Update Resource ... + /// + /// + /// + /// + /// + Task Update( + string resource, + string value, + string language = null + ); + + /// + /// Add Or Update Resource ... + /// + /// + /// + /// + /// + Task AddOrUpdate( + string resource, + string value, + string language = null + ); + + /// + /// Add Specified Resource ... + /// + /// + /// + Task AddEntity(XStringDto item); + + /// + /// Update Specified Entity ... + /// + /// + /// + Task UpdateEntity(XStringDto item); + + /// + /// Add Or Update Specified Entitiy ... + /// + /// + /// + Task AddOrUpdateEntity(XStringDto item); + + /// + /// Add Specified Locale Resource ... + /// + /// + /// + /// + Task AddByLocaleResource( + XLocaleResourceDto item, + string resource + ); + + /// + /// Update Specified Locale Resource ... + /// + /// + /// + /// + Task UpdateByLocaleResource( + XLocaleResourceDto item, + string resource + ); + + /// + /// Add Or Update Resource By Locale ... + /// + /// + /// + /// + Task AddOrUpdateByLocaleResource( + XLocaleResourceDto item, + string resource + ); + + /// + /// Add Or Update all XResourceDto(s) Locales ... + /// + /// + /// + Task> AddByResource(XResourceDto item); + #endregion + + // + #region Remove Actions ... + /// + /// Remove all Specified Language's Resources ... + /// + /// + /// + Task RemoveLanguageResources(string language); + + /// + /// Remove all Specified Resource Ids instances ... + /// + /// + /// + Task> RemoveResource(string resource); + + /// + /// Remove Specified Resource ... + /// + /// + /// + /// + Task Remove( + string resource, + string language = null + ); + + /// + /// Remove all Resource of Specified XResourceDto ... + /// + /// + /// + Task RemoveByResource(XResourceDto item); + #endregion + } +} \ No newline at end of file diff --git a/Models/Dtos/XStringDto.cs b/Models/Dtos/XStringDto.cs new file mode 100644 index 0000000..65bbb1f --- /dev/null +++ b/Models/Dtos/XStringDto.cs @@ -0,0 +1,12 @@ +using xModels.Base; + +namespace xStringService.Models.Dtos +{ + public class XStringDto : XBaseDto + { + public int Id { get; set; } + public string Language { get; set; } + public string ResourceTitle { get; set; } + public string TranslatedValue { get; set; } + } +} \ No newline at end of file diff --git a/Models/Entities/XString.cs b/Models/Entities/XString.cs new file mode 100644 index 0000000..99b95b0 --- /dev/null +++ b/Models/Entities/XString.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using xModels.Base; + +namespace xStringService.Models.Entities +{ + public class XString : XBaseIntIDEntity + { + [Required] + [StringLength (10)] + public string Language { get; set; } + + [Required] + [StringLength (255)] + public string ResourceTitle { get; set; } + + [Required] + public string TranslatedValue { get; set; } + } +} \ No newline at end of file diff --git a/Providers/XStringProvider.cs b/Providers/XStringProvider.cs new file mode 100644 index 0000000..1cb5399 --- /dev/null +++ b/Providers/XStringProvider.cs @@ -0,0 +1,1183 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reactive.Concurrency; +using System.Threading.Tasks; +using xCommons.Configurations; +using xCommons.Extensions; +using xDataService.Configuration; +using xDataService.Extensions; +using xExceptions.Constants; +using xModels.Dtos; +using xStringService.Extensions; +using xStringService.Interfaces; +using xStringService.Interfaces.Entities; +using xStringService.Models.Dtos; +using xStringService.Models.Entities; + +namespace xStringService.Providers +{ + public class XStringProvider : IXStringProvider + { + // + #region Props ... + public IXStringRepository Repository { get; } + public XAppConfiguration AppConfiguration { get; } + public XDataServiceConfiguration DataConfiguration { get; } + #endregion + + // + #region Constructor ... + public XStringProvider( + IXStringRepository repository, + XAppConfiguration appConfiguration, + XDataServiceConfiguration dataConfiguration + ) + { + // + Repository = repository; + AppConfiguration = appConfiguration; + DataConfiguration = dataConfiguration; + } + #endregion + + // + #region Retrievers ... + /// + /// Retrieve all Exists Languages ... + /// + /// + public async Task> GetLanguages() + { + // + var result = (await Repository.GetAllAsync()) + .AsQueryable() + .Select(e => e.Language) + .Distinct() + .ToList(); + + // + // Check Configuration Default Language Exists ... + var hasDefaultLanguage = !AppConfiguration.DefaultLanguage.IsNullOrEmpty(); + if (hasDefaultLanguage) + { + // + // Find Default Language on Result ... + hasDefaultLanguage = result.Any(e => e.ToNormalString() == AppConfiguration.DefaultLanguage.ToNormalString()); + if (!hasDefaultLanguage) + { + result.Add(AppConfiguration.DefaultLanguage); + } + } + + // + result = result + .Distinct() + .ToList(); + + // + return result; + } + + /// + /// Check Specified Resource Exists or not ... + /// + /// + /// + /// + public async Task IsResourceExists( + string resource, + string language = null + ) + { + // + var result = false; + + // + // Validate ... + result = !resource.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + XStringDto entity = null; + if (language.IsNullOrEmpty()) + { + // + entity = await Repository + .FindOneAsync(e => e.ResourceTitle == resource) + .ToDynamicObject(); + } + else + { + // + entity = await Repository + .FindOneAsync(e => e.ResourceTitle == resource && + e.Language.ToNormalString() == language.ToNormalString() + ) + .ToDynamicObject(); + } + result = !entity.IsNullOrDefault(); + + // + return result; + } + + /// + /// Retrieve Specified Translation of Specified Resource ... + /// + /// + /// + /// + public async Task GetResourceValue( + string resource, + string language = null + ) + { + // + var result = ""; + + // + // Normalize ... + if (language.IsNullOrEmpty()) + { + language = AppConfiguration.DefaultLanguage; + } + + // + // Validate ... + var isValid = !resource.IsNullOrEmpty() && + !language.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Langauage Exists ... + var languages = await GetLanguages(); + isValid = languages.Any(l => l.ToNormalString() == language.ToNormalString()); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + // Check Resource Exists ... + isValid = await IsResourceExists(resource); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + var entity = await Repository.FindOneAsync(e => + e.ResourceTitle == resource && + e.Language.ToNormalString() == language.ToNormalString() + ); + isValid = !entity.IsNullOrDefault(); + if (!isValid) + { + XException.ActionFailed.Throw(); + } + + // + result = entity.TranslatedValue; + + // + return result; + } + + /// + /// Retrieve an Specified Resource Items ... + /// + /// + /// + public async Task> GetResources(string resource) + { + // + // Validate ... + var isValid = await IsResourceExists(resource); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + var result = (await Repository + .FindManyAsync(e => e.ResourceTitle == resource)) + .ToXStringDtos(); + + // + return result; + } + + /// + /// Retrieve Specified Resource Items as XResourceDto Presentation ... + /// + /// + /// + public async Task GetResource(string resource) + { + // + // Validate ... + bool isExists = await IsResourceExists(resource); + if (!isExists) + { + XException.NotFound.Throw(); + } + + // + // Retrieve String Dto (s) ... + var resources = await GetResources(resource); + if (!resource.HasChild()) + { + XException.NotFound.Throw(); + } + + // + var result = new XResourceDto + { + Resource = resource, + Locales = resources.ToXLocaleResourceDtos() + }; + + return result; + } + #endregion + + // + #region Query ... + /// + /// Query Resource IDs ... + /// + /// + /// + public async Task> QueryResourceIds(XQuery query) + { + // + // Normalize ... + query = query.NormalizeQuery(DataConfiguration); + + // + // Read Resource IDs ... + var items = Repository + .AsQueryable() + .Select(e => e.ResourceTitle) + .Distinct(); + + // + var totalItemsCount = items.Count(); + + // + // Apply Filter ... + if (totalItemsCount > 0 && + !query.Filter.IsNullOrEmpty()) + { + // + items = items + .Where(e => e.ToNormalString().Contains(query.Filter.ToNormalString())); + } + + // + var filteredItemsCount = items.Count(); + var totalPagesCount = query.CountPages(totalItemsCount); + var filteredPagesCount = query.CountPages(filteredItemsCount); + + // + // Apply Paging / Sorting ... + if (totalItemsCount > 0 && + filteredItemsCount > 0) + { + // + items = items.ApplyPaging( + query.Page, + query.PageSize + ); + } + + // + // Prepare result ... + var result = new XQueryResult + { + Page = query.Page, + PageSize = query.PageSize, + TotalPages = totalPagesCount, + TotalItems = totalItemsCount, + TotalFilteredPages = filteredPagesCount, + TotalFilteredItems = filteredItemsCount + }; + + // + return result; + } + + /// + /// Query Specified Language Resources ... + /// + /// + /// + /// + public async Task> QueryLanguageResources( + XQuery query, + string language = null // + ) + { + // + // Normalize ... + query = query.NormalizeQuery(DataConfiguration); + + // + // Validate ... + if (query.IsNull()) + { + XException.InvalidArgs.Throw(); + } + + // + XQueryResult result = null; + if (language.IsNullOrEmpty()) + { + // + result = (await Repository.QueryAsync(query)) + .ToDynamicObject(); + } + else + { + // + result = (await Repository.ConditionalQueryAsync( + e => e.Language.ToNormalString() == language.ToNormalString(), + query + )) + .ToDynamicObject(); + } + + // + return result; + } + + /// + /// Query Locale Resources ... + /// + /// + /// + /// + public async Task> QueryLocaleResources( + XQuery query, + string language = null // + ) + { + // + // Normalize ... + query.NormalizeQuery(DataConfiguration); + + // + // Validate ... + if (query.IsNull()) + { + XException.InvalidArgs.Throw(); + } + + // + IEnumerable items = null; + if (!language.IsNullOrEmpty()) + { + items = (await Repository + .FindManyAsync(e => e.Language.ToNormalString() == language.ToNormalString())) + .ToXLocaleResourceDtos(); + } + else + { + items = (await Repository.GetAllAsync()) + .ToXLocaleResourceDtos(); + } + + // + var totalItemsCount = items.Count(); + + // + // Apply Filter ... + if (totalItemsCount > 0 && + !query.Filter.IsNullOrEmpty()) + { + // + items = items.ApplyFilter(query.Filter); + } + + // + var filteredItemsCount = items.Count(); + var totalPagesCount = query.CountPages(totalItemsCount); + var filteredPagesCount = query.CountPages(filteredItemsCount); + + // + // Apply Paging/Sorting ... + if (totalItemsCount > 0 && + filteredItemsCount > 0) + { + // + // Apply Paging ... + items = items.ApplyPaging( + query.Page, + query.PageSize + ); + + // + // Apply Sorting ... + items = items.ApplySorting( + query.SortBy, + query.IsAscending + ); + } + + // + // Prepare Result ... + var result = new XQueryResult + { + Page = query.Page, + PageSize = query.PageSize, + TotalPages = totalPagesCount, + TotalItems = totalItemsCount, + TotalFilteredPages = filteredPagesCount, + TotalFilteredItems = filteredItemsCount + }; + + // + return result; + } + + /// + /// Conditional Query Resources ... + /// + /// + /// + /// + /// + public async Task> ConditionalQueryResources( + XQuery query, + Expression> condition, + string language = null + ) + { + // + // Normalize ... + query = query.NormalizeQuery(DataConfiguration); + + // + if (!language.IsNullOrEmpty()) + { + // + // Renew and Update Condition by Language Checking ... + var compiledCondition = condition.Compile(); + condition = + e => compiledCondition(e) && + e.Language.ToNormalString() == language.ToNormalString(); + } + + // + var result = (await Repository.ConditionalQueryAsync(condition, query)) + .ToDynamicObject(); + + // + return result; + } + #endregion + + // + #region Add/Update Actions ... + /// + /// Add Specified Resource ... + /// + /// + /// + /// + /// + public async Task Add( + string resource, + string value, + string language = null + ) + { + // + bool result = false; + + // + // Normalize ... + if (language.IsNullOrEmpty()) + { + language = AppConfiguration.DefaultLanguage; + } + + // + // Validate ... + result = + !value.IsNullOrEmpty() && + !resource.IsNullOrEmpty() && + !language.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + // Check Exists ... + bool isExists = await IsResourceExists(resource, language); + result = !isExists; + if (!result) + { + XException.Duplicate.Throw(); + } + + // + // Prepare Entity to Add ... + XString entity = new XString + { + Language = language, + TranslatedValue = value, + ResourceTitle = resource, + }; + var added = await Repository.AddAsync(entity); + result = !added.IsNullOrDefault(); + + // + return result; + } + + /// + /// Update Resource ... + /// + /// + /// + /// + /// + public async Task Update( + string resource, + string value, + string language = null + ) + { + // + bool result = false; + + // + // Normalize ... + if (language.IsNullOrEmpty()) + { + language = AppConfiguration.DefaultLanguage; + } + + // + // Validate ... + result = + !value.IsNullOrEmpty() && + !language.IsNullOrEmpty() && + !resource.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + // Check Value Must Exists ... + result = await IsResourceExists( + resource: resource, + language: language + ); + if (!result) + { + XException.NotFound.Throw(); + } + + // + var entity = await Repository.FindOneAsync(e => + e.ResourceTitle == resource && + e.Language.ToNormalString() == language.ToNormalString() + ); + if (entity.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Update Entity ... + entity.TranslatedValue = value; + entity = await Repository.UpdateAsync(entity.Id, entity); + result = !entity.IsNullOrDefault(); + + // + return result; + } + + /// + /// Add Or Update Resource ... + /// + /// + /// + /// + /// + public async Task AddOrUpdate( + string resource, + string value, + string language = null + ) + { + // + var result = false; + + // + // Normalize ... + if (language.IsNullOrEmpty()) + { + language = AppConfiguration.DefaultLanguage; + } + + // + // Check Existsance ... + bool isExists = await IsResourceExists( + resource: resource, + language: language + ); + + // + // Act Based on Existance ... + if (isExists) + { + // + result = await Update( + value: value, + resource: resource, + language: language + ); + } + else + { + // + result = await Add( + value: value, + resource: resource, + language: language + ); + } + + // + return result; + } + + /// + /// Add Specified Resource ... + /// + /// + /// + public async Task AddEntity(XStringDto item) + { + // + // Validate ... + bool isValid = !item.IsNull() && + !item.ResourceTitle.IsNullOrEmpty() && + !item.TranslatedValue.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Normalize ... + if (item.Language.IsNullOrEmpty()) + { + item.Language = AppConfiguration.DefaultLanguage; + } + isValid = !item.Language.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Resource Doesn't Exists ... + isValid = await IsResourceExists( + resource: item.ResourceTitle, + language: item.Language + ); + if (isValid) + { + XException.Duplicate.Throw(); + } + + // + var result = new XString + { + Language = item.Language, + ResourceTitle = item.ResourceTitle, + TranslatedValue = item.TranslatedValue + }; + result = await Repository.AddAsync(result); + if (result.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + return result.ToDynamicObject(); + } + + /// + /// Update Specified Entity ... + /// + /// + /// + public async Task UpdateEntity(XStringDto item) + { + // + // Validate ... + bool isValid = !item.IsNull() && + !item.ResourceTitle.IsNullOrEmpty() && + !item.TranslatedValue.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Normalize ... + if (item.Language.IsNullOrEmpty()) + { + item.Language = AppConfiguration.DefaultLanguage; + } + isValid = !item.Language.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Resource Exists ... + isValid = await IsResourceExists( + resource: item.ResourceTitle, + language: item.Language + ); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + var entity = await Repository.FindOneAsync(e => + e.ResourceTitle == item.ResourceTitle && + e.Language.ToNormalString() == item.Language.ToNormalString() + ); + if (entity.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Update Entity ... + entity.TranslatedValue = item.TranslatedValue; + entity = await Repository.UpdateAsync(entity.Id, entity); + if (entity.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + XStringDto result = entity.ToDynamicObject(); + + // + return result; + } + + /// + /// Add Or Update Specified Entitiy ... + /// + /// + /// + public async Task AddOrUpdateEntity(XStringDto item) + { + // + // Validate ... + bool isValid = !item.IsNull() && + !item.ResourceTitle.IsNullOrEmpty() && + !item.TranslatedValue.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Normalize ... + if (item.Language.IsNullOrEmpty()) + { + item.Language = AppConfiguration.DefaultLanguage; + } + isValid = !item.Language.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Resource Exists ... + var isExists = await IsResourceExists( + resource: item.ResourceTitle, + language: item.Language + ); + + // + XStringDto result = null; + if (!isExists) + { + result = await AddEntity(item); + } + else + { + result = await UpdateEntity(item); + } + if (result.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + return result; + } + + /// + /// Add Specified Locale Resource ... + /// + /// + /// + /// + public async Task AddByLocaleResource( + XLocaleResourceDto item, + string resource + ) + { + // + // Validate ... + bool isValid = + !item.IsNull() && + !resource.IsNullOrEmpty() && + !item.Value.IsNullOrEmpty() && + !item.Language.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Specified Resource / Language Exists ... + isValid = await IsResourceExists( + resource: resource, + language: item.Language + ); + if (isValid) + { + XException.Duplicate.Throw(); + } + + // + // Prepare Item to Add ... + var result = new XStringDto + { + Language = item.Language, + ResourceTitle = resource, + TranslatedValue = item.Value + }; + result = await AddEntity(result); + + // + return result; + } + + /// + /// Update Specified Locale Resource ... + /// + /// + /// + /// + public async Task UpdateByLocaleResource( + XLocaleResourceDto item, + string resource + ) + { + // + // Validate ... + bool isValid = + !item.IsNull() && + !resource.IsNullOrEmpty() && + !item.Value.IsNullOrEmpty() && + !item.Language.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Specified Resource / Language Exists ... + isValid = await IsResourceExists( + resource: resource, + language: item.Language + ); + if (!isValid) + { + XException.NotFound.Throw(); + } + + // + var entity = await Repository.FindOneAsync(e => + e.ResourceTitle == resource && + e.Language.ToNormalString() == item.Language.ToNormalString() + ); + if (entity.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Update ... + entity.TranslatedValue = item.Value; + entity = await Repository.UpdateAsync(entity.Id, entity); + if (entity.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + XStringDto result = entity.ToDynamicObject(); + return result; + } + + /// + /// Add Or Update Resource By Locale ... + /// + /// + /// + /// + public async Task AddOrUpdateByLocaleResource( + XLocaleResourceDto item, + string resource + ) + { + // + // Validate ... + bool isValid = + !item.IsNull() && + !resource.IsNullOrEmpty() && + !item.Value.IsNullOrEmpty() && + !item.Language.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Specified Resource / Language Exists ... + isValid = await IsResourceExists( + resource: resource, + language: item.Language + ); + + // + XStringDto result = null; + if (!isValid) + { + // + result = await AddByLocaleResource( + item: item, + resource: resource + ); + } + else + { + // + result = await UpdateByLocaleResource( + item: item, + resource: resource + ); + } + if (result.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + return result; + } + + /// + /// Add Or Update all XResourceDto(s) Locales ... + /// + /// + /// + public async Task> AddByResource(XResourceDto item) + { + // + // Validate ... + bool isValid = + !item.IsNull() && + item.Locales.HasChild() && + !item.Resource.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + var result = await Task + .WhenAll(item.Locales + .Select(async e => await AddOrUpdateByLocaleResource(e, item.Resource))); + + // + return result; + } + #endregion + + // + #region Remove Actions ... + /// + /// Remove all Specified Language's Resources ... + /// + /// + /// + public async Task RemoveLanguageResources(string language) + { + // + // Validate ... + bool isValid = !language.IsNullOrEmpty(); + if (!isValid) + { + return; + } + + // + var entities = await Repository + .FindManyAsync(e => e.Language.ToNormalString() == language.ToNormalString()); + await Repository.RemoveRangeAsync(entities); + } + + /// + /// Remove all Specified Resource Ids instances ... + /// + /// + /// + public async Task> RemoveResource(string resource) + { + // + // Validate ... + if (resource.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + var result = new List(); + var entities = await Repository.FindManyAsync(e => e.ResourceTitle == resource); + foreach (var entity in entities) + { + // + var removed = await Repository.RemoveAsync(entity); + if (!removed.IsNullOrDefault()) + { + result.Add(removed.ToXStringDto()); + } + } + + // + return result; + } + + /// + /// Remove Specified Resource ... + /// + /// + /// + /// + public async Task Remove( + string resource, + string language = null + ) + { + // + bool result = false; + + // + // Normalize ... + if (language.IsNullOrEmpty()) + { + language = AppConfiguration.DefaultLanguage; + } + + // + // Validate ... + result = + !language.IsNullOrEmpty() && + !resource.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + // Check Resource Exists ... + result = await IsResourceExists( + language: language, + resource: resource + ); + if (!result) + { + return result; + } + + // + // Retrieve Entity ... + var entity = await Repository.FindOneAsync(e => + e.ResourceTitle == resource && + e.Language.ToNormalString() == language.ToNormalString() + ); + result = !entity.IsNullOrDefault(); + if (!result) + { + return result; + } + + // + // Delete ... + entity = await Repository.RemoveAsync(entity.Id); + result = !entity.IsNullOrDefault(); + + // + return result; + } + + /// + /// Remove all Resource of Specified XResourceDto ... + /// + /// + /// + public async Task RemoveByResource(XResourceDto item) + { + // + bool isValid = + !item.IsNullOrDefault() && + item.Locales.HasChild() && + !item.Resource.IsNullOrEmpty(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + foreach (var locale in item.Locales) + { + // + await Remove( + resource: item.Resource, + language: locale.Language + ); + } + } + #endregion + } +} \ No newline at end of file