v0.15.0 9006957

favorites_cache.go RawHistoryFolder

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}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close