Cleanup the search people API method

This commit is contained in:
Joseph Milazzo 2025-05-09 15:25:49 -05:00
parent a5c1c2e75f
commit 19d2e20f24
6 changed files with 22 additions and 17 deletions

View file

@ -48,10 +48,15 @@ public class PersonController : BaseApiController
return Ok(await _unitOfWork.PersonRepository.GetPersonDtoByName(name, User.GetUserId())); return Ok(await _unitOfWork.PersonRepository.GetPersonDtoByName(name, User.GetUserId()));
} }
[HttpGet("search-people")] /// <summary>
public async Task<ActionResult<List<PersonDto>>> SearchPeople([FromQuery] string name) /// Find a person by name or alias against a query string
/// </summary>
/// <param name="queryString"></param>
/// <returns></returns>
[HttpGet("search")]
public async Task<ActionResult<List<PersonDto>>> SearchPeople([FromQuery] string queryString)
{ {
var people = await _unitOfWork.PersonRepository.SearchPeople(name); var people = await _unitOfWork.PersonRepository.SearchPeople(queryString);
return Ok(people.Select(person => _mapper.Map<PersonDto>(person)).ToList()); return Ok(people.Select(person => _mapper.Map<PersonDto>(person)).ToList());
} }

View file

@ -68,7 +68,7 @@ public interface IPersonRepository
Task<IList<Person>> GetPeopleByNames(List<string> normalizedNames, PersonIncludes includes = PersonIncludes.Aliases); Task<IList<Person>> GetPeopleByNames(List<string> normalizedNames, PersonIncludes includes = PersonIncludes.Aliases);
Task<Person?> GetPersonByAniListId(int aniListId, PersonIncludes includes = PersonIncludes.Aliases); Task<Person?> GetPersonByAniListId(int aniListId, PersonIncludes includes = PersonIncludes.Aliases);
Task<IList<Person>> SearchPeople(string query, PersonIncludes includes = PersonIncludes.Aliases); Task<IList<Person>> SearchPeople(string searchQuery, PersonIncludes includes = PersonIncludes.Aliases);
} }
public class PersonRepository : IPersonRepository public class PersonRepository : IPersonRepository
@ -305,12 +305,14 @@ public class PersonRepository : IPersonRepository
.FirstOrDefaultAsync(); .FirstOrDefaultAsync();
} }
public async Task<IList<Person>> SearchPeople(string query, PersonIncludes includes = PersonIncludes.Aliases) public async Task<IList<Person>> SearchPeople(string searchQuery, PersonIncludes includes = PersonIncludes.Aliases)
{ {
searchQuery = searchQuery.ToNormalized();
return await _context.Person return await _context.Person
.Includes(includes) .Includes(includes)
.Where(p => EF.Functions.Like(p.Name, $"%{query}%") .Where(p => EF.Functions.Like(p.Name, $"%{searchQuery}%")
|| p.Aliases.Any(pa => EF.Functions.Like(pa.Alias, $"%{query}%"))) || p.Aliases.Any(pa => EF.Functions.Like(pa.Alias, $"%{searchQuery}%")))
.ToListAsync(); .ToListAsync();
} }

View file

