data

package
v0.0.0-...-2fb9175 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 22, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrRecordNotFound = errors.New("record not found")
	ErrEditConflict   = errors.New("edit conflict")
)
View Source
var (
	ErrDuplicateEmail    = errors.New("duplicate email")
	ErrDuplicateUsername = errors.New("duplicate username")
)
View Source
var AnonymousUser = &User{}

Functions

func ValidateArticle

func ValidateArticle(v *validator.Validator, article *Article)

func ValidateComment

func ValidateComment(v *validator.Validator, comment *Comment)

func ValidateEmail

func ValidateEmail(v *validator.Validator, email string)

func ValidatePasswordPlaintext

func ValidatePasswordPlaintext(v *validator.Validator, password string)

func ValidateUser

func ValidateUser(v *validator.Validator, user User)

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.

func (*Article) SortTags

func (a *Article) SortTags()

SortTags sorts the article's tags alphabetically for consistent ordering

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 Comment

type Comment struct {
	ID        int64     `json:"id"`
	Body      string    `json:"body"`
	ArticleID int64     `json:"-"`
	AuthorID  int64     `json:"-"`
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
	Author    Profile   `json:"author"`
}

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

func NewModelStore(db *pgxpool.Pool, timeout time.Duration, userCache *UserCache) ModelStore

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 TagStore

type TagStore struct {
	// contains filtered or unexported fields
}

func (*TagStore) GetAll

func (s *TagStore) GetAll() ([]string, error)

GetAll retrieves all tags from the database.

type TagStoreInterface

type TagStoreInterface interface {
	// GetAll retrieves all tags from the tags table.
	GetAll() ([]string, error)
}

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

func (u *User) IsAnonymous() bool

IsAnonymous returns true if the user is the special AnonymousUser user.

func (*User) ToProfile

func (u *User) ToProfile(following bool) Profile

ToProfile converts a User to a Profile with the specified following status.

type UserCache

type UserCache struct {
	// contains filtered or unexported fields
}

UserCache wraps go-cache to provide type-safe user caching

func NewUserCache

func NewUserCache(defaultExpiration, cleanupInterval time.Duration) *UserCache

NewUserCache creates a new user cache with the specified TTL and cleanup interval

func (*UserCache) Delete

func (uc *UserCache) Delete(userID int64)

Delete removes a user from the cache

func (*UserCache) Get

func (uc *UserCache) Get(userID int64) (*User, bool)

Get retrieves a user from the cache if it exists and hasn't expired

func (*UserCache) Set

func (uc *UserCache) Set(userID int64, user *User)

Set stores a user in the cache with the default expiration time

type UserStore

type UserStore struct {
	// contains filtered or unexported fields
}

func (UserStore) FollowUser

func (s UserStore) FollowUser(followerID, followedID int64) error

FollowUser creates a follow relationship between two users.

func (UserStore) GetByEmail

func (s UserStore) GetByEmail(email string) (*User, error)

GetByEmail retrieves a user by their email address.

func (UserStore) GetByID

func (s UserStore) GetByID(id int64) (*User, error)

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

func (s UserStore) GetByUsername(username string) (*User, error)

GetByUsername retrieves a user by their username from the database.

func (UserStore) Insert

func (s UserStore) Insert(user *User) error

Insert adds a new record in the users table.

func (UserStore) IsFollowing

func (s UserStore) IsFollowing(followerID, followedID int64) (bool, error)

IsFollowing checks if followerID is following followedID.

func (UserStore) UnfollowUser

func (s UserStore) UnfollowUser(followerID, followedID int64) error

UnfollowUser removes a follow relationship between two users.

func (UserStore) Update

func (s UserStore) Update(user *User) error

Update updates an existing user record in the database. Invalidates the cache for the updated user.

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
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL