using Quadarax.Foundation.Core.Business.Processor.Enums; using Quadarax.Foundation.Core.Business.Processor.Task; using Quadarax.Foundation.Core.Logging; using Quadarax.Foundation.Core.Object; namespace Quadarax.Foundation.Core.Business.Processor.Providers; public abstract class ProcessorStorageProvider : DisposableObject, IProcessorStorageProvider { #region *** Properties *** public bool IsOpen { get; private set; } #endregion #region *** Fields *** private readonly ILog _log; #endregion #region *** Constructors *** protected ProcessorStorageProvider() { _log = new ConsoleLogger().GetLogger(GetType()); } #endregion public void Open() { if (IsOpen) throw new InvalidOperationException("Storage provider has been already opened."); OnOpen(); IsOpen = true; Log(LogSeverityEnum.Debug, "Storage provider has been opened."); } public void Close() { if (!IsOpen) throw new InvalidOperationException("Storage provider has been already closed."); OnClose(); IsOpen = false; Log(LogSeverityEnum.Debug, "Storage provider has been closed."); } public bool EnsureStorage() { var result = OnEnsureStorage(); Log(LogSeverityEnum.Debug, $"Storage provider has been ensured with result '{result}'."); return result; } public ITaskIdentifier Create(ITaskItemData item) { if (item == null) throw new ArgumentNullException(nameof(item)); EnsureOpen(); var result = OnCreate(item); Log(LogSeverityEnum.Debug, $"Task item '{result}' has been created in storage."); return result; } public ITaskItemData[] Get(params ITaskIdentifier[] ids) { if (ids == null) throw new ArgumentNullException(nameof(ids)); if (ids.Length > 0) throw new ArgumentOutOfRangeException(nameof(ids), "must have at least one element in array."); EnsureOpen(); var result = OnGet(ids); Log(LogSeverityEnum.Debug, $"Gets {result.Length} items by {ids.Length} identifiers from storage."); return result; } public void Set(params ITaskItemData[] items) { if (items == null) throw new ArgumentNullException(nameof(items)); if (items.Length > 0) throw new ArgumentOutOfRangeException(nameof(items), "must have at least one element in array."); EnsureOpen(); var storedItems = OnGet(items.Select(x => x as ITaskIdentifier).ToArray()); var cntUpdated = 0; var cntSkipped = 0; foreach (var storedItem in storedItems) { var item = items.First(x => x.Id == storedItem.Id); if (item != storedItem) { OnSetOne(item); cntUpdated++; Log(LogSeverityEnum.Debug, $"Task item '{item}' has been updated in storage."); } else { cntSkipped++; Log(LogSeverityEnum.Debug, $"Task item '{item}' skip to update. No relevant changes detected."); } } Log(LogSeverityEnum.Debug, $"Task items has been updated ({cntUpdated} or {items.Length}) in storage (skipped {cntSkipped} of {items.Length})."); } public void Delete(params ITaskIdentifier[] ids) { if (ids == null) throw new ArgumentNullException(nameof(ids)); if (ids.Length > 0) throw new ArgumentOutOfRangeException(nameof(ids), "must have at least one element in array."); EnsureOpen(); var items = OnGet(ids); foreach (var item in items) { OnDeleteOne(item); Log(LogSeverityEnum.Debug, $"Task item '{item}' has been deleted from storage."); } } public abstract IQueryable Query(params ProcessStatusEnum[] statuses); #region *** Private Operations & Virtuals *** protected virtual void Log(LogSeverityEnum type, string message, Exception? e = null) { _log.Log(type, message, e); } protected void EnsureOpen() { if (!IsOpen) Open(); } protected abstract void OnOpen(); protected abstract void OnClose(); protected abstract bool OnEnsureStorage(); protected abstract ITaskIdentifier OnCreate(ITaskItemData item); protected abstract ITaskItemData[] OnGet(ITaskIdentifier[] ids); protected abstract void OnDeleteOne(ITaskItemData item); protected abstract void OnSetOne(ITaskItemData item); #endregion }