@ -2,16 +2,13 @@ import { Injectable } from '@angular/core';
import {HttpClient, HttpParams} from "@angular/common/http"; import {HttpClient, HttpParams} from "@angular/common/http";
import {environment} from "../../environments/environment"; import {environment} from "../../environments/environment";
import {Person, PersonRole} from "../_models/metadata/person"; import {Person, PersonRole} from "../_models/metadata/person";
import {SeriesFilterV2} from "../_models/metadata/v2/series-filter-v2";
import {PaginatedResult} from "../_models/pagination"; import {PaginatedResult} from "../_models/pagination";
import {Series} from "../_models/series"; import {Series} from "../_models/series";
import {map} from "rxjs/operators"; import {map} from "rxjs/operators";
import {UtilityService} from "../shared/_services/utility.service"; import {UtilityService} from "../shared/_services/utility.service";
import {BrowsePerson} from "../_models/person/browse-person"; import {BrowsePerson} from "../_models/person/browse-person";
import {Chapter} from "../_models/chapter";
import {StandaloneChapter} from "../_models/standalone-chapter"; import {StandaloneChapter} from "../_models/standalone-chapter";
import {TextResonse} from "../_types/text-response"; import {TextResonse} from "../_types/text-response";
import {al} from "@angular/router/router_module.d-6zbCxc1T";
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -31,7 +28,7 @@ export class PersonService {
} }
searchPerson(name: string) { searchPerson(name: string) {
return this.httpClient.get<Array<Person>>(this.baseUrl + `person/search-people?name=${name}`); return this.httpClient.get<Array<Person>>(this.baseUrl + `person/search?queryString=${encodeURIComponent(name)}`);
} }
getRolesForPerson(personId: number) { getRolesForPerson(personId: number) {

View file

@ -5,7 +5,8 @@ import {
AsyncValidatorFn, AsyncValidatorFn,
FormControl, FormControl,
FormGroup, FormGroup,
ReactiveFormsModule, ValidationErrors, ReactiveFormsModule,
ValidationErrors,
Validators Validators
} from "@angular/forms"; } from "@angular/forms";
import {Person} from "../../../_models/metadata/person"; import {Person} from "../../../_models/metadata/person";
@ -27,7 +28,6 @@ import {SettingItemComponent} from "../../../settings/_components/setting-item/s
import {AccountService} from "../../../_services/account.service"; import {AccountService} from "../../../_services/account.service";
import {ToastrService} from "ngx-toastr"; import {ToastrService} from "ngx-toastr";
import {EditListComponent} from "../../../shared/edit-list/edit-list.component"; import {EditListComponent} from "../../../shared/edit-list/edit-list.component";
import {al} from "@angular/router/router_module.d-6zbCxc1T";
enum TabID { enum TabID {
General = 'general-tab', General = 'general-tab',

View file

@ -73,6 +73,7 @@ export class MergePersonModalComponent implements OnInit {
} }
this.typeAheadSettings.fetchFn = (filter: string) => { this.typeAheadSettings.fetchFn = (filter: string) => {
if (filter.length == 0) return of([]); if (filter.length == 0) return of([]);
return this.personService.searchPerson(filter).pipe(map(people => { return this.personService.searchPerson(filter).pipe(map(people => {
return people.filter(p => this.utilityService.filter(p.name, filter) && p.id != this.person.id); return people.filter(p => this.utilityService.filter(p.name, filter) && p.id != this.person.id);
})); }));

View file

@ -10,7 +10,7 @@ import {
} from '@angular/core'; } from '@angular/core';
import {ActivatedRoute, Router} from "@angular/router"; import {ActivatedRoute, Router} from "@angular/router";
import {PersonService} from "../_services/person.service"; import {PersonService} from "../_services/person.service";
import {BehaviorSubject, EMPTY, Observable, of, switchMap, tap} from "rxjs"; import {BehaviorSubject, EMPTY, Observable, switchMap, tap} from "rxjs";
import {Person, PersonRole} from "../_models/metadata/person"; import {Person, PersonRole} from "../_models/metadata/person";
import {AsyncPipe} from "@angular/common"; import {AsyncPipe} from "@angular/common";
import {ImageComponent} from "../shared/image/image.component"; import {ImageComponent} from "../shared/image/image.component";
@ -19,7 +19,7 @@ import {
SideNavCompanionBarComponent SideNavCompanionBarComponent
} from "../sidenav/_components/side-nav-companion-bar/side-nav-companion-bar.component"; } from "../sidenav/_components/side-nav-companion-bar/side-nav-companion-bar.component";
import {ReadMoreComponent} from "../shared/read-more/read-more.component"; import {ReadMoreComponent} from "../shared/read-more/read-more.component";
import {TagBadgeComponent, TagBadgeCursor} from "../shared/tag-badge/tag-badge.component"; import {TagBadgeCursor} from "../shared/tag-badge/tag-badge.component";
import {PersonRolePipe} from "../_pipes/person-role.pipe"; import {PersonRolePipe} from "../_pipes/person-role.pipe";
import {CarouselReelComponent} from "../carousel/_components/carousel-reel/carousel-reel.component"; import {CarouselReelComponent} from "../carousel/_components/carousel-reel/carousel-reel.component";
import {FilterComparison} from "../_models/metadata/v2/filter-comparison"; import {FilterComparison} from "../_models/metadata/v2/filter-comparison";