chore: init project
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
using InboxIntel.Application.Abstractions;
|
||||
using InboxIntel.Application.Common;
|
||||
using InboxIntel.Application.DTOs;
|
||||
using InboxIntel.Infrastructure.Persistence;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace InboxIntel.Infrastructure.Search;
|
||||
|
||||
/// <summary>
|
||||
/// Structured + full-text search. Structured filters compose as SQL WHERE
|
||||
/// clauses; free text uses PostgreSQL FTS via the generated SearchVector column
|
||||
/// (EF.Functions.ToTsVector/Matches translate to @@ / to_tsquery).
|
||||
/// </summary>
|
||||
public class SearchService : ISearchService
|
||||
{
|
||||
private readonly AppDbContext _db;
|
||||
public SearchService(AppDbContext db) => _db = db;
|
||||
|
||||
public async Task<PagedResult<EmailSummaryDto>> SearchAsync(Guid userId, SearchRequestDto r, CancellationToken ct = default)
|
||||
{
|
||||
var q = _db.Emails.AsNoTracking().Where(e => e.UserId == userId);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(r.Sender))
|
||||
q = q.Where(e => e.Sender!.Address.Contains(r.Sender) || e.Sender.DisplayName!.Contains(r.Sender));
|
||||
if (!string.IsNullOrWhiteSpace(r.Domain))
|
||||
q = q.Where(e => e.Sender!.Domain!.Name == r.Domain);
|
||||
if (r.From is { } from)
|
||||
q = q.Where(e => e.SentAtUtc >= new DateTimeOffset(from.ToDateTime(TimeOnly.MinValue), TimeSpan.Zero));
|
||||
if (r.To is { } to)
|
||||
q = q.Where(e => e.SentAtUtc <= new DateTimeOffset(to.ToDateTime(TimeOnly.MaxValue), TimeSpan.Zero));
|
||||
if (r.IsUnread is { } unread)
|
||||
q = q.Where(e => e.IsUnread == unread);
|
||||
if (r.HasAttachments is { } att)
|
||||
q = q.Where(e => e.HasAttachments == att);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(r.Query))
|
||||
{
|
||||
// PostgreSQL full-text match against the generated tsvector.
|
||||
var term = r.Query.Trim();
|
||||
q = q.Where(e => e.SearchVector!.Matches(EF.Functions.PlainToTsQuery("english", term)));
|
||||
}
|
||||
|
||||
var total = await q.CountAsync(ct);
|
||||
var items = await q
|
||||
.OrderByDescending(e => e.SentAtUtc)
|
||||
.Skip((r.Page - 1) * r.PageSize)
|
||||
.Take(r.PageSize)
|
||||
.Select(e => new EmailSummaryDto(
|
||||
e.Id, e.GmailMessageId, e.Subject, e.Snippet,
|
||||
e.Sender!.Address, e.Sender.DisplayName, e.SentAtUtc,
|
||||
e.IsUnread, e.HasAttachments, e.SizeEstimateBytes, e.Category))
|
||||
.ToListAsync(ct);
|
||||
|
||||
return new PagedResult<EmailSummaryDto>
|
||||
{
|
||||
Items = items, Page = r.Page, PageSize = r.PageSize, TotalCount = total
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user