diff --git a/Configuration/XDataBaseConfiguration.cs b/Configuration/XDataBaseConfiguration.cs index c43fec9..2fa6357 100644 --- a/Configuration/XDataBaseConfiguration.cs +++ b/Configuration/XDataBaseConfiguration.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using xDataService.Constants; namespace xDataService.Configuration @@ -17,6 +18,12 @@ namespace xDataService.Configuration /// Connection String which provide Requires Data to Connect to Db Provider ... /// /// - public string ConnectionString { get; set; } + public string ConnectionString { get; set; } + + /// + /// Holds Seeding items ... + /// nameof(TEntity) => TEntity + /// + public IDictionary> SeedItems { get; set; } = new Dictionary>(); } } \ No newline at end of file diff --git a/Configuration/XDataServiceConfiguration.cs b/Configuration/XDataServiceConfiguration.cs index c7d97fa..2a196c8 100644 --- a/Configuration/XDataServiceConfiguration.cs +++ b/Configuration/XDataServiceConfiguration.cs @@ -19,7 +19,7 @@ namespace xDataService.Configuration /// /// /// - public Dictionary Databases { get; set; } = new Dictionary(); + public IDictionary Databases { get; set; } = new Dictionary(); /// /// Enable Soft Delete Entities or Not ... @@ -27,6 +27,11 @@ namespace xDataService.Configuration /// public bool EnableSoftDelete { get; set; } + /// + /// Specified Seeding Mode ... + /// + public XDbSeedingMode SeedingMode { get; set; } = XDbSeedingMode.None; + /// /// Enable Tracking of Entities ... /// Only Used on EFCore ... diff --git a/Constants/XDbSeedingMode.cs b/Constants/XDbSeedingMode.cs new file mode 100644 index 0000000..ca7dfc7 --- /dev/null +++ b/Constants/XDbSeedingMode.cs @@ -0,0 +1,23 @@ +namespace xDataService.Constants +{ + /// + /// All Seeding Data Mode ... + /// + public enum XDbSeedingMode + { + /// + /// No Seed Data ... + /// + None, + + /// + /// Seed Only New Items ... + /// + AddIfNotExists, + + /// + /// Seed Force (Add/Update) ... + /// + AddOrUpdate, + } +} \ No newline at end of file diff --git a/DI/XDIHelperExtension.cs b/DI/XDIHelperExtension.cs index 528d43f..5a7bdf5 100644 --- a/DI/XDIHelperExtension.cs +++ b/DI/XDIHelperExtension.cs @@ -1,7 +1,7 @@ using System; using System.Linq; +using System.Runtime.InteropServices; using Microsoft.AspNetCore.Builder; -using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -11,7 +11,6 @@ using xDataService.Configuration; using xDataService.Constants; using xDataService.Extensions; using xDataService.Helpers; -using xDataService.Interfaces; using xDataService.Models; using xExceptions.Constants; @@ -34,6 +33,25 @@ namespace xDataService.DI .GetSection(ConfigurationNodeNames.DATA_SERVICE_NODE); var result = xDataServiceConfigSection.Get(); + // + // Reading Seeders ... + if (!result.IsNull() && + result.Databases.HasChild()) + { + // + result + .Databases + .ToList() + .ForEach(db => + { + // + // TODO: Fix this ... + var sectionName = $"{ConfigurationNodeNames.DATA_SERVICE_NODE}:{nameof(XDataServiceConfiguration.Databases)}:{db.Key}:{nameof(XDataBaseConfiguration.SeedItems)}"; + // var seedItems = source.GetSectionAsDictionary(sectionName); + // db.Value.SeedItems = seedItems; + }); + } + // return result; } @@ -229,7 +247,8 @@ namespace xDataService.DI public static void UseXDatabase( this IApplicationBuilder source, - XDatabaseDescriptor descriptor + XDatabaseDescriptor descriptor, + bool isDevelopmentEnvironment = false ) { // @@ -244,6 +263,14 @@ namespace xDataService.DI XException.InvalidArgs.Throw(); } + // + var withPlayground = false; + if (isDevelopmentEnvironment) + { + // + withPlayground = true; + } + // // Check Repositories Exists ... isValid = descriptor.HasRepositories(); @@ -265,61 +292,66 @@ namespace xDataService.DI .ToList() .ForEach(r => { + // + Log($"Start Using Repository of: {r.Entity}"); + + // + // Check Seeder Exists ... + isValid = r.HasSeeder(); + if (isValid) + { + // + var seeder = (dynamic)scope.ServiceProvider.GetService(r.SeederService); + isValid = seeder != null; + if (isValid) + { + // + Log($"Start Seeding {r.Entity} ..."); + + // + // Seeding ... + seeder + .Seed() + .RunTask(); + } + } + // // Check GraphQL Support ... isValid = r.HasGraphSupport(); if (isValid) { // - // Inject GraphQL Type Helper ... - var helper = scope.ServiceProvider.GetService(r.GraphTypeHelperService); - isValid = !helper.IsNullOrDefault(); - if (!isValid) - { - // - Log($"unable to find GraphQLTypeHelper for Entiy: {r.Entity}"); - XException.NotFound.Throw(); - } + // Use WebSockets ... + source.UseWebSockets(); // - var methods = source.GetType().GetMethods(); - isValid = - !methods.IsNull() && - methods.HasChild(); + // Inject GraphQL Type Helper ... + var helper = (dynamic)scope.ServiceProvider.GetService(r.GraphTypeHelperService); + isValid = helper != null; if (isValid) { // - try - { - // - // UseGraphQL ... - var method = methods.First(m => - m.IsGenericMethod && - m.Name == "UseGraphQL" && - m.GetGenericArguments().Length == 1 && - m.GetParameters().Length == 1 - ); - var genericMethod = method.MakeGenericMethod(r.GraphSchema); - genericMethod.Invoke(null, ((dynamic)helper).GetGraphQLPath()); - - // - // UseGraphQLWebSockets ... - method = methods.First(m => - m.IsGenericMethod && - m.Name == "UseGraphQLWebSockets" && - m.GetGenericArguments().Length == 1 && - m.GetParameters().Length == 0 - ); - genericMethod = method.MakeGenericMethod(r.GraphSchema); - genericMethod.Invoke(null, null); - - // - Log($"Register GraphQL Middleware for Entity {r.Entity} Successfully ..."); - } - catch (Exception ex) - { - Log($"Registration GraphQL Middleware for Entity {r.Entity} failed due {ex.Message} ..."); - } + string graphPath = helper.GetGraphQLPath(); + typeof(XDataServiceHelper).InvokeGenericMethod( + methodName: "UseXGraphQL", + runtimeTypes: [ + r.Entity, + r.Key, + r.GraphType, + r.GraphTypeKey, + r.GraphQuery, + r.GraphTypeHelperService, + r.GraphTypeHelperImplementation, + r.GraphSchema + ], + args: [ + source, + graphPath, + withPlayground, + null + ] + ); } } }); @@ -343,42 +375,6 @@ namespace xDataService.DI { Console.WriteLine($"{XLogTag} => {message}"); } - - /// - /// Do Seeding Initialization Data on DbContext - /// - /// - private static void SeedData( - this IApplicationBuilder app - ) - { - // - using (var scope = app.ApplicationServices.CreateScope()) - { - // - var dbSeeder = scope.ServiceProvider.GetService(); - Console.WriteLine($"XDataService: dbSeeder retrieved from DI is => {!dbSeeder.IsNull()}"); - - // - if (!dbSeeder.IsNull()) - { - try - { - // - dbSeeder.Seed() - .GetAwaiter() - .GetResult(); - } - catch (Exception ex) - { - // - Console.WriteLine(" "); - Console.WriteLine($"XDataService: Seeding Error: {ex.Message}"); - XException.InvalidConfiguration.Throw(); - } - } - } - } #endregion } } \ No newline at end of file diff --git a/Extensions/XRepositoryDescriptorExtensions.cs b/Extensions/XRepositoryDescriptorExtensions.cs index 58eaf16..a9bb8ef 100644 --- a/Extensions/XRepositoryDescriptorExtensions.cs +++ b/Extensions/XRepositoryDescriptorExtensions.cs @@ -1,10 +1,20 @@ using xCommons.Extensions; +using xDataService.Db; +using xDataService.EFRepositories; +using xDataService.Events; +using xDataService.InMemRepositories; +using xDataService.Interfaces; using xDataService.Models; +using xDataService.MongoRepositories; +using xDataService.Providers; +using xModels.Base; namespace xDataService.Extensions { public static class XRepositoryDescriptorExtensions { + // + #region Hasers ... /// /// Validate a Descriptor ... /// @@ -64,6 +74,7 @@ namespace xDataService.Extensions // var result = source.IsValid() && + source.HasRepository() && !source.GraphType.IsNull() && !source.GraphQuery.IsNull() && !source.GraphSchema.IsNull() && @@ -108,5 +119,185 @@ namespace xDataService.Extensions // return result; } + + /// + /// Check a Descriptor Has Seeder or not ... + /// + /// + /// + public static bool HasSeeder(this XRepositoryDescriptor source) + { + // + var result = + source.IsValid() && + source.HasRepository() && + !source.SeederService.IsNull() && + !source.SeederImplementation.IsNull(); + + // + return result; + } + #endregion + + // + #region Builders ... + public static XRepositoryDescriptor AddEntity( + this XRepositoryDescriptor source + ) + where TEntity : XBaseEntity + { + // + if (source.IsNull()) + { + source = new XRepositoryDescriptor(); + } + + // + source.Key = typeof(TKey); + source.Entity = typeof(TEntity); + + // + return source; + } + + public static XRepositoryDescriptor AddEvents( + this XRepositoryDescriptor source + ) + where TEntity : XBaseEntity + where TEventsService : IXBaseRepositoryEvents + where TEventsImplementation : XBaseRepositoryEvents + { + // + if (source.IsNull()) + { + // + source = new XRepositoryDescriptor(); + source = source.AddEntity(); + } + + // + source.EventsService = typeof(TEventsService); + source.EventsImplementation = typeof(TEventsImplementation); + + // + return source; + } + + public static XRepositoryDescriptor AddKeyGenerator( + this XRepositoryDescriptor source + ) + where TEntity : XBaseEntity + where TKeyGeneratorService : IXKeyGenerator + where TKeyGeneratorImplementation : XKeyGenerator + { + // + if (source.IsNull()) + { + // + source = new XRepositoryDescriptor(); + source = source.AddEntity(); + } + + // + source.KeyGeneratorService = typeof(TKeyGeneratorService); + source.KeyGeneratorImplementation = typeof(TKeyGeneratorImplementation); + + // + return source; + } + + public static XRepositoryDescriptor AddSeeder( + this XRepositoryDescriptor source + ) + where TEntity : XBaseEntity + where TSeederService : IXBaseDbSeeder + where TSeederImplementation : XBaseDbSeeder + { + // + if (source.IsNull()) + { + // + source = new XRepositoryDescriptor(); + source = source.AddEntity(); + } + + // + source.SeederService = typeof(TSeederService); + source.SeederImplementation = typeof(TSeederImplementation); + + // + return source; + } + + public static XRepositoryDescriptor AddEFRepository( + this XRepositoryDescriptor source + ) + where TContext : XDbContext + where TEntity : XBaseEntity + where TRepositoryService : IXBaseRepository + where TRepositoryImplementation : XBaseEFRepository + { + // + if (source.IsNull()) + { + // + source = new XRepositoryDescriptor(); + source = source.AddEntity(); + } + + // + source.RepositoryService = typeof(TRepositoryService); + source.RepositoryImplementation = typeof(TRepositoryImplementation); + + // + return source; + } + + public static XRepositoryDescriptor AddMongoRepository( + this XRepositoryDescriptor source + ) + where TEntity : XBaseEntity + where TRepositoryService : IXBaseRepository + where TRepositoryImplementation : XBaseMongoRepository + { + // + if (source.IsNull()) + { + // + source = new XRepositoryDescriptor(); + source = source.AddEntity(); + } + + // + source.RepositoryService = typeof(TRepositoryService); + source.RepositoryImplementation = typeof(TRepositoryImplementation); + + // + return source; + } + + public static XRepositoryDescriptor AddInMemoryRepository( + this XRepositoryDescriptor source + ) + where TEntity : XBaseEntity + where TRepositoryService : IXBaseRepository + where TRepositoryImplementation : XBaseInMemoryRepository + { + // + if (source.IsNull()) + { + // + source = new XRepositoryDescriptor(); + source = source.AddEntity(); + } + + // + source.RepositoryService = typeof(TRepositoryService); + source.RepositoryImplementation = typeof(TRepositoryImplementation); + + // + return source; + } + #endregion } } \ No newline at end of file diff --git a/Helpers/XDataServiceHelper.cs b/Helpers/XDataServiceHelper.cs index 1667f5c..58b4c39 100644 --- a/Helpers/XDataServiceHelper.cs +++ b/Helpers/XDataServiceHelper.cs @@ -1,5 +1,6 @@ using System; using GraphQL.Server; +using GraphQL.Server.Ui.Playground; using GraphQL.Types; using Microsoft.AspNetCore.Builder; using Microsoft.EntityFrameworkCore; @@ -448,7 +449,7 @@ namespace xDataService.Helpers where TKeyGeneratorImplementation : XKeyGenerator where TGraphTypeHelperService : IXBaseGraphQLTypeHelper where TGraphQuery : XBaseGraphQLQuery - where TRepositoryImplementation : XBaseInMemoryRepositoy + where TRepositoryImplementation : XBaseInMemoryRepository where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper { // @@ -513,6 +514,144 @@ namespace xDataService.Helpers } } + /// + /// Register Repository ... + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void AddXRepository< + TEntity, + TKey, + TKeyGeneratorService, + TKeyGeneratorImplementation, + TEventsService, + TEventsImplementation, + TGraph, + TGraphKey, + TGraphQuery, + TGraphTypeHelperService, + TGraphTypeHelperImplementation, + TGraphSchema, + TRepositoryService, + TRepositoryImplementation, + TSeederService, + TSeederImplementation + >( + IServiceCollection source, + XInMemoryRepositoryDescriptor repositoryDescriptor, + ServiceLifetime lifetime = ServiceLifetime.Scoped + ) + where TGraphSchema : Schema + where TGraphKey : IGraphType + where TEntity : XBaseEntity + where TSeederService : IXBaseDbSeeder + where TSeederImplementation : XBaseDbSeeder + where TGraph : XBaseGraphObjectType + where TEventsService : IXBaseRepositoryEvents + where TKeyGeneratorService : IXKeyGenerator + where TRepositoryService : IXBaseRepository + where TEventsImplementation : XBaseRepositoryEvents + where TKeyGeneratorImplementation : XKeyGenerator + where TGraphTypeHelperService : IXBaseGraphQLTypeHelper + where TGraphQuery : XBaseGraphQLQuery + where TRepositoryImplementation : XBaseInMemoryRepository + where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper + { + // + var isValid = repositoryDescriptor.IsValid(); + if (!isValid) + { + return; + } + + // + // Register KeyGenerator ... + isValid = repositoryDescriptor.HasKeyGenerator(); + if (isValid) + { + // + AddXKeyGenerator( + source, + repositoryDescriptor, + lifetime + ); + } + + // + // Register Events ... + isValid = repositoryDescriptor.HasEvents(); + if (isValid) + { + // + AddXEvents( + source, + repositoryDescriptor, + lifetime + ); + } + + // + // Register Graph ... + isValid = repositoryDescriptor.HasGraphSupport(); + if (isValid) + { + // + AddXGraphQL( + source, + repositoryDescriptor, + lifetime + ); + } + + // + // Register Repository ... + isValid = repositoryDescriptor.HasRepository(); + if (isValid) + { + // + source.Add( + new ServiceDescriptor( + repositoryDescriptor.RepositoryService, + repositoryDescriptor.RepositoryImplementation, + lifetime + ) + ); + } + + // + // DbSeeder ... + isValid = repositoryDescriptor.HasSeeder(); + if (isValid) + { + // + source.Add( + new ServiceDescriptor( + repositoryDescriptor.SeederService, + repositoryDescriptor.SeederImplementation, + lifetime + ) + ); + } + } + /// /// Register Repository ... /// @@ -630,6 +769,144 @@ namespace xDataService.Helpers } } + /// + /// Register Repository ... + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void AddXRepository< + TEntity, + TKey, + TKeyGeneratorService, + TKeyGeneratorImplementation, + TEventsService, + TEventsImplementation, + TGraph, + TGraphKey, + TGraphQuery, + TGraphTypeHelperService, + TGraphTypeHelperImplementation, + TGraphSchema, + TRepositoryService, + TRepositoryImplementation, + TSeederService, + TSeederImplementation + >( + IServiceCollection source, + XMongoRepositoryDescriptor repositoryDescriptor, + ServiceLifetime lifetime = ServiceLifetime.Scoped + ) + where TGraphSchema : Schema + where TGraphKey : IGraphType + where TEntity : XBaseEntity + where TGraph : XBaseGraphObjectType + where TSeederService : IXBaseDbSeeder + where TEventsService : IXBaseRepositoryEvents + where TKeyGeneratorService : IXKeyGenerator + where TRepositoryService : IXBaseRepository + where TSeederImplementation : XBaseDbSeeder + where TEventsImplementation : XBaseRepositoryEvents + where TKeyGeneratorImplementation : XKeyGenerator + where TRepositoryImplementation : XBaseMongoRepository + where TGraphTypeHelperService : IXBaseGraphQLTypeHelper + where TGraphQuery : XBaseGraphQLQuery + where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper + { + // + var isValid = repositoryDescriptor.IsValid(); + if (!isValid) + { + return; + } + + // + // Register KeyGenerator ... + isValid = repositoryDescriptor.HasKeyGenerator(); + if (isValid) + { + // + AddXKeyGenerator( + source, + repositoryDescriptor, + lifetime + ); + } + + // + // Register Events ... + isValid = repositoryDescriptor.HasEvents(); + if (isValid) + { + // + AddXEvents( + source, + repositoryDescriptor, + lifetime + ); + } + + // + // Register Graph ... + isValid = repositoryDescriptor.HasGraphSupport(); + if (isValid) + { + // + AddXGraphQL( + source, + repositoryDescriptor, + lifetime + ); + } + + // + // Register Repository ... + isValid = repositoryDescriptor.HasRepository(); + if (isValid) + { + // + source.Add( + new ServiceDescriptor( + repositoryDescriptor.RepositoryService, + repositoryDescriptor.RepositoryImplementation, + lifetime + ) + ); + } + + // + // DbSeeder ... + isValid = repositoryDescriptor.HasSeeder(); + if (isValid) + { + // + source.Add( + new ServiceDescriptor( + repositoryDescriptor.SeederService, + repositoryDescriptor.SeederImplementation, + lifetime + ) + ); + } + } + /// /// Register Repository ... /// @@ -750,6 +1027,147 @@ namespace xDataService.Helpers } } + /// + /// Register Repository ... + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void AddXRepository< + TEntity, + TKey, + TKeyGeneratorService, + TKeyGeneratorImplementation, + TEventsService, + TEventsImplementation, + TGraph, + TGraphKey, + TGraphQuery, + TGraphTypeHelperService, + TGraphTypeHelperImplementation, + TGraphSchema, + TRepositoryService, + TRepositoryImplementation, + TContext, + TSeederService, + TSeederImplementation + >( + IServiceCollection source, + XEFRepositoryDescriptor repositoryDescriptor, + ServiceLifetime lifetime = ServiceLifetime.Scoped + ) + where TGraphSchema : Schema + where TContext : XDbContext + where TGraphKey : IGraphType + where TEntity : XBaseEntity + where TGraph : XBaseGraphObjectType + where TSeederService : IXBaseDbSeeder + where TEventsService : IXBaseRepositoryEvents + where TSeederImplementation : XBaseDbSeeder + where TKeyGeneratorService : IXKeyGenerator + where TRepositoryService : IXBaseRepository + where TEventsImplementation : XBaseRepositoryEvents + where TKeyGeneratorImplementation : XKeyGenerator + where TGraphTypeHelperService : IXBaseGraphQLTypeHelper + where TGraphQuery : XBaseGraphQLQuery + where TRepositoryImplementation : XBaseEFRepository + where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper + { + // + var isValid = repositoryDescriptor.IsValid(); + if (!isValid) + { + return; + } + + // + // Register KeyGenerator ... + isValid = repositoryDescriptor.HasKeyGenerator(); + if (isValid) + { + // + AddXKeyGenerator( + source, + repositoryDescriptor, + lifetime + ); + } + + // + // Register Events ... + isValid = repositoryDescriptor.HasEvents(); + if (isValid) + { + // + AddXEvents( + source, + repositoryDescriptor, + lifetime + ); + } + + // + // Register Graph ... + isValid = repositoryDescriptor.HasGraphSupport(); + if (isValid) + { + // + AddXGraphQL( + source, + repositoryDescriptor, + lifetime + ); + } + + // + // Register Repository ... + isValid = repositoryDescriptor.HasRepository(); + if (isValid) + { + // + source.Add( + new ServiceDescriptor( + repositoryDescriptor.RepositoryService, + repositoryDescriptor.RepositoryImplementation, + lifetime + ) + ); + } + + // + // DbSeeder ... + isValid = repositoryDescriptor.HasSeeder(); + if (isValid) + { + // + source.Add( + new ServiceDescriptor( + repositoryDescriptor.SeederService, + repositoryDescriptor.SeederImplementation, + lifetime + ) + ); + } + } + /// /// Register Repository ... /// @@ -800,7 +1218,7 @@ namespace xDataService.Helpers where TEventsImplementation : XBaseRepositoryEvents where TKeyGeneratorImplementation : XKeyGenerator where TGraphTypeHelperService : IXBaseGraphQLTypeHelper - where TRepositoryImplementation : XBaseInMemoryRepositoy + where TRepositoryImplementation : XBaseInMemoryRepository where TGraphQuery : XBaseGraphQLQuery where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper { @@ -898,79 +1316,113 @@ namespace xDataService.Helpers } } - /// - /// Register Repository ... - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public static void UseXRepository< + // /// + // /// Register Repository ... + // /// + // /// + // /// + // /// + // /// + // /// + // /// + // /// + // /// + // /// + // /// + // /// + // /// + // /// + // /// + // /// + // /// + // /// + // /// + // public static void UseXRepository< + // TEntity, + // TKey, + // TKeyGeneratorService, + // TKeyGeneratorImplementation, + // TEventsService, + // TEventsImplementation, + // TGraph, + // TGraphKey, + // TGraphQuery, + // TGraphTypeHelperService, + // TGraphTypeHelperImplementation, + // TGraphSchema, + // TRepositoryService, + // TRepositoryImplementation, + // TContext + // >( + // IApplicationBuilder source, + // XEFRepositoryDescriptor repositoryDescriptor + // ) + // where TGraphSchema : Schema + // where TContext : XDbContext + // where TGraphKey : IGraphType + // where TEntity : XBaseEntity + // where TGraph : XBaseGraphObjectType + // where TEventsService : IXBaseRepositoryEvents + // where TKeyGeneratorService : IXKeyGenerator + // where TRepositoryService : IXBaseRepository + // where TEventsImplementation : XBaseRepositoryEvents + // where TKeyGeneratorImplementation : XKeyGenerator + // where TGraphTypeHelperService : IXBaseGraphQLTypeHelper + // where TGraphQuery : XBaseGraphQLQuery + // where TRepositoryImplementation : XBaseEFRepository + // where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper + // { + // // + // var isValid = repositoryDescriptor.IsValid(); + // if (!isValid) + // { + // return; + // } + + // // + // // GraphQL ... + // isValid = repositoryDescriptor.HasGraphSupport(); + // if (isValid) + // { + // // + // UseXGraphQL( + // source, + // repositoryDescriptor + // ); + // } + // } + + public static void UseXGraphQL< TEntity, TKey, - TKeyGeneratorService, - TKeyGeneratorImplementation, - TEventsService, - TEventsImplementation, TGraph, TGraphKey, TGraphQuery, TGraphTypeHelperService, TGraphTypeHelperImplementation, - TGraphSchema, - TRepositoryService, - TRepositoryImplementation, - TContext + TGraphSchema >( IApplicationBuilder source, - XEFRepositoryDescriptor repositoryDescriptor + string graphPath, + bool withPlayGround = false, + GraphQLPlaygroundOptions options = null ) where TGraphSchema : Schema - where TContext : XDbContext where TGraphKey : IGraphType where TEntity : XBaseEntity where TGraph : XBaseGraphObjectType - where TEventsService : IXBaseRepositoryEvents - where TKeyGeneratorService : IXKeyGenerator - where TRepositoryService : IXBaseRepository - where TEventsImplementation : XBaseRepositoryEvents - where TKeyGeneratorImplementation : XKeyGenerator where TGraphTypeHelperService : IXBaseGraphQLTypeHelper where TGraphQuery : XBaseGraphQLQuery - where TRepositoryImplementation : XBaseEFRepository where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper { // - var isValid = repositoryDescriptor.IsValid(); - if (!isValid) - { - return; - } + source.UseGraphQL(graphPath); + source.UseGraphQLWebSockets(); // - // GraphQL ... - isValid = repositoryDescriptor.HasGraphSupport(); - if (isValid) + if (withPlayGround) { - // - UseXGraphQL( - source, - repositoryDescriptor - ); + source.UseGraphQLPlayground(options); } } #endregion diff --git a/InMemRepositories/XBaseInMemoryRepositoy.cs b/InMemRepositories/XBaseInMemoryRepository.cs similarity index 99% rename from InMemRepositories/XBaseInMemoryRepositoy.cs rename to InMemRepositories/XBaseInMemoryRepository.cs index c74d0da..fec2bcf 100644 --- a/InMemRepositories/XBaseInMemoryRepositoy.cs +++ b/InMemRepositories/XBaseInMemoryRepository.cs @@ -23,7 +23,7 @@ namespace xDataService.InMemRepositories /// /// /// - public abstract class XBaseInMemoryRepositoy : IXBaseRepository + public abstract class XBaseInMemoryRepository : IXBaseRepository where TEntity : XBaseEntity { // @@ -36,7 +36,7 @@ namespace xDataService.InMemRepositories // #region Constructor ... - public XBaseInMemoryRepositoy( + public XBaseInMemoryRepository( XDataServiceConfiguration configuration, IXKeyGenerator keyGenerator = null, IXBaseRepositoryEvents baseRepositoryEvents = null diff --git a/Interfaces/IXDbSeeder.cs b/Interfaces/IXBaseDbSeeder.cs similarity index 58% rename from Interfaces/IXDbSeeder.cs rename to Interfaces/IXBaseDbSeeder.cs index b0a2807..30742e3 100644 --- a/Interfaces/IXDbSeeder.cs +++ b/Interfaces/IXBaseDbSeeder.cs @@ -1,19 +1,25 @@ using System.Threading.Tasks; using xDataService.Configuration; +using xModels.Base; -namespace xDataService.Interfaces { +namespace xDataService.Interfaces +{ /// /// Db Seeder used to seed data on Database on startup time ... /// - public interface IXDbSeeder { - IXDbSeederConfig Config { get; } + public interface IXBaseDbSeeder + where TEntity : XBaseEntity + { + string Database { get; } + + IXBaseRepository Repository { get; } + XDataServiceConfiguration DataServiceConfiguration { get; } /// /// do all seeding action by helping of Repositories here ... - /// don't forget to check UpdateExists value on IXDbSeederConfig for prevent system of duplicate Entity adding on startups ... /// /// - Task Seed (); + Task Seed(); } } \ No newline at end of file diff --git a/Interfaces/IXDataServiceHelper.cs b/Interfaces/IXDataServiceHelper.cs deleted file mode 100644 index 7723d47..0000000 --- a/Interfaces/IXDataServiceHelper.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using MongoDB.Bson.Serialization.Conventions; -using xDataService.Constants; - -namespace xDataService.Interfaces { - public interface IXDataServiceHelper { - /// - /// register DbContext implementation on DI Container ... - /// Only Used in EFCore ... - /// - /// - /// - /// - /// - /// - void AddDbContext ( - IServiceCollection services, - string connectionString, - XDbProviders dbProvider, - ServiceLifetime lifetime, - Action optionsBuilder = null - ); - - /// - /// register all Entities Repositories and Events on DI Container ... - /// implementations of IXBaseRepository and IXBaseRepositoryEvent ... - /// - /// - /// - void AddRepositories ( - IServiceCollection services, - ServiceLifetime lifetime - ); - - /// - /// Regitster KeyGenerators for Repositories ... - /// - /// - void AddKeyGenerators (IServiceCollection services); - - /// - /// register DBSeeder Configuration on DI Container ... - /// - /// - /// - void AddDbSeederConfiguration ( - IServiceCollection services, - IConfiguration configuration - ); - - /// - /// register Data Seeder on DI Container ... - /// implementation of IXDbSeeder ... - /// - /// - /// - /// - /// - void AddDbSeeder ( - IServiceCollection services, - IConfiguration config, - ServiceLifetime lifetime - ) where TDbSeeder : IXDbSeeder; - - /// - /// Set Mongo Convention Pack ... - /// - /// - ConventionPack MongoConventionPacks (); - - /// - /// Configure all required MongoDb Class Mappers and etc here ... - /// - void RegisterMongoExtras (); - } -} \ No newline at end of file diff --git a/Interfaces/IXDbSeederConfig.cs b/Interfaces/IXDbSeederConfig.cs deleted file mode 100644 index 92d41ab..0000000 --- a/Interfaces/IXDbSeederConfig.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace xDataService.Interfaces { - /// - /// this Configuration used to Carry all Entity Descriptors collections - /// can readable by appSettings.json file for providing dynamic data seeding ... - /// - public interface IXDbSeederConfig { - /// - /// determines an Entity can Update when Exists or not ... - /// this must handled by consumer on IXDbSeeder Seed method implementation ... - /// - /// - bool UpdateExists { get; set; } - } -} \ No newline at end of file diff --git a/Interfaces/IXGraphQLHelper.cs b/Interfaces/IXGraphQLHelper.cs deleted file mode 100644 index 0c96bdb..0000000 --- a/Interfaces/IXGraphQLHelper.cs +++ /dev/null @@ -1,75 +0,0 @@ -using GraphQL.Server; -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.DependencyInjection; - -namespace xDataService.Interfaces { - /// - /// this is a helper class which provides all requirements to providing GraphQL - /// based data manipulating mechanism ... - /// - public interface IXGraphQLHelper { - /// - /// Register all GraphQL Enum Types ... - /// Enum Types use to Map string values to Enum values in propper way and vise versa in GraphQL ... - /// must extended from EnumerationGraphType ... - /// - void AddXGraphEnumTypes (IServiceCollection services); - - /// - /// Register all GraphQL Object Types ... - /// GraphQL works based on Types, so for representing each data you have to define a Type ... - /// must extended from ObjectGraphType or XBaseGraphObjectType - /// - void AddXGraphObjectTypes (IServiceCollection services); - - /// - /// Register all GraphQL Input Types ... - /// InputTypes represent recieving data structure in GraphQL for doing mutations ... - /// must extended from InputObjectGraphType ... - /// - void AddXGraphInputTypes (IServiceCollection services); - - /// - /// Register all GraphQL Queries ... - /// Queries in GraphQL used to provide data fetch and retrieve mechanism ... - /// extended from ObjectGraphType ... - /// - void AddXGraphQueries (IServiceCollection services); - - /// - /// Register all GraphQL Mutations ... - /// Mutations is an Action types in GraphQL which data changed through them, like as Add, Update, Delete ... - /// must extends from ObjectGraphType ... - /// - void AddXGraphMutations (IServiceCollection services); - - /// - /// Register all GraphQL Subscriptions ... - /// Subscriptions are listeners to specific events on data in GraphQL ... - /// must extended from ObjectGraphType and implements IXBaseRepositoryEvents ... - /// - void AddXGraphSubscriptions (IServiceCollection services); - - /// - /// Register all GraphQL Schemas ... - /// each available Entity in Database must described to GraphQL with all Graph based stuffs such as : - /// Queries, Types and etc, this must done through an Schema class. - /// must extended from Schema ... - /// - void AddXGraphSchemas (IServiceCollection services); - - /// - /// Add Schemas to GraphQL Builder ... - /// here you must add all registered Schemas to GraphQLBuilder ... - /// - /// - /// - IGraphQLBuilder AddXGraphTypes (IGraphQLBuilder builder); - - /// - /// Use all Registered Schemas by GraphQL and and GraphQLWebSockets ... - /// - /// - void UseXGraph (IApplicationBuilder app); - } -} \ No newline at end of file diff --git a/Models/XRepositoryDescriptor.cs b/Models/XRepositoryDescriptor.cs index 48ed6e3..c7bb2f2 100644 --- a/Models/XRepositoryDescriptor.cs +++ b/Models/XRepositoryDescriptor.cs @@ -99,13 +99,23 @@ namespace xDataService.Models /// Repository Data Access Design Pattern ... /// /// - public Type RepositoryService { get; set; } + public Type RepositoryService { get; set; } = null; /// /// Repository Data Access Design Pattern ... /// /// - public Type RepositoryImplementation { get; set; } + public Type RepositoryImplementation { get; set; } = null; + + /// + /// Database Data Seeder ... + /// + public Type SeederService { get; set; } = null; + + /// + /// Database Data Seeder ... + /// + public Type SeederImplementation { get; set; } = null; } /// @@ -128,9 +138,9 @@ namespace xDataService.Models /// a Repository Descriptor ... /// public class XRepositoryDescriptor< - TEntity, - TKey, - TKeyGeneratorService, + TEntity, + TKey, + TKeyGeneratorService, TKeyGeneratorImplementation > : XRepositoryDescriptor where TEntity : XBaseEntity @@ -149,16 +159,16 @@ namespace xDataService.Models /// a Repository Descriptor ... /// public class XRepositoryDescriptor< - TEntity, - TKey, - TKeyGeneratorService, - TKeyGeneratorImplementation, - TEventsService, + TEntity, + TKey, + TKeyGeneratorService, + TKeyGeneratorImplementation, + TEventsService, TEventsImplementation > : XRepositoryDescriptor< - TEntity, - TKey, - TKeyGeneratorService, + TEntity, + TKey, + TKeyGeneratorService, TKeyGeneratorImplementation > where TEntity : XBaseEntity @@ -179,24 +189,24 @@ namespace xDataService.Models /// a Repository Descriptor ... /// public class XRepositoryDescriptor< - TEntity, - TKey, - TKeyGeneratorService, - TKeyGeneratorImplementation, - TEventsService, - TEventsImplementation, - TGraph, - TGraphKey, - TGraphQuery, - TGraphTypeHelperService, - TGraphTypeHelperImplementation, + TEntity, + TKey, + TKeyGeneratorService, + TKeyGeneratorImplementation, + TEventsService, + TEventsImplementation, + TGraph, + TGraphKey, + TGraphQuery, + TGraphTypeHelperService, + TGraphTypeHelperImplementation, TGraphSchema > : XRepositoryDescriptor< - TEntity, - TKey, - TKeyGeneratorService, - TKeyGeneratorImplementation, - TEventsService, + TEntity, + TKey, + TKeyGeneratorService, + TKeyGeneratorImplementation, + TEventsService, TEventsImplementation > where TGraphSchema : Schema @@ -227,32 +237,32 @@ namespace xDataService.Models /// a Repository Descriptor ... /// public class XInMemoryRepositoryDescriptor< - TEntity, - TKey, - TKeyGeneratorService, - TKeyGeneratorImplementation, - TEventsService, - TEventsImplementation, - TGraph, - TGraphKey, - TGraphQuery, - TGraphTypeHelperService, - TGraphTypeHelperImplementation, - TGraphSchema, - TRepositoryService, + TEntity, + TKey, + TKeyGeneratorService, + TKeyGeneratorImplementation, + TEventsService, + TEventsImplementation, + TGraph, + TGraphKey, + TGraphQuery, + TGraphTypeHelperService, + TGraphTypeHelperImplementation, + TGraphSchema, + TRepositoryService, TRepositoryImplementation > : XRepositoryDescriptor< - TEntity, - TKey, - TKeyGeneratorService, - TKeyGeneratorImplementation, - TEventsService, - TEventsImplementation, - TGraph, - TGraphKey, - TGraphQuery, - TGraphTypeHelperService, - TGraphTypeHelperImplementation, + TEntity, + TKey, + TKeyGeneratorService, + TKeyGeneratorImplementation, + TEventsService, + TEventsImplementation, + TGraph, + TGraphKey, + TGraphQuery, + TGraphTypeHelperService, + TGraphTypeHelperImplementation, TGraphSchema > where TGraphSchema : Schema @@ -265,7 +275,7 @@ namespace xDataService.Models where TEventsImplementation : XBaseRepositoryEvents where TKeyGeneratorImplementation : XKeyGenerator where TGraphTypeHelperService : IXBaseGraphQLTypeHelper - where TRepositoryImplementation : XBaseInMemoryRepositoy + where TRepositoryImplementation : XBaseInMemoryRepository where TGraphQuery : XBaseGraphQLQuery where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper { @@ -277,36 +287,98 @@ namespace xDataService.Models } } + /// + /// a Repository Descriptor ... + /// + public class XInMemoryRepositoryDescriptor< + TEntity, + TKey, + TKeyGeneratorService, + TKeyGeneratorImplementation, + TEventsService, + TEventsImplementation, + TGraph, + TGraphKey, + TGraphQuery, + TGraphTypeHelperService, + TGraphTypeHelperImplementation, + TGraphSchema, + TRepositoryService, + TRepositoryImplementation, + TSeederService, + TSeederImplementation + > : XRepositoryDescriptor< + TEntity, + TKey, + TKeyGeneratorService, + TKeyGeneratorImplementation, + TEventsService, + TEventsImplementation, + TGraph, + TGraphKey, + TGraphQuery, + TGraphTypeHelperService, + TGraphTypeHelperImplementation, + TGraphSchema + > + where TGraphSchema : Schema + where TGraphKey : IGraphType + where TEntity : XBaseEntity + where TGraph : XBaseGraphObjectType + where TSeederService : IXBaseDbSeeder + where TEventsService : IXBaseRepositoryEvents + where TKeyGeneratorService : IXKeyGenerator + where TRepositoryService : IXBaseRepository + where TSeederImplementation : XBaseDbSeeder + where TEventsImplementation : XBaseRepositoryEvents + where TKeyGeneratorImplementation : XKeyGenerator + where TGraphTypeHelperService : IXBaseGraphQLTypeHelper + where TRepositoryImplementation : XBaseInMemoryRepository + where TGraphQuery : XBaseGraphQLQuery + where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper + { + public XInMemoryRepositoryDescriptor() : base() + { + // + SeederService = typeof(TSeederService); + SeederImplementation = typeof(TSeederImplementation); + + // + RepositoryService = typeof(TRepositoryService); + RepositoryImplementation = typeof(TRepositoryImplementation); + } + } + /// /// a Repository Descriptor ... /// public class XMongoRepositoryDescriptor< - TEntity, - TKey, - TKeyGeneratorService, - TKeyGeneratorImplementation, - TEventsService, - TEventsImplementation, - TGraph, - TGraphKey, - TGraphQuery, - TGraphTypeHelperService, - TGraphTypeHelperImplementation, - TGraphSchema, - TRepositoryService, + TEntity, + TKey, + TKeyGeneratorService, + TKeyGeneratorImplementation, + TEventsService, + TEventsImplementation, + TGraph, + TGraphKey, + TGraphQuery, + TGraphTypeHelperService, + TGraphTypeHelperImplementation, + TGraphSchema, + TRepositoryService, TRepositoryImplementation > : XRepositoryDescriptor< - TEntity, - TKey, - TKeyGeneratorService, - TKeyGeneratorImplementation, - TEventsService, - TEventsImplementation, - TGraph, - TGraphKey, - TGraphQuery, - TGraphTypeHelperService, - TGraphTypeHelperImplementation, + TEntity, + TKey, + TKeyGeneratorService, + TKeyGeneratorImplementation, + TEventsService, + TEventsImplementation, + TGraph, + TGraphKey, + TGraphQuery, + TGraphTypeHelperService, + TGraphTypeHelperImplementation, TGraphSchema > where TGraphSchema : Schema @@ -331,6 +403,68 @@ namespace xDataService.Models } } + /// + /// a Repository Descriptor ... + /// + public class XMongoRepositoryDescriptor< + TEntity, + TKey, + TKeyGeneratorService, + TKeyGeneratorImplementation, + TEventsService, + TEventsImplementation, + TGraph, + TGraphKey, + TGraphQuery, + TGraphTypeHelperService, + TGraphTypeHelperImplementation, + TGraphSchema, + TRepositoryService, + TRepositoryImplementation, + TSeederService, + TSeederImplementation + > : XRepositoryDescriptor< + TEntity, + TKey, + TKeyGeneratorService, + TKeyGeneratorImplementation, + TEventsService, + TEventsImplementation, + TGraph, + TGraphKey, + TGraphQuery, + TGraphTypeHelperService, + TGraphTypeHelperImplementation, + TGraphSchema + > + where TGraphSchema : Schema + where TGraphKey : IGraphType + where TEntity : XBaseEntity + where TGraph : XBaseGraphObjectType + where TSeederService : IXBaseDbSeeder + where TEventsService : IXBaseRepositoryEvents + where TSeederImplementation : XBaseDbSeeder + where TKeyGeneratorService : IXKeyGenerator + where TRepositoryService : IXBaseRepository + where TEventsImplementation : XBaseRepositoryEvents + where TKeyGeneratorImplementation : XKeyGenerator + where TRepositoryImplementation : XBaseMongoRepository + where TGraphTypeHelperService : IXBaseGraphQLTypeHelper + where TGraphQuery : XBaseGraphQLQuery + where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper + { + public XMongoRepositoryDescriptor() : base() + { + // + SeederService = typeof(TSeederService); + SeederImplementation = typeof(TSeederImplementation); + + // + RepositoryService = typeof(TRepositoryService); + RepositoryImplementation = typeof(TRepositoryImplementation); + } + } + /// /// a Repository Descriptor ... /// @@ -356,12 +490,12 @@ namespace xDataService.Models TKeyGeneratorService, TKeyGeneratorImplementation, TEventsService, - TEventsImplementation, - TGraph, - TGraphKey, - TGraphQuery, - TGraphTypeHelperService, - TGraphTypeHelperImplementation, + TEventsImplementation, + TGraph, + TGraphKey, + TGraphQuery, + TGraphTypeHelperService, + TGraphTypeHelperImplementation, TGraphSchema > where TGraphSchema : Schema @@ -387,4 +521,69 @@ namespace xDataService.Models RepositoryImplementation = typeof(TRepositoryImplementation); } } + + /// + /// a Repository Descriptor ... + /// + public class XEFRepositoryDescriptor< + TEntity, + TKey, + TKeyGeneratorService, + TKeyGeneratorImplementation, + TEventsService, + TEventsImplementation, + TGraph, + TGraphKey, + TGraphQuery, + TGraphTypeHelperService, + TGraphTypeHelperImplementation, + TGraphSchema, + TRepositoryService, + TRepositoryImplementation, + TContext, + TSeederService, + TSeederImplementation + > : XRepositoryDescriptor< + TEntity, + TKey, + TKeyGeneratorService, + TKeyGeneratorImplementation, + TEventsService, + TEventsImplementation, + TGraph, + TGraphKey, + TGraphQuery, + TGraphTypeHelperService, + TGraphTypeHelperImplementation, + TGraphSchema + > + where TGraphSchema : Schema + where TContext : XDbContext + where TGraphKey : IGraphType + where TEntity : XBaseEntity + where TGraph : XBaseGraphObjectType + where TSeederService : IXBaseDbSeeder + where TEventsService : IXBaseRepositoryEvents + where TSeederImplementation : XBaseDbSeeder + where TKeyGeneratorService : IXKeyGenerator + where TRepositoryService : IXBaseRepository + where TEventsImplementation : XBaseRepositoryEvents + where TKeyGeneratorImplementation : XKeyGenerator + where TGraphTypeHelperService : IXBaseGraphQLTypeHelper + where TGraphQuery : XBaseGraphQLQuery + where TRepositoryImplementation : XBaseEFRepository + where TGraphTypeHelperImplementation : XBaseGraphQLTypeHelper + { + public XEFRepositoryDescriptor() : base() + { + // + SeederService = typeof(TSeederService); + SeederImplementation = typeof(TSeederImplementation); + + // + Context = typeof(TContext); + RepositoryService = typeof(TRepositoryService); + RepositoryImplementation = typeof(TRepositoryImplementation); + } + } } \ No newline at end of file diff --git a/Providers/XBaseDbSeeder.cs b/Providers/XBaseDbSeeder.cs new file mode 100644 index 0000000..a25c4d9 --- /dev/null +++ b/Providers/XBaseDbSeeder.cs @@ -0,0 +1,129 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using xCommons.Extensions; +using xDataService.Configuration; +using xDataService.Constants; +using xDataService.Interfaces; +using xModels.Base; + +namespace xDataService.Providers +{ + public abstract class XBaseDbSeeder : IXBaseDbSeeder + where TEntity : XBaseEntity + { + public string Database { get; } + + public IXBaseRepository Repository { get; } + + public XDataServiceConfiguration DataServiceConfiguration { get; } + + public XBaseDbSeeder( + string database, + IXBaseRepository repository, + XDataServiceConfiguration dataServiceConfiguration + ) + { + // + this.Database = database; + this.Repository = repository; + this.DataServiceConfiguration = dataServiceConfiguration; + } + + public async Task Seed() + { + // + var entityName = nameof(TEntity); + + // + // Validate Seed ... + var isValid = + DataServiceConfiguration.SeedingMode != XDbSeedingMode.None && + DataServiceConfiguration + .Databases + .Any(db => + db.Key == Database && + db.Value.SeedItems + .Any(si => + si.Key == entityName && + si.Value.HasChild())); + if (!isValid) + { + return; + } + + // + // Extract Seeding Items ... + var seedItems = DataServiceConfiguration + .Databases[Database] + .SeedItems[entityName] + .ToList(); + foreach (var item in seedItems) + { + // + try + { + // + // Try to convert Item to Entity ... + var entity = ((object)item).FromDynamicObject(); + + // + // Check Item Exists or not ... + var isExist = false; + TEntity exists = null; + var asyncEnumerable = this.Repository.GetAllAsAsyncEnumerable(); + await foreach (var e in asyncEnumerable) + { + // + isExist = e.IsSameContent( + dest: entity, + propertyBlackList: new List + { + nameof(entity.Id), + nameof(entity.Deleted) + }); + if (isExist) + { + exists = e; + break; + } + } + + // + // Seed Based on Seed Mode ... + var seedMode = DataServiceConfiguration.SeedingMode; + switch (seedMode) + { + // + case XDbSeedingMode.AddIfNotExists: + // + if (!isExist) + { + // + exists = await Repository.AddAsync(entity); + } + break; + + // + case XDbSeedingMode.AddOrUpdate: + // + exists = exists.UpdateData( + updateWith: entity, + propertyBlackList: new List + { + nameof(entity.Id), + nameof(entity.Deleted) + } + ); + + // + await Repository.AddOrUpdateAsync(exists); + break; + } + } + catch + { } + } + } + } +} \ No newline at end of file