reactredux/webapi/DataProviders/Abstractions/DataProviderBase.cs

265 lines
11 KiB
C#

using System.Linq.Expressions;
using Microsoft.Extensions.Logging;
using MongoDB.Bson.Serialization;
using MongoDB.Driver;
using DomainResults.Common;
using Core.Abstractions.DomainObjects;
namespace DataProviders.Abstractions {
public abstract class DataProviderBase<T> where T : DomainObjectDocumentBase<T> {
private protected const string _databaseName = "reactredux";
private protected readonly ILogger<DataProviderBase<T>> _logger;
private protected readonly IMongoClient _client;
private protected readonly IIdGenerator _idGenerator;
private protected readonly ISessionService _sessionService;
private protected List<T>? _collection;
/// <summary>
/// Main constructor
/// </summary>
/// <param name="logger"></param>
/// <param name="client"></param>
/// <param name="idGenerator"></param>
/// <param name="dataProviderUtils"></param>
public DataProviderBase(
ILogger<DataProviderBase<T>> logger,
IMongoClient client,
IIdGenerator idGenerator,
ISessionService sessionService
) {
_logger = logger;
_client = client;
_idGenerator = idGenerator;
_sessionService = sessionService;
}
#region Insert
private protected (Guid?, IDomainResult) Insert(T obj, string collectionName) =>
InsertAsync(obj, collectionName).Result;
private protected (Guid?, IDomainResult) Insert(T obj, string collectionName, Guid sessionId) =>
InsertAsync(obj, collectionName, sessionId).Result;
private protected Task<(Guid?, IDomainResult)> InsertAsync(T obj, string collectionName) =>
InsertAsyncCore(obj, collectionName, null);
private protected Task<(Guid?, IDomainResult)> InsertAsync(T obj, string collectionName, Guid sessionId) =>
InsertAsyncCore(obj, collectionName, sessionId);
#endregion
#region InsertMany
private protected (List<Guid>?, IDomainResult) InsertMany(List<T> objList, string collectionName) =>
InsertManyAsync(objList, collectionName).Result;
private protected (List<Guid>?, IDomainResult) InsertMany(List<T> objList, string collectionName, Guid sessionId) =>
InsertManyAsync(objList, collectionName, sessionId).Result;
private protected Task<(List<Guid>?, IDomainResult)> InsertManyAsync(List<T> objList, string collectionName) =>
InsertManyAsyncCore(objList, collectionName, null);
private protected Task<(List<Guid>?, IDomainResult)> InsertManyAsync(List<T> objList, string collectionName, Guid sessionId) =>
InsertManyAsyncCore(objList, collectionName, sessionId);
#endregion
#region Get
private protected (List<T>?, IDomainResult) GetWithPredicate(Expression<Func<T, bool>> predicate, string collectionName) =>
GetWithPredicateCore(predicate, 0, 0, collectionName);
private protected (List<T>?, IDomainResult) GetWithPredicate(Expression<Func<T, bool>> predicate, int skip, int limit, string collectionName) =>
GetWithPredicateCore(predicate, skip, limit, collectionName);
#endregion
#region Update
private protected (Guid?, IDomainResult) UpdateWithPredicate(T obj, Expression<Func<T, bool>> predicate, string collectionName) =>
UpdateWithPredicateAsync(obj, predicate, collectionName).Result;
private protected (Guid?, IDomainResult) UpdateWithPredicate(T obj, Expression<Func<T, bool>> predicate, string collectionName, Guid sessionId) =>
UpdateWithPredicateAsync(obj, predicate, collectionName, sessionId).Result;
private protected Task<(Guid?, IDomainResult)> UpdateWithPredicateAsync(T obj, Expression<Func<T, bool>> predicate, string collectionName) =>
UpdateWithPredicateAsyncCore(obj, predicate, collectionName, null);
private protected Task<(Guid?, IDomainResult)> UpdateWithPredicateAsync(T obj, Expression<Func<T, bool>> predicate, string collectionName, Guid sessionId) =>
UpdateWithPredicateAsyncCore(obj, predicate, collectionName, sessionId);
#endregion
#region Exists
private protected (Guid?, IDomainResult) Exists(Guid id, string collectionName) {
var (_resultList, result) = GetWithPredicate(x => x.Id == id, 0, 0, collectionName);
return (result.Status != DomainOperationStatus.Failed && _resultList != null && _resultList.Count > 0
? id
:null,
result);
}
#endregion
#region Delete
private protected IDomainResult DeleteWithPredicate(Expression<Func<T, bool>> predicate, string collectionName) =>
DeleteWithPredicateAsync(predicate, collectionName).Result;
private protected IDomainResult DeleteWithPredicate(Expression<Func<T, bool>> predicate, string collectionName, Guid sessionId) =>
DeleteWithPredicateAsync(predicate, collectionName, sessionId).Result;
private protected Task<IDomainResult> DeleteWithPredicateAsync(Expression<Func<T, bool>> predicate, string collectionName) =>
DeleteWithPredicateAsyncCore(predicate, collectionName, null);
private protected Task<IDomainResult> DeleteWithPredicateAsync(Expression<Func<T, bool>> predicate, string collectionName, Guid sessionId) =>
DeleteWithPredicateAsyncCore(predicate, collectionName, sessionId);
#endregion
#region DeleteMany
private protected IDomainResult DeleteManyWithPredicate(Expression<Func<T, bool>> predicate, string collectionName) =>
DeleteManyWithPredicateAsync(predicate, collectionName).Result;
private protected IDomainResult DeleteManyWithPredicate(Expression<Func<T, bool>> predicate, string collectionName, Guid sessionId) =>
DeleteManyWithPredicateAsync(predicate, collectionName, sessionId).Result;
private protected Task<IDomainResult> DeleteManyWithPredicateAsync(Expression<Func<T, bool>> predicate, string collectionName) =>
DeleteManyWithPredicateAsyncCore(predicate, collectionName, null);
private protected Task<IDomainResult> DeleteManyWithPredicateAsync(Expression<Func<T, bool>> predicate, string collectionName, Guid sessionId) =>
DeleteManyWithPredicateAsyncCore(predicate, collectionName, sessionId);
#endregion
#region Core methods
private async protected Task<(Guid?, IDomainResult)> InsertAsyncCore(T obj, string collectionName, Guid? sessionId) {
try {
if (_collection != null) {
obj.Id = Guid.NewGuid();
_collection.Add(obj);
return IDomainResult.Success(obj.Id);
}
var collection = _client.GetDatabase(_databaseName).GetCollection<T>(collectionName);
if (sessionId != null)
await collection.InsertOneAsync(_sessionService.GetSession(sessionId.Value), obj);
else
collection.InsertOne(obj);
return IDomainResult.Success(obj.Id);
}
catch (Exception ex) {
_logger.LogError(ex, "Data provider error");
return IDomainResult.Failed<Guid?>();
}
}
private async Task<(List<Guid>?, IDomainResult)> InsertManyAsyncCore(List<T> objList, string collectionName, Guid? sessionId) {
try {
if (_collection != null) {
_collection = _collection.Concat(objList).ToList();
return IDomainResult.Success(objList.Select(x => x.Id).ToList());
}
var collection = _client.GetDatabase(_databaseName).GetCollection<T>(collectionName);
if (sessionId != null)
await collection.InsertManyAsync(_sessionService.GetSession(sessionId.Value), objList);
else
collection.InsertMany(objList);
return IDomainResult.Success(objList.Select(x => x.Id).ToList());
}
catch (Exception ex) {
_logger.LogError(ex, "Data provider error");
return IDomainResult.Failed<List<Guid>?>();
}
}
private (List<T>?, IDomainResult) GetWithPredicateCore(Expression<Func<T, bool>> predicate, int skip, int limit, string collectionName) {
try {
List<T>? result;
if (_collection != null) {
result = _collection?.AsQueryable()
.Where(predicate).ToList();
}
else {
result = _client.GetDatabase(_databaseName).GetCollection<T>(collectionName)
.Find(predicate).Skip(skip).Limit(limit).ToList();
}
return result != null && result.Count > 0
? IDomainResult.Success(result)
: IDomainResult.NotFound<List<T>?>();
}
catch (Exception ex) {
_logger.LogError(ex, "Data provider error");
return IDomainResult.Failed<List<T>?>();
}
}
private async Task<(Guid?, IDomainResult)> UpdateWithPredicateAsyncCore(T obj, Expression<Func<T, bool>> predicate, string collectionName, Guid? sessionId) {
try {
if (_collection != null) {
// remove element(s) from list
foreach (var element in _collection.AsQueryable().Where(predicate))
_collection = _collection.Where(x => x.Id != element.Id).ToList();
// add updated element
_collection.Add(obj);
}
else {
var collection = _client.GetDatabase(_databaseName).GetCollection<T>(collectionName);
if (sessionId != null)
await collection.ReplaceOneAsync(_sessionService.GetSession(sessionId.Value), predicate, obj);
else
await collection.ReplaceOneAsync(predicate, obj);
}
return IDomainResult.Success(obj.Id);
}
catch (Exception ex) {
_logger.LogError(ex, "Data provider error");
return IDomainResult.Failed<Guid?>();
}
}
private async Task<IDomainResult> DeleteWithPredicateAsyncCore(Expression<Func<T, bool>> predicate, string collectionName, Guid? sessionId) {
try {
var collection = _client.GetDatabase(_databaseName).GetCollection<T>(collectionName);
if (sessionId != null)
await collection.DeleteOneAsync<T>(_sessionService.GetSession(sessionId.Value), predicate);
else
await collection.DeleteOneAsync<T>(predicate);
return IDomainResult.Success();
}
catch (Exception ex) {
_logger.LogError(ex, "Data provider error");
return IDomainResult.Failed();
}
}
private async Task<IDomainResult> DeleteManyWithPredicateAsyncCore(Expression<Func<T, bool>> predicate, string collectionName, Guid? sessionId) {
try {
var collection = _client.GetDatabase(_databaseName).GetCollection<T>(collectionName);
if (sessionId != null)
await collection.DeleteManyAsync(_sessionService.GetSession(sessionId.Value), predicate);
else
await collection.DeleteManyAsync(predicate);
return IDomainResult.Success();
}
catch (Exception ex) {
_logger.LogError(ex, "Data provider error");
return IDomainResult.Failed();
}
}
#endregion
}
}