package forum import ( "fmt" "time" "dk/internal/database" "zombiezen.com/go/sqlite" ) // Builder provides a fluent interface for creating forum posts type Builder struct { forum *Forum db *database.DB } // NewBuilder creates a new forum post builder func NewBuilder(db *database.DB) *Builder { now := time.Now().Unix() return &Builder{ forum: &Forum{ db: db, Posted: now, LastPost: now, // Default to same as posted time Parent: 0, // Default to thread (no parent) Replies: 0, // Default to no replies }, db: db, } } // WithAuthor sets the author user ID func (b *Builder) WithAuthor(authorID int) *Builder { b.forum.Author = authorID return b } // WithTitle sets the forum post title func (b *Builder) WithTitle(title string) *Builder { b.forum.Title = title return b } // WithContent sets the forum post content func (b *Builder) WithContent(content string) *Builder { b.forum.Content = content return b } // WithParent sets the parent post ID (for replies) func (b *Builder) WithParent(parentID int) *Builder { b.forum.Parent = parentID return b } // AsReply is a convenience method to set this as a reply to another post func (b *Builder) AsReply(parentID int) *Builder { return b.WithParent(parentID) } // AsThread ensures this is a top-level thread (parent = 0) func (b *Builder) AsThread() *Builder { b.forum.Parent = 0 return b } // WithPosted sets the posted timestamp func (b *Builder) WithPosted(posted int64) *Builder { b.forum.Posted = posted return b } // WithPostedTime sets the posted timestamp from a time.Time func (b *Builder) WithPostedTime(t time.Time) *Builder { b.forum.Posted = t.Unix() return b } // WithLastPost sets the last post timestamp func (b *Builder) WithLastPost(lastPost int64) *Builder { b.forum.LastPost = lastPost return b } // WithLastPostTime sets the last post timestamp from a time.Time func (b *Builder) WithLastPostTime(t time.Time) *Builder { b.forum.LastPost = t.Unix() return b } // WithReplies sets the initial reply count func (b *Builder) WithReplies(replies int) *Builder { b.forum.Replies = replies return b } // Create saves the forum post to the database and returns the created post with ID func (b *Builder) Create() (*Forum, error) { // Use a transaction to ensure we can get the ID var forum *Forum err := b.db.Transaction(func(tx *database.Tx) error { query := `INSERT INTO forum (posted, last_post, author, parent, replies, title, content) VALUES (?, ?, ?, ?, ?, ?, ?)` if err := tx.Exec(query, b.forum.Posted, b.forum.LastPost, b.forum.Author, b.forum.Parent, b.forum.Replies, b.forum.Title, b.forum.Content); err != nil { return fmt.Errorf("failed to insert forum post: %w", err) } // Get the last insert ID var id int err := tx.Query("SELECT last_insert_rowid()", func(stmt *sqlite.Stmt) error { id = stmt.ColumnInt(0) return nil }) if err != nil { return fmt.Errorf("failed to get insert ID: %w", err) } b.forum.ID = id forum = b.forum return nil }) if err != nil { return nil, err } return forum, nil }