using System; using System.Collections.Generic; using System.Linq; using System.Security.Principal; using System.Text; using System.Threading.Tasks; namespace Blog3000.Shared { public class BlogPostSearch { private readonly Func> postSource; private readonly Func> headerSource; private readonly string searchTerm; private readonly List tokens = new List(); private bool invalidTermsRemoved; /// /// /// /// searchTerm or NULL to return the latest items only public BlogPostSearch( Func> postSource, Func> headerSource, string searchTerm) { this.postSource = postSource; this.headerSource = headerSource; this.searchTerm = searchTerm; TokenizeTerm(); } public bool IsNonEmptyTerm { get { return tokens.Count > 0; } } public bool InvalidTermsRemoved { get { return invalidTermsRemoved; } } public bool RequiresFullText { get { return tokens.Where(c => !c.StartsWith("#")).FirstOrDefault() != null; } } /// /// /// /// Search results or latest items when searchterm is null public async Task> ExecAsync( int startIdx, int pageMaxSize, bool findLastPage) { IAsyncEnumerable fetch; if (!IsNonEmptyTerm) { fetch = headerSource() .Where(p => (p.StickyMenuPos ?? -1) < 0) .OrderByDescending(p => p.Revisions?.Latest()?.ChangedAt ?? DateTime.MinValue) .ThenByDescending(p => p.Title); } else { if (!RequiresFullText) { var efetch = headerSource(); foreach (var tok in tokens) { if (tok.StartsWith("#")) { efetch = efetch .Where( p => ( ((p.Topics != null) && (p.Topics.Find(t => t.ToLowerInvariant().Contains(tok)) != null)) ) ); } } fetch = efetch; } else { var efetch = postSource(); foreach (var tok in tokens) { System.Diagnostics.Debug.WriteLine($"Tok: {tok}"); if (tok.StartsWith("#")) { efetch = efetch .Where( p => ( ((p.Topics != null) && (p.Topics.Find(t => t.ToLowerInvariant().Contains(tok)) != null)) ) ); } else { efetch = ((IAsyncEnumerable)efetch) .Where( p => ( ((p.Title?.ToLowerInvariant() ?? "").Contains(tok)) || ((p.Text?.ToLowerInvariant() ?? "").Contains(tok)) || ((p.Abstract?.ToLowerInvariant() ?? "").Contains(tok)) || ((p.Topics != null) && (p.Topics.Find(t => t.ToLowerInvariant().Contains(tok)) != null)) ) ); } } fetch = efetch; } fetch = fetch .OrderByDescending(p => p.Revisions?.Latest()?.ChangedAt ?? DateTime.MinValue) .OrderByDescending(p => p.Title); } List res; if (!findLastPage) { res = await fetch .Skip(startIdx) .Take(pageMaxSize) .ToListAsync(); } else { var count = await fetch.CountAsync(); var sidx = count - pageMaxSize; if (sidx < 0) sidx = 0; res = await fetch .Skip(sidx) .Take(pageMaxSize) .ToListAsync(); } return res; } private void TokenizeTerm() { if (searchTerm != null) { foreach (var t in searchTerm.ToLowerInvariant().Split(" ")) // Improve { if (!String.IsNullOrWhiteSpace(t) && (t.Length >= 2)) { tokens.Add(t); } else invalidTermsRemoved = true; } } } } }