@page "/search"
@page "/search/{SearchTerms}"
@using Microsoft.EntityFrameworkCore
@using Microsoft.Extensions.Logging
@using MudBlazor
@using NpgsqlTypes
@using OpenArchival.DataAccess
@using Persic
@using Npgsql.EntityFrameworkCore.PostgreSQL
@using System.Linq
@using System.Linq.Expressions
@using OpenArchival.Blazor.ArtifactGroupingDisplay
All
Tags
Defects
Listed Names
Title
Description
Filenames
Artifact Transcriptions
@if (_totalResults > 0)
{
@_totalResults results found
}
@if (_artifactGroupings.Count > 0)
{
@foreach (var grouping in _artifactGroupings)
{
}
}
@inject IDbContextFactory ContextFactory;
@inject ILogger Logger;
@inject NavigationManager NavigationManager;
@code {
public enum SearchFilterType
{
All,
Tags,
Defects,
ListedNames,
Title,
Description,
Filenames,
ArtifactTranscriptions
}
[Parameter]
public string SearchTerms { get; set; } = "";
private SearchFilterType _selectedFilter = SearchFilterType.All;
private List _artifactGroupings { get; set; } = [];
private int _currentPage { get; set; } = 1;
private int _totalPages { get; set; } = 0;
private int _totalResults { get; set; } = 0;
private const int PageSize = 20;
// Field to store the current filter logic
private Expression> _currentFilterPredicate;
protected override async Task OnParametersSetAsync()
{
if (!string.IsNullOrWhiteSpace(SearchTerms))
{
await PerformSearchAsync();
}
}
private async Task HandleSearchKeyDown(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs args)
{
if (args.Key != "Enter" || string.IsNullOrWhiteSpace(SearchTerms))
{
return;
}
NavigationManager.NavigateTo($"/search/{SearchTerms}");
await PerformSearchAsync();
}
///
/// Sets the search predicate, calculates total results, and loads the first page.
///
private async Task PerformSearchAsync()
{
// Determine which filter expression to use based on the radio button selection
switch (_selectedFilter)
{
case SearchFilterType.Tags:
_currentFilterPredicate = x => x.TagsSearchVector.Matches(SearchTerms);
break;
case SearchFilterType.Title:
_currentFilterPredicate = x => x.TitleSearchVector.Matches(SearchTerms);
break;
case SearchFilterType.Description:
_currentFilterPredicate = x => x.DescriptionSearchVector.Matches(SearchTerms);
break;
case SearchFilterType.Defects:
_currentFilterPredicate = x => x.DefectsSearchVector.Matches(SearchTerms);
break;
case SearchFilterType.Filenames:
_currentFilterPredicate = x => x.FilenamesSearchVector.Matches(SearchTerms);
break;
case SearchFilterType.ArtifactTranscriptions:
_currentFilterPredicate = x => x.FileContentSearchVector.Matches(SearchTerms);
break;
case SearchFilterType.ListedNames:
_currentFilterPredicate = x => x.ListedNamesSearchVector.Matches(SearchTerms);
break;
case SearchFilterType.All:
default:
_currentFilterPredicate = x => x.AllSearchVector.Matches(SearchTerms);
break;
}
// Get the total count using the chosen filter
await using var context = await ContextFactory.CreateDbContextAsync();
_totalResults = await context.ArtifactGroupings.Where(_currentFilterPredicate).CountAsync();
_totalPages = (int)Math.Ceiling(_totalResults / (double)PageSize);
// Load the first page with the chosen filter
await LoadPageAsync(1);
}
private async Task OnPageChangedAsync(int page)
{
await LoadPageAsync(page);
}
///
/// Fetches a specific page of data from the database using the currently set filter.
///
private async Task LoadPageAsync(int page)
{
_currentPage = page;
if (_currentFilterPredicate == null) // Don't run if no search has been performed
{
return;
}
await using var context = await ContextFactory.CreateDbContextAsync();
// The query uses the dynamically set filter predicate
_artifactGroupings = await context.ArtifactGroupings
.Where(_currentFilterPredicate)
.Include(x => x.ChildArtifactEntries)
.ThenInclude(x => x.Files)
.OrderBy(x => x.Id)
.Skip((_currentPage - 1) * PageSize)
.Take(PageSize)
.ToListAsync();
StateHasChanged();
}
}