Files
xModels/Providers/XBaseInMemoryStore.cs
T
2024-01-25 04:37:38 +03:30

521 lines
17 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using xCommons.Extensions;
using xModels.Base;
using xModels.Interfaces;
namespace xModels.Providers {
public abstract class XBaseInMemoryStore<T, TKey> : IXBaseStore<T, TKey>
where T : XBaseStorableDto<TKey> {
/// <summary>
/// this is main store of items ...
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
private static ConcurrentBag<T> STORE = new ConcurrentBag<T> ();
//
#region Retrieve ...
/// <summary>
/// Retrieve all Exists Items ...
/// </summary>
/// <returns></returns>
public Task<IEnumerable<T>> GetAll () {
//
var result = STORE.AsEnumerable ();
return Task.FromResult (result);
}
/// <summary>
/// Retrieve specific Item by key ...
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public Task<T> Get (TKey key) {
//
return IsExistsByKey (key)
.ContinueWith (isExistsTask => {
//
var isExists = isExistsTask
.RunTask ();
//
if (!isExists) {
return null;
}
//
try {
var result = STORE
.FirstOrDefault (i => GetKey (i).Equals (key));
return result;
} catch {
return null;
}
});
}
/// <summary>
/// retrieve items based on specific condition ...
/// </summary>
/// <param name="condition"></param>
/// <returns></returns>
public Task<IEnumerable<T>> FindMany (Expression<Func<T, bool>> condition) {
//
// Validate Args ...
if (condition.IsNull ()) {
return Task.FromResult (new List<T> ().AsEnumerable ());
}
//
var whereFunc = condition.Compile ();
var result = STORE.Where (whereFunc);
//
return Task.FromResult (result);
}
/// <summary>
/// retrieve item based on specific condition ...
/// </summary>
/// <param name="condition"></param>
/// <returns></returns>
public Task<T> FindOne (Expression<Func<T, bool>> condition) {
//
// Validate Args ...
if (condition.IsNull ()) {
return null;
}
//
var whereFunc = condition.Compile ();
var result = STORE.FirstOrDefault (whereFunc);
//
return Task.FromResult (result);
}
#endregion
//
#region Add ...
/// <summary>
/// add specific item to Store ...
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public Task<bool> Add (T item) {
//
// Validate Args ...
if (item.IsNull () || GetKey (item).IsNull ()) {
return Task.FromResult (false);
}
//
// Try to add item ...
return IsExistsByKey (GetKey (item))
.ContinueWith (isExistsTask => {
//
// Check item exists in Store or not ...
var isExists = isExistsTask.RunTask ();
if (isExists) {
return false;
}
//
// Add Item to Store ...
STORE.Add (item);
//
return true;
});
}
/// <summary>
/// Add a Collection of Items on Store ...
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
public Task<bool> AddMany (XBaseRangeRequest<T> items) {
//
// Validate Args ...
if (
items.IsNull () ||
!items.Items.HasChild ()
) {
return Task.FromResult (false);
}
//
// Retrieve Must Add Items ...
var mustAddItems = items.Items
.Where (i => !GetKey (i)
.IsNull () && !STORE
.Any (si => GetKey (i).Equals (GetKey (si)))
);
if (!mustAddItems.HasChild ()) {
return Task.FromResult (false);
}
//
// Add Items ...
try {
//
mustAddItems
.ToList ()
.ForEach (mi => STORE.Add (mi));
//
return Task.FromResult (true);
} catch {
return Task.FromResult (false);
}
}
#endregion
//
#region Remove ...
/// <summary>
/// Remove an item from store ...
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public Task<bool> Remove (T item) {
//
// Validate Args ...
if (
item.IsNull () ||
!STORE
.Any (i => GetKey (i)
.Equals (GetKey (item)))
) {
return Task.FromResult (false);
}
//
try {
//
RemoveItemFromStore (item);
return Task.FromResult (true);
} catch {
return Task.FromResult (false);
}
}
/// <summary>
/// remove an item by it's Key ...
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public Task<bool> RemoveByKey (TKey key) {
return Get (key)
.ContinueWith (getTask => {
//
// retrieve item by it's Key ...
var item = getTask
.RunTask ();
//
// Check item exists ...
if (item.IsNull ()) {
return false;
}
//
// Try to remove item ...
var result = false;
try {
//
result = Remove (item)
.RunTask ();
} catch {
result = false;
}
//
return result;
});
}
/// <summary>
/// remove a collection of items at once ...
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
public Task<bool> RemoveMany (XBaseRangeRequest<T> items) {
//
// Validate Args ...
if (
items.IsNull () ||
!items.Items.HasChild ()
) {
return Task.FromResult (false);
}
//
var mustRemovedItems = items.Items
.Where (i => STORE
.Any (si => GetKey (si).Equals (GetKey (i)))
);
if (!mustRemovedItems.HasChild ()) {
return Task.FromResult (false);
}
//
try {
//
RemoveItemsFromStore (mustRemovedItems);
return Task.FromResult (true);
} catch {
return Task.FromResult (false);
}
}
#endregion
//
#region Update ...
/// <summary>
/// Update Exists Item in store ...
/// </summary>
/// <param name="item"></param>
/// <param name="propertyWhiteList"></param>
/// <param name="propertyBlackList"></param>
/// <param name="propertyValueProviders"></param>
/// <param name="updateWithNullOrEmptyValues"></param>
/// <returns></returns>
public Task<T> Update (
T item,
ICollection<string> propertyWhiteList = null,
ICollection<string> propertyBlackList = null,
ICollection<KeyValuePair<string, Func<T, object>>> propertyValueProviders = null,
bool updateWithNullOrEmptyValues = false
) {
return Get (GetKey (item))
.ContinueWith (getTask => {
//
var existsItem = getTask
.RunTask ();
//
// Validate item Exists ...
if (existsItem.IsNull ()) {
return null;
}
//
try {
//
var updatedItem = existsItem;
updatedItem.UpdateData (
updateWith: item,
propertyWhiteList: propertyWhiteList,
propertyBlackList: propertyBlackList,
propertyValueProviders: propertyValueProviders,
updateWithNullOrEmptyValues: updateWithNullOrEmptyValues,
throwExceptionOnFails: true
);
//
RemoveItemFromStore (existsItem);
STORE.Add (updatedItem);
//
return updatedItem;
} catch {
return null;
}
});
}
/// <summary>
/// Update a Collection of Exists Items ...
/// </summary>
/// <param name="items"></param>
/// <param name="propertyWhiteList"></param>
/// <param name="propertyBlackList"></param>
/// <param name="propertyValueProviders"></param>
/// <param name="updateWithNullOrEmptyValues"></param>
/// <returns></returns>
public Task<bool> UpdateMany (
XBaseRangeRequest<T> items,
ICollection<string> propertyWhiteList = null,
ICollection<string> propertyBlackList = null,
ICollection<KeyValuePair<string, Func<T, object>>> propertyValueProviders = null,
bool updateWithNullOrEmptyValues = false
) {
//
// Validate Args ...
if (
items.IsNull () ||
!items.Items.HasChild ()
) {
return Task.FromResult (false);
}
//
// retrieve must updated items ...
var mustUpdateItems = items
.Items
.Where (i => STORE
.Any (
si => GetKey (i).Equals (GetKey (si)))
);
if (!mustUpdateItems.HasChild ()) {
return Task.FromResult (false);
}
//
// Do Tasks ...
var mustUpdateTasks = mustUpdateItems.Select (i => Update (
i,
propertyWhiteList : propertyWhiteList,
propertyBlackList : propertyBlackList,
propertyValueProviders : propertyValueProviders,
updateWithNullOrEmptyValues : updateWithNullOrEmptyValues
));
return Task.WhenAll (mustUpdateTasks)
.ContinueWith (updateTasks => {
//
var updatedItems = updateTasks
.RunTask ();
//
if (!updatedItems.HasChild ()) {
return false;
} else {
return true;
}
});
}
#endregion
//
#region Exists ...
/// <summary>
/// retrieve item(s) exists based on specific condition ...
/// </summary>
/// <param name="condition"></param>
/// <returns></returns>
public Task<bool> IsExists (Expression<Func<T, bool>> condition) {
//
// Validate Args ...
if (condition.IsNull ()) {
return Task.FromResult (false);
}
//
var whereFunc = condition.Compile ();
var result = STORE.Any (whereFunc);
//
return Task.FromResult (result);
}
/// <summary>
/// is exists an item by providing it's key ...
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public Task<bool> IsExistsByKey (TKey key) {
return Task.Run (() => {
return STORE.Any (i => GetKey (i).Equals (key));
});
}
#endregion
//
#region Count ...
/// <summary>
/// Count Exists items ...
/// </summary>
/// <returns></returns>
public Task<int> Count () {
//
var result = STORE.Count ();
return Task.FromResult (result);
}
#endregion
//
#region Keys ...
/// <summary>
/// set Object Key ...
/// </summary>
/// <param name="item"></param>
/// <param name="id"></param>
public void SetKey (
ref T item,
TKey id
) {
//
var props = item.GetType ().GetProperties ();
var keyProp = props.FirstOrDefault (p => p.Name == "Id");
if (keyProp.IsNull ()) {
return;
}
//
Type t = Nullable.GetUnderlyingType (keyProp.PropertyType) ?? keyProp.PropertyType;
object safeValue = (id == null) ? null : Convert.ChangeType (id, t);
keyProp.SetValue (item, safeValue, null);
}
/// <summary>
/// Get Object Key ...
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public TKey GetKey (T item) {
//
var props = item.GetType ().GetProperties ();
var keyProp = props.FirstOrDefault (p => p.Name == "Id");
//
var keyString = string.Empty;
if (keyProp.IsNull ()) {
keyString = string.Empty;
} else {
keyString = keyProp.GetValue (item).ToString ();
}
//
if (keyString.IsNullOrEmpty ()) {
return default (TKey);
}
//
// Prevent Deserializing issues throug JsonReader ...
if (keyString.IsGuid () && typeof (TKey) == typeof (Guid)) {
return item.Id;
}
//
TKey result;
try {
result = keyString.FromJSON<TKey> ();
} catch {
result = keyString.ConvertTo<TKey> ();
}
return result;
}
#endregion
//
#region Private ...
private void RemoveItemFromStore (T item) {
STORE = new ConcurrentBag<T> (
STORE.Except (new [] { item })
);
}
private void RemoveItemsFromStore (IEnumerable<T> items) {
STORE = new ConcurrentBag<T> (
STORE.Except (items)
);
}
#endregion
}
}