···55 "io"
66)
7788-// MediaHandler defines common operations for media handlers
99-//
1010-// This interface captures the shared behavior across media handlers for polymorphic handling of different media types.
88+// MediaHandler defines common operations for media handlers and captures the shared behavior across media handlers for polymorphic handling of different media types.
119type MediaHandler interface {
1212- // SearchAndAdd searches for media and allows user to select and add to queue
1313- SearchAndAdd(ctx context.Context, query string, interactive bool) error
1414- // List lists all media items with optional status filtering
1515- List(ctx context.Context, status string) error
1616- // UpdateStatus changes the status of a media item
1717- UpdateStatus(ctx context.Context, id, status string) error
1818- // Remove removes a media item from the queue
1919- Remove(ctx context.Context, id string) error
2020- // SetInputReader sets the input reader for interactive prompts
2121- SetInputReader(reader io.Reader)
2222- // Close cleans up resources
2323- Close() error
1010+ SearchAndAdd(ctx context.Context, query string, interactive bool) error // SearchAndAdd searches for media and allows user to select and add to queue
1111+ List(ctx context.Context, status string) error // List lists all media items with optional status filtering
1212+ UpdateStatus(ctx context.Context, id, status string) error // UpdateStatus changes the status of a media item
1313+ Remove(ctx context.Context, id string) error // Remove removes a media item from the queue
1414+ SetInputReader(reader io.Reader) // SetInputReader sets the input reader for interactive prompts
1515+ Close() error // Close cleans up resources
2416}
25172618// Searchable defines search behavior for media handlers
···99)
10101111// MediaConfig defines configuration for a media repository
1212-//
1313-// T should be a pointer type (*models.Book, *models.Movie, *models.TVShow)
1412type MediaConfig[T models.Model] struct {
1513 TableName string // TableName is the database table name (e.g., "books", "movies", "tv_shows")
1614 New func() T // New creates a new zero-value instance of T
···2321}
24222523// BaseMediaRepository provides shared CRUD operations for media types
2626-//
2727-// This generic implementation eliminates duplicate code across Book, Movie, and TV repositories.
2828-// Type-specific behavior is configured via MediaConfig.
2929-//
3030-// T should be a pointer type (*models.Book, *models.Movie, *models.TVShow)
3124type BaseMediaRepository[T models.Model] struct {
3225 db *sql.DB
3326 config MediaConfig[T]
···6457}
65586659// Get retrieves a media item by ID
6767-//
6868-// Returns T directly (which is already a pointer type like *models.Book)
6960func (r *BaseMediaRepository[T]) Get(ctx context.Context, id int64) (T, error) {
7061 query := fmt.Sprintf("SELECT * FROM %s WHERE id = ?", r.config.TableName)
7162 row := r.db.QueryRowContext(ctx, query, id)
···109100}
110101111102// ListQuery executes a custom query and scans results
112112-//
113113-// Returns []T where T is a pointer type (e.g., []*models.Book)
114103func (r *BaseMediaRepository[T]) ListQuery(ctx context.Context, query string, args ...any) ([]T, error) {
115104 rows, err := r.db.QueryContext(ctx, query, args...)
116105 if err != nil {
···140129 return count, nil
141130}
142131143143-// buildPlaceholders generates "?,?,?" for SQL placeholders
144132func buildPlaceholders(values []any) string {
145133 if len(values) == 0 {
146134 return ""
···77)
8899// MediaRepository defines CRUD operations for media types (Books, Movies, TV)
1010-//
1111-// This interface captures the shared behavior across media repositories
1210type MediaRepository[T models.Model] interface {
1313- // Create stores a new media item and returns its assigned ID
1414- Create(ctx context.Context, item *T) (int64, error)
1515-1616- // Get retrieves a media item by ID
1717- Get(ctx context.Context, id int64) (*T, error)
1818-1919- // Update modifies an existing media item
2020- Update(ctx context.Context, item *T) error
2121-2222- // Delete removes a media item by ID
2323- Delete(ctx context.Context, id int64) error
2424-2525- // List retrieves media items with optional filtering and sorting
2626- List(ctx context.Context, opts any) ([]*T, error)
2727-2828- // Count returns the number of media items matching conditions
2929- Count(ctx context.Context, opts any) (int64, error)
1111+ Create(ctx context.Context, item *T) (int64, error) // Create stores a new media item and returns its assigned ID
1212+ Get(ctx context.Context, id int64) (*T, error) // Get retrieves a media item by ID
1313+ Update(ctx context.Context, item *T) error // Update modifies an existing media item
1414+ Delete(ctx context.Context, id int64) error // Delete removes a media item by ID
1515+ List(ctx context.Context, opts any) ([]*T, error) // List retrieves media items with optional filtering and sorting
1616+ Count(ctx context.Context, opts any) (int64, error) // Count returns the number of media items matching conditions
3017}
31183232-// StatusFilterable extends MediaRepository with status-based filtering
3333-//
3434-// Media types (Books, Movies, TV) support status-based queries like "queued", "reading", "watching", "watched", "finished"
1919+// StatusFilterable extends MediaRepository with status-based filtering for queries like "queued", "reading", "watching", "watched", "finished"
3520type StatusFilterable[T models.Model] interface {
3621 MediaRepository[T]
3737-3822 // GetByStatus retrieves all items with the given status
3923 GetByStatus(ctx context.Context, status string) ([]*T, error)
4024}
+13-16
internal/repo/movie_repository.go
···1010 "github.com/stormlightlabs/noteleaf/internal/models"
1111)
12121313+// MovieListOptions defines options for listing movies
1414+type MovieListOptions struct {
1515+ Status string
1616+ Year int
1717+ MinRating float64
1818+ Search string
1919+ SortBy string
2020+ SortOrder string
2121+ Limit int
2222+ Offset int
2323+}
2424+1325// MovieRepository provides database operations for movies
1426type MovieRepository struct {
1527 *BaseMediaRepository[*models.Movie]
···3749 },
3850 }
39514040- return &MovieRepository{
4141- BaseMediaRepository: NewBaseMediaRepository(db, config),
4242- db: db,
4343- }
5252+ return &MovieRepository{BaseMediaRepository: NewBaseMediaRepository(db, config), db: db}
4453}
45544655// Create stores a new movie and returns its assigned ID
···211220 movie.Watched = &now
212221 return r.Update(ctx, movie)
213222}
214214-215215-// MovieListOptions defines options for listing movies
216216-type MovieListOptions struct {
217217- Status string
218218- Year int
219219- MinRating float64
220220- Search string
221221- SortBy string
222222- SortOrder string
223223- Limit int
224224- Offset int
225225-}