Files
tm_back/internal/company_category/repository.go
T
2026-05-17 17:21:36 +03:30

259 lines
6.6 KiB
Go

package company_category
import (
"context"
"errors"
"time"
"tm/pkg/logger"
orm "tm/pkg/mongo"
"tm/pkg/response"
"go.mongodb.org/mongo-driver/v2/bson"
)
// Repository defines the interface for category data operations
type Repository interface {
Create(ctx context.Context, category *Category) error
Update(ctx context.Context, category *Category) error
GetByID(ctx context.Context, id string) (*Category, error)
GetByIDs(ctx context.Context, ids []string) ([]Category, error)
GetByName(ctx context.Context, name string) (*Category, error)
Search(ctx context.Context, form *SearchForm, pagination *response.Pagination) (*orm.PaginatedResult[Category], error)
Delete(ctx context.Context, id string) error
TogglePublish(ctx context.Context, id string) (bool, error)
}
// categoryRepository implements the Repository interface using the MongoDB ORM
type categoryRepository struct {
ormRepo orm.Repository[Category]
logger logger.Logger
}
// NewCategoryRepository creates a new category repository
func NewRepository(mongoManager *orm.ConnectionManager, logger logger.Logger) Repository {
// Create indexes using the ORM's index management
indexes := []orm.Index{
*orm.NewIndex("name_idx", bson.D{{Key: "name", Value: 1}}),
*orm.NewIndex("published_idx", bson.D{{Key: "published", Value: 1}}),
}
// Create indexes
err := mongoManager.CreateIndexes("company_categories", indexes)
if err != nil {
logger.Warn("Failed to create category indexes", map[string]interface{}{
"error": err.Error(),
})
}
// Create ORM repository
ormRepo := orm.NewRepository[Category](mongoManager.GetCollection("company_categories"), logger)
return &categoryRepository{
ormRepo: ormRepo,
logger: logger,
}
}
// Create creates a new category
func (r *categoryRepository) Create(ctx context.Context, category *Category) error {
// Set created/updated timestamps using Unix timestamps
now := time.Now().Unix()
category.SetCreatedAt(now)
// Use ORM to create category
err := r.ormRepo.Create(ctx, category)
if err != nil {
r.logger.Error("Failed to create category", map[string]interface{}{
"error": err.Error(),
"name": category.Name,
})
return err
}
r.logger.Info("Category created successfully", map[string]interface{}{
"category_id": category.ID,
"name": category.Name,
"published": category.Published,
})
return nil
}
// GetByID retrieves a category by ID
func (r *categoryRepository) GetByID(ctx context.Context, id string) (*Category, error) {
category, err := r.ormRepo.FindByID(ctx, id)
if err != nil {
if errors.Is(err, orm.ErrDocumentNotFound) {
return nil, errors.New("category not found")
}
r.logger.Error("Failed to get category by ID", map[string]interface{}{
"error": err.Error(),
"category_id": id,
})
return nil, err
}
return category, nil
}
// GetByIDs retrieves categories by IDs
func (r *categoryRepository) GetByIDs(ctx context.Context, ids []string) ([]Category, error) {
objectIDs := make([]bson.ObjectID, len(ids))
for i, id := range ids {
objectID, err := bson.ObjectIDFromHex(id)
if err != nil {
return nil, err
}
objectIDs[i] = objectID
}
filter := bson.M{"_id": bson.M{"$in": objectIDs}}
paginationBuilder := orm.NewPaginationBuilder().
Build()
result, err := r.ormRepo.FindAll(ctx, filter, paginationBuilder)
if err != nil {
return nil, err
}
return result.Items, nil
}
// GetByName retrieves a category by name
func (r *categoryRepository) GetByName(ctx context.Context, name string) (*Category, error) {
category, err := r.ormRepo.FindOne(ctx, bson.M{"name": name})
if err != nil {
return nil, err
}
return category, nil
}
// Update updates a category
func (r *categoryRepository) Update(ctx context.Context, category *Category) error {
// Set updated timestamp using Unix timestamp
category.SetUpdatedAt(time.Now().Unix())
// Use ORM to update category
err := r.ormRepo.Update(ctx, category)
if err != nil {
r.logger.Error("Failed to update category", map[string]interface{}{
"error": err.Error(),
"category_id": category.ID,
})
return err
}
r.logger.Info("Category updated successfully", map[string]interface{}{
"category_id": category.ID,
"name": category.Name,
})
return nil
}
// Delete deletes a category
func (r *categoryRepository) Delete(ctx context.Context, id string) error {
// Get category first
_, err := r.GetByID(ctx, id)
if err != nil {
return err
}
// Delete from database
err = r.ormRepo.Delete(ctx, id)
if err != nil {
r.logger.Error("Failed to delete category", map[string]interface{}{
"error": err.Error(),
"category_id": id,
})
return err
}
r.logger.Info("Category deleted successfully", map[string]interface{}{
"category_id": id,
})
return nil
}
// Search retrieves categories with search and filters
func (r *categoryRepository) Search(ctx context.Context, form *SearchForm, pagination *response.Pagination) (*orm.PaginatedResult[Category], error) {
// Build filter
filter := bson.M{}
if form.Search != nil && *form.Search != "" {
// Use regex search for case-insensitive partial matching
searchRegex := bson.M{
"$regex": *form.Search,
"$options": "i", // case-insensitive
}
filter["$or"] = []bson.M{
{"name": searchRegex},
{"description": searchRegex},
}
}
if form.Published != nil {
filter["published"] = *form.Published
}
mongoPagination, err := orm.BuildListPagination(
pagination.Limit,
pagination.Offset,
pagination.Cursor,
pagination.SortBy,
pagination.SortOrder,
filter,
orm.ListPaginationOptions{},
)
if err != nil {
return nil, err
}
result, err := r.ormRepo.FindAll(ctx, filter, mongoPagination)
if err != nil {
r.logger.Error("Failed to search categories", map[string]interface{}{
"error": err.Error(),
})
return nil, err
}
return result, nil
}
// TogglePublish toggles category publish status
func (r *categoryRepository) TogglePublish(ctx context.Context, id string) (bool, error) {
// Get category first
category, err := r.GetByID(ctx, id)
if err != nil {
return false, err
}
// Update publish status
category.Published = !category.Published
now := time.Now().Unix()
category.SetUpdatedAt(now)
// Set published_at timestamp if publishing
category.PublishedAt = &now
// Update in database
err = r.ormRepo.Update(ctx, category)
if err != nil {
r.logger.Error("Failed to toggle category publish status", map[string]interface{}{
"error": err.Error(),
"category_id": id,
"published": category.Published,
})
return false, err
}
r.logger.Info("Category publish status updated successfully", map[string]interface{}{
"category_id": id,
"published": category.Published,
})
return category.Published, nil
}