Sort the story list without a leading The, A or An

This commit is contained in:
tim
2026-09-27 23:38:28 +02:00
parent df9959a078
commit ee611cd283
2 changed files with 19 additions and 2 deletions
+11 -2
View File
@@ -6,6 +6,7 @@ site without losing text.
""" """
import json import json
import re
import sqlite3 import sqlite3
from collections.abc import Iterator from collections.abc import Iterator
from contextlib import contextmanager from contextlib import contextmanager
@@ -120,6 +121,14 @@ def _story(row: sqlite3.Row | None) -> dict[str, Any] | None:
return d return d
_ARTICLE = re.compile(r"^(?:the|an?)\s+", re.I)
def sort_title(title: str | None) -> str:
"""The key that sorts a story list by title, without a leading "The", "A" or "An"."""
return _ARTICLE.sub("", (title or "").strip()).casefold()
class Store: class Store:
def __init__(self, path: Path) -> None: def __init__(self, path: Path) -> None:
self.path = Path(path) self.path = Path(path)
@@ -190,8 +199,8 @@ class Store:
AND c.on_site = 0) AS offsite_count, AND c.on_site = 0) AS offsite_count,
(SELECT COUNT(*) FROM chapters c WHERE c.story_id = s.id AND c.included = 1 (SELECT COUNT(*) FROM chapters c WHERE c.story_id = s.id AND c.included = 1
AND (SELECT COUNT(*) FROM revisions r WHERE r.chapter_id = c.id) > 1) AS revised_count AND (SELECT COUNT(*) FROM revisions r WHERE r.chapter_id = c.id) > 1) AS revised_count
FROM stories s ORDER BY s.title COLLATE NOCASE""").fetchall() FROM stories s""").fetchall()
return [_story(r) for r in rows] return [_story(r) for r in sorted(rows, key=lambda r: sort_title(r["title"]))]
def update_story(self, story_id: int, **fields: Any) -> None: def update_story(self, story_id: int, **fields: Any) -> None:
if not fields: if not fields:
+8
View File
@@ -47,6 +47,14 @@ def test_list_stories_counts_offsite_and_revised_chapters(tmp_path):
assert story["revised_count"] == 1 assert story["revised_count"] == 1
def test_list_stories_sorts_titles_without_leading_articles(tmp_path):
store = Store(tmp_path / "db.sqlite")
for n, title in enumerate(["The Zebra", "an Owl", "Anthem", "A Bee", "Theory", "Cat"]):
store.create_story(f"https://example/s/{n}", "example", title, "A", [])
titles = [s["title"] for s in store.list_stories()]
assert titles == ["Anthem", "A Bee", "Cat", "an Owl", "Theory", "The Zebra"]
def test_cover_replaces_previous_cover(tmp_path): def test_cover_replaces_previous_cover(tmp_path):
store = Store(tmp_path / "db.sqlite") store = Store(tmp_path / "db.sqlite")
sid = store.create_story("u", "s", "T", "A", []) sid = store.create_story("u", "s", "T", "A", [])