add season and series to unified search result type

This commit is contained in:
Justin Edmund 2025-12-20 04:14:51 -08:00
parent 7793715a30
commit 18ab04b32d
2 changed files with 52 additions and 17 deletions

View file

@ -390,15 +390,7 @@ describe('SearchAdapter', () => {
global.fetch = vi.fn().mockResolvedValue({ global.fetch = vi.fn().mockResolvedValue({
ok: true, ok: true,
json: async () => ({ json: async () => ({
results: [], results: []
page: 2,
total_pages: 5,
meta: {
count: 0,
page: 2,
per_page: 20,
total_pages: 5
}
}) })
}) })
@ -420,8 +412,8 @@ describe('SearchAdapter', () => {
}) })
) )
expect(result.page).toBe(2) // Unified search only returns results, no pagination metadata
expect(result.totalPages).toBe(5) expect(result.results).toEqual([])
}) })
}) })
}) })

View file

@ -35,8 +35,9 @@ export interface SearchParams {
} }
/** /**
* Individual search result item * Individual search result item from type-specific search endpoints
* Represents a weapon, character, or summon * (searchWeapons, searchCharacters, searchSummons)
* These return full entity data with camelCase field names (transformed by BaseAdapter)
*/ */
export interface SearchResult { export interface SearchResult {
/** Unique entity ID */ /** Unique entity ID */
@ -65,7 +66,40 @@ export interface SearchResult {
} }
/** /**
* Search API response structure * Character series reference for unified search
*/
export interface UnifiedSearchSeriesRef {
id: string
slug: string
name: { en: string; ja: string }
}
/**
* Individual search result item from unified search endpoint (searchAll)
* Uses PgSearch.multisearch which returns different field structure
* Field names are camelCase after BaseAdapter transformation
*/
export interface UnifiedSearchResult {
/** Unique entity ID (from searchable_id) */
searchableId: string
/** Type of entity */
searchableType: 'Weapon' | 'Character' | 'Summon'
/** Granblue game ID */
granblueId: string
/** English name */
nameEn?: string
/** Japanese name */
nameJp?: string
/** Element type (1-6 for different elements) */
element?: number
/** Season (characters only) */
season?: number | null
/** Series (characters only) */
series?: UnifiedSearchSeriesRef[] | null
}
/**
* Search API response structure for type-specific endpoints
* Contains results and pagination metadata * Contains results and pagination metadata
*/ */
export interface SearchResponse { export interface SearchResponse {
@ -86,6 +120,14 @@ export interface SearchResponse {
} }
} }
/**
* Search API response structure for unified search endpoint
*/
export interface UnifiedSearchResponse {
/** Array of search results */
results: UnifiedSearchResult[]
}
/** /**
* Adapter for search-related API operations * Adapter for search-related API operations
* Handles entity search with filtering, pagination, and caching * Handles entity search with filtering, pagination, and caching
@ -221,11 +263,12 @@ export class SearchAdapter extends BaseAdapter {
/** /**
* Searches across all entity types (weapons, characters, summons) * Searches across all entity types (weapons, characters, summons)
* Uses PgSearch.multisearch which returns a different response structure
* *
* @param params - Search parameters * @param params - Search parameters
* @returns Promise resolving to search results * @returns Promise resolving to unified search results
*/ */
async searchAll(params: SearchParams = {}): Promise<SearchResponse> { async searchAll(params: SearchParams = {}): Promise<UnifiedSearchResponse> {
const body = this.buildSearchBody(params, { const body = this.buildSearchBody(params, {
element: true, element: true,
rarity: true, rarity: true,
@ -243,7 +286,7 @@ export class SearchAdapter extends BaseAdapter {
// Search endpoints don't use credentials to avoid CORS // Search endpoints don't use credentials to avoid CORS
// Rails expects params nested under 'search' key // Rails expects params nested under 'search' key
// Per-page is sent via X-Per-Page header // Per-page is sent via X-Per-Page header
return this.request<SearchResponse>('/search/all', { return this.request<UnifiedSearchResponse>('/search', {
method: 'POST', method: 'POST',
body: { search: body }, body: { search: body },
credentials: 'omit', credentials: 'omit',