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 : IXBaseStore where T : XBaseStorableDto { /// /// this is main store of items ... /// /// /// private static ConcurrentBag STORE = new ConcurrentBag(); // private readonly IXBaseStoreEvents events; // #region Constructor ... protected XBaseInMemoryStore( IXBaseStoreEvents events = null ) { this.events = events; } #endregion // #region Retrieve ... /// /// Retrieve all Exists Items ... /// /// public Task> GetAll() { // var result = STORE.AsEnumerable(); return Task.FromResult(result); } /// /// Retrieve specific Item by key ... /// /// /// public Task 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; } }); } /// /// retrieve items based on specific condition ... /// /// /// public Task> FindMany(Expression> condition) { // // Validate Args ... if (condition.IsNull()) { return Task.FromResult(new List().AsEnumerable()); } // var whereFunc = condition.Compile(); var result = STORE.Where(whereFunc); // return Task.FromResult(result); } /// /// retrieve item based on specific condition ... /// /// /// public Task FindOne(Expression> condition) { // // Validate Args ... if (condition.IsNull()) { return null; } // var whereFunc = condition.Compile(); var result = STORE.FirstOrDefault(whereFunc); // return Task.FromResult(result); } #endregion // #region Add ... /// /// add specific item to Store ... /// /// /// public Task 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); OnAdd(item); // return true; }); } /// /// Add a Collection of Items on Store ... /// /// /// public Task AddMany(XBaseRangeRequest 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)); // OnAddMany(mustAddItems); // return Task.FromResult(true); } catch { return Task.FromResult(false); } } #endregion // #region Remove ... /// /// Remove an item from store ... /// /// /// public Task 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); } } /// /// remove an item by it's Key ... /// /// /// public Task 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; }); } /// /// remove a collection of items at once ... /// /// /// public Task RemoveMany(XBaseRangeRequest 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 ... /// /// Update Exists Item in store ... /// /// /// /// /// /// /// public Task Update( T item, ICollection propertyWhiteList = null, ICollection propertyBlackList = null, ICollection>> 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); OnUpdate(item); // return updatedItem; } catch { return null; } }); } /// /// Update a Collection of Exists Items ... /// /// /// /// /// /// /// public Task UpdateMany( XBaseRangeRequest items, ICollection propertyWhiteList = null, ICollection propertyBlackList = null, ICollection>> 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 { // OnUpdateMany(mustUpdateItems); return true; } }); } #endregion // #region Exists ... /// /// retrieve item(s) exists based on specific condition ... /// /// /// public Task IsExists(Expression> condition) { // // Validate Args ... if (condition.IsNull()) { return Task.FromResult(false); } // var whereFunc = condition.Compile(); var result = STORE.Any(whereFunc); // return Task.FromResult(result); } /// /// is exists an item by providing it's key ... /// /// /// public Task IsExistsByKey(TKey key) { return Task.Run(() => { return STORE.Any(i => GetKey(i).Equals(key)); }); } #endregion // #region Count ... /// /// Count Exists items ... /// /// public Task Count() { // var result = STORE.Count(); return Task.FromResult(result); } #endregion // #region Keys ... /// /// set Object Key ... /// /// /// 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); } /// /// Get Object Key ... /// /// /// 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(); } catch { result = keyString.ConvertTo(); } return result; } #endregion // #region Private ... private void RemoveItemFromStore(T item) { // STORE = new ConcurrentBag( STORE.Except(new[] { item }) ); // OnRemove(item); } private void RemoveItemsFromStore(IEnumerable items) { // STORE = new ConcurrentBag( STORE.Except(items) ); // OnRemoveMany(items); } // #region Event Notifiers ... private void OnAdd(T item) { // if (!events.IsNull()) { events.AddEvent(new XBaseStorableDtoEventModel(item)); } } private void OnUpdate(T item) { // if (!events.IsNull()) { events.UpdateEvent(new XBaseStorableDtoEventModel(item)); } } private void OnRemove(T item) { // if (!events.IsNull()) { events.RemoveEvent(new XBaseStorableDtoEventModel(item)); } } private void OnAddMany(IEnumerable items) { // if (!events.IsNull()) { events.AddManyEvent(new XBaseStorableDtoEventModel>(items)); } } private void OnUpdateMany(IEnumerable items) { // if (!events.IsNull()) { events.UpdateManyEvent(new XBaseStorableDtoEventModel>(items)); } } private void OnRemoveMany(IEnumerable items) { // if (!events.IsNull()) { events.RemoveManyEvent(new XBaseStorableDtoEventModel>(items)); } } #endregion #endregion } }