Goondex/internal/db/studio_store.go
Stu Leak 16fb407a3c v0.1.0-dev4: Add web frontend with UI component library
- Implement full web interface with Go html/template server
- Add GX component library (buttons, dialogs, tables, forms, etc.)
- Create scene/performer/studio/movie detail and listing pages
- Add Adult Empire scraper for additional metadata sources
- Implement movie support with database schema
- Add import and sync services for data management
- Include comprehensive API and frontend documentation
- Add custom color scheme and responsive layout

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 10:47:30 -05:00

202 lines
5.7 KiB
Go

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
}