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 (); // #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); // 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)); // 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); // 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 { 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 }) ); } private void RemoveItemsFromStore (IEnumerable items) { STORE = new ConcurrentBag ( STORE.Except (items) ); } #endregion } }