Documentation
¶
Index ¶
- Variables
- func ValidateArticle(v *validator.Validator, article *Article)
- func ValidateComment(v *validator.Validator, comment *Comment)
- func ValidateEmail(v *validator.Validator, email string)
- func ValidatePasswordPlaintext(v *validator.Validator, password string)
- func ValidateUser(v *validator.Validator, user User)
- type Article
- type ArticleFilters
- type ArticleStore
- func (s *ArticleStore) DeleteBySlug(slug string, authorID int64) error
- func (s *ArticleStore) FavoriteBySlug(slug string, userID int64) (*Article, error)
- func (s *ArticleStore) GetBySlug(slug string, currentUser *User) (*Article, error)
- func (s *ArticleStore) GetIDBySlug(slug string) (int64, error)
- func (s *ArticleStore) InsertAndReturn(article *Article, currentUser *User) (*Article, error)
- func (s *ArticleStore) InsertTags(tags ...string) error
- func (s *ArticleStore) List(filters ArticleFilters, currentUser *User) ([]Article, int, error)
- func (s *ArticleStore) UnfavoriteBySlug(slug string, userID int64) (*Article, error)
- func (s *ArticleStore) Update(article *Article) error
- type ArticleStoreInterface
- type Comment
- type CommentStore
- type CommentStoreInterface
- type ModelStore
- type Profile
- type TagStore
- type TagStoreInterface
- type User
- type UserCache
- type UserStore
- func (s UserStore) FollowUser(followerID, followedID int64) error
- func (s UserStore) GetByEmail(email string) (*User, error)
- func (s UserStore) GetByID(id int64) (*User, error)
- func (s UserStore) GetByUsername(username string) (*User, error)
- func (s UserStore) Insert(user *User) error
- func (s UserStore) IsFollowing(followerID, followedID int64) (bool, error)
- func (s UserStore) UnfollowUser(followerID, followedID int64) error
- func (s UserStore) Update(user *User) error
- type UserStoreInterface
Constants ¶
This section is empty.
Variables ¶
var ( ErrRecordNotFound = errors.New("record not found") ErrEditConflict = errors.New("edit conflict") )
var ( ErrDuplicateEmail = errors.New("duplicate email") ErrDuplicateUsername = errors.New("duplicate username") )
var AnonymousUser = &User{}
Functions ¶
func ValidateArticle ¶
func ValidateComment ¶
func ValidateEmail ¶
func ValidateUser ¶
ValidateUser checks the values provided by the user are valid. It performs validation on the Name, Email and Password fields.
Types ¶
type Article ¶
type Article struct {
ID int64 `json:"-"`
Slug string `json:"slug"`
Title string `json:"title"`
Description string `json:"description"`
Body string `json:"body,omitempty"`
TagList []string `json:"tagList"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
FavoritesCount int `json:"favoritesCount"`
Favorited bool `json:"favorited"`
AuthorID int64 `json:"-"`
Author Profile `json:"author"`
Version int `json:"-"`
}
func (*Article) GenerateSlug ¶
func (a *Article) GenerateSlug()
GenerateSlug generates a URL-friendly slug from the article title.
type ArticleFilters ¶
type ArticleFilters struct {
Tag string // Filter articles by tag name (exact match)
Author string // Filter articles by author username
Favorited string // Filter articles favorited by a specific username
Feed bool // If true, only return articles from users that the current user follows
Limit int // Maximum number of articles to return
Offset int // Number of articles to skip (for pagination)
}
ArticleFilters holds filtering and pagination parameters for listing articles
func (ArticleFilters) Validate ¶
func (f ArticleFilters) Validate(v *validator.Validator)
Validate checks that the ArticleFilters fields are valid. Note: Pagination parameters (Limit and Offset) are validated and normalized by the readPagination helper before reaching this method.
type ArticleStore ¶
type ArticleStore struct {
// contains filtered or unexported fields
}
func (*ArticleStore) DeleteBySlug ¶
func (s *ArticleStore) DeleteBySlug(slug string, authorID int64) error
func (*ArticleStore) FavoriteBySlug ¶
func (s *ArticleStore) FavoriteBySlug(slug string, userID int64) (*Article, error)
FavoriteBySlug favorites an article for the given user and returns the updated article. Uses a single CTE query for optimal performance - no separate transaction needed.
func (*ArticleStore) GetBySlug ¶
func (s *ArticleStore) GetBySlug(slug string, currentUser *User) (*Article, error)
GetBySlug retrieves an article by its slug.
func (*ArticleStore) GetIDBySlug ¶
func (s *ArticleStore) GetIDBySlug(slug string) (int64, error)
GetIDBySlug retrieves just the article ID by its slug. This is a lightweight alternative to GetBySlug when only the ID is needed.
func (*ArticleStore) InsertAndReturn ¶
func (s *ArticleStore) InsertAndReturn(article *Article, currentUser *User) (*Article, error)
InsertAndReturn inserts an article and populates it with database-generated fields and author details. Modifies the input article object in place and uses currentUser from context instead of querying the database.
func (*ArticleStore) InsertTags ¶
func (s *ArticleStore) InsertTags(tags ...string) error
func (*ArticleStore) List ¶
func (s *ArticleStore) List(filters ArticleFilters, currentUser *User) ([]Article, int, error)
List retrieves articles with optional filtering and pagination. Returns articles ordered by most recent first (created_at DESC). Uses JOINs to efficiently fetch favorited and following status in a single query.
func (*ArticleStore) UnfavoriteBySlug ¶
func (s *ArticleStore) UnfavoriteBySlug(slug string, userID int64) (*Article, error)
UnfavoriteBySlug unfavorites an article for the given user and returns the updated article. Uses a single CTE query for optimal performance - no separate transaction needed.
func (*ArticleStore) Update ¶
func (s *ArticleStore) Update(article *Article) error
type ArticleStoreInterface ¶
type ArticleStoreInterface interface {
// InsertAndReturn inserts an article and returns the complete article with author details in a single query.
// This is more efficient than Insert followed by GetBySlug as it eliminates an extra database round trip.
InsertAndReturn(article *Article, currentUser *User) (*Article, error)
// GetIDBySlug retrieves just the article ID by its slug (lightweight alternative to GetBySlug).
GetIDBySlug(slug string) (int64, error)
// GetBySlug retrieves a specific record from the articles table by slug.
GetBySlug(slug string, currentUser *User) (*Article, error)
// List retrieves articles with optional filtering and pagination.
List(filters ArticleFilters, currentUser *User) ([]Article, int, error)
// FavoriteBySlug favorites the article with the given slug for the user and returns the updated article.
FavoriteBySlug(slug string, userID int64) (*Article, error)
// UnfavoriteBySlug unfavorites the article with the given slug for the user and returns the updated article.
UnfavoriteBySlug(slug string, userID int64) (*Article, error)
// DeleteBySlug deletes the article with the given slug.
DeleteBySlug(slug string, userID int64) error
// Update an existing article record.
Update(article *Article) error
// InsertTags inserts tags into the tags table (used for async operations).
InsertTags(tags ...string) error
}
type CommentStore ¶
type CommentStore struct {
// contains filtered or unexported fields
}
func (*CommentStore) GetByArticleID ¶
func (s *CommentStore) GetByArticleID(articleID int64) ([]Comment, error)
GetByArticleID retrieves all comments for an article by its article ID. Returns comments with author details, ordered by creation time (newest first). Uses JOIN to efficiently fetch author information in a single query.
func (*CommentStore) InsertAndReturn ¶
func (s *CommentStore) InsertAndReturn(comment *Comment, currentUser *User) (*Comment, error)
InsertAndReturn inserts a comment and populates it with database-generated fields and author details. Modifies the input comment object in place and uses currentUser from context instead of querying the database.
func (*CommentStore) SetFollowingStatus ¶
func (s *CommentStore) SetFollowingStatus(comments []Comment, currentUserID int64) error
SetFollowingStatus efficiently checks and sets the following status for all comment authors. Uses a single query with IN clause to check all authors at once.
type CommentStoreInterface ¶
type CommentStoreInterface interface {
// InsertAndReturn inserts a comment and returns it with author details populated from currentUser.
// Uses the currentUser from context instead of querying the database for author information.
InsertAndReturn(comment *Comment, currentUser *User) (*Comment, error)
// GetByArticleID retrieves all comments with author details for an article by its article ID.
GetByArticleID(articleID int64) ([]Comment, error)
// SetFollowingStatus efficiently checks and sets the following status for all comment authors.
SetFollowingStatus(comments []Comment, currentUserID int64) error
}
type ModelStore ¶
type ModelStore struct {
Users UserStoreInterface
Articles ArticleStoreInterface
Tags TagStoreInterface
Comments CommentStoreInterface
}
func NewModelStore ¶
type Profile ¶
type Profile struct {
Username string `json:"username"`
Bio string `json:"bio"`
Image string `json:"image"`
Following bool `json:"following"`
}
Profile represents a user's public profile with follow status.
type TagStoreInterface ¶
type User ¶
type User struct {
ID int64 `json:"-"`
Username string `json:"username"`
Email string `json:"email"`
Password password `json:"-"`
Image string `json:"image"`
Bio string `json:"bio"`
Token string `json:"token"`
Version int `json:"-"`
}
func (*User) IsAnonymous ¶
IsAnonymous returns true if the user is the special AnonymousUser user.
type UserCache ¶
type UserCache struct {
// contains filtered or unexported fields
}
UserCache wraps go-cache to provide type-safe user caching
func NewUserCache ¶
NewUserCache creates a new user cache with the specified TTL and cleanup interval
type UserStore ¶
type UserStore struct {
// contains filtered or unexported fields
}
func (UserStore) FollowUser ¶
FollowUser creates a follow relationship between two users.
func (UserStore) GetByEmail ¶
GetByEmail retrieves a user by their email address.
func (UserStore) GetByID ¶
GetByID retrieves a user by their ID from the database. Uses cache if available, otherwise queries the database and caches the result.
func (UserStore) GetByUsername ¶
GetByUsername retrieves a user by their username from the database.
func (UserStore) IsFollowing ¶
IsFollowing checks if followerID is following followedID.
func (UserStore) UnfollowUser ¶
UnfollowUser removes a follow relationship between two users.
type UserStoreInterface ¶
type UserStoreInterface interface {
// Insert a new record into the users table.
Insert(user *User) error
// GetByEmail returns a specific record from the users table.
GetByEmail(email string) (*User, error)
// GetByID retrieves a specific record from the users table by ID.
GetByID(id int64) (*User, error)
// GetByUsername retrieves a specific record from the users table by username.
GetByUsername(username string) (*User, error)
// FollowUser records that a user is following another user
FollowUser(followerID, followedID int64) error
// UnfollowUser records that a user has unfollowed another user
UnfollowUser(followerID, followedID int64) error
// IsFollowing checks if a user is following another user
IsFollowing(followerID, followedID int64) (bool, error)
// Update an existing user record.
Update(user *User) error
}