package main import ( "fmt" "strings" ) // CreatePost — the canonical "make a new post" mutation. The bump_at is set // to the current time; the post is added to the postsByBumpedAt index; the // channels (if any) are added to the post_channels join map. type CreatePost struct { AuthorID string Title string Body string Channels []string // Set by Validate, used by Apply and AffectedAuthors. resolvedPostID string } func (m *CreatePost) Kind() string { return "create_post" } func (m *CreatePost) AffectedAuthors() []string { return []string{m.AuthorID} } func (m *CreatePost) Validate(s *Store) error { if strings.TrimSpace(m.AuthorID) == "" { return &ValidationError{Field: "author_id", Message: "required"} } if _, ok := s.GetAuthor(m.AuthorID); !ok { return &ValidationError{Field: "author_id", Message: fmt.Sprintf("unknown author %q", m.AuthorID)} } if strings.TrimSpace(m.Body) == "" { return &ValidationError{Field: "body", Message: "required"} } for _, ch := range m.Channels { if _, ok := s.GetChannel(ch); !ok { return &ValidationError{Field: "channels", Message: fmt.Sprintf("unknown channel %q", ch)} } } return nil } func (m *CreatePost) Apply(s *Store, lock LockRegion) error { now := s.Now() p := &Post{ ID: s.NewID(), AuthorID: m.AuthorID, Title: m.Title, Body: m.Body, BumpedAt: now, CreatedAt: now, UpdatedAt: now, Channels: append([]string(nil), m.Channels...), } m.resolvedPostID = p.ID s.mu.Lock() defer s.mu.Unlock() s.posts[p.ID] = p s.indexInsertPost(p) if len(m.Channels) > 0 { s.postChannels[p.ID] = append([]string(nil), m.Channels...) } return nil } func (m *CreatePost) ResolvedPostID() string { return m.resolvedPostID }