mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 00:11:37 -06:00
fix(books): honour the metadata score sort when series are collapsed
The collapsed order by had no metadataScore case, so the sort was dropped and the list fell back to title order. Order by metadata_score there and select it in the collapsed jump-bucket query that shares the order by. Fixes #1638
This commit is contained in:
@@ -41,6 +41,7 @@ import {
|
||||
CUSTOM_FIELD_TYPE_OPERATORS,
|
||||
EMPTY_CONTENT_FILTER_RULES,
|
||||
FIELD_OPERATORS,
|
||||
SORT_FIELDS,
|
||||
customRuleField,
|
||||
type CustomMetadataFieldType,
|
||||
type RuleField,
|
||||
@@ -1987,6 +1988,15 @@ describe('BookQueryBuilder.buildCollapseOrderBy', () => {
|
||||
expect(BookQueryBuilder.buildCollapseOrderBy([{ field: 'updatedAt', dir: 'asc' }], 1)).toBe('updated_at ASC NULLS LAST, r.id ASC');
|
||||
});
|
||||
|
||||
it('generates metadataScore sort against the representative row', () => {
|
||||
expect(BookQueryBuilder.buildCollapseOrderBy([{ field: 'metadataScore', dir: 'asc' }], 1)).toBe('metadata_score ASC NULLS LAST, r.id ASC');
|
||||
expect(BookQueryBuilder.buildCollapseOrderBy([{ field: 'metadataScore', dir: 'desc' }], 1)).toBe('metadata_score DESC NULLS LAST, r.id ASC');
|
||||
});
|
||||
|
||||
it.each(SORT_FIELDS.filter((field) => field !== 'relevance'))('honours the %s browse sort instead of falling back to title', (field) => {
|
||||
expect(BookQueryBuilder.buildCollapseOrderBy([{ field, dir: 'desc' }], 1)).not.toBe('sort_title ASC NULLS LAST, r.id ASC');
|
||||
});
|
||||
|
||||
it('generates fileSize sort using the primary file', () => {
|
||||
expect(BookQueryBuilder.buildCollapseOrderBy([{ field: 'fileSize', dir: 'desc' }], 1)).toBe(
|
||||
'(SELECT bf.size_bytes FROM book_files bf WHERE bf.id = r.primary_file_id) DESC NULLS LAST, r.id ASC',
|
||||
|
||||
@@ -1166,6 +1166,9 @@ export class BookQueryBuilder {
|
||||
case 'pageCount':
|
||||
parts.push(`page_count ${D} NULLS LAST`);
|
||||
break;
|
||||
case 'metadataScore':
|
||||
parts.push(`metadata_score ${D} NULLS LAST`);
|
||||
break;
|
||||
case 'updatedAt':
|
||||
parts.push(`updated_at ${D} NULLS LAST`);
|
||||
break;
|
||||
|
||||
@@ -1275,6 +1275,7 @@ export class BookRepository {
|
||||
book_metadata.published_year,
|
||||
book_metadata.publisher,
|
||||
book_metadata.page_count,
|
||||
book_metadata.metadata_score,
|
||||
NULLIF(lower(btrim(book_metadata.series_name)), '') AS norm_series
|
||||
${source.baseExtraSelect}
|
||||
FROM books
|
||||
@@ -1301,6 +1302,7 @@ export class BookRepository {
|
||||
base.published_year,
|
||||
base.publisher,
|
||||
base.page_count,
|
||||
base.metadata_score,
|
||||
ubr.rating,
|
||||
base.primary_author_sort_name AS author_sort_name,
|
||||
COALESCE(base.norm_series, lower(base.title)) AS sort_title,
|
||||
|
||||
@@ -396,6 +396,22 @@ describe('Jump buckets invariant (e2e)', { timeout: SCENARIO_TIMEOUT_MS }, () =>
|
||||
}
|
||||
}
|
||||
|
||||
it('applies a secondary metadataScore tier to collapsed buckets without breaking the anchors', async () => {
|
||||
const sort: SortSpec[] = [
|
||||
{ field: 'title', dir: 'asc' },
|
||||
{ field: 'metadataScore', dir: 'desc' },
|
||||
];
|
||||
const [bucketsResponse, listing] = await Promise.all([fetchBuckets(sort, true), fetchListing(sort, true)]);
|
||||
|
||||
expect(bucketsResponse.total).toBe(listing.total);
|
||||
expect(bucketsResponse.buckets.length).toBeGreaterThan(1);
|
||||
for (const bucket of bucketsResponse.buckets) {
|
||||
const seeded = seededById.get((listing.items[bucket.index] as BookCard).id);
|
||||
expect(seeded).toBeDefined();
|
||||
expect(expectedBucketKey(seeded!, 'title', true, bucketsResponse.granularity)).toBe(bucket.key);
|
||||
}
|
||||
});
|
||||
|
||||
it('preserves every populated year when sparse years fit the bounded capacity', async () => {
|
||||
const response = await fetchBuckets([{ field: 'publishedYear', dir: 'asc' }], false);
|
||||
const expectedYears = [...new Set([...seededById.values()].flatMap((book) => (book.publishedYear === null ? [] : [String(book.publishedYear)])))];
|
||||
|
||||
Reference in New Issue
Block a user