package repository import ( "context" "errors" "time" "github.com/google/uuid" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "tm/internal/domain" "tm/pkg/logger" ) // CompanyRepositoryImpl implements the CompanyRepository interface type CompanyRepositoryImpl struct { collection *mongo.Collection logger logger.Logger } // NewCompanyRepository creates a new company repository func NewCompanyRepository(db *mongo.Database, logger logger.Logger) domain.CompanyRepository { collection := db.Collection("companies") // Create indexes ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() // Name index nameIndex := mongo.IndexModel{ Keys: bson.D{{"name", 1}}, } // Created at index createdAtIndex := mongo.IndexModel{ Keys: bson.D{{"created_at", -1}}, } _, err := collection.Indexes().CreateMany(ctx, []mongo.IndexModel{ nameIndex, createdAtIndex, }) if err != nil { logger.Warn("Failed to create company indexes", map[string]interface{}{ "error": err.Error(), }) } return &CompanyRepositoryImpl{ collection: collection, logger: logger, } } // Create creates a new company func (r *CompanyRepositoryImpl) Create(ctx context.Context, company *domain.Company) error { // Set created/updated timestamps now := time.Now() company.CreatedAt = now company.UpdatedAt = now // Insert company _, err := r.collection.InsertOne(ctx, company) if err != nil { if mongo.IsDuplicateKeyError(err) { return errors.New("company already exists") } r.logger.Error("Failed to create company", map[string]interface{}{ "error": err.Error(), "company_id": company.ID.String(), }) return err } r.logger.Info("Company created successfully", map[string]interface{}{ "company_id": company.ID.String(), "name": company.Name, }) return nil } // GetByID retrieves a company by ID func (r *CompanyRepositoryImpl) GetByID(ctx context.Context, id uuid.UUID) (*domain.Company, error) { var company domain.Company filter := bson.M{"_id": id} err := r.collection.FindOne(ctx, filter).Decode(&company) if err != nil { if err == mongo.ErrNoDocuments { return nil, errors.New("company not found") } r.logger.Error("Failed to get company by ID", map[string]interface{}{ "error": err.Error(), "company_id": id.String(), }) return nil, err } return &company, nil } // Update updates a company func (r *CompanyRepositoryImpl) Update(ctx context.Context, company *domain.Company) error { // Set updated timestamp company.UpdatedAt = time.Now() filter := bson.M{"_id": company.ID} update := bson.M{"$set": company} result, err := r.collection.UpdateOne(ctx, filter, update) if err != nil { r.logger.Error("Failed to update company", map[string]interface{}{ "error": err.Error(), "company_id": company.ID.String(), }) return err } if result.MatchedCount == 0 { return errors.New("company not found") } r.logger.Info("Company updated successfully", map[string]interface{}{ "company_id": company.ID.String(), "name": company.Name, }) return nil } // Delete deletes a company func (r *CompanyRepositoryImpl) Delete(ctx context.Context, id uuid.UUID) error { filter := bson.M{"_id": id} result, err := r.collection.DeleteOne(ctx, filter) if err != nil { r.logger.Error("Failed to delete company", map[string]interface{}{ "error": err.Error(), "company_id": id.String(), }) return err } if result.DeletedCount == 0 { return errors.New("company not found") } r.logger.Info("Company deleted successfully", map[string]interface{}{ "company_id": id.String(), }) return nil } // List retrieves companies with pagination func (r *CompanyRepositoryImpl) List(ctx context.Context, limit, offset int) ([]*domain.Company, error) { var companies []*domain.Company // Build options opts := options.Find() opts.SetLimit(int64(limit)) opts.SetSkip(int64(offset)) opts.SetSort(bson.D{{"created_at", -1}}) // Sort by created_at desc cursor, err := r.collection.Find(ctx, bson.M{}, opts) if err != nil { r.logger.Error("Failed to list companies", map[string]interface{}{ "error": err.Error(), "limit": limit, "offset": offset, }) return nil, err } defer cursor.Close(ctx) if err = cursor.All(ctx, &companies); err != nil { r.logger.Error("Failed to decode companies", map[string]interface{}{ "error": err.Error(), }) return nil, err } return companies, nil } // UpdateInterests updates company interests func (r *CompanyRepositoryImpl) UpdateInterests(ctx context.Context, id uuid.UUID, interests *domain.InterestProfile) error { filter := bson.M{"_id": id} update := bson.M{ "$set": bson.M{ "interests": interests, "updated_at": time.Now(), }, } result, err := r.collection.UpdateOne(ctx, filter, update) if err != nil { r.logger.Error("Failed to update company interests", map[string]interface{}{ "error": err.Error(), "company_id": id.String(), }) return err } if result.MatchedCount == 0 { return errors.New("company not found") } r.logger.Info("Company interests updated successfully", map[string]interface{}{ "company_id": id.String(), }) return nil }