summaryrefslogtreecommitdiffstats
path: root/internal/db/posts_test.go
diff options
context:
space:
mode:
authorivar <i@oiee.no>2026-04-04 16:10:52 +0200
committerivar <i@oiee.no>2026-04-04 16:10:52 +0200
commitf045a49e6feb6f448faea073821a9661f8b710a3 (patch)
tree8dcb53284d3f35b8ae2e4d1ca180c223b5d02784 /internal/db/posts_test.go
parentd239993644aae8c29d5fc37e8c6209850140807c (diff)
downloadnebbet.no-f045a49e6feb6f448faea073821a9661f8b710a3.tar.xz
nebbet.no-f045a49e6feb6f448faea073821a9661f8b710a3.zip
feat: add RenamePost with transactional rename and redirect creation
Implement RenamePost method that atomically: 1. Fetches the post record by old slug 2. Inserts a new record with the new slug 3. Deletes the old slug post 4. Collapses redirect chains (updates any redirects pointing to oldSlug to point to newSlug) 5. Creates a redirect from oldSlug to newSlug All operations are transactional (all-or-nothing). Includes two comprehensive tests: - TestRenamePost: basic rename with redirect creation and old slug deletion - TestRenamePost_CollapsesChain: verifies redirect chains are collapsed correctly Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/db/posts_test.go')
-rw-r--r--internal/db/posts_test.go70
1 files changed, 70 insertions, 0 deletions
diff --git a/internal/db/posts_test.go b/internal/db/posts_test.go
index ec596c3..26664ce 100644
--- a/internal/db/posts_test.go
+++ b/internal/db/posts_test.go
@@ -78,3 +78,73 @@ func TestAddRedirect_Upsert(t *testing.T) {
t.Errorf("got %q, want %q", got, "second")
}
}
+
+func TestRenamePost(t *testing.T) {
+ m := openTestDB(t)
+
+ original := PostRecord{
+ Slug: "original-slug",
+ Title: "My Post",
+ Date: "2026-04-04",
+ Tags: []string{"go"},
+ Draft: false,
+ Blocks: `[{"type":"paragraph","data":{"text":"hello"}}]`,
+ UpdatedAt: 1000000,
+ }
+ if err := m.UpsertPost(original); err != nil {
+ t.Fatalf("UpsertPost: %v", err)
+ }
+
+ if err := m.RenamePost("original-slug", "new-slug"); err != nil {
+ t.Fatalf("RenamePost: %v", err)
+ }
+
+ // New slug exists with same content
+ got, err := m.GetPost("new-slug")
+ if err != nil {
+ t.Fatalf("GetPost new-slug: %v", err)
+ }
+ if got.Title != "My Post" {
+ t.Errorf("title: got %q, want %q", got.Title, "My Post")
+ }
+
+ // Old slug is gone
+ _, err = m.GetPost("original-slug")
+ if err == nil {
+ t.Error("expected old slug to be deleted, but GetPost returned no error")
+ }
+
+ // Redirect exists
+ toSlug, err := m.GetRedirect("original-slug")
+ if err != nil {
+ t.Fatalf("GetRedirect: %v", err)
+ }
+ if toSlug != "new-slug" {
+ t.Errorf("redirect: got %q, want %q", toSlug, "new-slug")
+ }
+}
+
+func TestRenamePost_CollapsesChain(t *testing.T) {
+ m := openTestDB(t)
+
+ // Create post at "b"
+ if err := m.UpsertPost(PostRecord{Slug: "b", Title: "B", Blocks: "[]", UpdatedAt: 1}); err != nil {
+ t.Fatalf("UpsertPost: %v", err)
+ }
+ // Existing redirect a -> b
+ if err := m.AddRedirect("a", "b"); err != nil {
+ t.Fatalf("AddRedirect: %v", err)
+ }
+ // Rename b -> c: should collapse a -> c
+ if err := m.RenamePost("b", "c"); err != nil {
+ t.Fatalf("RenamePost: %v", err)
+ }
+
+ got, err := m.GetRedirect("a")
+ if err != nil {
+ t.Fatalf("GetRedirect a: %v", err)
+ }
+ if got != "c" {
+ t.Errorf("chain collapse: got %q, want %q", got, "c")
+ }
+}