1package cache
2
3import (
4 "context"
5 "database/sql"
6
7 "github.com/bnema/dumber/internal/cache/generic"
8 "github.com/bnema/dumber/internal/db"
9)
10
11// FavoritesDBOperations implements DatabaseOperations for favorites cache.
12// Handles loading, persisting, and deleting favorites from the database.
13type FavoritesDBOperations struct {
14 queries db.DatabaseQuerier
15}
16
17// NewFavoritesDBOperations creates a new FavoritesDBOperations instance.
18func NewFavoritesDBOperations(queries db.DatabaseQuerier) *FavoritesDBOperations {
19 return &FavoritesDBOperations{
20 queries: queries,
21 }
22}
23
24// LoadAll loads all favorites from the database.
25// Returns a map of URL -> Favorite.
26func (f *FavoritesDBOperations) LoadAll(ctx context.Context) (map[string]db.Favorite, error) {
27 favorites, err := f.queries.GetAllFavorites(ctx)
28 if err != nil {
29 return nil, err
30 }
31
32 result := make(map[string]db.Favorite, len(favorites))
33 for _, fav := range favorites {
34 result[fav.Url] = fav
35 }
36
37 return result, nil
38}
39
40// Persist saves a favorite to the database.
41// Uses UPSERT logic: if URL exists, updates metadata; otherwise creates new.
42func (f *FavoritesDBOperations) Persist(ctx context.Context, url string, favorite db.Favorite) error {
43 // Check if favorite already exists
44 _, err := f.queries.GetFavoriteByURL(ctx, url)
45 if err == sql.ErrNoRows {
46 // Create new favorite
47 return f.queries.CreateFavorite(ctx, url, favorite.Title, favorite.FaviconUrl)
48 } else if err != nil {
49 return err
50 }
51
52 // Update existing favorite
53 return f.queries.UpdateFavorite(ctx, favorite.Title, favorite.FaviconUrl, url)
54}
55
56// Delete removes a favorite from the database.
57func (f *FavoritesDBOperations) Delete(ctx context.Context, url string) error {
58 return f.queries.DeleteFavorite(ctx, url)
59}
60
61// FavoritesCache is a specialized cache for favorites.
62// It wraps GenericCache with favorites-specific helper methods.
63type FavoritesCache struct {
64 *generic.GenericCache[string, db.Favorite]
65}
66
67// NewFavoritesCache creates a new favorites cache.
68func NewFavoritesCache(queries db.DatabaseQuerier) *FavoritesCache {
69 dbOps := NewFavoritesDBOperations(queries)
70 return &FavoritesCache{
71 GenericCache: generic.NewGenericCache(dbOps),
72 }
73}
74
75// GetAll returns all favorites as a slice, ordered by position.
76// This is a convenience method for the frontend.
77func (f *FavoritesCache) GetAll() []db.Favorite {
78 // Get all favorites from the cache using the List method
79 favorites := f.GenericCache.List()
80
81 // Sort by position
82 // Note: favorites should already be ordered by position from DB load,
83 // but this ensures consistency even if items were added at runtime.
84 for i := 0; i < len(favorites)-1; i++ {
85 for j := i + 1; j < len(favorites); j++ {
86 if favorites[i].Position > favorites[j].Position {
87 favorites[i], favorites[j] = favorites[j], favorites[i]
88 }
89 }
90 }
91
92 return favorites
93}