5d721705b7
- Updated the MongoDB driver from v1.17.4 to v2.3.0, ensuring compatibility with the latest features and improvements. - Refactored company-related entity and repository files to utilize the new driver, replacing `primitive.ObjectID` with `bson.ObjectID` for ID handling. - Adjusted the configuration in `.drone.yml` to include the `main` branch in the trigger settings, enhancing CI/CD pipeline flexibility.
265 lines
6.8 KiB
Go
265 lines
6.8 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) ([]Category, int64, 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 NewCategoryRepository(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) ([]Category, int64, 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
|
|
}
|
|
|
|
// Build sort
|
|
sort := "created_at"
|
|
if pagination.SortBy != "" {
|
|
sort = pagination.SortBy
|
|
}
|
|
|
|
sortOrder := "desc"
|
|
if pagination.SortOrder != "" {
|
|
sortOrder = pagination.SortOrder
|
|
}
|
|
|
|
// Build pagination
|
|
paginationBuilder := orm.NewPaginationBuilder().
|
|
Limit(pagination.Limit).
|
|
Skip(pagination.Offset).
|
|
SortBy(sort, sortOrder).
|
|
Build()
|
|
|
|
// Use ORM to find categories
|
|
result, err := r.ormRepo.FindAll(ctx, filter, paginationBuilder)
|
|
if err != nil {
|
|
r.logger.Error("Failed to search categories", map[string]interface{}{
|
|
"error": err.Error(),
|
|
})
|
|
return nil, 0, err
|
|
}
|
|
|
|
return result.Items, result.TotalCount, 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
|
|
}
|