feat(store): add kind column splitting manga and novel libraries

This commit is contained in:
2026-08-06 03:01:07 +07:00
parent 44a8df43e1
commit dcec12ae72
2 changed files with 132 additions and 12 deletions
+101
View File
@@ -660,3 +660,104 @@ func TestDisplayChapter(t *testing.T) {
t.Errorf("DisplayLatest() = %q, want %q", got, "Ch 11")
}
}
func TestUpsertKindDefaultsToManga(t *testing.T) {
store := newTestStore(t)
got, err := store.Upsert(Bookmark{
Key: "asura:solo", Site: "asura", SeriesID: "solo", UpdatedAt: 1000,
})
if err != nil {
t.Fatalf("Upsert: %v", err)
}
if got.Kind != KindManga {
t.Fatalf("Kind = %q, want %q", got.Kind, KindManga)
}
}
func TestUpsertKindRoundTrips(t *testing.T) {
store := newTestStore(t)
got, err := store.Upsert(Bookmark{
Key: "lightnovelworld:a-will-eternal", Site: "lightnovelworld",
SeriesID: "a-will-eternal", Kind: KindNovel, UpdatedAt: 1000,
})
if err != nil {
t.Fatalf("Upsert: %v", err)
}
if got.Kind != KindNovel {
t.Fatalf("Kind = %q, want %q", got.Kind, KindNovel)
}
}
// The real hazard: a client that predates the column sends no kind at all. That
// must keep the stored library, not silently demote a novel to manga.
func TestUpsertEmptyKindKeepsStoredValue(t *testing.T) {
store := newTestStore(t)
if _, err := store.Upsert(Bookmark{
Key: "lightnovelworld:a-will-eternal", Site: "lightnovelworld",
SeriesID: "a-will-eternal", Kind: KindNovel, LastChapterNum: 10, UpdatedAt: 1000,
}); err != nil {
t.Fatalf("seed: %v", err)
}
got, err := store.Upsert(Bookmark{
Key: "lightnovelworld:a-will-eternal", Site: "lightnovelworld",
SeriesID: "a-will-eternal", Kind: "", LastChapterNum: 11, UpdatedAt: 2000,
})
if err != nil {
t.Fatalf("Upsert: %v", err)
}
if got.Kind != KindNovel {
t.Fatalf("Kind = %q, want %q — an empty kind must not reset the library", got.Kind, KindNovel)
}
if got.LastChapterNum != 11 {
t.Fatalf("LastChapterNum = %v, want 11 — progress in the same request must still land", got.LastChapterNum)
}
}
// A database created before this column exists must gain it, backfilled as
// manga, without losing anything.
func TestLegacyDatabaseGainsKindAsManga(t *testing.T) {
dbPath := filepath.Join(t.TempDir(), "legacy.db")
legacy, err := sql.Open("sqlite", dbPath)
if err != nil {
t.Fatalf("open legacy db: %v", err)
}
if _, err := legacy.Exec(`
CREATE TABLE bookmarks (
key TEXT PRIMARY KEY,
site TEXT NOT NULL,
series_id TEXT NOT NULL,
title TEXT,
series_url TEXT,
cover TEXT,
last_chapter TEXT,
last_chapter_num REAL,
last_chapter_url TEXT,
updated_at INTEGER NOT NULL
)`); err != nil {
t.Fatalf("create legacy schema: %v", err)
}
if _, err := legacy.Exec(`
INSERT INTO bookmarks (key, site, series_id, title, updated_at)
VALUES ('asura:legacy', 'asura', 'legacy', 'Legacy Series', 123)`); err != nil {
t.Fatalf("seed legacy row: %v", err)
}
if err := legacy.Close(); err != nil {
t.Fatalf("close legacy db: %v", err)
}
store, err := Open(dbPath)
if err != nil {
t.Fatalf("Open on legacy db: %v", err)
}
t.Cleanup(func() { store.Close() })
list, err := store.List()
if err != nil {
t.Fatalf("List: %v", err)
}
if len(list) != 1 || list[0].Kind != KindManga {
t.Fatalf("legacy row should backfill as manga, got %+v", list)
}
}