v0.30.0 eb3068f

favicon_repo.go RawHistoryFolder

1package sqlite
2
3import (
4	"context"
5	"database/sql"
6	"errors"
7	"sync"
8	"time"
9
10	"github.com/bnema/dumber/internal/application/port"
11	"github.com/bnema/dumber/internal/domain/favicon"
12	"github.com/bnema/dumber/internal/infrastructure/persistence/sqlite/sqlc"
13)
14
15type faviconRepo struct {
16	queries *sqlc.Queries
17}
18
19func NewFaviconRepository(db *sql.DB) port.FaviconRepository {
20	return &faviconRepo{queries: sqlc.New(db)}
21}
22
23type lazyFaviconRepository struct {
24	provider port.DatabaseProvider
25	repo     port.FaviconRepository
26	once     sync.Once
27	initErr  error
28}
29
30func NewLazyFaviconRepository(provider port.DatabaseProvider) port.FaviconRepository {
31	return &lazyFaviconRepository{provider: provider}
32}
33
34func (r *lazyFaviconRepository) init(ctx context.Context) error {
35	r.once.Do(func() {
36		db, err := r.provider.DB(ctx)
37		if err != nil {
38			r.initErr = err
39			return
40		}
41		r.repo = NewFaviconRepository(db)
42	})
43	return r.initErr
44}
45
46func (r *lazyFaviconRepository) Get(ctx context.Context, key favicon.Key) (*favicon.Metadata, error) {
47	if err := r.init(ctx); err != nil {
48		return nil, err
49	}
50	return r.repo.Get(ctx, key)
51}
52
53func (r *lazyFaviconRepository) FindFirst(ctx context.Context, keys []favicon.Key) (*favicon.Metadata, error) {
54	if err := r.init(ctx); err != nil {
55		return nil, err
56	}
57	return r.repo.FindFirst(ctx, keys)
58}
59
60func (r *lazyFaviconRepository) Upsert(ctx context.Context, meta favicon.Metadata) error {
61	if err := r.init(ctx); err != nil {
62		return err
63	}
64	return r.repo.Upsert(ctx, meta)
65}
66
67func (r *lazyFaviconRepository) UpdateLastChecked(ctx context.Context, key favicon.Key, contentHash string, checkedAt time.Time) error {
68	if err := r.init(ctx); err != nil {
69		return err
70	}
71	return r.repo.UpdateLastChecked(ctx, key, contentHash, checkedAt)
72}
73
74func (r *lazyFaviconRepository) Delete(ctx context.Context, key favicon.Key) error {
75	if err := r.init(ctx); err != nil {
76		return err
77	}
78	return r.repo.Delete(ctx, key)
79}
80
81func (r *faviconRepo) Get(ctx context.Context, key favicon.Key) (*favicon.Metadata, error) {
82	row, err := r.queries.GetFavicon(ctx, string(key))
83	if err != nil {
84		if errors.Is(err, sql.ErrNoRows) {
85			return nil, nil
86		}
87		return nil, err
88	}
89	return faviconFromRow(row), nil
90}
91
92func (r *faviconRepo) FindFirst(ctx context.Context, keys []favicon.Key) (*favicon.Metadata, error) {
93	for _, key := range keys {
94		meta, err := r.Get(ctx, key)
95		if err != nil {
96			return nil, err
97		}
98		if meta != nil {
99			return meta, nil
100		}
101	}
102	return nil, nil
103}
104
105func (r *faviconRepo) Upsert(ctx context.Context, meta favicon.Metadata) error {
106	return r.queries.UpsertFavicon(ctx, sqlc.UpsertFaviconParams{
107		Key:           string(meta.Key),
108		SourceUrl:     nullString(meta.SourceURL),
109		PageUrl:       nullString(meta.PageURL),
110		Source:        string(meta.Source),
111		ContentHash:   meta.ContentHash,
112		ContentType:   nullString(meta.ContentType),
113		UpdatedAt:     meta.UpdatedAt,
114		LastCheckedAt: meta.LastCheckedAt,
115	})
116}
117
118func (r *faviconRepo) UpdateLastChecked(ctx context.Context, key favicon.Key, contentHash string, checkedAt time.Time) error {
119	return r.queries.UpdateFaviconLastChecked(ctx, sqlc.UpdateFaviconLastCheckedParams{
120		Key:           string(key),
121		ContentHash:   contentHash,
122		LastCheckedAt: checkedAt,
123	})
124}
125
126func (r *faviconRepo) Delete(ctx context.Context, key favicon.Key) error {
127	return r.queries.DeleteFavicon(ctx, string(key))
128}
129
130func faviconFromRow(row sqlc.Favicon) *favicon.Metadata {
131	return &favicon.Metadata{
132		Key:           favicon.Key(row.Key),
133		SourceURL:     row.SourceUrl.String,
134		PageURL:       row.PageUrl.String,
135		Source:        favicon.Source(row.Source),
136		ContentHash:   row.ContentHash,
137		ContentType:   row.ContentType.String,
138		UpdatedAt:     row.UpdatedAt,
139		LastCheckedAt: row.LastCheckedAt,
140	}
141}

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