165 lines
5.3 KiB
C#
165 lines
5.3 KiB
C#
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<IAsyncEnumerable<BlogPost>> postSource;
|
|
private readonly Func<IAsyncEnumerable<BlogPostHeader>> headerSource;
|
|
private readonly string searchTerm;
|
|
|
|
|
|
private readonly List<string> tokens = new List<string>();
|
|
|
|
private bool invalidTermsRemoved;
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="searchTerm">searchTerm or NULL to return the latest items only</param>
|
|
public BlogPostSearch(
|
|
Func<IAsyncEnumerable<BlogPost>> postSource,
|
|
Func<IAsyncEnumerable<BlogPostHeader>> 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; }
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <returns>Search results or latest items when searchterm is null</returns>
|
|
public async Task<List<BlogPostHeader>> ExecAsync(
|
|
int startIdx, int pageMaxSize, bool findLastPage)
|
|
{
|
|
IAsyncEnumerable<BlogPostHeader> 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<BlogPost>)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<BlogPostHeader> 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|