Initial Commit ...

This commit is contained in:
2024-01-25 04:41:17 +03:30
commit ff4d0d5dcb
51 changed files with 5949 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
#
# DotNet ...
bin
obj
#
# Natural Docs ...
Documentation/*
@@ -0,0 +1,82 @@
using xDataService.Constants;
namespace xDataService.Configuration {
/// <summary>
/// Represent Configurations of DataService Module ...
/// </summary>
public partial class XDataServiceConfiguration {
/// <summary>
/// Provider Type ...
/// </summary>
/// <value></value>
public XDbProviders Provider { get; set; }
/// <summary>
/// Enable Soft Delete Entities or Not ...
/// </summary>
/// <value></value>
public bool EnableSoftDelete { get; set; }
/// <summary>
/// Connection String which provide Requires Data to Connect to Db Provider ...
/// </summary>
/// <value></value>
public string ConnectionString { get; set; }
/// <summary>
/// Enable Tracking of Entities ...
/// Only Used on EFCore ...
/// </summary>
/// <value></value>
public bool EnableTracking { get; set; } = false;
/// <summary>
/// Enable Logging Details of Errors ...
/// Only Used on EFCore ...
/// </summary>
/// <value></value>
public bool EnableDetailedErrors { get; set; } = false;
/// <summary>
/// Enable Logging Sensitive Data ...
/// Only Used on EFCore ...
/// </summary>
/// <value></value>
public bool EnableSensitiveDataLogging { get; set; } = false;
/// <summary>
/// this is a way to provide Default Pagination Data on XQuery based requests ...
/// </summary>
/// <returns></returns>
public PagingConfiguration PagingConfiguration { get; set; } = new PagingConfiguration ();
/// <summary>
/// the base path for providing GraphQL ...
/// </summary>
/// <value></value>
public string GraphQLBasePath { get; set; } = "/graphql";
}
/// <summary>
/// this is a way to provide Default Pagination Data on XQuery based requests ...
/// </summary>
public partial class PagingConfiguration {
/// <summary>
/// Default Page Size ...
/// </summary>
/// <value></value>
public int DefaultPageSize { get; set; } = XDataServiceConstants.DEFAULT_PAGE_SIZE;
/// <summary>
/// restrict Maximum Page Size ...
/// </summary>
/// <value></value>
public int MaxAvailablePageSize { get; set; } = XDataServiceConstants.MAX_AVAILABLE_PAGE_SIZE;
/// <summary>
/// restrice Minimum Page Size ...
/// </summary>
/// <value></value>
public int MinAvailablePageSize { get; set; } = XDataServiceConstants.MIN_AVAILABLE_PAGE_SIZE;
}
}
@@ -0,0 +1,8 @@
namespace xDataService.Configuration {
public partial class XDbProviderConfigurations {
/// <summary>
/// Default ConnectionString Name ...
/// </summary>
public const string DEFAULT_CONNECTION_NAME = "DataConnection";
}
}
+7
View File
@@ -0,0 +1,7 @@
namespace xDataService.Constants {
public partial struct ConfigurationNodeNames {
public const string DB_PROVIDER_NODE = "XDBProvider";
public const string DATA_SERVICE_NODE = "DataServiceConfiguration";
public const string DATA_SERVICE_DB_SEED_NODE = "DbSeeder";
}
}
+10
View File
@@ -0,0 +1,10 @@
namespace xDataService.Constants {
/// <summary>
/// Default Pagination Values ...
/// </summary>
public partial struct XDataServiceConstants {
public static int DEFAULT_PAGE_SIZE = 50;
public static int MAX_AVAILABLE_PAGE_SIZE = 500;
public static int MIN_AVAILABLE_PAGE_SIZE = 20;
}
}
+23
View File
@@ -0,0 +1,23 @@
namespace xDataService.Constants {
/// <summary>
/// Represent Supported DBMS for Managing Data ...
/// </summary>
public enum XDbProviders {
None,
MySQL,
SQLite,
SQLServer,
MongoDB,
}
/// <summary>
/// Represent Supported DBMS for Managing Data ...
/// </summary>
public partial struct ProviderType {
public const string MySQL = "MYSQL";
public const string SQLite = "SQLITE";
public const string SQLServer = "SQLSERVER";
public const string MongoDB = "MONGODB";
}
}
+480
View File
@@ -0,0 +1,480 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using xCommons.Configurations;
using xCommons.Controllers;
using xCommons.Extensions;
using xCommons.Providers;
using xModels.Interfaces;
using xExceptions.Constants;
using xModels.Base;
using xModels.Dtos;
using xDataService.Interfaces;
namespace xDataService.Controllers {
public abstract class XBaseEntityController<TEntity, TKey> : XBaseController, IXEntityControllerActions<TEntity, TKey>
where TEntity : XBaseEntity<TKey> {
public readonly IXBaseRepository<TEntity, TKey> repository;
protected XBaseEntityController (
ILogger logger,
XAppConfiguration appConfiguration,
XValidationProvider validationProvider,
IXBaseRepository<TEntity, TKey> repository
) : base (
logger,
appConfiguration,
validationProvider
) {
//
this.repository = repository;
}
//
#region Interface Implementations ...
//
#region Retrieve ...
[HttpGet ("{id}")]
public virtual async Task<ActionResult<TEntity>> Get (
[FromRoute] TKey id, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool containsDetail = false
) {
//
try {
//
// Validate Args ...
ValidationProvider.NotNull (id);
//
// Get Result ...
var result = await repository
.GetAsync (
id,
ignoreSoftDeleteds : ignoreSoftDeleteds,
containsDetail : containsDetail
);
//
return Ok (result
.ToDynamicObject ());
} catch (Exception ex) {
//
var result = GetExceptionActionResult (ex);
return result;
}
}
[HttpGet]
public virtual async Task<ActionResult<IEnumerable<TEntity>>> GetAll (
[FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool containsDetail = false
) {
//
try {
//
// Get Result ...
var result = await repository
.GetAllAsync (
ignoreSoftDeleteds: ignoreSoftDeleteds,
containsDetail: containsDetail
);
//
return Ok (result
.ToDynamicObject ());
} catch (Exception ex) {
//
var result = GetExceptionActionResult (ex);
return result;
}
}
[HttpGet ("FindOne/{query}")]
public virtual async Task<ActionResult<TEntity>> FindOne (
[FromRoute] string query, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool containsDetail = false
) {
//
try {
//
// Validate Args ...
ValidationProvider.NotEmpty (query);
//
// Get Result ...
var result = await repository
.FindOneAsync (t =>
t.PropValuesContains (query),
ignoreSoftDeleteds : ignoreSoftDeleteds,
containsDetail : containsDetail
);
//
return Ok (result
.ToDynamicObject ());
} catch (Exception ex) {
//
var result = GetExceptionActionResult (ex);
return result;
}
}
[HttpGet ("FindMany/{query}")]
public virtual async Task<ActionResult<IEnumerable<TEntity>>> FindMany (
[FromRoute] string query, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool containsDetail = false
) {
//
try {
//
// Validate Args ...
ValidationProvider.NotEmpty (query);
//
// Get Result ...
var result = await repository
.FindManyAsync (t =>
t.PropValuesContains (query),
ignoreSoftDeleteds : ignoreSoftDeleteds,
containsDetail : containsDetail
);
//
return Ok (result
.ToDynamicObject ());
} catch (Exception ex) {
//
var result = GetExceptionActionResult (ex);
return result;
}
}
[HttpGet ("Query")]
public virtual async Task<ActionResult<XQueryResult<TEntity>>> Query (
[FromQuery] XQuery query, [FromQuery] bool ignoreSoftDeleteds = true
) {
//
try {
//
// Validate Args ...
ValidationProvider.NotNull (query);
//
// Get Result ...
var result = await repository
.QueryAsync (
query,
ignoreSoftDeleteds : ignoreSoftDeleteds
);
//
return Ok (result
.ToDynamicObject ());
} catch (Exception ex) {
//
var result = GetExceptionActionResult (ex);
return result;
}
}
//
// TODO: Fix this ...
// [HttpGet ("RequestPage")]
// public virtual async Task<ActionResult<XPageResponse<TEntity>>> RequestPage (
// [FromQuery] XPageRequest request, [FromQuery] bool ignoreSoftDeleteds = true, [FromQuery] bool containsDetail = false
// ) {
// //
// try {
// //
// // Validate Args ...
// ValidationProvider.NotNull (request);
// //
// // Get Result ...
// var result = await repository
// .RequestPageAsync (
// request,
// ignoreSoftDeleteds : ignoreSoftDeleteds,
// containsDetail : containsDetail
// );
// //
// return Ok (result
// .ToDynamicObject ());
// } catch (Exception ex) {
// //
// var result = GetExceptionActionResult (ex);
// return result;
// }
// }
#endregion
//
#region Add ...
[HttpPost]
public virtual async Task<ActionResult<TEntity>> Add (
[FromBody] TEntity item
) {
//
try {
//
// Validate Args ...
if (!ModelState.IsValid) {
XException.InvalidArgs.Throw ();
}
ValidationProvider.NotNull (item);
//
// Get Result ...
var result = await repository
.AddAsync (
item,
saveChanges : true
);
//
return Ok (result
.ToDynamicObject ());
} catch (Exception ex) {
//
var result = GetExceptionActionResult (ex);
return result;
}
}
[HttpPost ("AddOrUpdate")]
public virtual async Task<ActionResult<TEntity>> AddOrUpdate (
[FromBody] TEntity item
) {
//
try {
//
// Validate Args ...
if (!ModelState.IsValid) {
XException.InvalidArgs.Throw ();
}
ValidationProvider.NotNull (item);
//
// Get Result ...
var result = await repository
.AddOrUpdateAsync (
item,
saveChanges : true
);
//
return Ok (result
.ToDynamicObject ());
} catch (Exception ex) {
//
var result = GetExceptionActionResult (ex);
return result;
}
}
[HttpPost ("AddMany")]
public virtual async Task<ActionResult> AddMany (
[FromBody] XBaseRangeRequest<TEntity> request
) {
//
try {
//
// Validate Args ...
if (!ModelState.IsValid) {
XException.InvalidArgs.Throw ();
}
await ValidationProvider
.GroupValidationBuilder ()
.AddNotNull (request)
.AddNotZeroChilds (request.Items)
.ValidateGroupAsync ();
//
// Get Result ...
await repository
.AddRangeAsync (
request.Items,
saveChanges : true
);
//
return Ok ();
} catch (Exception ex) {
//
var result = GetExceptionActionResult (ex);
return result;
}
}
#endregion
//
#region Update ...
[HttpPut ("{id}")]
public virtual async Task<ActionResult<TEntity>> Update (
[FromRoute] TKey id, [FromBody] TEntity item
) {
//
try {
//
// Validate Args ...
if (!ModelState.IsValid) {
XException.InvalidArgs.Throw ();
}
await ValidationProvider
.GroupValidationBuilder ()
.AddNotNull (id, item)
.ValidateGroupAsync ();
//
// Get Result ...
var result = await repository
.UpdateAsync (
id,
item,
saveChanges : true
);
//
return Ok (result
.ToDynamicObject ());
} catch (Exception ex) {
//
var result = GetExceptionActionResult (ex);
return result;
}
}
[HttpPost ("UpdateMany")]
public virtual async Task<ActionResult<bool>> UpdateMany (
[FromBody] XBaseRangeRequest<TEntity> request
) {
//
try {
//
// Validate Args ...
if (!ModelState.IsValid) {
XException.InvalidArgs.Throw ();
}
await ValidationProvider
.GroupValidationBuilder ()
.AddNotNull (request)
.AddNotZeroChilds (request.Items)
.ValidateGroupAsync ();
//
// Get Result ...
var result = await repository
.UpdateRangeAsync (
request.Items,
saveChanges : true
);
//
return Ok (result
.ToDynamicObject ());
} catch (Exception ex) {
//
var result = GetExceptionActionResult (ex);
return result;
}
}
#endregion
//
#region Exists ...
[HttpGet ("{id}/IsExists")]
public virtual async Task<ActionResult<bool>> IsExists (
[FromRoute] TKey id, [FromQuery] bool ignoreSoftDeleteds = true
) {
//
try {
//
// Validate Args ...
ValidationProvider.NotNull (id);
//
// Get Result ...
var result = await repository
.IsExistsAsync (
id,
ignoreSoftDeleteds : ignoreSoftDeleteds
);
//
return Ok (result
.ToDynamicObject ());
} catch (Exception ex) {
//
var result = GetExceptionActionResult (ex);
return result;
}
}
#endregion
//
#region Remove ...
[HttpDelete ("{id}")]
public virtual async Task<ActionResult<TEntity>> Remove (
[FromRoute] TKey id,
bool softDelete = true
) {
//
try {
//
// Validate Args ...
ValidationProvider.NotNull (id);
//
// Get Result ...
var result = await repository
.RemoveAsync (
id,
saveChanges : true,
softDelete : softDelete
);
//
return Ok (result
.ToDynamicObject ());
} catch (Exception ex) {
//
var result = GetExceptionActionResult (ex);
return result;
}
}
[HttpPost ("RemoveMany")]
public virtual async Task<ActionResult> RemoveMany (
[FromBody] XBaseRangeRequest<TEntity> request,
bool softDelete = true
) {
//
try {
//
// Validate Args ...
await ValidationProvider
.GroupValidationBuilder ()
.AddNotNull (request)
.AddNotZeroChilds (request.Items)
.ValidateGroupAsync ();
//
// Get Result ...
await repository
.RemoveRangeAsync (
request.Items,
saveChanges : true,
softDelete : softDelete
);
//
return Ok ();
} catch (Exception ex) {
//
var result = GetExceptionActionResult (ex);
return result;
}
}
#endregion
#endregion
}
}
+622
View File
@@ -0,0 +1,622 @@
using System;
using System.Collections.Generic;
using System.Linq;
using GraphQL.Server;
using GraphQL.Server.Ui.Playground;
using Microsoft.AspNetCore.Builder;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Conventions;
using MySql.EntityFrameworkCore.Extensions;
using xCommons.Extensions;
using xDataService.Configuration;
using xDataService.Constants;
using xDataService.Db;
using xDataService.Extensions;
using xDataService.Interfaces;
using xExceptions.Constants;
using xModels.Base;
namespace xDataService.DI {
public static class XDIHelperExtension {
/// <summary>
/// Extract Connection String From IConfiguration
/// </summary>
/// <param name="config"></param>
/// <param name="connectionName"></param>
/// <returns></returns>
public static string GetXConnectionString (
this IConfiguration config,
string connectionName = null
) {
//
if (connectionName.IsNullOrEmpty ()) {
connectionName = XDbProviderConfigurations.DEFAULT_CONNECTION_NAME;
}
//
return config.GetConnectionString (connectionName);
}
/// <summary>
/// Retrieve Data Provider Type from Configurations
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static XDbProviders GetXDbProviderType (this IConfiguration source) {
//
var provider = (source[$"{ConfigurationNodeNames.DB_PROVIDER_NODE}"])
.ToNormalString ();
//
return provider.ToDbProvider ();
}
/// <summary>
/// Retrive XDataService Configurations
/// </summary>
/// <param name="source"></param>
/// <param name="connectionName"></param>
/// <returns></returns>
public static XDataServiceConfiguration GetXDataServiceConfiguration (
this IConfiguration source,
string connectionName = null
) {
//
var xDataServiceConfigSection = source
.GetSection (ConfigurationNodeNames.DATA_SERVICE_NODE);
var result = xDataServiceConfigSection.Get<XDataServiceConfiguration> ();
//
result.Provider = source.GetXDbProviderType ();
result.ConnectionString = source.GetXConnectionString (connectionName);
//
return result;
}
/// <summary>
/// Register XDataService Configuration
/// </summary>
/// <param name="services"></param>
/// <param name="configuration"></param>
/// <param name="connectionName"></param>
public static void AddXDataServiceConfiguration (
this IServiceCollection services,
IConfiguration configuration,
string connectionName = null
) {
//
var dataServiceConfiguration = configuration
.GetXDataServiceConfiguration (connectionName);
if (dataServiceConfiguration.IsNull ()) {
dataServiceConfiguration = new XDataServiceConfiguration ();
}
//
services.AddSingleton<XDataServiceConfiguration> (dataServiceConfiguration);
}
/// <summary>
/// Register XDataService Configuration
/// </summary>
/// <param name="services"></param>
/// <param name="configuration"></param>
public static void AddXDataServiceConfiguration (
this IServiceCollection services,
XDataServiceConfiguration configuration
) {
//
if (configuration.IsNull ()) {
configuration = new XDataServiceConfiguration ();
}
//
services.AddSingleton<XDataServiceConfiguration> (configuration);
}
/// <summary>
/// Register XDataService on DI
/// Only Used when EFCore Provider configured to use ...
/// </summary>
/// <param name="services"></param>
/// <param name="config"></param>
/// <param name="lifetime"></param>
/// <param name="connectionName"></param>
/// <param name="optionsBuilder"></param>
public static void AddXDataService<TDbContext, TDbSeeder> (
this IServiceCollection services,
IConfiguration config,
ServiceLifetime lifetime,
string connectionName = null,
Action<dynamic> optionsBuilder = null
)
where TDbContext : XDbContext
where TDbSeeder : IXDbSeeder {
//
// Register DataService Configuration ...
if (services.GetRegisteredService<XDataServiceConfiguration> ().IsNull ()) {
Console.WriteLine ($"XDataService: there is no provided DataService Config, try to register default ...");
services.AddXDataServiceConfiguration (config, connectionName);
}
//
// prevent from going forward if there is no Provider configured ...
var providerType = config.GetXDbProviderType ();
Console.WriteLine ($"XDataService: registered db provider type is => {providerType} ...");
if (providerType == XDbProviders.None) {
return;
}
//
// Retrieve IXDataServiceHelper ...
var dataServiceHelper = services.GetRegisteredService<IXDataServiceHelper> ();
if (!dataServiceHelper.IsNull ()) {
//
// Use Db Context Helper ...
Console.WriteLine ($"XDataService: use provided IXDbContextHelper ...");
//
// Retrieve Connection String ...
var addContext = true;
var connectionString = config.GetXConnectionString (connectionName);
switch (providerType) {
//
case XDbProviders.MySQL:
addContext = true;
services.AddEntityFrameworkMySQL ();
break;
//
case XDbProviders.SQLite:
addContext = true;
services.AddEntityFrameworkSqlite ();
break;
//
case XDbProviders.SQLServer:
addContext = true;
services.AddEntityFrameworkSqlServer ();
break;
//
case XDbProviders.MongoDB:
addContext = false;
break;
}
//
// Register DbContext in DI ...
if (addContext) {
dataServiceHelper.AddDbContext (
services,
connectionString,
providerType,
lifetime,
optionsBuilder
);
//
// Register Unit Of Works ...
services.Add (new ServiceDescriptor (typeof (IXUnitOfWorks<TDbContext>), typeof (XUnitOfWorks<TDbContext>), lifetime));
}
//
// Comment this in related to Task no. 27 ...
// Register IXSequentialGuid for handle XBaseGuidEntities ...
// services.AddSingleton<IXSequentialGuid, XSequentialGuid> ();
//
// Register All Repository Patterns ...
AddRepositories<TDbContext, TDbSeeder> (services, config, lifetime, providerType);
} else {
Console.WriteLine ($"XDataService: there is no provided IXDbContextHelper, data service registration failed ...");
}
}
/// <summary>
/// Register XDataService on DI
/// Only Used when non EFCore Provider configured to use ...
/// </summary>
/// <param name="services"></param>
/// <param name="config"></param>
/// <param name="lifetime"></param>
/// <param name="connectionName"></param>
public static void AddXDataService<TDbSeeder> (
this IServiceCollection services,
IConfiguration config,
ServiceLifetime lifetime,
string connectionName = null
)
where TDbSeeder : IXDbSeeder {
//
// Register DataService Configuration ...
if (services.GetRegisteredService<XDataServiceConfiguration> ().IsNull ()) {
Console.WriteLine ($"XDataService: there is no provided DataService Config, try to register default ...");
services.AddXDataServiceConfiguration (config, connectionName);
}
//
// prevent from going forward if there is no Provider configured ...
var providerType = config.GetXDbProviderType ();
Console.WriteLine ($"XDataService: registered db provider type is => {providerType} ...");
if (providerType == XDbProviders.None) {
return;
}
//
// Retrieve IXDataServiceHelper ...
var dataServiceHelper = services.GetRegisteredService<IXDataServiceHelper> ();
if (!dataServiceHelper.IsNull ()) {
//
// Use Db Context Helper ...
Console.WriteLine ($"XDataService: use provided IXDataServiceHelper ...");
//
// Retrieve Connection String ...
var connectionString = config.GetXConnectionString (connectionName);
switch (providerType) {
//
case XDbProviders.MySQL:
case XDbProviders.SQLite:
case XDbProviders.SQLServer:
Console.WriteLine ($"XDataService: for EF Provider Types use AddXDataService<TDbContext, TDbSeeder> instead of AddXDataService<TDbSeeder> ...");
XException.InvalidConfiguration.Throw ();
break;
//
case XDbProviders.MongoDB:
//
#region XBaseEntity Mappers ...
//
// Map ID as BsonId here ...
BsonClassMap.RegisterClassMap<XBaseEntity<Guid>> (cm => {
//
cm.AutoMap ();
cm.MapIdMember (c => c.Id);
});
BsonClassMap.RegisterClassMap<XBaseEntity<int>> (cm => {
//
cm.AutoMap ();
cm.MapIdMember (c => c.Id);
});
BsonClassMap.RegisterClassMap<XBaseEntity<string>> (cm => {
//
cm.AutoMap ();
cm.MapIdMember (c => c.Id);
});
#endregion
//
var conventionPacks = dataServiceHelper.MongoConventionPacks ();
if (!conventionPacks.IsNull ()) {
ConventionRegistry.Register (
nameof (
dataServiceHelper.MongoConventionPacks
),
conventionPacks,
type => !type.FullName
.IsNullOrEmpty ()
);
}
//
dataServiceHelper.RegisterMongoExtras ();
break;
}
//
// Comment this in related to Task no. 27 ...
// Register IXSequentialGuid for handle XBaseGuidEntities ...
// services.AddSingleton<IXSequentialGuid, XSequentialGuid> ();
//
// Register All Repository Patterns ...
AddRepositories<TDbSeeder> (services, config, lifetime, providerType);
} else {
Console.WriteLine ($"XDataService: there is no provided IXDbContextHelper, data service registration failed ...");
}
}
/// <summary>
/// Register XGraphQL service ...
/// </summary>
/// <param name="services"></param>
/// <param name="options"></param>
public static void AddXGraphQL (
this IServiceCollection services,
Action<GraphQLOptions> options = null
) {
//
var xGraphQLHelper = services.GetRegisteredService<IXGraphQLHelper> ();
if (!xGraphQLHelper.IsNull ()) {
//
xGraphQLHelper.AddXGraphEnumTypes (services);
xGraphQLHelper.AddXGraphObjectTypes (services);
xGraphQLHelper.AddXGraphInputTypes (services);
xGraphQLHelper.AddXGraphQueries (services);
xGraphQLHelper.AddXGraphMutations (services);
xGraphQLHelper.AddXGraphSubscriptions (services);
xGraphQLHelper.AddXGraphSchemas (services);
//
// Add GraphQL Server ...
if (options.IsNull ()) {
//
options = x => { };
Console.WriteLine ($"XDataService: there is no provided GraphQLOption, use default ...");
}
//
var xGraphQlBuilder = services.AddGraphQL (options)
.AddNewtonsoftJson (deserializerSettings => { }, serializerSettings => { })
.AddWebSockets ()
.AddDataLoader ()
.AddGraphTypes ();
//
xGraphQLHelper.AddXGraphTypes (xGraphQlBuilder);
} else {
Console.WriteLine ($"XDataService: there is no provided IXGraphQLHelper, data service registration failed ...");
}
}
/// <summary>
/// Use XDataService MiddleWare
/// </summary>
/// <param name="app"></param>
public static void UseXDataService (
this IApplicationBuilder app
) {
app.SeedData ();
}
/// <summary>
/// Use XGraphQL Middleware ...
/// </summary>
/// <param name="app"></param>
/// <param name="options"></param>
/// <param name="withPlayground"></param>
public static void UseXGraphQL (
this IApplicationBuilder app,
GraphQLPlaygroundOptions options = null,
bool withPlayground = true
) {
//
// Use GraphQl WebSockets ...
app.UseWebSockets ();
//
// Registered Graph Types ...
using (var scope = app.ApplicationServices.CreateScope ()) {
//
var xGraphQLHelper = scope.ServiceProvider.GetService<IXGraphQLHelper> ();
if (!xGraphQLHelper.IsNull ()) {
xGraphQLHelper.UseXGraph (app);
} else {
Console.WriteLine ($"XDataService: there is no provided IXGraphQLHelper, data service GraphQL not using ...");
}
}
//
// Use GraphQL Playground UI ...
if (withPlayground) {
app.UseGraphQLPlayground (options);
}
}
//
#region Private ...
/// <summary>
/// Register Repositories on DI as Services
/// </summary>
/// <param name="services"></param>
/// <param name="config"></param>
/// <param name="lifetime"></param>
/// <param name="provider"></param>
private static void AddRepositories<TDbContext, TDbSeeder> (
IServiceCollection services,
IConfiguration config,
ServiceLifetime lifetime,
XDbProviders provider
)
where TDbContext : XDbContext
where TDbSeeder : IXDbSeeder {
//
// Add Repositories Based On Provider Here ...
switch (provider) {
case XDbProviders.MySQL:
case XDbProviders.SQLite:
case XDbProviders.SQLServer:
AddEFRepositories<TDbContext> (services, lifetime);
break;
case XDbProviders.MongoDB:
Console.WriteLine ($"XDataService: for Mongo Provider Types use AddXDataService<TDbSeeder> instead of AddXDataService<TDbContext, TDbSeeder> ...");
XException.InvalidConfiguration.Throw ();
break;
}
//
// Retrieve IXDataServiceHelper ...
var dataServiceHelper = services.GetRegisteredService<IXDataServiceHelper> ();
if (dataServiceHelper.IsNull ()) {
//
Console.WriteLine ($"XDataService: there is no provided IXDataServiceHelper, db seeder registration failed ...");
return;
}
//
// Add DbSeeder Configuration ...
dataServiceHelper.AddDbSeederConfiguration (services, config);
//
// Add Db Seeder ...
dataServiceHelper.AddDbSeeder<TDbSeeder> (services, config, lifetime);
}
/// <summary>
/// Register Repositories on DI as Services
/// </summary>
/// <param name="services"></param>
/// <param name="config"></param>
/// <param name="lifetime"></param>
/// <param name="provider"></param>
private static void AddRepositories<TDbSeeder> (
IServiceCollection services,
IConfiguration config,
ServiceLifetime lifetime,
XDbProviders provider
)
where TDbSeeder : IXDbSeeder {
//
// Add Repositories Based On Provider Here ...
switch (provider) {
//
case XDbProviders.MySQL:
case XDbProviders.SQLite:
case XDbProviders.SQLServer:
Console.WriteLine ($"XDataService: for EF Provider Types use AddXDataService<TDbContext, TDbSeeder> instead of AddXDataService<TDbSeeder> ...");
XException.InvalidConfiguration.Throw ();
break;
//
case XDbProviders.MongoDB:
AddMongoRepositories (services, lifetime);
break;
}
//
// Retrieve IXDataServiceHelper ...
var dataServiceHelper = services.GetRegisteredService<IXDataServiceHelper> ();
if (dataServiceHelper.IsNull ()) {
//
Console.WriteLine ($"XDataService: there is no provided IXDataServiceHelper, db seeder registration failed ...");
return;
}
//
// Add DbSeeder Configuration ...
dataServiceHelper.AddDbSeederConfiguration (services, config);
//
// Add Db Seeder ...
dataServiceHelper.AddDbSeeder<TDbSeeder> (services, config, lifetime);
}
/// <summary>
/// Add Entity Framework Repositories
/// </summary>
/// <param name="services"></param>
/// <param name="lifetime"></param>
private static void AddEFRepositories<TDbContext> (
this IServiceCollection services,
ServiceLifetime lifetime
)
where TDbContext : XDbContext {
//
var repoServices = new List<ServiceDescriptor> ();
//
var dataServiceConfig = services.GetRegisteredService<XDataServiceConfiguration> ();
if (!dataServiceConfig.IsNull ()) {
//
// Register Base Repositories if Required ...
}
//
// Adding Services to DI ...
if (repoServices.Count > 0) {
repoServices
.ToList ()
.ForEach (s => services.Add (s));
}
//
// Retrieve IXDataServiceHelper ...
var dataServiceHelper = services.GetRegisteredService<IXDataServiceHelper> ();
if (!dataServiceHelper.IsNull ()) {
//
// Register Repositories ...
dataServiceHelper.AddRepositories (services, lifetime);
//
// Register KeyGenerators ...
dataServiceHelper.AddKeyGenerators (services);
}
}
/// <summary>
/// Add MongoDb Repositories
/// </summary>
/// <param name="services"></param>
/// <param name="lifetime"></param>
private static void AddMongoRepositories (
this IServiceCollection services,
ServiceLifetime lifetime
) {
//
var repoServices = new List<ServiceDescriptor> ();
//
var dataServiceConfig = services.GetRegisteredService<XDataServiceConfiguration> ();
if (!dataServiceConfig.IsNull ()) {
//
// Register Base Repositories if Required ...
}
//
// Adding Services to DI ...
if (repoServices.Count > 0) {
repoServices
.ToList ()
.ForEach (s => services.Add (s));
}
//
// Retrieve IXDataServiceHelper ...
var dataServiceHelper = services.GetRegisteredService<IXDataServiceHelper> ();
if (!dataServiceHelper.IsNull ()) {
//
// Register Repositories ...
dataServiceHelper.AddRepositories (services, lifetime);
//
// Register KeyGenerators ...
dataServiceHelper.AddKeyGenerators (services);
}
}
/// <summary>
/// Do Seeding Initialization Data on DbContext
/// </summary>
/// <param name="app"></param>
private static void SeedData (
this IApplicationBuilder app
) {
//
using (var scope = app.ApplicationServices.CreateScope ()) {
//
var dbSeeder = scope.ServiceProvider.GetService<IXDbSeeder> ();
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
}
}
+78
View File
@@ -0,0 +1,78 @@
using Microsoft.EntityFrameworkCore;
using xDataService.Configuration;
namespace xDataService.Db {
/// <summary>
/// Provide an abstraction layout arround DBContext ...
/// Only Used on EFCore ...
/// </summary>
public abstract class XDbContext : DbContext {
private readonly XDataServiceConfiguration config;
//
#region Entities ...
//
// Register Default and Base Entities ...
#endregion
//
// Constructor ...
public XDbContext (
DbContextOptions options,
XDataServiceConfiguration config
) : base (options) {
//
try {
Database.EnsureCreated ();
Database.Migrate ();
} catch { }
this.config = config;
}
//
// Prepare Fluent API ...
protected override void OnModelCreating (ModelBuilder modelBuilder) {
//
OnXModelCreating (modelBuilder);
//
// Since this class inherit from Identity Db Context,
// we have to pass this to Building Identity Models ...
base.OnModelCreating (modelBuilder);
}
//
public abstract void OnXModelCreating (ModelBuilder modelBuilder);
//
// Prepare Configuring ...
protected override void OnConfiguring (DbContextOptionsBuilder optionsBuilder) {
//
if (config.EnableDetailedErrors) {
optionsBuilder.EnableDetailedErrors ();
}
//
if (config.EnableSensitiveDataLogging) {
optionsBuilder.EnableSensitiveDataLogging ();
}
//
if (config.EnableTracking) {
optionsBuilder.UseQueryTrackingBehavior (QueryTrackingBehavior.TrackAll);
} else {
optionsBuilder.UseQueryTrackingBehavior (QueryTrackingBehavior.NoTracking);
}
//
OnXConfiguring (optionsBuilder);
//
base.OnConfiguring (optionsBuilder);
}
//
public abstract void OnXConfiguring (DbContextOptionsBuilder optionsBuilder);
}
}
+44
View File
@@ -0,0 +1,44 @@
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using xDataService.Interfaces;
using xModels.Base;
namespace xDataService.Db {
/// <summary>
/// Provide Unit Of Works Design Pattern for Db Transactions ...
/// Only Used on EFCore ...
/// </summary>
/// <typeparam name="TDbContext"></typeparam>
public class XUnitOfWorks<TDbContext> : IXUnitOfWorks<TDbContext>
where TDbContext : XDbContext {
public TDbContext DbContext { get; }
public XUnitOfWorks (TDbContext context) {
this.DbContext = context;
}
public DbSet<T> GetDbSet<T, TKey> ()
where T : XBaseEntity<TKey> {
return DbContext.Set<T> ();
}
/// <summary>
/// Save Changes
/// </summary>
public int SaveChanges () {
return DbContext.SaveChanges ();
}
/// <summary>
/// Save Changes Async
/// </summary>
/// <returns></returns>
public async Task<int> SaveChangesAsync () {
return await DbContext.SaveChangesAsync ();
}
public void Dispose () {
DbContext.Dispose ();
}
}
}
File diff suppressed because it is too large Load Diff
+63
View File
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using xDataService.Interfaces;
using xDataService.Models;
namespace xDataService.Events {
/// <summary>
/// Some Events can be Raised on Some Actions Happens on Repositories ...
/// this is the Base Events Class ...
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class XBaseRepositoryEvents<T> : IXBaseRepositoryEvents<T> {
//
private readonly ISubject<XBaseEventModel<T>> onAddSubject;
private readonly ISubject<XBaseEventModel<T>> onUpdateSubject;
private readonly ISubject<XBaseEventModel<T>> onRemoveSubject;
//
private readonly ISubject<XBaseEventModel<IEnumerable<T>>> onAddManySubject;
private readonly ISubject<XBaseEventModel<IEnumerable<T>>> onUpdateManySubject;
private readonly ISubject<XBaseEventModel<IEnumerable<T>>> onRemoveManySubject;
//
protected XBaseRepositoryEvents () {
//
onAddSubject = new ReplaySubject<XBaseEventModel<T>> (1);
onUpdateSubject = new ReplaySubject<XBaseEventModel<T>> (1);
onRemoveSubject = new ReplaySubject<XBaseEventModel<T>> (1);
//
onAddManySubject = new ReplaySubject<XBaseEventModel<IEnumerable<T>>> (1);
onUpdateManySubject = new ReplaySubject<XBaseEventModel<IEnumerable<T>>> (1);
onRemoveManySubject = new ReplaySubject<XBaseEventModel<IEnumerable<T>>> (1);
}
//
public void AddEvent (XBaseEventModel<T> model) => onAddSubject.OnNext (model);
public void UpdateEvent (XBaseEventModel<T> model) => onUpdateSubject.OnNext (model);
public void RemoveEvent (XBaseEventModel<T> model) => onRemoveSubject.OnNext (model);
//
public void AddManyEvent (XBaseEventModel<IEnumerable<T>> model) => onAddManySubject.OnNext (model);
public void UpdateManyEvent (XBaseEventModel<IEnumerable<T>> model) => onUpdateManySubject.OnNext (model);
public void RemoveManyEvent (XBaseEventModel<IEnumerable<T>> model) => onRemoveManySubject.OnNext (model);
//
public IObservable<XBaseEventModel<T>> OnAddObservable => onAddSubject.AsObservable ();
public IObservable<XBaseEventModel<T>> OnUpdateObservable => onUpdateSubject.AsObservable ();
public IObservable<XBaseEventModel<T>> OnRemoveObservable => onRemoveSubject.AsObservable ();
//
public IObservable<XBaseEventModel<IEnumerable<T>>> OnAddManyObservable => onAddManySubject.AsObservable ();
public IObservable<XBaseEventModel<IEnumerable<T>>> OnUpdateManyObservable => onUpdateManySubject.AsObservable ();
public IObservable<XBaseEventModel<IEnumerable<T>>> OnRemoveManyObservable => onRemoveManySubject.AsObservable ();
}
}
+43
View File
@@ -0,0 +1,43 @@
using System;
using Microsoft.EntityFrameworkCore.Infrastructure;
using MySql.EntityFrameworkCore.Infrastructure;
namespace xDataService.Extensions {
public static class DbContextOptionExtensions {
/// <summary>
/// convert dynamic object to MySqlDbContextOptionBuilder ...
/// Only Used in EFCore ...
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static Action<MySQLDbContextOptionsBuilder> ToMySQLDbContextOptionsBuilder (
this Action<dynamic> source
) {
return ((Action<MySQLDbContextOptionsBuilder>) source);
}
/// <summary>
/// convert dynamic object to SqliteDbContextOptionBuilder ...
/// Only Used in EFCore ...
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static Action<SqliteDbContextOptionsBuilder> ToSqliteDbContextOptionsBuilder (
this Action<dynamic> source
) {
return ((Action<SqliteDbContextOptionsBuilder>) source);
}
/// <summary>
/// convert dynamic object to SqlServerDbContextOptionBuilder ...
/// Only Used in EFCore ...
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static Action<SqlServerDbContextOptionsBuilder> ToSqlServerDbContextOptionsBuilder (
this Action<dynamic> source
) {
return ((Action<SqlServerDbContextOptionsBuilder>) source);
}
}
}
+67
View File
@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using xCommons.Extensions;
using xModels.Base;
namespace xDataService.Extensions {
public static class EntityExtensions {
/// <summary>
/// return all values of an entity properties as a json string ...
/// </summary>
/// <param name="item"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static string GetPropValues<T> (this T item)
where T : XBaseEntity<T> {
//
var props = item.GetType ().GetProperties ();
var vals = props.Select (p => p.GetValue (item));
//
return vals.ToJSON ();
}
/// <summary>
/// check values of all properties of an Entity contains specific value or not ...
/// </summary>
/// <param name="item"></param>
/// <param name="value"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static bool PropValuesContains<T> (this T item, string value)
where T : XBaseEntity<T> => item.GetPropValues ()
.ToNormalString ()
.Contains (value);
/// <summary>
/// Retrieve Default Column Map of specific Entity ...
/// </summary>
/// <param name="item"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IDictionary<string, Expression<Func<T, object>>> GetDefaultColumnsMap<T> (this T item)
where T : XBaseEntity<T> {
//
if (item.IsNull ()) {
return null;
}
//
var result = new Dictionary<string, Expression<Func<T, object>>> ();
var props = item.GetType ().GetProperties ();
//
foreach (var prop in props) {
result.Add (
prop.Name,
t => t.GetType ().GetProperty (prop.Name).GetValue (t, null));
}
//
return result;
}
}
}
+503
View File
@@ -0,0 +1,503 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using xCommons.Extensions;
using xDataService.Constants;
using xExceptions.Constants;
using xModels.Base;
namespace xDataService.Extensions {
public static class IQueryableExtensions {
/// <summary>
/// Apply Search Filter on a Query
/// </summary>
/// <param name="source"></param>
/// <param name="filter"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IQueryable<T> ApplyFilter<T, TKey> (
this IQueryable<T> source,
string filter
)
where T : XBaseEntity<TKey> {
//
// Apply Filter ...
return source.Where (r => r.PropValuesContains (filter));
}
/// <summary>
/// Apply Search Filter on a Query
/// </summary>
/// <param name="source"></param>
/// <param name="filter"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static async Task<IQueryable<T>> ApplyFilterAsync<T, TKey> (
this IQueryable<T> source,
string filter
)
where T : XBaseEntity<TKey> {
//
// Where Clause ...
Expression<Func<T, bool>> whereClause = r => r
.PropValuesContains (filter);
//
// Generate Where Function ...
var whereFunc = whereClause.Compile ();
//
// Get Enumerable ...
var enumerator = source
.AsAsyncEnumerable ();
//
var result = new List<T> ();
await
foreach (var entity in enumerator) {
//
var isApproved = whereFunc (entity);
if (isApproved) {
result.Add (entity);
}
}
//
return result.AsQueryable ();
}
/// <summary>
/// Apply Search Filter on a Enumerable
/// </summary>
/// <param name="source"></param>
/// <param name="filter"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static async Task<IEnumerable<T>> ApplyFilterAsync<T, TKey> (
this IEnumerable<T> source,
string filter
)
where T : XBaseEntity<TKey> {
//
// Where Clause ...
Expression<Func<T, bool>> whereClause = r => r
.PropValuesContains (filter);
//
// Generate Where Function ...
var whereFunc = whereClause.Compile ();
//
// Get Enumerable ...
var enumerator = source
.AsQueryable ()
.AsAsyncEnumerable ();
//
var result = new List<T> ();
await
foreach (var entity in enumerator) {
//
var isApproved = whereFunc (entity);
if (isApproved) {
result.Add (entity);
}
}
//
return result
.AsEnumerable ();
}
/// <summary>
/// Apply Search Filter on a Enumerable
/// </summary>
/// <param name="source"></param>
/// <param name="filter"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<T> ApplyFilter<T> (
this IEnumerable<T> source,
string filter
)
where T : class {
//
// Apply Filter ...
return source.Where (r => r.PropValuesContains (filter));
}
/// <summary>
/// provide a way to Order an IQueryable by string FieldName ...
/// </summary>
/// <param name="query"></param>
/// <param name="propertyName"></param>
/// <typeparam name="TSource"></typeparam>
/// <returns></returns>
public static IOrderedQueryable<TSource> OrderBy<TSource> (
this IQueryable<TSource> query,
string propertyName
) {
//
var entityType = typeof (TSource);
//
// Create x => x.PropName
var propertyInfo = entityType.GetProperty (propertyName);
if (propertyInfo.IsNull ()) {
XException.InvalidArgs.Throw ();
}
//
ParameterExpression arg = Expression.Parameter (entityType, "x");
MemberExpression property = Expression.Property (arg, propertyName);
var selector = Expression.Lambda (property, new ParameterExpression[] { arg });
//
// Get System.Linq.Queryable.OrderBy() method.
var enumarableType = typeof (System.Linq.Queryable);
var method = enumarableType.GetMethods ()
.Where (m => m.Name == "OrderBy" && m.IsGenericMethodDefinition)
.Where (m => {
//
var parameters = m.GetParameters ().ToList ();
//
// Put more restriction here to ensure selecting the right overload
return parameters.Count == 2; // overload that has 2 parameters
}).Single ();
//
// The linq's OrderBy<TSource, TKey> has two generic types, which provided here ...
MethodInfo genericMethod = method
.MakeGenericMethod (entityType, propertyInfo.PropertyType);
/*
Call query.OrderBy(selector), with query and selector: x=> x.PropName
Note that we pass the selector as Expression to the method and we don't compile it.
By doing so EF can extract "order by" columns and generate SQL for it.
*/
var newQuery = (IOrderedQueryable<TSource>) genericMethod
.Invoke (genericMethod, new object[] { query, selector });
//
return newQuery;
}
/// <summary>
/// provide a way to Order an IEnumerable by string FieldName ...
/// </summary>
/// <param name="query"></param>
/// <param name="propertyName"></param>
/// <typeparam name="TSource"></typeparam>
/// <returns></returns>
public static IOrderedEnumerable<TSource> OrderBy<TSource> (
this IEnumerable<TSource> query,
string propertyName
) {
//
var entityType = typeof (TSource);
var propertyInfo = entityType.GetProperty (propertyName);
if (propertyInfo.IsNull ()) {
XException.InvalidArgs.Throw ();
}
//
return query.OrderBy (x => propertyInfo.GetValue (x, null));
}
/// <summary>
/// provide a way to Order an IQueryable by string FieldName ...
/// </summary>
/// <param name="query"></param>
/// <param name="propertyName"></param>
/// <typeparam name="TSource"></typeparam>
/// <returns></returns>
public static IOrderedQueryable<TSource> OrderByDescending<TSource> (
this IQueryable<TSource> query,
string propertyName
) {
//
var entityType = typeof (TSource);
//
// Create x => x.PropName
var propertyInfo = entityType.GetProperty (propertyName);
if (propertyInfo.IsNull ()) {
XException.InvalidArgs.Throw ();
}
//
ParameterExpression arg = Expression.Parameter (entityType, "x");
MemberExpression property = Expression.Property (arg, propertyName);
var selector = Expression.Lambda (property, new ParameterExpression[] { arg });
//
// Get System.Linq.Queryable.OrderBy() method.
var enumarableType = typeof (System.Linq.Queryable);
var method = enumarableType.GetMethods ()
.Where (m => m.Name == "OrderByDescending" && m.IsGenericMethodDefinition)
.Where (m => {
//
var parameters = m.GetParameters ().ToList ();
//
// Put more restriction here to ensure selecting the right overload
return parameters.Count == 2; // overload that has 2 parameters
}).Single ();
//
// The linq's OrderBy<TSource, TKey> has two generic types, which provided here ...
MethodInfo genericMethod = method
.MakeGenericMethod (entityType, propertyInfo.PropertyType);
/*
Call query.OrderBy(selector), with query and selector: x=> x.PropName
Note that we pass the selector as Expression to the method and we don't compile it.
By doing so EF can extract "order by" columns and generate SQL for it.
*/
var newQuery = (IOrderedQueryable<TSource>) genericMethod
.Invoke (genericMethod, new object[] { query, selector });
//
return newQuery;
}
/// <summary>
/// provide a way to Order an IEnumerable by string FieldName ...
/// </summary>
/// <param name="query"></param>
/// <param name="propertyName"></param>
/// <typeparam name="TSource"></typeparam>
/// <returns></returns>
public static IOrderedEnumerable<TSource> OrderByDescending<TSource> (
this IEnumerable<TSource> query,
string propertyName
) {
//
var entityType = typeof (TSource);
var propertyInfo = entityType.GetProperty (propertyName);
if (propertyInfo.IsNull ()) {
XException.InvalidArgs.Throw ();
}
//
return query.OrderByDescending (x => propertyInfo.GetValue (x, null));
}
/// <summary>
/// Apply Sorting on a query
/// </summary>
/// <param name="source"></param>
/// <param name="sortBy"></param>
/// <param name="isAscending"></param>
/// <param name="columnsMap"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IQueryable<T> ApplySorting<T, TKey> (
this IQueryable<T> source,
string sortBy,
bool isAscending,
IDictionary<string, Expression<Func<T, object>>> columnsMap = null
)
where T : XBaseEntity<TKey> {
//
if (columnsMap == null) {
//
columnsMap = source.FirstOrDefault ()
.GetDefaultColumnsMap ();
//
if (columnsMap == null) {
return source;
}
}
//
// Validate SortBy ...
var sortByItem = columnsMap.Keys
.FirstOrDefault (p =>
p.ToNormalString () == sortBy.ToNormalString ());
if (sortByItem.IsNullOrEmpty ()) {
return source;
}
//
// Apply Sorting ...
if (isAscending) {
return source.OrderBy (sortByItem);
} else {
return source.OrderByDescending (sortByItem);
}
}
/// <summary>
/// Apply Sorting on a query
/// </summary>
/// <param name="source"></param>
/// <param name="sortBy"></param>
/// <param name="isAscending"></param>
/// <param name="columnsMap"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<T> ApplySorting<T, TKey> (
this IEnumerable<T> source,
string sortBy,
bool isAscending,
IDictionary<string, Expression<Func<T, object>>> columnsMap = null
)
where T : XBaseEntity<TKey> {
//
if (columnsMap == null) {
//
columnsMap = source.FirstOrDefault ()
.GetDefaultColumnsMap ();
//
if (columnsMap == null) {
return source;
}
}
//
// Validate SortBy ...
var sortByItem = columnsMap.Keys
.FirstOrDefault (p =>
p.ToNormalString () == sortBy.ToNormalString ());
if (sortByItem.IsNullOrEmpty ()) {
return source;
}
//
// Apply Sorting ...
if (isAscending) {
return source.OrderBy (sortByItem);
} else {
return source.OrderByDescending (sortByItem);
}
}
/// <summary>
/// Apply Sorting on a Enumerable
/// </summary>
/// <param name="source"></param>
/// <param name="sortBy"></param>
/// <param name="isAscending"></param>
/// <param name="columnsMap"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<T> ApplySorting<T> (
this IEnumerable<T> source,
string sortBy,
bool isAscending,
IDictionary<string, Expression<Func<T, object>>> columnsMap = null
)
where T : class {
//
if (columnsMap == null) {
//
columnsMap = source.FirstOrDefault ()
.GetDefaultColumnsMap ();
//
if (columnsMap == null) {
return source;
}
}
//
// Validate SortBy ...
var sortByItem = columnsMap.Keys
.FirstOrDefault (p =>
p.ToNormalString () == sortBy.ToNormalString ());
if (sortByItem.IsNullOrEmpty ()) {
return source;
}
//
// Apply Sorting ...
if (isAscending) {
return source.OrderBy (sortByItem);
} else {
return source.OrderByDescending (sortByItem);
}
}
/// <summary>
/// Apply Paging on a qury
/// </summary>
/// <param name="source"></param>
/// <param name="page"></param>
/// <param name="pageSize"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IQueryable<T> ApplyPaging<T> (
this IQueryable<T> source,
int? page,
int? pageSize
) {
//
if (!page.HasValue ||
page <= 0) {
page = 1;
}
//
if (!pageSize.HasValue ||
pageSize <= 0 ||
pageSize > XDataServiceConstants.MAX_AVAILABLE_PAGE_SIZE) {
pageSize = XDataServiceConstants.DEFAULT_PAGE_SIZE;
}
//
var pageVal = page.GetValueOrDefault ();
var pageSizeVal = pageSize.GetValueOrDefault ();
//
return source
.Skip ((pageVal - 1) * pageSizeVal)
.Take (pageSizeVal);
}
/// <summary>
/// Apply Paging on a Enumerable
/// </summary>
/// <param name="source"></param>
/// <param name="page"></param>
/// <param name="pageSize"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<T> ApplyPaging<T> (
this IEnumerable<T> source,
int? page,
int? pageSize
) {
//
if (!page.HasValue ||
page <= 0) {
page = 1;
}
//
if (!pageSize.HasValue ||
pageSize <= 0 ||
pageSize > XDataServiceConstants.MAX_AVAILABLE_PAGE_SIZE) {
pageSize = XDataServiceConstants.DEFAULT_PAGE_SIZE;
}
//
var pageVal = page.GetValueOrDefault ();
var pageSizeVal = pageSize.GetValueOrDefault ();
//
return source
.Skip ((pageVal - 1) * pageSizeVal)
.Take (pageSizeVal);
}
}
}
@@ -0,0 +1,82 @@
using System.Linq;
using xCommons.Extensions;
using xDataService.Configuration;
using xDataService.Constants;
namespace xDataService.Extensions {
public static class XDataServiceConfigurationExtensions {
/// <summary>
/// Extract Provider enum from Provider Type ...
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static XDbProviders ToDbProvider (this string source) {
//
if (source.IsNullOrEmpty ()) {
return XDbProviders.None;
}
//
source = source.ToNormalString ();
//
var result = source == ProviderType.MySQL.ToNormalString () ?
XDbProviders.MySQL :
source == ProviderType.SQLite.ToNormalString () ?
XDbProviders.SQLite :
source == ProviderType.SQLServer.ToNormalString () ?
XDbProviders.SQLServer :
source == ProviderType.MongoDB.ToNormalString () ?
XDbProviders.MongoDB :
XDbProviders.None;
//
return result;
}
/// <summary>
/// Retrieve Mongo URI from ConnectionString
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static string GetMongoDbURI (this XDataServiceConfiguration source) {
//
var parts = source.GetConnectionParts ();
var result = parts
.Where (p => p.Trim ().StartsWith ("Uri="))
.FirstOrDefault ();
result = result.Replace ("Uri=", "").Trim ();
//
return result;
}
/// <summary>
/// Retrieve Mongo Database Name from Connaction string
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static string GetMongoDbDatabase (this XDataServiceConfiguration source) {
//
var parts = source.GetConnectionParts ();
var result = parts
.Where (p => p.Trim ().StartsWith ("Database="))
.FirstOrDefault ();
result = result.Replace ("Database=", "").Trim ();
//
return result;
}
//
#region Private ...
private static string[] GetConnectionParts (this XDataServiceConfiguration source) {
//
var result = source.ConnectionString.Split (';');
//
return result;
}
#endregion
}
}
+28
View File
@@ -0,0 +1,28 @@
using GraphQL;
using GraphQL.Types;
using xDataService.Constants;
using xModels.Dtos;
namespace xDataService.Extensions {
public static class XGraphQLExtensions {
public static TKey GetIdArgument<TKey> (this IResolveFieldContext<object> source) {
return source.GetArgument<TKey> (XGraphQLHelper.GetIdArgument<IntGraphType>().Name);
}
public static bool GetIgnoreSoftDeletedArgument<T> (this IResolveFieldContext<T> source) {
return source.GetArgument<bool> (XGraphQLHelper.IgnoreSoftDeletedArgument.Name);
}
public static bool GetContainsDetailArgument<T> (this IResolveFieldContext<T> source) {
return source.GetArgument<bool> (XGraphQLHelper.ContainsDetailArgument.Name);
}
public static string GetSearchQueryArgument<T> (this IResolveFieldContext<T> source) {
return source.GetArgument<string> (XGraphQLHelper.SearchQueryArgument.Name);
}
public static XQuery GetQueryArgument<T> (this IResolveFieldContext<T> source) {
return source.GetArgument<XQuery> (XGraphQLHelper.QueryArgument.Name);
}
}
}
+61
View File
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Core.Bindings;
using MongoDB.Driver.Core.Clusters;
using MongoDB.Driver.Core.Servers;
using MongoDB.Driver.Core.WireProtocol.Messages.Encoders;
using MongoDB.Driver.Linq;
using xDataService.Mongo;
namespace xDataService.Extensions {
public static class XMongoDbExtensions {
public static Guid ToGuid (this ObjectId source) {
//
var bytes = source
.ToByteArray ()
.Concat (new byte[] { 5, 5, 5, 5 })
.ToArray ();
//
var result = new Guid (bytes);
//
return result;
}
public static ObjectId ToObjectId (this Guid source) {
//
var bytes = source
.ToByteArray ()
.Take (12)
.ToArray ();
//
var result = new ObjectId (bytes);
//
return result;
}
public static IAsyncEnumerable<T> ToAsyncEnumerable<T> (this IAsyncCursorSource<T> asyncCursorSource) {
return new XAsyncEnumerableAdapter<T> (asyncCursorSource);
}
public static async IAsyncEnumerable<T> ToAsyncEnumerable<T> (this IAsyncCursor<T> source) {
while (await source.MoveNextAsync ()) {
foreach (var current in source.Current) {
yield return current;
}
}
}
public static XMongoAsyncCursor<T> ToAsyncCursor<T> (this IQueryable<T> source) {
return new XMongoAsyncCursor<T> (source);
}
}
}
+21
View File
@@ -0,0 +1,21 @@
using GraphQL.Types;
using xModels.Base;
namespace xDataService.GraphQL
{
/// <summary>
/// Base Entity GraphType Object ...
/// </summary>
/// <typeparam name="TKey"></typeparam>
public abstract class XBaseGraphObjectType<T, TKey> : ObjectGraphType<T>
where T : XBaseEntity<TKey> {
public XBaseGraphObjectType () {
//
Name = $"{typeof(T).Name}GraphType";
//
Field (x => x.Id);
Field (x => x.Deleted);
}
}
}
+17
View File
@@ -0,0 +1,17 @@
using GraphQL.Types;
using xDataService.Models;
using xModels.Base;
namespace xDataService.GraphQL {
public class XBaseGraphQLEventType<TEntity, TKey, TGraphType> : ObjectGraphType<XBaseEventModel<TEntity>>
where TGraphType : IGraphType
where TEntity : XBaseEntity<TKey> {
public XBaseGraphQLEventType () {
//
Name = nameof (XBaseGraphQLEventType<TEntity, TKey, TGraphType>);
//
Field (x => x.Model, type : typeof (TGraphType));
}
}
}
+167
View File
@@ -0,0 +1,167 @@
using System;
using System.Linq.Expressions;
using GraphQL.Types;
using xCommons.Extensions;
using xDataService.Configuration;
using xDataService.Constants;
using xDataService.Extensions;
using xDataService.Interfaces;
using xDataService.Models;
using xModels.Base;
namespace xDataService.GraphQL {
public abstract class XBaseGraphQLQuery<TEntity, TKey, TGraph, TGraphKey> : ObjectGraphType, IXBaseGraphQLQuery<TEntity, TKey, TGraph, TGraphKey>
where TEntity : XBaseEntity<TKey>
where TGraph : IGraphType
where TGraphKey : IGraphType {
//
private readonly XDataServiceConfiguration configuration;
private readonly IXBaseRepository<TEntity, TKey> repository;
private readonly IXBaseGraphQLTypeHelper<TEntity, TKey> helper;
//
public XBaseGraphQLQuery (
XDataServiceConfiguration configuration,
IXBaseRepository<TEntity, TKey> repository,
IXBaseGraphQLTypeHelper<TEntity, TKey> helper
) {
//
this.helper = helper;
this.repository = repository;
this.configuration = configuration;
//
Name = GetType ().Name;
//
#region Retrieve ...
//
// Get ...
FieldAsync<TGraph> (
name: helper.GetInQuerySingleName (),
arguments: new QueryArguments (
XGraphQLHelper.GetIdArgument<TGraphKey> (),
XGraphQLHelper.IgnoreSoftDeletedArgument,
XGraphQLHelper.ContainsDetailArgument
),
resolve : async context =>
await repository
.GetAsync (
id: context.GetIdArgument<TKey> (),
ignoreSoftDeleteds: context.GetIgnoreSoftDeletedArgument (),
containsDetail: context.GetContainsDetailArgument ()
)
.ToDynamicObject ()
);
//
// GetAll ...
FieldAsync<ListGraphType<TGraph>> (
name: helper.GetInQueryCollectionName (),
arguments: new QueryArguments (
XGraphQLHelper.IgnoreSoftDeletedArgument,
XGraphQLHelper.ContainsDetailArgument
),
resolve : async context =>
await repository
.GetAllAsync (
ignoreSoftDeleteds: context.GetIgnoreSoftDeletedArgument (),
containsDetail: context.GetContainsDetailArgument ()
)
.ToDynamicObject ()
);
//
// FindOne ...
FieldAsync<TGraph> (
name: helper.GetFindOneName (),
arguments: new QueryArguments (
XGraphQLHelper.SearchQueryArgument,
XGraphQLHelper.IgnoreSoftDeletedArgument,
XGraphQLHelper.ContainsDetailArgument
),
resolve : async (context) => {
//
var searchQuery = context.GetSearchQueryArgument ();
Expression<Func<TEntity, bool>> whereClase = pe => pe
.PropValuesContains (searchQuery);
//
return await repository
.FindOneAsync (
whereClause: whereClase,
ignoreSoftDeleteds: context.GetIgnoreSoftDeletedArgument (),
containsDetail: context.GetContainsDetailArgument ()
)
.ToDynamicObject ();
}
);
//
// FindMany ...
FieldAsync<ListGraphType<TGraph>> (
name: helper.GetFindManyName (),
arguments: new QueryArguments (
XGraphQLHelper.SearchQueryArgument,
XGraphQLHelper.IgnoreSoftDeletedArgument,
XGraphQLHelper.ContainsDetailArgument
),
resolve : async (context) => {
//
var searchQuery = context.GetSearchQueryArgument ();
Expression<Func<TEntity, bool>> whereClase = pe => pe
.PropValuesContains (searchQuery);
//
return await repository
.FindManyAsync (
whereClause: whereClase,
ignoreSoftDeleteds: context.GetIgnoreSoftDeletedArgument (),
containsDetail: context.GetContainsDetailArgument ()
)
.ToDynamicObject ();
}
);
//
// Query ...
FieldAsync<XGraphQueryResult<TEntity, TGraph>> (
name: helper.GetQueryName (),
arguments: new QueryArguments (
XGraphQLHelper.QueryArgument,
XGraphQLHelper.IgnoreSoftDeletedArgument
),
resolve : async context =>
await repository
.QueryAsync (
query: context.GetQueryArgument (),
ignoreSoftDeleteds: context.GetIgnoreSoftDeletedArgument ()
)
.ToDynamicObject ()
);
//
// Count ...
FieldAsync<IntGraphType> (
name: helper.GetCountName (),
resolve: async context =>
await repository
.CountAsync ()
);
//
// Exists ...
FieldAsync<BooleanGraphType> (
name: helper.GetExistsName (),
arguments: new QueryArguments (
XGraphQLHelper.GetIdArgument<TGraphKey> ()
),
resolve : async context =>
await repository.IsExistsAsync (
context.GetIdArgument<TKey> ()
)
);
#endregion
}
}
}
+107
View File
@@ -0,0 +1,107 @@
using System.Collections.Generic;
using GraphQL.Resolvers;
using GraphQL.Types;
using xCommons.Extensions;
using xDataService.Events;
using xDataService.Interfaces;
using xDataService.Models;
using xModels.Base;
namespace xDataService.GraphQL {
public abstract class XBaseGraphQLSubscription<TEntity, TKey, TGraph> : ObjectGraphType
where TGraph : IGraphType
where TEntity : XBaseEntity<TKey> {
public XBaseGraphQLSubscription (IXBaseRepositoryEvents<TEntity> eventProvider = null) {
//
Name = GetType ().Name;
//
// Check if base repository patter registered ...
if (!eventProvider.IsNull ()) {
//
// Add ...
AddField (new EventStreamFieldType {
//
Name = nameof (XBaseRepositoryEvents<TEntity>.AddEvent),
Type = typeof (XBaseGraphQLEventType<TEntity, TKey, TGraph>),
Resolver = new FuncFieldResolver<XBaseEventModel<TEntity>> (
context => context.Source as XBaseEventModel<TEntity>
),
Subscriber = new EventStreamResolver<XBaseEventModel<TEntity>> (context => {
return eventProvider.OnAddObservable;
})
});
//
// Add Many ...
AddField (new EventStreamFieldType {
//
Name = nameof (XBaseRepositoryEvents<TEntity>.AddManyEvent),
Type = typeof (XBaseGraphQLEventType<TEntity, TKey, TGraph>),
Resolver = new FuncFieldResolver<XBaseEventModel<IEnumerable<TEntity>>> (
context => context.Source as XBaseEventModel<IEnumerable<TEntity>>
),
Subscriber = new EventStreamResolver<XBaseEventModel<IEnumerable<TEntity>>> (context => {
return eventProvider.OnAddManyObservable;
})
});
//
// Update ...
AddField (new EventStreamFieldType {
//
Name = nameof (XBaseRepositoryEvents<TEntity>.UpdateEvent),
Type = typeof (XBaseGraphQLEventType<TEntity, TKey, TGraph>),
Resolver = new FuncFieldResolver<XBaseEventModel<TEntity>> (
context => context.Source as XBaseEventModel<TEntity>
),
Subscriber = new EventStreamResolver<XBaseEventModel<TEntity>> (context => {
return eventProvider.OnUpdateObservable;
})
});
//
// Update Mnay ...
AddField (new EventStreamFieldType {
//
Name = nameof (XBaseRepositoryEvents<TEntity>.UpdateManyEvent),
Type = typeof (XBaseGraphQLEventType<TEntity, TKey, TGraph>),
Resolver = new FuncFieldResolver<XBaseEventModel<IEnumerable<TEntity>>> (
context => context.Source as XBaseEventModel<IEnumerable<TEntity>>
),
Subscriber = new EventStreamResolver<XBaseEventModel<IEnumerable<TEntity>>> (context => {
return eventProvider.OnUpdateManyObservable;
})
});
//
// Remove ...
AddField (new EventStreamFieldType {
//
Name = nameof (XBaseRepositoryEvents<TEntity>.RemoveEvent),
Type = typeof (XBaseGraphQLEventType<TEntity, TKey, TGraph>),
Resolver = new FuncFieldResolver<XBaseEventModel<TEntity>> (
context => context.Source as XBaseEventModel<TEntity>
),
Subscriber = new EventStreamResolver<XBaseEventModel<TEntity>> (context => {
return eventProvider.OnRemoveObservable;
})
});
//
// Remove Many ...
AddField (new EventStreamFieldType {
//
Name = nameof (XBaseRepositoryEvents<TEntity>.RemoveManyEvent),
Type = typeof (XBaseGraphQLEventType<TEntity, TKey, TGraph>),
Resolver = new FuncFieldResolver<XBaseEventModel<IEnumerable<TEntity>>> (
context => context.Source as XBaseEventModel<IEnumerable<TEntity>>
),
Subscriber = new EventStreamResolver<XBaseEventModel<IEnumerable<TEntity>>> (context => {
return eventProvider.OnRemoveManyObservable;
})
});
}
}
}
}
+64
View File
@@ -0,0 +1,64 @@
using xCommons.Extensions;
using xDataService.Configuration;
using xDataService.Interfaces;
using xModels.Base;
namespace xDataService.GraphQL {
public abstract class XBaseGraphQLTypeHelper<TEntity, TKey> : IXBaseGraphQLTypeHelper<TEntity, TKey>
where TEntity : XBaseEntity<TKey> {
//
private readonly XDataServiceConfiguration configuration;
//
public XBaseGraphQLTypeHelper (
XDataServiceConfiguration configuration = null
) {
this.configuration = configuration;
}
//
public abstract string GetInQueryCollectionName ();
public abstract string GetInQuerySingleName ();
//
public string GetFindOneName () {
return $"find{GetInQuerySingleName ().ToNormalString().Capitalize()}";
}
public string GetFindManyName () {
return $"find{GetInQueryCollectionName ().ToNormalString().Capitalize()}";
}
public string GetQueryName () {
return $"query{GetInQueryCollectionName().ToNormalString().Capitalize()}";
}
public string GetCountName () {
return $"count{GetInQueryCollectionName().ToNormalString().Capitalize()}";
}
public string GetExistsName () {
return $"exists{GetInQuerySingleName().ToNormalString().Capitalize()}";
}
public string GetGraphQLPath (string baseGraphPath = null) {
//
baseGraphPath = baseGraphPath.IsNullOrEmpty () ?
configuration.IsNull () || configuration.GraphQLBasePath.IsNullOrEmpty () ?
"" :
configuration.GraphQLBasePath :
baseGraphPath;
//
var basePath = baseGraphPath
.EndsWith ("/") ?
baseGraphPath
.Substring (0, baseGraphPath.Length - 1) :
baseGraphPath;
//
return $"{basePath}/{GetInQueryCollectionName().ToNormalString()}";
}
}
}
+79
View File
@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Linq;
using xCommons.Extensions;
namespace xDataService.Helpers {
public partial class XCursorHelper {
public static string ToCursor<T> (T id) {
//
// Check Numbers ...
if (id.ToString ().IsDigits ()) {
return Convert
.ToBase64String (BitConverter
.GetBytes (Convert.ToInt32 (id))
);
} else
//
// Check Guid ...
if (id.ToString ().IsGuid ()) {
return Convert
.ToBase64String (new Guid (id.ToString ())
.ToByteArray ());
} else
//
// Assume as String ...
{
return Convert
.ToBase64String (id
.ToString ().ToBytes ());
}
}
public static T FromCursor<T> (string cursor) {
//
// Check Numbers ...
var returnType = typeof (T);
if (returnType == typeof (int) ||
returnType == typeof (long) ||
returnType == typeof (decimal)) {
return Convert.ChangeType ((BitConverter
.ToInt32 (Convert
.FromBase64String (cursor),
0
))
.ToDynamicObject (), returnType);
} else
//
// Check Guid ...
if (returnType == typeof (Guid)) {
return Convert.ChangeType ((new Guid (
Convert.FromBase64String (cursor)
))
.ToDynamicObject (), returnType);
} else
//
// Assume as String ...
{
return Convert.ChangeType ((
Convert.FromBase64String (cursor)
)
.ToDynamicObject (), returnType);
}
}
public static (string firstCursor, string lastCursor) GetFirstAndLastCursor<T> (IEnumerable<T> ids) {
//
if (ids?.Any () != true) {
return (null, null);
}
//
var firstCursor = ToCursor (ids.First ());
var lastCursor = ToCursor (ids.Last ());
//
return (firstCursor, lastCursor);
}
}
}
+38
View File
@@ -0,0 +1,38 @@
using GraphQL.Types;
using xDataService.Models;
using xModels.Dtos;
namespace xDataService.Constants {
public static class XGraphQLHelper {
public static QueryArgument<TKey> GetIdArgument<TKey> ()
where TKey : IGraphType {
return new QueryArgument<TKey> {
Name = "id",
Description = "the id of entity, which you want to retrieve ..."
};
}
public static QueryArgument<BooleanGraphType> IgnoreSoftDeletedArgument = new QueryArgument<BooleanGraphType> {
Name = "ignoreSoftDeleteds",
DefaultValue = true,
Description = "determines result should ignore soft deleted items or not ..."
};
public static QueryArgument<BooleanGraphType> ContainsDetailArgument = new QueryArgument<BooleanGraphType> {
Name = "containsDetail",
DefaultValue = false,
Description = "determines result should contains navigation properties or not ..."
};
public static QueryArgument<StringGraphType> SearchQueryArgument = new QueryArgument<StringGraphType> {
Name = "searchQuery",
Description = "the value which had to looking for ..."
};
public static QueryArgument<XGraphQueryType> QueryArgument = new QueryArgument<XGraphQueryType> {
Name = "query",
DefaultValue = new XQuery (),
Description = "determines query structure info for retrieving data ..."
};
}
}
+9
View File
@@ -0,0 +1,9 @@
using GraphQL.Types;
using xModels.Base;
namespace xDataService.Interfaces {
public interface IXBaseGraphQLQuery<TEntity, TKey, TGraph, TGraphKey>
where TEntity : XBaseEntity<TKey>
where TGraph : IGraphType
where TGraphKey : IGraphType { }
}
+21
View File
@@ -0,0 +1,21 @@
using xModels.Base;
namespace xDataService.Interfaces {
public interface IXBaseGraphQLTypeHelper<TEntity, TKey>
where TEntity : XBaseEntity<TKey> {
string GetInQuerySingleName ();
string GetInQueryCollectionName ();
string GetFindOneName ();
string GetFindManyName ();
string GetQueryName ();
string GetCountName ();
string GetExistsName ();
string GetGraphQLPath (string baseGraphPath = null);
}
}
+273
View File
@@ -0,0 +1,273 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using xModels.Base;
using xModels.Dtos;
namespace xDataService.Interfaces {
/// <summary>
/// a Base Repository Interface for Manipulate
/// an Entity in DataBase
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IXBaseRepository<T, TKey> : IDisposable
where T : XBaseEntity<TKey> {
//
#region Add ...
/// <summary>
/// add a new Entity ...
/// </summary>
/// <param name="item"></param>
/// <param name="saveChanges"></param>
/// <returns></returns>
Task<T> AddAsync (
T item,
bool saveChanges = true
);
/// <summary>
/// add or update an Entity (add if not exists/update if exists) ...
/// </summary>
/// <param name="item"></param>
/// <param name="saveChanges"></param>
/// <returns></returns>
Task<T> AddOrUpdateAsync (
T item,
bool saveChanges = true
);
/// <summary>
/// add a range of new Entities ...
/// </summary>
/// <param name="items"></param>
/// <param name="saveChanges"></param>
/// <returns></returns>
Task AddRangeAsync (
IEnumerable<T> items,
bool saveChanges = true
);
#endregion
//
#region Remove ...
/// <summary>
/// remove an Entity by it's Id ...
/// </summary>
/// <param name="id"></param>
/// <param name="softDelete"></param>
/// <param name="saveChanges"></param>
/// <returns></returns>
Task<T> RemoveAsync (
TKey id,
bool softDelete = true,
bool saveChanges = true
);
/// <summary>
/// remove an Entity ...
/// </summary>
/// <param name="item"></param>
/// <param name="softDelete"></param>
/// <param name="saveChanges"></param>
/// <returns></returns>
Task<T> RemoveAsync (
T item,
bool softDelete = true,
bool saveChanges = true
);
/// <summary>
/// remove a range of exists Entities ...
/// </summary>
/// <param name="items"></param>
/// <param name="softDelete"></param>
/// <param name="saveChanges"></param>
/// <returns></returns>
Task RemoveRangeAsync (
IEnumerable<T> items,
bool softDelete = true,
bool saveChanges = true
);
#endregion
//
#region Retrieve ...
/// <summary>
/// retrieve whole items as queryable ...
/// </summary>
/// <returns></returns>
IQueryable<T> AsQueryable ();
/// <summary>
/// retrieve an Entity by it's Id ...
/// </summary>
/// <param name="id"></param>
/// <param name="ignoreSoftDeleteds"></param>
/// <param name="containsDetail"></param>
/// <returns></returns>
Task<T> GetAsync (
TKey id,
bool ignoreSoftDeleteds = true,
bool containsDetail = false
);
/// <summary>
/// retrieve all exists Entities ...
/// </summary>
/// <param name="ignoreSoftDeleteds"></param>
/// <param name="containsDetail"></param>
/// <returns></returns>
Task<IEnumerable<T>> GetAllAsync (
bool ignoreSoftDeleteds = true,
bool containsDetail = false
);
/// <summary>
/// find an Entity by providing a Conditional Expression ...
/// </summary>
/// <param name="whereClause"></param>
/// <param name="ignoreSoftDeleteds"></param>
/// <param name="containsDetail"></param>
/// <returns></returns>
Task<T> FindOneAsync (
Expression<Func<T, bool>> whereClause,
bool ignoreSoftDeleteds = true,
bool containsDetail = false
);
/// <summary>
/// find a collection of Entities by proving a Conditional Expression ...
/// </summary>
/// <param name="whereClause"></param>
/// <param name="ignoreSoftDeleteds"></param>
/// <param name="containsDetail"></param>
/// <returns></returns>
Task<IEnumerable<T>> FindManyAsync (
Expression<Func<T, bool>> whereClause,
bool ignoreSoftDeleteds = true,
bool containsDetail = false
);
/// <summary>
/// retrieve Entities based on XQuery Pagination structure ...
/// </summary>
/// <param name="query"></param>
/// <param name="ignoreSoftDeleteds"></param>
/// <returns></returns>
Task<XQueryResult<T>> QueryAsync (
XQuery query,
bool ignoreSoftDeleteds = true
);
/// <summary>
/// retrieve Entities based on XQuery Pagination structure by providing a Conditional Expression ...
/// </summary>
/// <param name="whereClause"></param>
/// <param name="query"></param>
/// <param name="ignoreSoftDeleteds"></param>
/// <returns></returns>
Task<XQueryResult<T>> ConditionalQueryAsync (
Expression<Func<T, bool>> whereClause,
XQuery query,
bool ignoreSoftDeleteds = true
);
#endregion
//
#region Update ...
/// <summary>
/// Update an Entity values ...
/// </summary>
/// <param name="id"></param>
/// <param name="item"></param>
/// <param name="saveChanges"></param>
/// <returns></returns>
Task<T> UpdateAsync (
TKey id,
T item,
bool saveChanges = true
);
/// <summary>
/// Update a range of Entities ...
/// </summary>
/// <param name="items"></param>
/// <param name="saveChanges"></param>
/// <returns></returns>
Task<bool> UpdateRangeAsync (
IEnumerable<T> items,
bool saveChanges = true
);
#endregion
//
#region Count ...
/// <summary>
/// count all exists Entities ...
/// </summary>
/// <param name="ignoreSoftDeleteds"></param>
/// <returns></returns>
Task<int> CountAsync (bool ignoreSoftDeleteds = true);
/// <summary>
/// count all exists Entities Pages by providing page size ...
/// </summary>
/// <param name="pageSize"></param>
/// <param name="totalItems"></param>
/// <returns></returns>
Task<int> PagesCountAsync (
int pageSize,
int? totalItems = null
);
#endregion
//
#region Exists ...
/// <summary>
/// Check an Entity exists or not ...
/// </summary>
/// <param name="id"></param>
/// <param name="ignoreSoftDeleteds"></param>
/// <returns></returns>
Task<bool> IsExistsAsync (
TKey id,
bool ignoreSoftDeleteds = true
);
#endregion
//
#region Unit Of Work ...
/// <summary>
/// Save all unsaved Transactions on DbContext ...
/// used fo Unit Of Works Design Pattern ...
/// </summary>
/// <returns></returns>
Task<int> SaveChangesAsync ();
#endregion
//
#region Key ...
TKey GetKey (T item);
void SetKey (
ref T item,
TKey id
);
Task<T> HandleKeyAsync (T item);
#endregion
//
#region Detach ...
void Detach (T item);
void Detach (IEnumerable<T> items);
void Detach (XQueryResult<T> query);
void Detach (XPageResponse<T> page);
#endregion
}
}
+27
View File
@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using xDataService.Models;
namespace xDataService.Interfaces {
public interface IXBaseRepositoryEvents<T> {
//
void AddEvent (XBaseEventModel<T> model);
void UpdateEvent (XBaseEventModel<T> model);
void RemoveEvent (XBaseEventModel<T> model);
//
void AddManyEvent (XBaseEventModel<IEnumerable<T>> model);
void UpdateManyEvent (XBaseEventModel<IEnumerable<T>> model);
void RemoveManyEvent (XBaseEventModel<IEnumerable<T>> model);
//
IObservable<XBaseEventModel<T>> OnAddObservable { get; }
IObservable<XBaseEventModel<T>> OnUpdateObservable { get; }
IObservable<XBaseEventModel<T>> OnRemoveObservable { get; }
//
IObservable<XBaseEventModel<IEnumerable<T>>> OnAddManyObservable { get; }
IObservable<XBaseEventModel<IEnumerable<T>>> OnUpdateManyObservable { get; }
IObservable<XBaseEventModel<IEnumerable<T>>> OnRemoveManyObservable { get; }
}
}
+78
View File
@@ -0,0 +1,78 @@
using System;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using MongoDB.Bson.Serialization.Conventions;
using xDataService.Constants;
namespace xDataService.Interfaces {
public interface IXDataServiceHelper {
/// <summary>
/// register DbContext implementation on DI Container ...
/// Only Used in EFCore ...
/// </summary>
/// <param name="services"></param>
/// <param name="connectionString"></param>
/// <param name="dbProvider"></param>
/// <param name="lifetime"></param>
/// <param name="optionsBuilder"></param>
void AddDbContext (
IServiceCollection services,
string connectionString,
XDbProviders dbProvider,
ServiceLifetime lifetime,
Action<dynamic> optionsBuilder = null
);
/// <summary>
/// register all Entities Repositories and Events on DI Container ...
/// implementations of IXBaseRepository and IXBaseRepositoryEvent ...
/// </summary>
/// <param name="services"></param>
/// <param name="lifetime"></param>
void AddRepositories (
IServiceCollection services,
ServiceLifetime lifetime
);
/// <summary>
/// Regitster KeyGenerators for Repositories ...
/// </summary>
/// <param name="services"></param>
void AddKeyGenerators (IServiceCollection services);
/// <summary>
/// register DBSeeder Configuration on DI Container ...
/// </summary>
/// <param name="services"></param>
/// <param name="configuration"></param>
void AddDbSeederConfiguration (
IServiceCollection services,
IConfiguration configuration
);
/// <summary>
/// register Data Seeder on DI Container ...
/// implementation of IXDbSeeder ...
/// </summary>
/// <param name="services"></param>
/// <param name="config"></param>
/// <param name="lifetime"></param>
/// <typeparam name="TDbSeeder"></typeparam>
void AddDbSeeder<TDbSeeder> (
IServiceCollection services,
IConfiguration config,
ServiceLifetime lifetime
) where TDbSeeder : IXDbSeeder;
/// <summary>
/// Set Mongo Convention Pack ...
/// </summary>
/// <returns></returns>
ConventionPack MongoConventionPacks ();
/// <summary>
/// Configure all required MongoDb Class Mappers and etc here ...
/// </summary>
void RegisterMongoExtras ();
}
}
+19
View File
@@ -0,0 +1,19 @@
using System.Threading.Tasks;
using xDataService.Configuration;
namespace xDataService.Interfaces {
/// <summary>
/// Db Seeder used to seed data on Database on startup time ...
/// </summary>
public interface IXDbSeeder {
IXDbSeederConfig Config { get; }
XDataServiceConfiguration DataServiceConfiguration { get; }
/// <summary>
/// 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 ...
/// </summary>
/// <returns></returns>
Task Seed ();
}
}
+14
View File
@@ -0,0 +1,14 @@
namespace xDataService.Interfaces {
/// <summary>
/// this Configuration used to Carry all Entity Descriptors collections
/// can readable by appSettings.json file for providing dynamic data seeding ...
/// </summary>
public interface IXDbSeederConfig {
/// <summary>
/// determines an Entity can Update when Exists or not ...
/// this must handled by consumer on IXDbSeeder Seed method implementation ...
/// </summary>
/// <value></value>
bool UpdateExists { get; set; }
}
}
+75
View File
@@ -0,0 +1,75 @@
using GraphQL.Server;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
namespace xDataService.Interfaces {
/// <summary>
/// this is a helper class which provides all requirements to providing GraphQL
/// based data manipulating mechanism ...
/// </summary>
public interface IXGraphQLHelper {
/// <summary>
/// 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 ...
/// </summary>
void AddXGraphEnumTypes (IServiceCollection services);
/// <summary>
/// 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<T> or XBaseGraphObjectType<TKey>
/// </summary>
void AddXGraphObjectTypes (IServiceCollection services);
/// <summary>
/// Register all GraphQL Input Types ...
/// InputTypes represent recieving data structure in GraphQL for doing mutations ...
/// must extended from InputObjectGraphType<T> ...
/// </summary>
void AddXGraphInputTypes (IServiceCollection services);
/// <summary>
/// Register all GraphQL Queries ...
/// Queries in GraphQL used to provide data fetch and retrieve mechanism ...
/// extended from ObjectGraphType ...
/// </summary>
void AddXGraphQueries (IServiceCollection services);
/// <summary>
/// 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 ...
/// </summary>
void AddXGraphMutations (IServiceCollection services);
/// <summary>
/// Register all GraphQL Subscriptions ...
/// Subscriptions are listeners to specific events on data in GraphQL ...
/// must extended from ObjectGraphType and implements IXBaseRepositoryEvents<TEntity> ...
/// </summary>
void AddXGraphSubscriptions (IServiceCollection services);
/// <summary>
/// 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 ...
/// </summary>
void AddXGraphSchemas (IServiceCollection services);
/// <summary>
/// Add Schemas to GraphQL Builder ...
/// here you must add all registered Schemas to GraphQLBuilder ...
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
IGraphQLBuilder AddXGraphTypes (IGraphQLBuilder builder);
/// <summary>
/// Use all Registered Schemas by GraphQL<T> and and GraphQLWebSockets<T> ...
/// </summary>
/// <param name="app"></param>
void UseXGraph (IApplicationBuilder app);
}
}
+12
View File
@@ -0,0 +1,12 @@
using System.Threading.Tasks;
using xModels.Base;
namespace xDataService.Interfaces {
public interface IXKeyGenerator<TEntity, TKey>
where TEntity : XBaseEntity<TKey> {
bool IsEmpty (TKey id);
Task<TKey> GenerateKey (
IXBaseRepository<TEntity, TKey> repository
);
}
}
+11
View File
@@ -0,0 +1,11 @@
using System;
namespace xDataService.Interfaces {
/// <summary>
/// this service provide Sequential GUID mechanism for Entity Ids ...
/// </summary>
public interface IXSequentialGuid {
Guid GetCurrentGuid ();
Guid Next ();
}
}
+20
View File
@@ -0,0 +1,20 @@
using System;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using xDataService.Db;
using xModels.Base;
namespace xDataService.Interfaces {
/// <summary>
/// Provide Unit Of Works Design Pattern for Db Transactions ...
/// Only Used on EFCore ...
/// </summary>
/// <typeparam name="TDbContext"></typeparam>
public interface IXUnitOfWorks<TDbContext> : IDisposable
where TDbContext : XDbContext {
TDbContext DbContext { get; }
DbSet<T> GetDbSet<T, TKey> () where T : XBaseEntity<TKey>;
int SaveChanges ();
Task<int> SaveChangesAsync ();
}
}
+13
View File
@@ -0,0 +1,13 @@
namespace xDataService.Models {
/// <summary>
/// Pass Data on Repository Events ...
/// </summary>
/// <typeparam name="T"></typeparam>
public class XBaseEventModel<T> {
public T Model { get; set; }
public XBaseEventModel (T model) {
Model = model;
}
}
}
+20
View File
@@ -0,0 +1,20 @@
using GraphQL.Types;
using xModels.Dtos;
namespace xDataService.Models {
public class XGraphQueryResult<TEntity, TGraph> : ObjectGraphType<XQueryResult<TEntity>>
where TGraph : IGraphType {
public XGraphQueryResult () {
//
Name = $"{typeof(TGraph).Name}QueryResult";
//
Field<ListGraphType<TGraph>> (nameof (XQueryResult<TEntity>.Items));
Field (x => x.Page);
Field (x => x.PageSize);
Field (x => x.TotalPages);
Field (x => x.TotalFilteredItems);
Field (x => x.TotalItems);
}
}
}
+19
View File
@@ -0,0 +1,19 @@
using GraphQL.Types;
using xModels.Dtos;
namespace xDataService.Models {
public class XGraphQueryType : InputObjectGraphType<XQuery> {
public XGraphQueryType () {
//
Name = "query";
//
Field (x => x.Filter);
Field (x => x.ContainsDetail);
Field (x => x.SortBy);
Field (x => x.IsAscending);
Field (x => x.Page);
Field (x => x.PageSize);
}
}
}
+73
View File
@@ -0,0 +1,73 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Driver;
namespace xDataService.Mongo {
public class XAsyncEnumerableAdapter<T> : IAsyncEnumerable<T> {
//
private readonly IAsyncCursorSource<T> asyncCursorSource;
//
public XAsyncEnumerableAdapter (IAsyncCursorSource<T> asyncCursorSource) {
this.asyncCursorSource = asyncCursorSource;
}
//
public IAsyncEnumerator<T> GetAsyncEnumerator (CancellationToken cancellationToken) =>
new XAsyncEnumeratorAdapter<T> (asyncCursorSource, cancellationToken);
}
public class XAsyncEnumeratorAdapter<T> : IAsyncEnumerator<T> {
private readonly IAsyncCursorSource<T> asyncCursorSource;
private readonly CancellationToken cancellationToken;
private IAsyncCursor<T> asyncCursor;
private IEnumerator<T> batchEnumerator;
public T Current => batchEnumerator.Current;
public XAsyncEnumeratorAdapter (
IAsyncCursorSource<T> asyncCursorSource,
CancellationToken cancellationToken
) {
//
this.asyncCursorSource = asyncCursorSource;
this.cancellationToken = cancellationToken;
}
public async ValueTask<bool> MoveNextAsync () {
//
if (asyncCursor == null) {
asyncCursor = await asyncCursorSource
.ToCursorAsync (cancellationToken);
}
//
if (batchEnumerator != null &&
batchEnumerator.MoveNext ()) {
return true;
}
//
if (asyncCursor != null &&
await asyncCursor.MoveNextAsync (cancellationToken)) {
//
batchEnumerator?.Dispose ();
batchEnumerator = asyncCursor.Current.GetEnumerator ();
//
return batchEnumerator.MoveNext ();
}
//
return false;
}
public async ValueTask DisposeAsync () {
//
await Task.CompletedTask;
asyncCursor?.Dispose ();
asyncCursor = null;
}
}
}
+31
View File
@@ -0,0 +1,31 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Driver;
namespace xDataService.Mongo {
public class XMongoAsyncCursor<T> : IAsyncCursor<T> {
public IEnumerable<T> Current { get; }
private IEnumerator<T> CurrentEnumerator { get; }
public XMongoAsyncCursor (IEnumerable<T> source) {
this.Current = source;
this.CurrentEnumerator = source.GetEnumerator ();
}
public void Dispose () {
CurrentEnumerator.Dispose ();
}
public bool MoveNext (CancellationToken cancellationToken = default) {
return CurrentEnumerator.MoveNext ();
}
public Task<bool> MoveNextAsync (CancellationToken cancellationToken = default) {
return Task.Run (
() => CurrentEnumerator.MoveNext (),
cancellationToken : cancellationToken
);
}
}
}
+56
View File
@@ -0,0 +1,56 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using xModels.Base;
namespace xDataService.Mongo {
public class XMongoQueryable<TEntity, TKey> : IMongoQueryable<TEntity>
where TEntity : XBaseEntity<TKey> {
private readonly IMongoCollection<TEntity> collection;
public Type ElementType { get; }
public IQueryable<TEntity> Items { get; }
public Expression Expression { get; }
public IQueryProvider Provider { get; }
public XMongoQueryable (
IQueryable<TEntity> items,
IMongoCollection<TEntity> collection
) {
//
this.Items = items;
this.collection = collection;
//
Provider = items.Provider;
Expression = items.Expression;
ElementType = items.ElementType;
}
public IEnumerator<TEntity> GetEnumerator () {
return Items.GetEnumerator ();
}
public QueryableExecutionModel GetExecutionModel () {
return collection.AsQueryable ().GetExecutionModel ();
}
public IAsyncCursor<TEntity> ToCursor (CancellationToken cancellationToken = default) {
return new XMongoAsyncCursor<TEntity> (Items);
}
public Task<IAsyncCursor<TEntity>> ToCursorAsync (CancellationToken cancellationToken = default) {
return Task.Run (() => new XMongoAsyncCursor<TEntity> (Items) as IAsyncCursor<TEntity>);
}
IEnumerator IEnumerable.GetEnumerator () {
return Items.GetEnumerator ();
}
}
}
+23
View File
@@ -0,0 +1,23 @@
using MongoDB.Driver;
namespace xDataService.Mongo {
public static class XMongoReadPreferenceResolver {
public static ReadPreference GetEffectiveReadPreference (
IClientSessionHandle session,
ReadPreference explicitReadPreference,
ReadPreference defaultReadPreference) {
if (explicitReadPreference != null) {
return explicitReadPreference;
}
if (session.IsInTransaction) {
var transactionReadPreference = session.WrappedCoreSession.CurrentTransaction.TransactionOptions.ReadPreference;
if (transactionReadPreference != null) {
return transactionReadPreference;
}
}
return defaultReadPreference ?? ReadPreference.Primary;
}
}
}
File diff suppressed because it is too large Load Diff
+41
View File
@@ -0,0 +1,41 @@
using System;
using System.Threading.Tasks;
using xCommons.Extensions;
using xDataService.Interfaces;
using xModels.Base;
namespace xDataService.Providers {
public class XGuidKeyGenerator<TEntity> : IXKeyGenerator<TEntity, Guid>
where TEntity : XBaseEntity<Guid> {
private readonly IXSequentialGuid sequentialGuid;
public XGuidKeyGenerator (
IXSequentialGuid sequentialGuid = null
) {
this.sequentialGuid = sequentialGuid;
}
public async Task<Guid> GenerateKey (
IXBaseRepository<TEntity, Guid> repository
) {
//
await Task.CompletedTask;
//
// Check if provided SequentialGuid ...
if (sequentialGuid.IsNull ()) {
return Guid.NewGuid ();
} else {
return sequentialGuid.Next ();
}
}
public bool IsEmpty (Guid id) {
//
var result = id.IsNull () || id.IsDefaultGuid ();
//
return result;
}
}
}
+33
View File
@@ -0,0 +1,33 @@
using System.Linq;
using System.Threading.Tasks;
using xCommons.Extensions;
using xDataService.Extensions;
using xDataService.Interfaces;
using xModels.Base;
namespace xDataService.Providers {
public class XIntKeyGenerator<TEntity> : IXKeyGenerator<TEntity, int>
where TEntity : XBaseEntity<int> {
public async Task<int> GenerateKey (IXBaseRepository<TEntity, int> repository) {
//
var items = (await repository.GetAllAsync ())
.OrderByDescending (nameof (XBaseEntity<int>.Id));
var last = items
.FirstOrDefault ();
//
var result = last.IsNull () ? 1 : last.Id + 1;
//
return result;
}
public bool IsEmpty (int id) {
//
var result = id <= 0;
//
return result;
}
}
}
+61
View File
@@ -0,0 +1,61 @@
using System;
using xDataService.Interfaces;
namespace xDataService.Helpers {
/// <summary>
/// this service provide Sequential GUID mechanism for Entity Ids ...
/// </summary>
public class XSequentialGuid : IXSequentialGuid {
private static int[] sqlOrderMap = null;
private static int[] SQLORDERMAP {
get {
if (sqlOrderMap == null) {
sqlOrderMap = new int[16] {
3,
2,
1,
0,
5,
4,
7,
6,
9,
8,
15,
14,
13,
12,
11,
10
};
// 3 - the least significant byte in Guid ByteArray [for SQL Server ORDER BY clause]
// 10 - the most significant byte in Guid ByteArray [for SQL Server ORDERY BY clause]
}
return sqlOrderMap;
}
}
private Guid currentGuid;
public XSequentialGuid () {
currentGuid = Guid.NewGuid ();
}
public Guid GetCurrentGuid () {
return currentGuid;
}
public Guid Next () {
byte[] bytes = currentGuid.ToByteArray ();
for (int mapIndex = 0; mapIndex < 16; mapIndex++) {
int bytesIndex = SQLORDERMAP[mapIndex];
bytes[bytesIndex]++;
if (bytes[bytesIndex] != 0) {
break; // No need to increment more significant bytes
}
}
currentGuid = new Guid (bytes);
return currentGuid;
}
}
}
+31
View File
@@ -0,0 +1,31 @@
using System;
using System.Threading.Tasks;
using xCommons.Extensions;
using xDataService.Interfaces;
using xModels.Base;
namespace xDataService.Providers {
public class XStringKeyGenerator : IXKeyGenerator<XBaseEntity<string>, string> {
private readonly IXSequentialGuid sequentialGuid;
public XStringKeyGenerator (IXSequentialGuid sequentialGuid = null) {
this.sequentialGuid = sequentialGuid;
}
public async Task<string> GenerateKey (IXBaseRepository<XBaseEntity<string>, string> repository) {
//
await Task.CompletedTask;
//
if (sequentialGuid.IsNull ()) {
return Guid.NewGuid ().ToString ();
} else {
return sequentialGuid.Next ().ToString ();
}
}
public bool IsEmpty (string id) {
return id.IsNullOrEmpty ();
}
}
}
+24
View File
@@ -0,0 +1,24 @@
# xDataService
it is a Part of xDashboard on SaherElm IT Center which provides:
- all required Repositories, UnitOfWorks and other tools related to Data Manipulation in xApiGateway workspace.
this module has following dependencies :
- xModels
- xCommons
for configure and use this Module refer to DI.XDIHelperExtension.cs file.
## Implementation
for using this modules and its provided tools and services for preparing your data provider usages
## Maintainer
Hadi Khazaee asl
[https://www.saherelm.ir](https://www.saherelm.ir)
[hadi_khazaee_asl@yahoo.com](mailto:hadi_khazaee_asl@yahoo.com)
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nuget" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
<add key="liget" value="https://nuget.saherelmhub.ir/v3/index.json" protocolVersion="3" />
</packageSources>
</configuration>
+65
View File
@@ -0,0 +1,65 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Runtime Definitions -->
<PropertyGroup>
<LangVersion>8.0</LangVersion>
<TargetFramework>netstandard2.0</TargetFramework>
<PackageId>xDashboard.xDataService</PackageId>
<Version>1.0.0</Version>
<Authors>Hadi Khazaee Asl</Authors>
<Company>SaherElm IT Center</Company>
<Description>
provide base requiremennts for Repository DataBase using and tools for using in xDashboard
project.
</Description>
<!-- Icon Definition -->
<PackageIcon>icon.png</PackageIcon>
</PropertyGroup>
<!-- Icon Handling -->
<ItemGroup>
<None Include="../../Resources/Images/favicon.png" Link="icon.png" Pack="true" PackagePath="\icon.png" />
</ItemGroup>
<!-- Local Modules -->
<ItemGroup>
<PackageReference Include="xDashboard.xModels" Version="1.0.0" />
<!-- <ProjectReference Include="../xModels/xModels.csproj" /> -->
</ItemGroup>
<!-- Dependencies -->
<ItemGroup>
<PackageReference Include="MongoDB.Driver" Version="2.13.2" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="5.0.0" />
</ItemGroup>
<!-- GraphQL -->
<ItemGroup>
<PackageReference Include="GraphQL" Version="3.0.0.2026" />
<PackageReference Include="GraphQL.Server.Ui.Voyager" Version="4.0.1" />
<PackageReference Include="GraphQL.SystemTextJson" Version="3.0.0.2026" />
<PackageReference Include="GraphQL.Server.Ui.Playground" Version="4.0.1" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore" Version="4.0.1" />
<PackageReference Include="GraphQL.Server.Transports.WebSockets" Version="4.0.1" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore.NewtonsoftJson" Version="4.0.1" />
</ItemGroup>
<!-- Ef Core -->
<ItemGroup>
<PackageReference Include="System.Reactive" Version="5.0.0" />
<PackageReference Include="MySql.EntityFrameworkCore" Version="3.1.14" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.14" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.14" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.14" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.14">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.14">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
</Project>