using Journal.Core.Models; namespace Journal.Core.Repositories; public class InMemoryFragmentRepository : IFragmentRepository { private readonly List _store = []; private readonly Lock _lock = new(); public List GetAll() { lock (_lock) { return _store.ToList(); } } public Fragment? GetById(Guid id) { lock (_lock) { return _store.FirstOrDefault(f => f.Id == id); } } public void Add(Fragment fragment) { if (fragment is null) throw new ArgumentNullException(nameof(fragment)); lock (_lock) { if (fragment.Tags != null) { fragment.Tags = [.. fragment.Tags .Where(t => !string.IsNullOrWhiteSpace(t)) .Select(t => t!.Trim())]; } if (!string.IsNullOrWhiteSpace(fragment.Type)) fragment.Type = fragment.Type.Trim(); if (!string.IsNullOrWhiteSpace(fragment.Description)) fragment.Description = fragment.Description.Trim(); _store.Add(fragment); } } public bool Remove(Guid id) { lock (_lock) { var item = _store.FirstOrDefault(f => f.Id == id); if (item is null) return false; return _store.Remove(item); } } public bool Update(Guid id, string? type = null, string? description = null, IEnumerable? tags = null, DateTimeOffset? time = null) { lock (_lock) { var item = _store.FirstOrDefault(f => f.Id == id); if (item is null) return false; if (type != null) { if (string.IsNullOrWhiteSpace(type)) throw new ArgumentException("Type cannot be empty", nameof(type)); item.Type = type.Trim(); } if (description != null) { if (string.IsNullOrWhiteSpace(description)) throw new ArgumentException("Description cannot be empty", nameof(description)); item.Description = description.Trim(); } if (tags != null) { item.Tags = [.. tags .Where(t => !string.IsNullOrWhiteSpace(t)) .Select(t => t!.Trim())]; } if (time.HasValue) item.Time = time.Value; return true; } } public List GetByTag(string tag) { var q = tag?.Trim(); if (string.IsNullOrWhiteSpace(q)) return []; lock (_lock) { return _store.Where(f => f.Tags?.Any(t => !string.IsNullOrWhiteSpace(t) && t.Contains(q, StringComparison.OrdinalIgnoreCase)) == true).ToList(); } } public List GetByType(string type) { var q = type?.Trim(); if (string.IsNullOrWhiteSpace(q)) return []; lock (_lock) { return _store.Where(f => !string.IsNullOrWhiteSpace(f.Type) && f.Type.Trim().Contains(q, StringComparison.OrdinalIgnoreCase)).ToList(); } } public List Search(string? type = null, string? tag = null, DateTimeOffset? timeAfter = null) { var results = _store.AsEnumerable(); var qType = type?.Trim(); var qTag = tag?.Trim(); lock (_lock) { if (!string.IsNullOrWhiteSpace(qType)) results = results.Where(f => !string.IsNullOrWhiteSpace(f.Type) && f.Type.Trim().Contains(qType, StringComparison.OrdinalIgnoreCase)); if (!string.IsNullOrWhiteSpace(qTag)) results = results.Where(f => f.Tags?.Any(t => !string.IsNullOrWhiteSpace(t) && t.Contains(qTag, StringComparison.OrdinalIgnoreCase)) == true); if (timeAfter.HasValue) results = results.Where(f => f.Time > timeAfter.Value); return results.ToList(); } } }