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 }