package db import ( "database/sql" "fmt" "time" "git.leaktechnologies.dev/stu/Goondex/internal/model" ) // StudioStore handles CRUD operations for studios type StudioStore struct { db *DB } // NewStudioStore creates a new studio store func NewStudioStore(db *DB) *StudioStore { return &StudioStore{db: db} } // Create inserts a new studio func (s *StudioStore) Create(studio *model.Studio) error { now := time.Now() studio.CreatedAt = now studio.UpdatedAt = now result, err := s.db.conn.Exec(` INSERT INTO studios (name, parent_id, image_path, image_url, description, source, source_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) `, studio.Name, studio.ParentID, studio.ImagePath, studio.ImageURL, studio.Description, studio.Source, studio.SourceID, studio.CreatedAt.Format(time.RFC3339), studio.UpdatedAt.Format(time.RFC3339)) if err != nil { return fmt.Errorf("failed to create studio: %w", err) } id, err := result.LastInsertId() if err != nil { return fmt.Errorf("failed to get last insert id: %w", err) } studio.ID = id return nil } // GetByID retrieves a studio by ID func (s *StudioStore) GetByID(id int64) (*model.Studio, error) { studio := &model.Studio{} var createdAt, updatedAt string err := s.db.conn.QueryRow(` SELECT id, name, COALESCE(parent_id, 0), COALESCE(image_path, ''), COALESCE(image_url, ''), COALESCE(description, ''), COALESCE(source, ''), COALESCE(source_id, ''), created_at, updated_at FROM studios WHERE id = ? `, id).Scan(&studio.ID, &studio.Name, &studio.ParentID, &studio.ImagePath, &studio.ImageURL, &studio.Description, &studio.Source, &studio.SourceID, &createdAt, &updatedAt) if err == sql.ErrNoRows { return nil, fmt.Errorf("studio not found") } if err != nil { return nil, fmt.Errorf("failed to get studio: %w", err) } studio.CreatedAt, _ = time.Parse(time.RFC3339, createdAt) studio.UpdatedAt, _ = time.Parse(time.RFC3339, updatedAt) return studio, nil } // Search searches for studios by name func (s *StudioStore) Search(query string) ([]model.Studio, error) { rows, err := s.db.conn.Query(` SELECT id, name, COALESCE(parent_id, 0), COALESCE(image_path, ''), COALESCE(image_url, ''), COALESCE(description, ''), COALESCE(source, ''), COALESCE(source_id, ''), created_at, updated_at FROM studios WHERE name LIKE ? ORDER BY name `, "%"+query+"%") if err != nil { return nil, fmt.Errorf("failed to search studios: %w", err) } defer rows.Close() var studios []model.Studio for rows.Next() { var studio model.Studio var createdAt, updatedAt string err := rows.Scan(&studio.ID, &studio.Name, &studio.ParentID, &studio.ImagePath, &studio.ImageURL, &studio.Description, &studio.Source, &studio.SourceID, &createdAt, &updatedAt) if err != nil { return nil, fmt.Errorf("failed to scan studio: %w", err) } studio.CreatedAt, _ = time.Parse(time.RFC3339, createdAt) studio.UpdatedAt, _ = time.Parse(time.RFC3339, updatedAt) studios = append(studios, studio) } return studios, nil } // Update updates an existing studio func (s *StudioStore) Update(studio *model.Studio) error { studio.UpdatedAt = time.Now() result, err := s.db.conn.Exec(` UPDATE studios SET name = ?, parent_id = ?, image_path = ?, image_url = ?, description = ?, source = ?, source_id = ?, updated_at = ? WHERE id = ? `, studio.Name, studio.ParentID, studio.ImagePath, studio.ImageURL, studio.Description, studio.Source, studio.SourceID, studio.UpdatedAt.Format(time.RFC3339), studio.ID) if err != nil { return fmt.Errorf("failed to update studio: %w", err) } rows, err := result.RowsAffected() if err != nil { return fmt.Errorf("failed to get rows affected: %w", err) } if rows == 0 { return fmt.Errorf("studio not found") } return nil } // GetSceneCount returns the number of scenes associated with a studio func (s *StudioStore) GetSceneCount(studioID int64) (int, error) { var count int err := s.db.conn.QueryRow(` SELECT COUNT(*) FROM scenes WHERE studio_id = ? `, studioID).Scan(&count) if err != nil { return 0, fmt.Errorf("failed to count scenes: %w", err) } return count, nil } // Delete deletes a studio by ID func (s *StudioStore) Delete(id int64) error { result, err := s.db.conn.Exec("DELETE FROM studios WHERE id = ?", id) if err != nil { return fmt.Errorf("failed to delete studio: %w", err) } rows, err := result.RowsAffected() if err != nil { return fmt.Errorf("failed to get rows affected: %w", err) } if rows == 0 { return fmt.Errorf("studio not found") } return nil } // Upsert inserts or updates a studio based on source_id func (s *StudioStore) Upsert(st *model.Studio) error { // Try to find existing studio by source_id existing, err := s.GetBySourceID(st.Source, st.SourceID) if err == nil && existing != nil { // Update existing st.ID = existing.ID return s.Update(st) } // Create new return s.Create(st) } // GetBySourceID retrieves a studio by its source and source_id func (s *StudioStore) GetBySourceID(source, sourceID string) (*model.Studio, error) { var st model.Studio var createdAt, updatedAt string err := s.db.conn.QueryRow(` SELECT id, name, COALESCE(parent_id, 0), COALESCE(image_path, ''), COALESCE(image_url, ''), COALESCE(description, ''), COALESCE(source, ''), COALESCE(source_id, ''), created_at, updated_at FROM studios WHERE source = ? AND source_id = ? `, source, sourceID).Scan( &st.ID, &st.Name, &st.ParentID, &st.ImagePath, &st.ImageURL, &st.Description, &st.Source, &st.SourceID, &createdAt, &updatedAt, ) if err == sql.ErrNoRows { return nil, nil } if err != nil { return nil, fmt.Errorf("failed to get studio: %w", err) } st.CreatedAt, _ = time.Parse(time.RFC3339, createdAt) st.UpdatedAt, _ = time.Parse(time.RFC3339, updatedAt) return &st, nil }