Files
QuoteForge/internal/repository/component.go
Mikhail Chusavitin 190a9aa0a3 Add initial backend implementation
- Go module with Gin, GORM, JWT, excelize dependencies
- Configuration loading from YAML with all settings
- GORM models for users, categories, components, configurations, alerts
- Repository layer for all entities
- Services: auth (JWT), pricing (median/average/weighted), components,
  quotes, configurations, export (CSV/XLSX), alerts
- Middleware: JWT auth, role-based access, CORS
- HTTP handlers for all API endpoints
- Main server with dependency injection and graceful shutdown

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 10:49:56 +03:00

128 lines
3.3 KiB
Go

package repository
import (
"time"
"github.com/mchus/quoteforge/internal/models"
"gorm.io/gorm"
)
type ComponentRepository struct {
db *gorm.DB
}
func NewComponentRepository(db *gorm.DB) *ComponentRepository {
return &ComponentRepository{db: db}
}
type ComponentFilter struct {
Category string
Vendor string
Search string
HasPrice bool
}
func (r *ComponentRepository) List(filter ComponentFilter, offset, limit int) ([]models.LotMetadata, int64, error) {
var components []models.LotMetadata
var total int64
query := r.db.Model(&models.LotMetadata{}).
Preload("Lot").
Preload("Category")
if filter.Category != "" {
query = query.Joins("JOIN qt_categories ON qt_lot_metadata.category_id = qt_categories.id").
Where("qt_categories.code = ?", filter.Category)
}
if filter.Vendor != "" {
query = query.Where("vendor = ?", filter.Vendor)
}
if filter.Search != "" {
search := "%" + filter.Search + "%"
query = query.Where("lot_name LIKE ? OR model LIKE ?", search, search)
}
if filter.HasPrice {
query = query.Where("current_price IS NOT NULL AND current_price > 0")
}
query.Count(&total)
// Sort by popularity + freshness, no price goes last
err := query.
Order("CASE WHEN current_price IS NULL OR current_price = 0 THEN 1 ELSE 0 END").
Order("popularity_score DESC").
Offset(offset).
Limit(limit).
Find(&components).Error
return components, total, err
}
func (r *ComponentRepository) GetByLotName(lotName string) (*models.LotMetadata, error) {
var component models.LotMetadata
err := r.db.
Preload("Lot").
Preload("Category").
Where("lot_name = ?", lotName).
First(&component).Error
if err != nil {
return nil, err
}
return &component, nil
}
func (r *ComponentRepository) GetMultiple(lotNames []string) ([]models.LotMetadata, error) {
var components []models.LotMetadata
err := r.db.
Preload("Lot").
Preload("Category").
Where("lot_name IN ?", lotNames).
Find(&components).Error
return components, err
}
func (r *ComponentRepository) Update(component *models.LotMetadata) error {
return r.db.Save(component).Error
}
func (r *ComponentRepository) Create(component *models.LotMetadata) error {
return r.db.Create(component).Error
}
func (r *ComponentRepository) GetVendors(category string) ([]string, error) {
var vendors []string
query := r.db.Model(&models.LotMetadata{}).Distinct("vendor")
if category != "" {
query = query.Joins("JOIN qt_categories ON qt_lot_metadata.category_id = qt_categories.id").
Where("qt_categories.code = ?", category)
}
err := query.Pluck("vendor", &vendors).Error
return vendors, err
}
func (r *ComponentRepository) IncrementRequestCount(lotName string) error {
now := time.Now()
return r.db.Model(&models.LotMetadata{}).
Where("lot_name = ?", lotName).
Updates(map[string]interface{}{
"request_count": gorm.Expr("request_count + 1"),
"last_request_date": now,
}).Error
}
// GetAllLots returns all lots from the existing lot table
func (r *ComponentRepository) GetAllLots() ([]models.Lot, error) {
var lots []models.Lot
err := r.db.Find(&lots).Error
return lots, err
}
// GetLotsWithoutMetadata returns lots that don't have qt_lot_metadata entries
func (r *ComponentRepository) GetLotsWithoutMetadata() ([]models.Lot, error) {
var lots []models.Lot
err := r.db.
Where("lot_name NOT IN (SELECT lot_name FROM qt_lot_metadata)").
Find(&lots).Error
return lots, err
}