detached 8f314a2

refactor(favorites): complete tags-first cleanup

commit
8f314a261186f860a52d3bbcf0106163b96e5987
author
brice · · 2026-06-28 08:06 UTC
parent
e4062c5
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
12 files · +216 -113
M docs/systemviews-wasm-crud-plan.md +4 -8
@@ -47,18 +47,14 @@ Preferred direction for new work:
4747 | Delete domain | `keyboard.ts`, `HistoryFilters.svelte` | `history_delete_domain` | Bridge client supports it. | Add domain-action UI and confirmation. |
4848 | Open row | `navigateTo(entry.url)` | Browser navigation | Static links exist. | Add keyboard open and active-row focus management. |
4949
50-### Favorites, folders, tags (`webui/src/pages/homepage/favorites/*`)
50+### Favorites and tags (`webui/src/pages/homepage/favorites/*`)
5151
5252 | Operation | Old Svelte surface | Backend message/API | Current WASM status | Gap |
5353 | --- | --- | --- | --- | --- |
54-| Read favorites | `FavoritesPanel.svelte`, `FavoriteGrid.svelte`, `FavoriteCard.svelte` | `favorite_list` | Present, but bare link list (`favorites_view.go`). | Add rich rows/cards, favicons, shortcut badges, folder/tag metadata. |
54+| Read favorites | `FavoritesPanel.svelte`, `FavoriteGrid.svelte`, `FavoriteCard.svelte` | `favorite_list` | Present, but bare link list (`favorites_view.go`) with tags-first data. | Add rich rows/cards, favicons, shortcut badges, and tag metadata. |
5555 | Create favorite | Old homepage hints imply adding/pinning from history; native omnibox toggle exists outside this page. | `ManageFavoritesUseCase.Add` exists, but no homepage/systemview message. | Missing from `port.HomepageFavorites`/`SystemviewFavoritesService` and handlers. | Add `favorite_create` handler/bridge and UI. |
56-| Update favorite | `FavoriteEditor.svelte` locally updates title and uses folder/shortcut/tag handlers. | `favorite_set_shortcut`, `favorite_set_folder`, `tag_assign`, `tag_remove`; no title update handler. | Partial bridge support. | Add `favorite_update` for title/favicon/url policy; keep folder/shortcut/tag specialized calls or fold into update after design. |
56+| Update favorite | `FavoriteEditor.svelte` locally updates title, shortcut, and tags. | `favorite_set_shortcut`, `tag_assign`, `tag_remove`; no title update handler. | Partial bridge support. | Add `favorite_update` for title/favicon/url policy; keep shortcut/tag specialized calls or fold into update after design. |
5757 | Delete favorite | `FavoriteEditor.svelte` local-only delete placeholder. | `ManageFavoritesUseCase.Remove` exists, but no homepage/systemview message. | Missing. | Add `favorite_delete` handler/bridge/UI. |
58-| Read folders | `FolderList.svelte` | `folder_list` | Present as static list. | Add counts, selected filter, empty state. |
59-| Create folder | `FolderList.svelte` inline create | `folder_create` | Bridge and handler exist. | Add interactive UI. |
60-| Update folder | Handler exists (`folder_update`). | `folder_update` | Bridge exists. | Add rename/icon UI. |
61-| Delete folder | Handler exists (`folder_delete`). | `folder_delete` | Bridge exists. | Add UI, confirm, refresh favorite folder state. |
6258 | Read tags | `TagCloud.svelte` | `tag_list` | Present as static list. | Add color chips and selection. |
6359 | Create tag | `TagCloud.svelte` inline create | `tag_create` | Bridge and handler exist. | Add UI with color picker/palette. |
6460 | Update tag | Handler exists (`tag_update`). | `tag_update` | Bridge exists. | Add rename/color edit UI. |
@@ -101,7 +97,7 @@ Implementation path:
10197 - Rendering now uses typed `github.com/a-h/templ` components under `internal/ui/systemviews/*.templ`; generated `*_templ.go` files are committed alongside source templates.
10298 - `make build-systemviews` runs `go tool templ generate -path internal/ui/systemviews -include-version=false` before building the WASM runtime.
10399 - History supports search, domain filters, pagination, analytics/domain summaries, single/range/domain deletion, row open actions, alerts, and keyboard navigation.
104-- Favorites supports create/update/delete for favorites, folders, and tags; folder/tag filters; shortcut editing; tag assignment/removal; alerts; and keyboard navigation.
100+- Favorites supports create/update/delete for favorites and tags; tag filters; shortcut editing; tag assignment/removal; alerts; and keyboard navigation.
105101 - Config supports editable appearance, search defaults, search shortcut CRUD, performance profile/custom values, keybinding set/reset/reset-all, success/error states, and refreshes the config payload/theme after save.
106102 - Native global actions use `toggle_*_systemview` names and open/focus/close History/Favorites/Config system views through the coordinator/right-split path.
107103 - Trust-boundary hardening includes templ HTML escaping, URL scheme sanitization for rendered links, sanitized CSS color use for tag swatches, serialized DOM action handling, and route-level error states.
@@ -47,18 +47,14 @@ Preferred direction for new work:
47 | Delete domain | `keyboard.ts`, `HistoryFilters.svelte` | `history_delete_domain` | Bridge client supports it. | Add domain-action UI and confirmation. |47 | Delete domain | `keyboard.ts`, `HistoryFilters.svelte` | `history_delete_domain` | Bridge client supports it. | Add domain-action UI and confirmation. |
48 | Open row | `navigateTo(entry.url)` | Browser navigation | Static links exist. | Add keyboard open and active-row focus management. |48 | Open row | `navigateTo(entry.url)` | Browser navigation | Static links exist. | Add keyboard open and active-row focus management. |
49 49
50-### Favorites, folders, tags (`webui/src/pages/homepage/favorites/*`)50+### Favorites and tags (`webui/src/pages/homepage/favorites/*`)
51 51
52 | Operation | Old Svelte surface | Backend message/API | Current WASM status | Gap |52 | Operation | Old Svelte surface | Backend message/API | Current WASM status | Gap |
53 | --- | --- | --- | --- | --- |53 | --- | --- | --- | --- | --- |
54-| Read favorites | `FavoritesPanel.svelte`, `FavoriteGrid.svelte`, `FavoriteCard.svelte` | `favorite_list` | Present, but bare link list (`favorites_view.go`). | Add rich rows/cards, favicons, shortcut badges, folder/tag metadata. |54+| Read favorites | `FavoritesPanel.svelte`, `FavoriteGrid.svelte`, `FavoriteCard.svelte` | `favorite_list` | Present, but bare link list (`favorites_view.go`) with tags-first data. | Add rich rows/cards, favicons, shortcut badges, and tag metadata. |
55 | Create favorite | Old homepage hints imply adding/pinning from history; native omnibox toggle exists outside this page. | `ManageFavoritesUseCase.Add` exists, but no homepage/systemview message. | Missing from `port.HomepageFavorites`/`SystemviewFavoritesService` and handlers. | Add `favorite_create` handler/bridge and UI. |55 | Create favorite | Old homepage hints imply adding/pinning from history; native omnibox toggle exists outside this page. | `ManageFavoritesUseCase.Add` exists, but no homepage/systemview message. | Missing from `port.HomepageFavorites`/`SystemviewFavoritesService` and handlers. | Add `favorite_create` handler/bridge and UI. |
56-| Update favorite | `FavoriteEditor.svelte` locally updates title and uses folder/shortcut/tag handlers. | `favorite_set_shortcut`, `favorite_set_folder`, `tag_assign`, `tag_remove`; no title update handler. | Partial bridge support. | Add `favorite_update` for title/favicon/url policy; keep folder/shortcut/tag specialized calls or fold into update after design. |56+| Update favorite | `FavoriteEditor.svelte` locally updates title, shortcut, and tags. | `favorite_set_shortcut`, `tag_assign`, `tag_remove`; no title update handler. | Partial bridge support. | Add `favorite_update` for title/favicon/url policy; keep shortcut/tag specialized calls or fold into update after design. |
57 | Delete favorite | `FavoriteEditor.svelte` local-only delete placeholder. | `ManageFavoritesUseCase.Remove` exists, but no homepage/systemview message. | Missing. | Add `favorite_delete` handler/bridge/UI. |57 | Delete favorite | `FavoriteEditor.svelte` local-only delete placeholder. | `ManageFavoritesUseCase.Remove` exists, but no homepage/systemview message. | Missing. | Add `favorite_delete` handler/bridge/UI. |
58-| Read folders | `FolderList.svelte` | `folder_list` | Present as static list. | Add counts, selected filter, empty state. |
59-| Create folder | `FolderList.svelte` inline create | `folder_create` | Bridge and handler exist. | Add interactive UI. |
60-| Update folder | Handler exists (`folder_update`). | `folder_update` | Bridge exists. | Add rename/icon UI. |
61-| Delete folder | Handler exists (`folder_delete`). | `folder_delete` | Bridge exists. | Add UI, confirm, refresh favorite folder state. |
62 | Read tags | `TagCloud.svelte` | `tag_list` | Present as static list. | Add color chips and selection. |58 | Read tags | `TagCloud.svelte` | `tag_list` | Present as static list. | Add color chips and selection. |
63 | Create tag | `TagCloud.svelte` inline create | `tag_create` | Bridge and handler exist. | Add UI with color picker/palette. |59 | Create tag | `TagCloud.svelte` inline create | `tag_create` | Bridge and handler exist. | Add UI with color picker/palette. |
64 | Update tag | Handler exists (`tag_update`). | `tag_update` | Bridge exists. | Add rename/color edit UI. |60 | Update tag | Handler exists (`tag_update`). | `tag_update` | Bridge exists. | Add rename/color edit UI. |
@@ -101,7 +97,7 @@ Implementation path:
101 - Rendering now uses typed `github.com/a-h/templ` components under `internal/ui/systemviews/*.templ`; generated `*_templ.go` files are committed alongside source templates.97 - Rendering now uses typed `github.com/a-h/templ` components under `internal/ui/systemviews/*.templ`; generated `*_templ.go` files are committed alongside source templates.
102 - `make build-systemviews` runs `go tool templ generate -path internal/ui/systemviews -include-version=false` before building the WASM runtime.98 - `make build-systemviews` runs `go tool templ generate -path internal/ui/systemviews -include-version=false` before building the WASM runtime.
103 - History supports search, domain filters, pagination, analytics/domain summaries, single/range/domain deletion, row open actions, alerts, and keyboard navigation.99 - History supports search, domain filters, pagination, analytics/domain summaries, single/range/domain deletion, row open actions, alerts, and keyboard navigation.
104-- Favorites supports create/update/delete for favorites, folders, and tags; folder/tag filters; shortcut editing; tag assignment/removal; alerts; and keyboard navigation.100+- Favorites supports create/update/delete for favorites and tags; tag filters; shortcut editing; tag assignment/removal; alerts; and keyboard navigation.
105 - Config supports editable appearance, search defaults, search shortcut CRUD, performance profile/custom values, keybinding set/reset/reset-all, success/error states, and refreshes the config payload/theme after save.101 - Config supports editable appearance, search defaults, search shortcut CRUD, performance profile/custom values, keybinding set/reset/reset-all, success/error states, and refreshes the config payload/theme after save.
106 - Native global actions use `toggle_*_systemview` names and open/focus/close History/Favorites/Config system views through the coordinator/right-split path.102 - Native global actions use `toggle_*_systemview` names and open/focus/close History/Favorites/Config system views through the coordinator/right-split path.
107 - Trust-boundary hardening includes templ HTML escaping, URL scheme sanitization for rendered links, sanitized CSS color use for tag swatches, serialized DOM action handling, and route-level error states.103 - Trust-boundary hardening includes templ HTML escaping, URL scheme sanitization for rendered links, sanitized CSS color use for tag swatches, serialized DOM action handling, and route-level error states.
M internal/domain/repository/mocks/favorite.go +48 -48
@@ -293,55 +293,55 @@ func (_c *MockFavoriteRepository_GetAll_Call) RunAndReturn(run func(ctx context.
293293 return _c
294294 }
295295
296-// GetByTag provides a mock function for the type MockFavoriteRepository
297-func (_mock *MockFavoriteRepository) GetByTag(ctx context.Context, tagID entity.TagID) ([]*entity.Favorite, error) {
298- ret := _mock.Called(ctx, tagID)
296+// GetByShortcut provides a mock function for the type MockFavoriteRepository
297+func (_mock *MockFavoriteRepository) GetByShortcut(ctx context.Context, key int) (*entity.Favorite, error) {
298+ ret := _mock.Called(ctx, key)
299299
300300 if len(ret) == 0 {
301- panic("no return value specified for GetByTag")
301+ panic("no return value specified for GetByShortcut")
302302 }
303303
304- var r0 []*entity.Favorite
304+ var r0 *entity.Favorite
305305 var r1 error
306- if returnFunc, ok := ret.Get(0).(func(context.Context, entity.TagID) ([]*entity.Favorite, error)); ok {
307- return returnFunc(ctx, tagID)
306+ if returnFunc, ok := ret.Get(0).(func(context.Context, int) (*entity.Favorite, error)); ok {
307+ return returnFunc(ctx, key)
308308 }
309- if returnFunc, ok := ret.Get(0).(func(context.Context, entity.TagID) []*entity.Favorite); ok {
310- r0 = returnFunc(ctx, tagID)
309+ if returnFunc, ok := ret.Get(0).(func(context.Context, int) *entity.Favorite); ok {
310+ r0 = returnFunc(ctx, key)
311311 } else {
312312 if ret.Get(0) != nil {
313- r0 = ret.Get(0).([]*entity.Favorite)
313+ r0 = ret.Get(0).(*entity.Favorite)
314314 }
315315 }
316- if returnFunc, ok := ret.Get(1).(func(context.Context, entity.TagID) error); ok {
317- r1 = returnFunc(ctx, tagID)
316+ if returnFunc, ok := ret.Get(1).(func(context.Context, int) error); ok {
317+ r1 = returnFunc(ctx, key)
318318 } else {
319319 r1 = ret.Error(1)
320320 }
321321 return r0, r1
322322 }
323323
324-// MockFavoriteRepository_GetByTag_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetByTag'
325-type MockFavoriteRepository_GetByTag_Call struct {
324+// MockFavoriteRepository_GetByShortcut_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetByShortcut'
325+type MockFavoriteRepository_GetByShortcut_Call struct {
326326 *mock.Call
327327 }
328328
329-// GetByTag is a helper method to define mock.On call
329+// GetByShortcut is a helper method to define mock.On call
330330 // - ctx context.Context
331-// - tagID entity.TagID
332-func (_e *MockFavoriteRepository_Expecter) GetByTag(ctx any, tagID any) *MockFavoriteRepository_GetByTag_Call {
333- return &MockFavoriteRepository_GetByTag_Call{Call: _e.mock.On("GetByTag", ctx, tagID)}
331+// - key int
332+func (_e *MockFavoriteRepository_Expecter) GetByShortcut(ctx any, key any) *MockFavoriteRepository_GetByShortcut_Call {
333+ return &MockFavoriteRepository_GetByShortcut_Call{Call: _e.mock.On("GetByShortcut", ctx, key)}
334334 }
335335
336-func (_c *MockFavoriteRepository_GetByTag_Call) Run(run func(ctx context.Context, tagID entity.TagID)) *MockFavoriteRepository_GetByTag_Call {
336+func (_c *MockFavoriteRepository_GetByShortcut_Call) Run(run func(ctx context.Context, key int)) *MockFavoriteRepository_GetByShortcut_Call {
337337 _c.Call.Run(func(args mock.Arguments) {
338338 var arg0 context.Context
339339 if args[0] != nil {
340340 arg0 = args[0].(context.Context)
341341 }
342- var arg1 entity.TagID
342+ var arg1 int
343343 if args[1] != nil {
344- arg1 = args[1].(entity.TagID)
344+ arg1 = args[1].(int)
345345 }
346346 run(
347347 arg0,
@@ -351,65 +351,65 @@ func (_c *MockFavoriteRepository_GetByTag_Call) Run(run func(ctx context.Context
351351 return _c
352352 }
353353
354-func (_c *MockFavoriteRepository_GetByTag_Call) Return(favorites []*entity.Favorite, err error) *MockFavoriteRepository_GetByTag_Call {
355- _c.Call.Return(favorites, err)
354+func (_c *MockFavoriteRepository_GetByShortcut_Call) Return(favorite *entity.Favorite, err error) *MockFavoriteRepository_GetByShortcut_Call {
355+ _c.Call.Return(favorite, err)
356356 return _c
357357 }
358358
359-func (_c *MockFavoriteRepository_GetByTag_Call) RunAndReturn(run func(ctx context.Context, tagID entity.TagID) ([]*entity.Favorite, error)) *MockFavoriteRepository_GetByTag_Call {
359+func (_c *MockFavoriteRepository_GetByShortcut_Call) RunAndReturn(run func(ctx context.Context, key int) (*entity.Favorite, error)) *MockFavoriteRepository_GetByShortcut_Call {
360360 _c.Call.Return(run)
361361 return _c
362362 }
363363
364-// GetByShortcut provides a mock function for the type MockFavoriteRepository
365-func (_mock *MockFavoriteRepository) GetByShortcut(ctx context.Context, key int) (*entity.Favorite, error) {
366- ret := _mock.Called(ctx, key)
364+// GetByTag provides a mock function for the type MockFavoriteRepository
365+func (_mock *MockFavoriteRepository) GetByTag(ctx context.Context, tagID entity.TagID) ([]*entity.Favorite, error) {
366+ ret := _mock.Called(ctx, tagID)
367367
368368 if len(ret) == 0 {
369- panic("no return value specified for GetByShortcut")
369+ panic("no return value specified for GetByTag")
370370 }
371371
372- var r0 *entity.Favorite
372+ var r0 []*entity.Favorite
373373 var r1 error
374- if returnFunc, ok := ret.Get(0).(func(context.Context, int) (*entity.Favorite, error)); ok {
375- return returnFunc(ctx, key)
374+ if returnFunc, ok := ret.Get(0).(func(context.Context, entity.TagID) ([]*entity.Favorite, error)); ok {
375+ return returnFunc(ctx, tagID)
376376 }
377- if returnFunc, ok := ret.Get(0).(func(context.Context, int) *entity.Favorite); ok {
378- r0 = returnFunc(ctx, key)
377+ if returnFunc, ok := ret.Get(0).(func(context.Context, entity.TagID) []*entity.Favorite); ok {
378+ r0 = returnFunc(ctx, tagID)
379379 } else {
380380 if ret.Get(0) != nil {
381- r0 = ret.Get(0).(*entity.Favorite)
381+ r0 = ret.Get(0).([]*entity.Favorite)
382382 }
383383 }
384- if returnFunc, ok := ret.Get(1).(func(context.Context, int) error); ok {
385- r1 = returnFunc(ctx, key)
384+ if returnFunc, ok := ret.Get(1).(func(context.Context, entity.TagID) error); ok {
385+ r1 = returnFunc(ctx, tagID)
386386 } else {
387387 r1 = ret.Error(1)
388388 }
389389 return r0, r1
390390 }
391391
392-// MockFavoriteRepository_GetByShortcut_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetByShortcut'
393-type MockFavoriteRepository_GetByShortcut_Call struct {
392+// MockFavoriteRepository_GetByTag_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetByTag'
393+type MockFavoriteRepository_GetByTag_Call struct {
394394 *mock.Call
395395 }
396396
397-// GetByShortcut is a helper method to define mock.On call
397+// GetByTag is a helper method to define mock.On call
398398 // - ctx context.Context
399-// - key int
400-func (_e *MockFavoriteRepository_Expecter) GetByShortcut(ctx any, key any) *MockFavoriteRepository_GetByShortcut_Call {
401- return &MockFavoriteRepository_GetByShortcut_Call{Call: _e.mock.On("GetByShortcut", ctx, key)}
399+// - tagID entity.TagID
400+func (_e *MockFavoriteRepository_Expecter) GetByTag(ctx any, tagID any) *MockFavoriteRepository_GetByTag_Call {
401+ return &MockFavoriteRepository_GetByTag_Call{Call: _e.mock.On("GetByTag", ctx, tagID)}
402402 }
403403
404-func (_c *MockFavoriteRepository_GetByShortcut_Call) Run(run func(ctx context.Context, key int)) *MockFavoriteRepository_GetByShortcut_Call {
404+func (_c *MockFavoriteRepository_GetByTag_Call) Run(run func(ctx context.Context, tagID entity.TagID)) *MockFavoriteRepository_GetByTag_Call {
405405 _c.Call.Run(func(args mock.Arguments) {
406406 var arg0 context.Context
407407 if args[0] != nil {
408408 arg0 = args[0].(context.Context)
409409 }
410- var arg1 int
410+ var arg1 entity.TagID
411411 if args[1] != nil {
412- arg1 = args[1].(int)
412+ arg1 = args[1].(entity.TagID)
413413 }
414414 run(
415415 arg0,
@@ -419,12 +419,12 @@ func (_c *MockFavoriteRepository_GetByShortcut_Call) Run(run func(ctx context.Co
419419 return _c
420420 }
421421
422-func (_c *MockFavoriteRepository_GetByShortcut_Call) Return(favorite *entity.Favorite, err error) *MockFavoriteRepository_GetByShortcut_Call {
423- _c.Call.Return(favorite, err)
422+func (_c *MockFavoriteRepository_GetByTag_Call) Return(favorites []*entity.Favorite, err error) *MockFavoriteRepository_GetByTag_Call {
423+ _c.Call.Return(favorites, err)
424424 return _c
425425 }
426426
427-func (_c *MockFavoriteRepository_GetByShortcut_Call) RunAndReturn(run func(ctx context.Context, key int) (*entity.Favorite, error)) *MockFavoriteRepository_GetByShortcut_Call {
427+func (_c *MockFavoriteRepository_GetByTag_Call) RunAndReturn(run func(ctx context.Context, tagID entity.TagID) ([]*entity.Favorite, error)) *MockFavoriteRepository_GetByTag_Call {
428428 _c.Call.Return(run)
429429 return _c
430430 }
@@ -293,55 +293,55 @@ func (_c *MockFavoriteRepository_GetAll_Call) RunAndReturn(run func(ctx context.
293 return _c293 return _c
294 }294 }
295 295
296-// GetByTag provides a mock function for the type MockFavoriteRepository296+// GetByShortcut provides a mock function for the type MockFavoriteRepository
297-func (_mock *MockFavoriteRepository) GetByTag(ctx context.Context, tagID entity.TagID) ([]*entity.Favorite, error) {297+func (_mock *MockFavoriteRepository) GetByShortcut(ctx context.Context, key int) (*entity.Favorite, error) {
298- ret := _mock.Called(ctx, tagID)298+ ret := _mock.Called(ctx, key)
299 299
300 if len(ret) == 0 {300 if len(ret) == 0 {
301- panic("no return value specified for GetByTag")301+ panic("no return value specified for GetByShortcut")
302 }302 }
303 303
304- var r0 []*entity.Favorite304+ var r0 *entity.Favorite
305 var r1 error305 var r1 error
306- if returnFunc, ok := ret.Get(0).(func(context.Context, entity.TagID) ([]*entity.Favorite, error)); ok {306+ if returnFunc, ok := ret.Get(0).(func(context.Context, int) (*entity.Favorite, error)); ok {
307- return returnFunc(ctx, tagID)307+ return returnFunc(ctx, key)
308 }308 }
309- if returnFunc, ok := ret.Get(0).(func(context.Context, entity.TagID) []*entity.Favorite); ok {309+ if returnFunc, ok := ret.Get(0).(func(context.Context, int) *entity.Favorite); ok {
310- r0 = returnFunc(ctx, tagID)310+ r0 = returnFunc(ctx, key)
311 } else {311 } else {
312 if ret.Get(0) != nil {312 if ret.Get(0) != nil {
313- r0 = ret.Get(0).([]*entity.Favorite)313+ r0 = ret.Get(0).(*entity.Favorite)
314 }314 }
315 }315 }
316- if returnFunc, ok := ret.Get(1).(func(context.Context, entity.TagID) error); ok {316+ if returnFunc, ok := ret.Get(1).(func(context.Context, int) error); ok {
317- r1 = returnFunc(ctx, tagID)317+ r1 = returnFunc(ctx, key)
318 } else {318 } else {
319 r1 = ret.Error(1)319 r1 = ret.Error(1)
320 }320 }
321 return r0, r1321 return r0, r1
322 }322 }
323 323
324-// MockFavoriteRepository_GetByTag_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetByTag'324+// MockFavoriteRepository_GetByShortcut_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetByShortcut'
325-type MockFavoriteRepository_GetByTag_Call struct {325+type MockFavoriteRepository_GetByShortcut_Call struct {
326 *mock.Call326 *mock.Call
327 }327 }
328 328
329-// GetByTag is a helper method to define mock.On call329+// GetByShortcut is a helper method to define mock.On call
330 // - ctx context.Context330 // - ctx context.Context
331-// - tagID entity.TagID331+// - key int
332-func (_e *MockFavoriteRepository_Expecter) GetByTag(ctx any, tagID any) *MockFavoriteRepository_GetByTag_Call {332+func (_e *MockFavoriteRepository_Expecter) GetByShortcut(ctx any, key any) *MockFavoriteRepository_GetByShortcut_Call {
333- return &MockFavoriteRepository_GetByTag_Call{Call: _e.mock.On("GetByTag", ctx, tagID)}333+ return &MockFavoriteRepository_GetByShortcut_Call{Call: _e.mock.On("GetByShortcut", ctx, key)}
334 }334 }
335 335
336-func (_c *MockFavoriteRepository_GetByTag_Call) Run(run func(ctx context.Context, tagID entity.TagID)) *MockFavoriteRepository_GetByTag_Call {336+func (_c *MockFavoriteRepository_GetByShortcut_Call) Run(run func(ctx context.Context, key int)) *MockFavoriteRepository_GetByShortcut_Call {
337 _c.Call.Run(func(args mock.Arguments) {337 _c.Call.Run(func(args mock.Arguments) {
338 var arg0 context.Context338 var arg0 context.Context
339 if args[0] != nil {339 if args[0] != nil {
340 arg0 = args[0].(context.Context)340 arg0 = args[0].(context.Context)
341 }341 }
342- var arg1 entity.TagID342+ var arg1 int
343 if args[1] != nil {343 if args[1] != nil {
344- arg1 = args[1].(entity.TagID)344+ arg1 = args[1].(int)
345 }345 }
346 run(346 run(
347 arg0,347 arg0,
@@ -351,65 +351,65 @@ func (_c *MockFavoriteRepository_GetByTag_Call) Run(run func(ctx context.Context
351 return _c351 return _c
352 }352 }
353 353
354-func (_c *MockFavoriteRepository_GetByTag_Call) Return(favorites []*entity.Favorite, err error) *MockFavoriteRepository_GetByTag_Call {354+func (_c *MockFavoriteRepository_GetByShortcut_Call) Return(favorite *entity.Favorite, err error) *MockFavoriteRepository_GetByShortcut_Call {
355- _c.Call.Return(favorites, err)355+ _c.Call.Return(favorite, err)
356 return _c356 return _c
357 }357 }
358 358
359-func (_c *MockFavoriteRepository_GetByTag_Call) RunAndReturn(run func(ctx context.Context, tagID entity.TagID) ([]*entity.Favorite, error)) *MockFavoriteRepository_GetByTag_Call {359+func (_c *MockFavoriteRepository_GetByShortcut_Call) RunAndReturn(run func(ctx context.Context, key int) (*entity.Favorite, error)) *MockFavoriteRepository_GetByShortcut_Call {
360 _c.Call.Return(run)360 _c.Call.Return(run)
361 return _c361 return _c
362 }362 }
363 363
364-// GetByShortcut provides a mock function for the type MockFavoriteRepository364+// GetByTag provides a mock function for the type MockFavoriteRepository
365-func (_mock *MockFavoriteRepository) GetByShortcut(ctx context.Context, key int) (*entity.Favorite, error) {365+func (_mock *MockFavoriteRepository) GetByTag(ctx context.Context, tagID entity.TagID) ([]*entity.Favorite, error) {
366- ret := _mock.Called(ctx, key)366+ ret := _mock.Called(ctx, tagID)
367 367
368 if len(ret) == 0 {368 if len(ret) == 0 {
369- panic("no return value specified for GetByShortcut")369+ panic("no return value specified for GetByTag")
370 }370 }
371 371
372- var r0 *entity.Favorite372+ var r0 []*entity.Favorite
373 var r1 error373 var r1 error
374- if returnFunc, ok := ret.Get(0).(func(context.Context, int) (*entity.Favorite, error)); ok {374+ if returnFunc, ok := ret.Get(0).(func(context.Context, entity.TagID) ([]*entity.Favorite, error)); ok {
375- return returnFunc(ctx, key)375+ return returnFunc(ctx, tagID)
376 }376 }
377- if returnFunc, ok := ret.Get(0).(func(context.Context, int) *entity.Favorite); ok {377+ if returnFunc, ok := ret.Get(0).(func(context.Context, entity.TagID) []*entity.Favorite); ok {
378- r0 = returnFunc(ctx, key)378+ r0 = returnFunc(ctx, tagID)
379 } else {379 } else {
380 if ret.Get(0) != nil {380 if ret.Get(0) != nil {
381- r0 = ret.Get(0).(*entity.Favorite)381+ r0 = ret.Get(0).([]*entity.Favorite)
382 }382 }
383 }383 }
384- if returnFunc, ok := ret.Get(1).(func(context.Context, int) error); ok {384+ if returnFunc, ok := ret.Get(1).(func(context.Context, entity.TagID) error); ok {
385- r1 = returnFunc(ctx, key)385+ r1 = returnFunc(ctx, tagID)
386 } else {386 } else {
387 r1 = ret.Error(1)387 r1 = ret.Error(1)
388 }388 }
389 return r0, r1389 return r0, r1
390 }390 }
391 391
392-// MockFavoriteRepository_GetByShortcut_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetByShortcut'392+// MockFavoriteRepository_GetByTag_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetByTag'
393-type MockFavoriteRepository_GetByShortcut_Call struct {393+type MockFavoriteRepository_GetByTag_Call struct {
394 *mock.Call394 *mock.Call
395 }395 }
396 396
397-// GetByShortcut is a helper method to define mock.On call397+// GetByTag is a helper method to define mock.On call
398 // - ctx context.Context398 // - ctx context.Context
399-// - key int399+// - tagID entity.TagID
400-func (_e *MockFavoriteRepository_Expecter) GetByShortcut(ctx any, key any) *MockFavoriteRepository_GetByShortcut_Call {400+func (_e *MockFavoriteRepository_Expecter) GetByTag(ctx any, tagID any) *MockFavoriteRepository_GetByTag_Call {
401- return &MockFavoriteRepository_GetByShortcut_Call{Call: _e.mock.On("GetByShortcut", ctx, key)}401+ return &MockFavoriteRepository_GetByTag_Call{Call: _e.mock.On("GetByTag", ctx, tagID)}
402 }402 }
403 403
404-func (_c *MockFavoriteRepository_GetByShortcut_Call) Run(run func(ctx context.Context, key int)) *MockFavoriteRepository_GetByShortcut_Call {404+func (_c *MockFavoriteRepository_GetByTag_Call) Run(run func(ctx context.Context, tagID entity.TagID)) *MockFavoriteRepository_GetByTag_Call {
405 _c.Call.Run(func(args mock.Arguments) {405 _c.Call.Run(func(args mock.Arguments) {
406 var arg0 context.Context406 var arg0 context.Context
407 if args[0] != nil {407 if args[0] != nil {
408 arg0 = args[0].(context.Context)408 arg0 = args[0].(context.Context)
409 }409 }
410- var arg1 int410+ var arg1 entity.TagID
411 if args[1] != nil {411 if args[1] != nil {
412- arg1 = args[1].(int)412+ arg1 = args[1].(entity.TagID)
413 }413 }
414 run(414 run(
415 arg0,415 arg0,
@@ -419,12 +419,12 @@ func (_c *MockFavoriteRepository_GetByShortcut_Call) Run(run func(ctx context.Co
419 return _c419 return _c
420 }420 }
421 421
422-func (_c *MockFavoriteRepository_GetByShortcut_Call) Return(favorite *entity.Favorite, err error) *MockFavoriteRepository_GetByShortcut_Call {422+func (_c *MockFavoriteRepository_GetByTag_Call) Return(favorites []*entity.Favorite, err error) *MockFavoriteRepository_GetByTag_Call {
423- _c.Call.Return(favorite, err)423+ _c.Call.Return(favorites, err)
424 return _c424 return _c
425 }425 }
426 426
427-func (_c *MockFavoriteRepository_GetByShortcut_Call) RunAndReturn(run func(ctx context.Context, key int) (*entity.Favorite, error)) *MockFavoriteRepository_GetByShortcut_Call {427+func (_c *MockFavoriteRepository_GetByTag_Call) RunAndReturn(run func(ctx context.Context, tagID entity.TagID) ([]*entity.Favorite, error)) *MockFavoriteRepository_GetByTag_Call {
428 _c.Call.Return(run)428 _c.Call.Return(run)
429 return _c429 return _c
430 }430 }
D internal/infrastructure/handlers/homepage/folders.go +0 -3
@@ -1,3 +0,0 @@
1-package homepage
2-
3-// Folder homepage handlers were removed with tags-only favorites.
@@ -1,3 +0,0 @@
1-package homepage
2-
3-// Folder homepage handlers were removed with tags-only favorites.
M internal/infrastructure/persistence/sqlite/favorite_repo.go +48 -11
@@ -42,7 +42,7 @@ func (r *favoriteRepo) Save(ctx context.Context, fav *entity.Favorite) error {
4242 if err != nil {
4343 return err
4444 }
45- favoriteFromRow(row, fav)
45+ favoriteFromRow(favoriteRowFromCreate(row), fav)
4646 return nil
4747 }
4848
@@ -54,7 +54,7 @@ func (r *favoriteRepo) FindByID(ctx context.Context, id entity.FavoriteID) (*ent
5454 }
5555 return nil, err
5656 }
57- fav := favoriteFromRow(row, nil)
57+ fav := favoriteFromRow(favoriteRowFromGetByID(row), nil)
5858 return fav, r.hydrateTags(ctx, []*entity.Favorite{fav})
5959 }
6060
@@ -66,7 +66,7 @@ func (r *favoriteRepo) FindByURL(ctx context.Context, url string) (*entity.Favor
6666 }
6767 return nil, err
6868 }
69- fav := favoriteFromRow(row, nil)
69+ fav := favoriteFromRow(favoriteRowFromGetByURL(row), nil)
7070 return fav, r.hydrateTags(ctx, []*entity.Favorite{fav})
7171 }
7272
@@ -75,7 +75,7 @@ func (r *favoriteRepo) GetAll(ctx context.Context) ([]*entity.Favorite, error) {
7575 if err != nil {
7676 return nil, err
7777 }
78- favorites := favoritesFromRows(rows)
78+ favorites := favoritesFromAllRows(rows)
7979 return favorites, r.hydrateTags(ctx, favorites)
8080 }
8181
@@ -84,7 +84,7 @@ func (r *favoriteRepo) GetByTag(ctx context.Context, tagID entity.TagID) ([]*ent
8484 if err != nil {
8585 return nil, err
8686 }
87- favorites := favoritesFromRows(rows)
87+ favorites := favoritesFromTagRows(rows)
8888 return favorites, r.hydrateTags(ctx, favorites)
8989 }
9090
@@ -96,7 +96,7 @@ func (r *favoriteRepo) GetByShortcut(ctx context.Context, key int) (*entity.Favo
9696 }
9797 return nil, err
9898 }
99- fav := favoriteFromRow(row, nil)
99+ fav := favoriteFromRow(favoriteRowFromGetByShortcut(row), nil)
100100 return fav, r.hydrateTags(ctx, []*entity.Favorite{fav})
101101 }
102102
@@ -155,15 +155,26 @@ func (r *favoriteRepo) hydrateTags(ctx context.Context, favorites []*entity.Favo
155155 return nil
156156 }
157157
158-func favoriteFromRow(row sqlc.Favorite, target *entity.Favorite) *entity.Favorite {
158+type favoriteRow struct {
159+ ID int64
160+ URL string
161+ Title sql.NullString
162+ FaviconURL sql.NullString
163+ ShortcutKey sql.NullInt64
164+ Position int64
165+ CreatedAt sql.NullTime
166+ UpdatedAt sql.NullTime
167+}
168+
169+func favoriteFromRow(row favoriteRow, target *entity.Favorite) *entity.Favorite {
159170 fav := target
160171 if fav == nil {
161172 fav = &entity.Favorite{}
162173 }
163174 fav.ID = entity.FavoriteID(row.ID)
164- fav.URL = row.Url
175+ fav.URL = row.URL
165176 fav.Title = row.Title.String
166- fav.FaviconURL = row.FaviconUrl.String
177+ fav.FaviconURL = row.FaviconURL.String
167178 fav.Position = int(row.Position)
168179 fav.CreatedAt = row.CreatedAt.Time
169180 fav.UpdatedAt = row.UpdatedAt.Time
@@ -177,10 +188,36 @@ func favoriteFromRow(row sqlc.Favorite, target *entity.Favorite) *entity.Favorit
177188 return fav
178189 }
179190
180-func favoritesFromRows(rows []sqlc.Favorite) []*entity.Favorite {
191+func favoriteRowFromCreate(row sqlc.CreateFavoriteRow) favoriteRow {
192+ return favoriteRow{ID: row.ID, URL: row.Url, Title: row.Title, FaviconURL: row.FaviconUrl, ShortcutKey: row.ShortcutKey, Position: row.Position, CreatedAt: row.CreatedAt, UpdatedAt: row.UpdatedAt}
193+}
194+
195+func favoriteRowFromGetByID(row sqlc.GetFavoriteByIDRow) favoriteRow {
196+ return favoriteRow{ID: row.ID, URL: row.Url, Title: row.Title, FaviconURL: row.FaviconUrl, ShortcutKey: row.ShortcutKey, Position: row.Position, CreatedAt: row.CreatedAt, UpdatedAt: row.UpdatedAt}
197+}
198+
199+func favoriteRowFromGetByURL(row sqlc.GetFavoriteByURLRow) favoriteRow {
200+ return favoriteRow{ID: row.ID, URL: row.Url, Title: row.Title, FaviconURL: row.FaviconUrl, ShortcutKey: row.ShortcutKey, Position: row.Position, CreatedAt: row.CreatedAt, UpdatedAt: row.UpdatedAt}
201+}
202+
203+func favoriteRowFromGetByShortcut(row sqlc.GetFavoriteByShortcutRow) favoriteRow {
204+ return favoriteRow{ID: row.ID, URL: row.Url, Title: row.Title, FaviconURL: row.FaviconUrl, ShortcutKey: row.ShortcutKey, Position: row.Position, CreatedAt: row.CreatedAt, UpdatedAt: row.UpdatedAt}
205+}
206+
207+func favoritesFromAllRows(rows []sqlc.GetAllFavoritesRow) []*entity.Favorite {
208+ favorites := make([]*entity.Favorite, len(rows))
209+ for i := range rows {
210+ row := rows[i]
211+ favorites[i] = favoriteFromRow(favoriteRow{ID: row.ID, URL: row.Url, Title: row.Title, FaviconURL: row.FaviconUrl, ShortcutKey: row.ShortcutKey, Position: row.Position, CreatedAt: row.CreatedAt, UpdatedAt: row.UpdatedAt}, nil)
212+ }
213+ return favorites
214+}
215+
216+func favoritesFromTagRows(rows []sqlc.GetFavoritesByTagRow) []*entity.Favorite {
181217 favorites := make([]*entity.Favorite, len(rows))
182218 for i := range rows {
183- favorites[i] = favoriteFromRow(rows[i], nil)
219+ row := rows[i]
220+ favorites[i] = favoriteFromRow(favoriteRow{ID: row.ID, URL: row.Url, Title: row.Title, FaviconURL: row.FaviconUrl, ShortcutKey: row.ShortcutKey, Position: row.Position, CreatedAt: row.CreatedAt, UpdatedAt: row.UpdatedAt}, nil)
184221 }
185222 return favorites
186223 }
@@ -42,7 +42,7 @@ func (r *favoriteRepo) Save(ctx context.Context, fav *entity.Favorite) error {
42 if err != nil {42 if err != nil {
43 return err43 return err
44 }44 }
45- favoriteFromRow(row, fav)45+ favoriteFromRow(favoriteRowFromCreate(row), fav)
46 return nil46 return nil
47 }47 }
48 48
@@ -54,7 +54,7 @@ func (r *favoriteRepo) FindByID(ctx context.Context, id entity.FavoriteID) (*ent
54 }54 }
55 return nil, err55 return nil, err
56 }56 }
57- fav := favoriteFromRow(row, nil)57+ fav := favoriteFromRow(favoriteRowFromGetByID(row), nil)
58 return fav, r.hydrateTags(ctx, []*entity.Favorite{fav})58 return fav, r.hydrateTags(ctx, []*entity.Favorite{fav})
59 }59 }
60 60
@@ -66,7 +66,7 @@ func (r *favoriteRepo) FindByURL(ctx context.Context, url string) (*entity.Favor
66 }66 }
67 return nil, err67 return nil, err
68 }68 }
69- fav := favoriteFromRow(row, nil)69+ fav := favoriteFromRow(favoriteRowFromGetByURL(row), nil)
70 return fav, r.hydrateTags(ctx, []*entity.Favorite{fav})70 return fav, r.hydrateTags(ctx, []*entity.Favorite{fav})
71 }71 }
72 72
@@ -75,7 +75,7 @@ func (r *favoriteRepo) GetAll(ctx context.Context) ([]*entity.Favorite, error) {
75 if err != nil {75 if err != nil {
76 return nil, err76 return nil, err
77 }77 }
78- favorites := favoritesFromRows(rows)78+ favorites := favoritesFromAllRows(rows)
79 return favorites, r.hydrateTags(ctx, favorites)79 return favorites, r.hydrateTags(ctx, favorites)
80 }80 }
81 81
@@ -84,7 +84,7 @@ func (r *favoriteRepo) GetByTag(ctx context.Context, tagID entity.TagID) ([]*ent
84 if err != nil {84 if err != nil {
85 return nil, err85 return nil, err
86 }86 }
87- favorites := favoritesFromRows(rows)87+ favorites := favoritesFromTagRows(rows)
88 return favorites, r.hydrateTags(ctx, favorites)88 return favorites, r.hydrateTags(ctx, favorites)
89 }89 }
90 90
@@ -96,7 +96,7 @@ func (r *favoriteRepo) GetByShortcut(ctx context.Context, key int) (*entity.Favo
96 }96 }
97 return nil, err97 return nil, err
98 }98 }
99- fav := favoriteFromRow(row, nil)99+ fav := favoriteFromRow(favoriteRowFromGetByShortcut(row), nil)
100 return fav, r.hydrateTags(ctx, []*entity.Favorite{fav})100 return fav, r.hydrateTags(ctx, []*entity.Favorite{fav})
101 }101 }
102 102
@@ -155,15 +155,26 @@ func (r *favoriteRepo) hydrateTags(ctx context.Context, favorites []*entity.Favo
155 return nil155 return nil
156 }156 }
157 157
158-func favoriteFromRow(row sqlc.Favorite, target *entity.Favorite) *entity.Favorite {158+type favoriteRow struct {
159+ ID int64
160+ URL string
161+ Title sql.NullString
162+ FaviconURL sql.NullString
163+ ShortcutKey sql.NullInt64
164+ Position int64
165+ CreatedAt sql.NullTime
166+ UpdatedAt sql.NullTime
167+}
168+
169+func favoriteFromRow(row favoriteRow, target *entity.Favorite) *entity.Favorite {
159 fav := target170 fav := target
160 if fav == nil {171 if fav == nil {
161 fav = &entity.Favorite{}172 fav = &entity.Favorite{}
162 }173 }
163 fav.ID = entity.FavoriteID(row.ID)174 fav.ID = entity.FavoriteID(row.ID)
164- fav.URL = row.Url175+ fav.URL = row.URL
165 fav.Title = row.Title.String176 fav.Title = row.Title.String
166- fav.FaviconURL = row.FaviconUrl.String177+ fav.FaviconURL = row.FaviconURL.String
167 fav.Position = int(row.Position)178 fav.Position = int(row.Position)
168 fav.CreatedAt = row.CreatedAt.Time179 fav.CreatedAt = row.CreatedAt.Time
169 fav.UpdatedAt = row.UpdatedAt.Time180 fav.UpdatedAt = row.UpdatedAt.Time
@@ -177,10 +188,36 @@ func favoriteFromRow(row sqlc.Favorite, target *entity.Favorite) *entity.Favorit
177 return fav188 return fav
178 }189 }
179 190
180-func favoritesFromRows(rows []sqlc.Favorite) []*entity.Favorite {191+func favoriteRowFromCreate(row sqlc.CreateFavoriteRow) favoriteRow {
192+ return favoriteRow{ID: row.ID, URL: row.Url, Title: row.Title, FaviconURL: row.FaviconUrl, ShortcutKey: row.ShortcutKey, Position: row.Position, CreatedAt: row.CreatedAt, UpdatedAt: row.UpdatedAt}
193+}
194+
195+func favoriteRowFromGetByID(row sqlc.GetFavoriteByIDRow) favoriteRow {
196+ return favoriteRow{ID: row.ID, URL: row.Url, Title: row.Title, FaviconURL: row.FaviconUrl, ShortcutKey: row.ShortcutKey, Position: row.Position, CreatedAt: row.CreatedAt, UpdatedAt: row.UpdatedAt}
197+}
198+
199+func favoriteRowFromGetByURL(row sqlc.GetFavoriteByURLRow) favoriteRow {
200+ return favoriteRow{ID: row.ID, URL: row.Url, Title: row.Title, FaviconURL: row.FaviconUrl, ShortcutKey: row.ShortcutKey, Position: row.Position, CreatedAt: row.CreatedAt, UpdatedAt: row.UpdatedAt}
201+}
202+
203+func favoriteRowFromGetByShortcut(row sqlc.GetFavoriteByShortcutRow) favoriteRow {
204+ return favoriteRow{ID: row.ID, URL: row.Url, Title: row.Title, FaviconURL: row.FaviconUrl, ShortcutKey: row.ShortcutKey, Position: row.Position, CreatedAt: row.CreatedAt, UpdatedAt: row.UpdatedAt}
205+}
206+
207+func favoritesFromAllRows(rows []sqlc.GetAllFavoritesRow) []*entity.Favorite {
208+ favorites := make([]*entity.Favorite, len(rows))
209+ for i := range rows {
210+ row := rows[i]
211+ favorites[i] = favoriteFromRow(favoriteRow{ID: row.ID, URL: row.Url, Title: row.Title, FaviconURL: row.FaviconUrl, ShortcutKey: row.ShortcutKey, Position: row.Position, CreatedAt: row.CreatedAt, UpdatedAt: row.UpdatedAt}, nil)
212+ }
213+ return favorites
214+}
215+
216+func favoritesFromTagRows(rows []sqlc.GetFavoritesByTagRow) []*entity.Favorite {
181 favorites := make([]*entity.Favorite, len(rows))217 favorites := make([]*entity.Favorite, len(rows))
182 for i := range rows {218 for i := range rows {
183- favorites[i] = favoriteFromRow(rows[i], nil)219+ row := rows[i]
220+ favorites[i] = favoriteFromRow(favoriteRow{ID: row.ID, URL: row.Url, Title: row.Title, FaviconURL: row.FaviconUrl, ShortcutKey: row.ShortcutKey, Position: row.Position, CreatedAt: row.CreatedAt, UpdatedAt: row.UpdatedAt}, nil)
184 }221 }
185 return favorites222 return favorites
186 }223 }
M internal/infrastructure/persistence/sqlite/queries/favorites.sql +15 -6
@@ -1,25 +1,34 @@
11 -- name: GetAllFavorites :many
2-SELECT * FROM favorites ORDER BY position ASC;
2+SELECT id, url, title, favicon_url, shortcut_key, position, created_at, updated_at
3+FROM favorites
4+ORDER BY position ASC;
35
46 -- name: GetFavoriteByID :one
5-SELECT * FROM favorites WHERE id = ? LIMIT 1;
7+SELECT id, url, title, favicon_url, shortcut_key, position, created_at, updated_at
8+FROM favorites
9+WHERE id = ? LIMIT 1;
610
711 -- name: GetFavoriteByURL :one
8-SELECT * FROM favorites WHERE url = ? LIMIT 1;
12+SELECT id, url, title, favicon_url, shortcut_key, position, created_at, updated_at
13+FROM favorites
14+WHERE url = ? LIMIT 1;
915
1016 -- name: GetFavoritesByTag :many
11-SELECT f.* FROM favorites f
17+SELECT f.id, f.url, f.title, f.favicon_url, f.shortcut_key, f.position, f.created_at, f.updated_at
18+FROM favorites f
1219 INNER JOIN favorite_tag_assignments fta ON f.id = fta.favorite_id
1320 WHERE fta.tag_id = ?
1421 ORDER BY f.position ASC;
1522
1623 -- name: GetFavoriteByShortcut :one
17-SELECT * FROM favorites WHERE shortcut_key = ? LIMIT 1;
24+SELECT id, url, title, favicon_url, shortcut_key, position, created_at, updated_at
25+FROM favorites
26+WHERE shortcut_key = ? LIMIT 1;
1827
1928 -- name: CreateFavorite :one
2029 INSERT INTO favorites (url, title, favicon_url, position, created_at, updated_at)
2130 VALUES (?, ?, ?, COALESCE((SELECT MAX(position) + 1 FROM favorites), 0), CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
22-RETURNING *;
31+RETURNING id, url, title, favicon_url, shortcut_key, position, created_at, updated_at;
2332
2433 -- name: UpdateFavorite :exec
2534 UPDATE favorites
@@ -1,25 +1,34 @@
1 -- name: GetAllFavorites :many1 -- name: GetAllFavorites :many
2-SELECT * FROM favorites ORDER BY position ASC;2+SELECT id, url, title, favicon_url, shortcut_key, position, created_at, updated_at
3+FROM favorites
4+ORDER BY position ASC;
3 5
4 -- name: GetFavoriteByID :one6 -- name: GetFavoriteByID :one
5-SELECT * FROM favorites WHERE id = ? LIMIT 1;7+SELECT id, url, title, favicon_url, shortcut_key, position, created_at, updated_at
8+FROM favorites
9+WHERE id = ? LIMIT 1;
6 10
7 -- name: GetFavoriteByURL :one11 -- name: GetFavoriteByURL :one
8-SELECT * FROM favorites WHERE url = ? LIMIT 1;12+SELECT id, url, title, favicon_url, shortcut_key, position, created_at, updated_at
13+FROM favorites
14+WHERE url = ? LIMIT 1;
9 15
10 -- name: GetFavoritesByTag :many16 -- name: GetFavoritesByTag :many
11-SELECT f.* FROM favorites f17+SELECT f.id, f.url, f.title, f.favicon_url, f.shortcut_key, f.position, f.created_at, f.updated_at
18+FROM favorites f
12 INNER JOIN favorite_tag_assignments fta ON f.id = fta.favorite_id19 INNER JOIN favorite_tag_assignments fta ON f.id = fta.favorite_id
13 WHERE fta.tag_id = ?20 WHERE fta.tag_id = ?
14 ORDER BY f.position ASC;21 ORDER BY f.position ASC;
15 22
16 -- name: GetFavoriteByShortcut :one23 -- name: GetFavoriteByShortcut :one
17-SELECT * FROM favorites WHERE shortcut_key = ? LIMIT 1;24+SELECT id, url, title, favicon_url, shortcut_key, position, created_at, updated_at
25+FROM favorites
26+WHERE shortcut_key = ? LIMIT 1;
18 27
19 -- name: CreateFavorite :one28 -- name: CreateFavorite :one
20 INSERT INTO favorites (url, title, favicon_url, position, created_at, updated_at)29 INSERT INTO favorites (url, title, favicon_url, position, created_at, updated_at)
21 VALUES (?, ?, ?, COALESCE((SELECT MAX(position) + 1 FROM favorites), 0), CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)30 VALUES (?, ?, ?, COALESCE((SELECT MAX(position) + 1 FROM favorites), 0), CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
22-RETURNING *;31+RETURNING id, url, title, favicon_url, shortcut_key, position, created_at, updated_at;
23 32
24 -- name: UpdateFavorite :exec33 -- name: UpdateFavorite :exec
25 UPDATE favorites34 UPDATE favorites
M internal/infrastructure/persistence/sqlite/sqlc/favorites.sql.go +95 -26
@@ -13,7 +13,7 @@ import (
1313 const CreateFavorite = `-- name: CreateFavorite :one
1414 INSERT INTO favorites (url, title, favicon_url, position, created_at, updated_at)
1515 VALUES (?, ?, ?, COALESCE((SELECT MAX(position) + 1 FROM favorites), 0), CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
16-RETURNING id, url, title, favicon_url, folder_id, shortcut_key, position, created_at, updated_at
16+RETURNING id, url, title, favicon_url, shortcut_key, position, created_at, updated_at
1717 `
1818
1919 type CreateFavoriteParams struct {
@@ -22,15 +22,25 @@ type CreateFavoriteParams struct {
2222 FaviconUrl sql.NullString `json:"favicon_url"`
2323 }
2424
25-func (q *Queries) CreateFavorite(ctx context.Context, arg CreateFavoriteParams) (Favorite, error) {
25+type CreateFavoriteRow struct {
26+ ID int64 `json:"id"`
27+ Url string `json:"url"`
28+ Title sql.NullString `json:"title"`
29+ FaviconUrl sql.NullString `json:"favicon_url"`
30+ ShortcutKey sql.NullInt64 `json:"shortcut_key"`
31+ Position int64 `json:"position"`
32+ CreatedAt sql.NullTime `json:"created_at"`
33+ UpdatedAt sql.NullTime `json:"updated_at"`
34+}
35+
36+func (q *Queries) CreateFavorite(ctx context.Context, arg CreateFavoriteParams) (CreateFavoriteRow, error) {
2637 row := q.db.QueryRowContext(ctx, CreateFavorite, arg.Url, arg.Title, arg.FaviconUrl)
27- var i Favorite
38+ var i CreateFavoriteRow
2839 err := row.Scan(
2940 &i.ID,
3041 &i.Url,
3142 &i.Title,
3243 &i.FaviconUrl,
33- &i.FolderID,
3444 &i.ShortcutKey,
3545 &i.Position,
3646 &i.CreatedAt,
@@ -49,24 +59,36 @@ func (q *Queries) DeleteFavorite(ctx context.Context, id int64) error {
4959 }
5060
5161 const GetAllFavorites = `-- name: GetAllFavorites :many
52-SELECT id, url, title, favicon_url, folder_id, shortcut_key, position, created_at, updated_at FROM favorites ORDER BY position ASC
62+SELECT id, url, title, favicon_url, shortcut_key, position, created_at, updated_at
63+FROM favorites
64+ORDER BY position ASC
5365 `
5466
55-func (q *Queries) GetAllFavorites(ctx context.Context) ([]Favorite, error) {
67+type GetAllFavoritesRow struct {
68+ ID int64 `json:"id"`
69+ Url string `json:"url"`
70+ Title sql.NullString `json:"title"`
71+ FaviconUrl sql.NullString `json:"favicon_url"`
72+ ShortcutKey sql.NullInt64 `json:"shortcut_key"`
73+ Position int64 `json:"position"`
74+ CreatedAt sql.NullTime `json:"created_at"`
75+ UpdatedAt sql.NullTime `json:"updated_at"`
76+}
77+
78+func (q *Queries) GetAllFavorites(ctx context.Context) ([]GetAllFavoritesRow, error) {
5679 rows, err := q.db.QueryContext(ctx, GetAllFavorites)
5780 if err != nil {
5881 return nil, err
5982 }
6083 defer rows.Close()
61- items := []Favorite{}
84+ items := []GetAllFavoritesRow{}
6285 for rows.Next() {
63- var i Favorite
86+ var i GetAllFavoritesRow
6487 if err := rows.Scan(
6588 &i.ID,
6689 &i.Url,
6790 &i.Title,
6891 &i.FaviconUrl,
69- &i.FolderID,
7092 &i.ShortcutKey,
7193 &i.Position,
7294 &i.CreatedAt,
@@ -86,18 +108,30 @@ func (q *Queries) GetAllFavorites(ctx context.Context) ([]Favorite, error) {
86108 }
87109
88110 const GetFavoriteByID = `-- name: GetFavoriteByID :one
89-SELECT id, url, title, favicon_url, folder_id, shortcut_key, position, created_at, updated_at FROM favorites WHERE id = ? LIMIT 1
111+SELECT id, url, title, favicon_url, shortcut_key, position, created_at, updated_at
112+FROM favorites
113+WHERE id = ? LIMIT 1
90114 `
91115
92-func (q *Queries) GetFavoriteByID(ctx context.Context, id int64) (Favorite, error) {
116+type GetFavoriteByIDRow struct {
117+ ID int64 `json:"id"`
118+ Url string `json:"url"`
119+ Title sql.NullString `json:"title"`
120+ FaviconUrl sql.NullString `json:"favicon_url"`
121+ ShortcutKey sql.NullInt64 `json:"shortcut_key"`
122+ Position int64 `json:"position"`
123+ CreatedAt sql.NullTime `json:"created_at"`
124+ UpdatedAt sql.NullTime `json:"updated_at"`
125+}
126+
127+func (q *Queries) GetFavoriteByID(ctx context.Context, id int64) (GetFavoriteByIDRow, error) {
93128 row := q.db.QueryRowContext(ctx, GetFavoriteByID, id)
94- var i Favorite
129+ var i GetFavoriteByIDRow
95130 err := row.Scan(
96131 &i.ID,
97132 &i.Url,
98133 &i.Title,
99134 &i.FaviconUrl,
100- &i.FolderID,
101135 &i.ShortcutKey,
102136 &i.Position,
103137 &i.CreatedAt,
@@ -107,18 +141,30 @@ func (q *Queries) GetFavoriteByID(ctx context.Context, id int64) (Favorite, erro
107141 }
108142
109143 const GetFavoriteByShortcut = `-- name: GetFavoriteByShortcut :one
110-SELECT id, url, title, favicon_url, folder_id, shortcut_key, position, created_at, updated_at FROM favorites WHERE shortcut_key = ? LIMIT 1
144+SELECT id, url, title, favicon_url, shortcut_key, position, created_at, updated_at
145+FROM favorites
146+WHERE shortcut_key = ? LIMIT 1
111147 `
112148
113-func (q *Queries) GetFavoriteByShortcut(ctx context.Context, shortcutKey sql.NullInt64) (Favorite, error) {
149+type GetFavoriteByShortcutRow struct {
150+ ID int64 `json:"id"`
151+ Url string `json:"url"`
152+ Title sql.NullString `json:"title"`
153+ FaviconUrl sql.NullString `json:"favicon_url"`
154+ ShortcutKey sql.NullInt64 `json:"shortcut_key"`
155+ Position int64 `json:"position"`
156+ CreatedAt sql.NullTime `json:"created_at"`
157+ UpdatedAt sql.NullTime `json:"updated_at"`
158+}
159+
160+func (q *Queries) GetFavoriteByShortcut(ctx context.Context, shortcutKey sql.NullInt64) (GetFavoriteByShortcutRow, error) {
114161 row := q.db.QueryRowContext(ctx, GetFavoriteByShortcut, shortcutKey)
115- var i Favorite
162+ var i GetFavoriteByShortcutRow
116163 err := row.Scan(
117164 &i.ID,
118165 &i.Url,
119166 &i.Title,
120167 &i.FaviconUrl,
121- &i.FolderID,
122168 &i.ShortcutKey,
123169 &i.Position,
124170 &i.CreatedAt,
@@ -128,18 +174,30 @@ func (q *Queries) GetFavoriteByShortcut(ctx context.Context, shortcutKey sql.Nul
128174 }
129175
130176 const GetFavoriteByURL = `-- name: GetFavoriteByURL :one
131-SELECT id, url, title, favicon_url, folder_id, shortcut_key, position, created_at, updated_at FROM favorites WHERE url = ? LIMIT 1
177+SELECT id, url, title, favicon_url, shortcut_key, position, created_at, updated_at
178+FROM favorites
179+WHERE url = ? LIMIT 1
132180 `
133181
134-func (q *Queries) GetFavoriteByURL(ctx context.Context, url string) (Favorite, error) {
182+type GetFavoriteByURLRow struct {
183+ ID int64 `json:"id"`
184+ Url string `json:"url"`
185+ Title sql.NullString `json:"title"`
186+ FaviconUrl sql.NullString `json:"favicon_url"`
187+ ShortcutKey sql.NullInt64 `json:"shortcut_key"`
188+ Position int64 `json:"position"`
189+ CreatedAt sql.NullTime `json:"created_at"`
190+ UpdatedAt sql.NullTime `json:"updated_at"`
191+}
192+
193+func (q *Queries) GetFavoriteByURL(ctx context.Context, url string) (GetFavoriteByURLRow, error) {
135194 row := q.db.QueryRowContext(ctx, GetFavoriteByURL, url)
136- var i Favorite
195+ var i GetFavoriteByURLRow
137196 err := row.Scan(
138197 &i.ID,
139198 &i.Url,
140199 &i.Title,
141200 &i.FaviconUrl,
142- &i.FolderID,
143201 &i.ShortcutKey,
144202 &i.Position,
145203 &i.CreatedAt,
@@ -149,27 +207,38 @@ func (q *Queries) GetFavoriteByURL(ctx context.Context, url string) (Favorite, e
149207 }
150208
151209 const GetFavoritesByTag = `-- name: GetFavoritesByTag :many
152-SELECT f.id, f.url, f.title, f.favicon_url, f.folder_id, f.shortcut_key, f.position, f.created_at, f.updated_at FROM favorites f
210+SELECT f.id, f.url, f.title, f.favicon_url, f.shortcut_key, f.position, f.created_at, f.updated_at
211+FROM favorites f
153212 INNER JOIN favorite_tag_assignments fta ON f.id = fta.favorite_id
154213 WHERE fta.tag_id = ?
155214 ORDER BY f.position ASC
156215 `
157216
158-func (q *Queries) GetFavoritesByTag(ctx context.Context, tagID int64) ([]Favorite, error) {
217+type GetFavoritesByTagRow struct {
218+ ID int64 `json:"id"`
219+ Url string `json:"url"`
220+ Title sql.NullString `json:"title"`
221+ FaviconUrl sql.NullString `json:"favicon_url"`
222+ ShortcutKey sql.NullInt64 `json:"shortcut_key"`
223+ Position int64 `json:"position"`
224+ CreatedAt sql.NullTime `json:"created_at"`
225+ UpdatedAt sql.NullTime `json:"updated_at"`
226+}
227+
228+func (q *Queries) GetFavoritesByTag(ctx context.Context, tagID int64) ([]GetFavoritesByTagRow, error) {
159229 rows, err := q.db.QueryContext(ctx, GetFavoritesByTag, tagID)
160230 if err != nil {
161231 return nil, err
162232 }
163233 defer rows.Close()
164- items := []Favorite{}
234+ items := []GetFavoritesByTagRow{}
165235 for rows.Next() {
166- var i Favorite
236+ var i GetFavoritesByTagRow
167237 if err := rows.Scan(
168238 &i.ID,
169239 &i.Url,
170240 &i.Title,
171241 &i.FaviconUrl,
172- &i.FolderID,
173242 &i.ShortcutKey,
174243 &i.Position,
175244 &i.CreatedAt,
@@ -13,7 +13,7 @@ import (
13 const CreateFavorite = `-- name: CreateFavorite :one13 const CreateFavorite = `-- name: CreateFavorite :one
14 INSERT INTO favorites (url, title, favicon_url, position, created_at, updated_at)14 INSERT INTO favorites (url, title, favicon_url, position, created_at, updated_at)
15 VALUES (?, ?, ?, COALESCE((SELECT MAX(position) + 1 FROM favorites), 0), CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)15 VALUES (?, ?, ?, COALESCE((SELECT MAX(position) + 1 FROM favorites), 0), CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
16-RETURNING id, url, title, favicon_url, folder_id, shortcut_key, position, created_at, updated_at16+RETURNING id, url, title, favicon_url, shortcut_key, position, created_at, updated_at
17 `17 `
18 18
19 type CreateFavoriteParams struct {19 type CreateFavoriteParams struct {
@@ -22,15 +22,25 @@ type CreateFavoriteParams struct {
22 FaviconUrl sql.NullString `json:"favicon_url"`22 FaviconUrl sql.NullString `json:"favicon_url"`
23 }23 }
24 24
25-func (q *Queries) CreateFavorite(ctx context.Context, arg CreateFavoriteParams) (Favorite, error) {25+type CreateFavoriteRow struct {
26+ ID int64 `json:"id"`
27+ Url string `json:"url"`
28+ Title sql.NullString `json:"title"`
29+ FaviconUrl sql.NullString `json:"favicon_url"`
30+ ShortcutKey sql.NullInt64 `json:"shortcut_key"`
31+ Position int64 `json:"position"`
32+ CreatedAt sql.NullTime `json:"created_at"`
33+ UpdatedAt sql.NullTime `json:"updated_at"`
34+}
35+
36+func (q *Queries) CreateFavorite(ctx context.Context, arg CreateFavoriteParams) (CreateFavoriteRow, error) {
26 row := q.db.QueryRowContext(ctx, CreateFavorite, arg.Url, arg.Title, arg.FaviconUrl)37 row := q.db.QueryRowContext(ctx, CreateFavorite, arg.Url, arg.Title, arg.FaviconUrl)
27- var i Favorite38+ var i CreateFavoriteRow
28 err := row.Scan(39 err := row.Scan(
29 &i.ID,40 &i.ID,
30 &i.Url,41 &i.Url,
31 &i.Title,42 &i.Title,
32 &i.FaviconUrl,43 &i.FaviconUrl,
33- &i.FolderID,
34 &i.ShortcutKey,44 &i.ShortcutKey,
35 &i.Position,45 &i.Position,
36 &i.CreatedAt,46 &i.CreatedAt,
@@ -49,24 +59,36 @@ func (q *Queries) DeleteFavorite(ctx context.Context, id int64) error {
49 }59 }
50 60
51 const GetAllFavorites = `-- name: GetAllFavorites :many61 const GetAllFavorites = `-- name: GetAllFavorites :many
52-SELECT id, url, title, favicon_url, folder_id, shortcut_key, position, created_at, updated_at FROM favorites ORDER BY position ASC62+SELECT id, url, title, favicon_url, shortcut_key, position, created_at, updated_at
63+FROM favorites
64+ORDER BY position ASC
53 `65 `
54 66
55-func (q *Queries) GetAllFavorites(ctx context.Context) ([]Favorite, error) {67+type GetAllFavoritesRow struct {
68+ ID int64 `json:"id"`
69+ Url string `json:"url"`
70+ Title sql.NullString `json:"title"`
71+ FaviconUrl sql.NullString `json:"favicon_url"`
72+ ShortcutKey sql.NullInt64 `json:"shortcut_key"`
73+ Position int64 `json:"position"`
74+ CreatedAt sql.NullTime `json:"created_at"`
75+ UpdatedAt sql.NullTime `json:"updated_at"`
76+}
77+
78+func (q *Queries) GetAllFavorites(ctx context.Context) ([]GetAllFavoritesRow, error) {
56 rows, err := q.db.QueryContext(ctx, GetAllFavorites)79 rows, err := q.db.QueryContext(ctx, GetAllFavorites)
57 if err != nil {80 if err != nil {
58 return nil, err81 return nil, err
59 }82 }
60 defer rows.Close()83 defer rows.Close()
61- items := []Favorite{}84+ items := []GetAllFavoritesRow{}
62 for rows.Next() {85 for rows.Next() {
63- var i Favorite86+ var i GetAllFavoritesRow
64 if err := rows.Scan(87 if err := rows.Scan(
65 &i.ID,88 &i.ID,
66 &i.Url,89 &i.Url,
67 &i.Title,90 &i.Title,
68 &i.FaviconUrl,91 &i.FaviconUrl,
69- &i.FolderID,
70 &i.ShortcutKey,92 &i.ShortcutKey,
71 &i.Position,93 &i.Position,
72 &i.CreatedAt,94 &i.CreatedAt,
@@ -86,18 +108,30 @@ func (q *Queries) GetAllFavorites(ctx context.Context) ([]Favorite, error) {
86 }108 }
87 109
88 const GetFavoriteByID = `-- name: GetFavoriteByID :one110 const GetFavoriteByID = `-- name: GetFavoriteByID :one
89-SELECT id, url, title, favicon_url, folder_id, shortcut_key, position, created_at, updated_at FROM favorites WHERE id = ? LIMIT 1111+SELECT id, url, title, favicon_url, shortcut_key, position, created_at, updated_at
112+FROM favorites
113+WHERE id = ? LIMIT 1
90 `114 `
91 115
92-func (q *Queries) GetFavoriteByID(ctx context.Context, id int64) (Favorite, error) {116+type GetFavoriteByIDRow struct {
117+ ID int64 `json:"id"`
118+ Url string `json:"url"`
119+ Title sql.NullString `json:"title"`
120+ FaviconUrl sql.NullString `json:"favicon_url"`
121+ ShortcutKey sql.NullInt64 `json:"shortcut_key"`
122+ Position int64 `json:"position"`
123+ CreatedAt sql.NullTime `json:"created_at"`
124+ UpdatedAt sql.NullTime `json:"updated_at"`
125+}
126+
127+func (q *Queries) GetFavoriteByID(ctx context.Context, id int64) (GetFavoriteByIDRow, error) {
93 row := q.db.QueryRowContext(ctx, GetFavoriteByID, id)128 row := q.db.QueryRowContext(ctx, GetFavoriteByID, id)
94- var i Favorite129+ var i GetFavoriteByIDRow
95 err := row.Scan(130 err := row.Scan(
96 &i.ID,131 &i.ID,
97 &i.Url,132 &i.Url,
98 &i.Title,133 &i.Title,
99 &i.FaviconUrl,134 &i.FaviconUrl,
100- &i.FolderID,
101 &i.ShortcutKey,135 &i.ShortcutKey,
102 &i.Position,136 &i.Position,
103 &i.CreatedAt,137 &i.CreatedAt,
@@ -107,18 +141,30 @@ func (q *Queries) GetFavoriteByID(ctx context.Context, id int64) (Favorite, erro
107 }141 }
108 142
109 const GetFavoriteByShortcut = `-- name: GetFavoriteByShortcut :one143 const GetFavoriteByShortcut = `-- name: GetFavoriteByShortcut :one
110-SELECT id, url, title, favicon_url, folder_id, shortcut_key, position, created_at, updated_at FROM favorites WHERE shortcut_key = ? LIMIT 1144+SELECT id, url, title, favicon_url, shortcut_key, position, created_at, updated_at
145+FROM favorites
146+WHERE shortcut_key = ? LIMIT 1
111 `147 `
112 148
113-func (q *Queries) GetFavoriteByShortcut(ctx context.Context, shortcutKey sql.NullInt64) (Favorite, error) {149+type GetFavoriteByShortcutRow struct {
150+ ID int64 `json:"id"`
151+ Url string `json:"url"`
152+ Title sql.NullString `json:"title"`
153+ FaviconUrl sql.NullString `json:"favicon_url"`
154+ ShortcutKey sql.NullInt64 `json:"shortcut_key"`
155+ Position int64 `json:"position"`
156+ CreatedAt sql.NullTime `json:"created_at"`
157+ UpdatedAt sql.NullTime `json:"updated_at"`
158+}
159+
160+func (q *Queries) GetFavoriteByShortcut(ctx context.Context, shortcutKey sql.NullInt64) (GetFavoriteByShortcutRow, error) {
114 row := q.db.QueryRowContext(ctx, GetFavoriteByShortcut, shortcutKey)161 row := q.db.QueryRowContext(ctx, GetFavoriteByShortcut, shortcutKey)
115- var i Favorite162+ var i GetFavoriteByShortcutRow
116 err := row.Scan(163 err := row.Scan(
117 &i.ID,164 &i.ID,
118 &i.Url,165 &i.Url,
119 &i.Title,166 &i.Title,
120 &i.FaviconUrl,167 &i.FaviconUrl,
121- &i.FolderID,
122 &i.ShortcutKey,168 &i.ShortcutKey,
123 &i.Position,169 &i.Position,
124 &i.CreatedAt,170 &i.CreatedAt,
@@ -128,18 +174,30 @@ func (q *Queries) GetFavoriteByShortcut(ctx context.Context, shortcutKey sql.Nul
128 }174 }
129 175
130 const GetFavoriteByURL = `-- name: GetFavoriteByURL :one176 const GetFavoriteByURL = `-- name: GetFavoriteByURL :one
131-SELECT id, url, title, favicon_url, folder_id, shortcut_key, position, created_at, updated_at FROM favorites WHERE url = ? LIMIT 1177+SELECT id, url, title, favicon_url, shortcut_key, position, created_at, updated_at
178+FROM favorites
179+WHERE url = ? LIMIT 1
132 `180 `
133 181
134-func (q *Queries) GetFavoriteByURL(ctx context.Context, url string) (Favorite, error) {182+type GetFavoriteByURLRow struct {
183+ ID int64 `json:"id"`
184+ Url string `json:"url"`
185+ Title sql.NullString `json:"title"`
186+ FaviconUrl sql.NullString `json:"favicon_url"`
187+ ShortcutKey sql.NullInt64 `json:"shortcut_key"`
188+ Position int64 `json:"position"`
189+ CreatedAt sql.NullTime `json:"created_at"`
190+ UpdatedAt sql.NullTime `json:"updated_at"`
191+}
192+
193+func (q *Queries) GetFavoriteByURL(ctx context.Context, url string) (GetFavoriteByURLRow, error) {
135 row := q.db.QueryRowContext(ctx, GetFavoriteByURL, url)194 row := q.db.QueryRowContext(ctx, GetFavoriteByURL, url)
136- var i Favorite195+ var i GetFavoriteByURLRow
137 err := row.Scan(196 err := row.Scan(
138 &i.ID,197 &i.ID,
139 &i.Url,198 &i.Url,
140 &i.Title,199 &i.Title,
141 &i.FaviconUrl,200 &i.FaviconUrl,
142- &i.FolderID,
143 &i.ShortcutKey,201 &i.ShortcutKey,
144 &i.Position,202 &i.Position,
145 &i.CreatedAt,203 &i.CreatedAt,
@@ -149,27 +207,38 @@ func (q *Queries) GetFavoriteByURL(ctx context.Context, url string) (Favorite, e
149 }207 }
150 208
151 const GetFavoritesByTag = `-- name: GetFavoritesByTag :many209 const GetFavoritesByTag = `-- name: GetFavoritesByTag :many
152-SELECT f.id, f.url, f.title, f.favicon_url, f.folder_id, f.shortcut_key, f.position, f.created_at, f.updated_at FROM favorites f210+SELECT f.id, f.url, f.title, f.favicon_url, f.shortcut_key, f.position, f.created_at, f.updated_at
211+FROM favorites f
153 INNER JOIN favorite_tag_assignments fta ON f.id = fta.favorite_id212 INNER JOIN favorite_tag_assignments fta ON f.id = fta.favorite_id
154 WHERE fta.tag_id = ?213 WHERE fta.tag_id = ?
155 ORDER BY f.position ASC214 ORDER BY f.position ASC
156 `215 `
157 216
158-func (q *Queries) GetFavoritesByTag(ctx context.Context, tagID int64) ([]Favorite, error) {217+type GetFavoritesByTagRow struct {
218+ ID int64 `json:"id"`
219+ Url string `json:"url"`
220+ Title sql.NullString `json:"title"`
221+ FaviconUrl sql.NullString `json:"favicon_url"`
222+ ShortcutKey sql.NullInt64 `json:"shortcut_key"`
223+ Position int64 `json:"position"`
224+ CreatedAt sql.NullTime `json:"created_at"`
225+ UpdatedAt sql.NullTime `json:"updated_at"`
226+}
227+
228+func (q *Queries) GetFavoritesByTag(ctx context.Context, tagID int64) ([]GetFavoritesByTagRow, error) {
159 rows, err := q.db.QueryContext(ctx, GetFavoritesByTag, tagID)229 rows, err := q.db.QueryContext(ctx, GetFavoritesByTag, tagID)
160 if err != nil {230 if err != nil {
161 return nil, err231 return nil, err
162 }232 }
163 defer rows.Close()233 defer rows.Close()
164- items := []Favorite{}234+ items := []GetFavoritesByTagRow{}
165 for rows.Next() {235 for rows.Next() {
166- var i Favorite236+ var i GetFavoritesByTagRow
167 if err := rows.Scan(237 if err := rows.Scan(
168 &i.ID,238 &i.ID,
169 &i.Url,239 &i.Url,
170 &i.Title,240 &i.Title,
171 &i.FaviconUrl,241 &i.FaviconUrl,
172- &i.FolderID,
173 &i.ShortcutKey,242 &i.ShortcutKey,
174 &i.Position,243 &i.Position,
175 &i.CreatedAt,244 &i.CreatedAt,
M internal/infrastructure/persistence/sqlite/sqlc/querier.go +6 -6
@@ -13,7 +13,7 @@ type Querier interface {
1313 AddToWhitelist(ctx context.Context, domain string) error
1414 AssignTagToFavorite(ctx context.Context, arg AssignTagToFavoriteParams) error
1515 CapVisitCount(ctx context.Context, arg CapVisitCountParams) error
16- CreateFavorite(ctx context.Context, arg CreateFavoriteParams) (Favorite, error)
16+ CreateFavorite(ctx context.Context, arg CreateFavoriteParams) (CreateFavoriteRow, error)
1717 CreateTag(ctx context.Context, arg CreateTagParams) (FavoriteTag, error)
1818 DeleteAllHistory(ctx context.Context) error
1919 // Deletes exited browser sessions older than the given cutoff time.
@@ -32,7 +32,7 @@ type Querier interface {
3232 DeleteTag(ctx context.Context, id int64) error
3333 DeleteZoomLevel(ctx context.Context, domain string) error
3434 GetActiveBrowserSession(ctx context.Context) (Session, error)
35- GetAllFavorites(ctx context.Context) ([]Favorite, error)
35+ GetAllFavorites(ctx context.Context) ([]GetAllFavoritesRow, error)
3636 GetAllMostVisited(ctx context.Context) ([]History, error)
3737 GetAllRecentHistory(ctx context.Context) ([]History, error)
3838 GetAllRecentHistoryByDomain(ctx context.Context, domain sql.NullString) ([]History, error)
@@ -42,10 +42,10 @@ type Querier interface {
4242 GetDailyVisitCount(ctx context.Context, date interface{}) ([]GetDailyVisitCountRow, error)
4343 GetDomainStats(ctx context.Context, limit int64) ([]GetDomainStatsRow, error)
4444 GetFavicon(ctx context.Context, key string) (Favicon, error)
45- GetFavoriteByID(ctx context.Context, id int64) (Favorite, error)
46- GetFavoriteByShortcut(ctx context.Context, shortcutKey sql.NullInt64) (Favorite, error)
47- GetFavoriteByURL(ctx context.Context, url string) (Favorite, error)
48- GetFavoritesByTag(ctx context.Context, tagID int64) ([]Favorite, error)
45+ GetFavoriteByID(ctx context.Context, id int64) (GetFavoriteByIDRow, error)
46+ GetFavoriteByShortcut(ctx context.Context, shortcutKey sql.NullInt64) (GetFavoriteByShortcutRow, error)
47+ GetFavoriteByURL(ctx context.Context, url string) (GetFavoriteByURLRow, error)
48+ GetFavoritesByTag(ctx context.Context, tagID int64) ([]GetFavoritesByTagRow, error)
4949 GetHistoryByURL(ctx context.Context, url string) (History, error)
5050 GetHistoryStats(ctx context.Context) (GetHistoryStatsRow, error)
5151 GetHourlyDistribution(ctx context.Context) ([]GetHourlyDistributionRow, error)
@@ -13,7 +13,7 @@ type Querier interface {
13 AddToWhitelist(ctx context.Context, domain string) error13 AddToWhitelist(ctx context.Context, domain string) error
14 AssignTagToFavorite(ctx context.Context, arg AssignTagToFavoriteParams) error14 AssignTagToFavorite(ctx context.Context, arg AssignTagToFavoriteParams) error
15 CapVisitCount(ctx context.Context, arg CapVisitCountParams) error15 CapVisitCount(ctx context.Context, arg CapVisitCountParams) error
16- CreateFavorite(ctx context.Context, arg CreateFavoriteParams) (Favorite, error)16+ CreateFavorite(ctx context.Context, arg CreateFavoriteParams) (CreateFavoriteRow, error)
17 CreateTag(ctx context.Context, arg CreateTagParams) (FavoriteTag, error)17 CreateTag(ctx context.Context, arg CreateTagParams) (FavoriteTag, error)
18 DeleteAllHistory(ctx context.Context) error18 DeleteAllHistory(ctx context.Context) error
19 // Deletes exited browser sessions older than the given cutoff time.19 // Deletes exited browser sessions older than the given cutoff time.
@@ -32,7 +32,7 @@ type Querier interface {
32 DeleteTag(ctx context.Context, id int64) error32 DeleteTag(ctx context.Context, id int64) error
33 DeleteZoomLevel(ctx context.Context, domain string) error33 DeleteZoomLevel(ctx context.Context, domain string) error
34 GetActiveBrowserSession(ctx context.Context) (Session, error)34 GetActiveBrowserSession(ctx context.Context) (Session, error)
35- GetAllFavorites(ctx context.Context) ([]Favorite, error)35+ GetAllFavorites(ctx context.Context) ([]GetAllFavoritesRow, error)
36 GetAllMostVisited(ctx context.Context) ([]History, error)36 GetAllMostVisited(ctx context.Context) ([]History, error)
37 GetAllRecentHistory(ctx context.Context) ([]History, error)37 GetAllRecentHistory(ctx context.Context) ([]History, error)
38 GetAllRecentHistoryByDomain(ctx context.Context, domain sql.NullString) ([]History, error)38 GetAllRecentHistoryByDomain(ctx context.Context, domain sql.NullString) ([]History, error)
@@ -42,10 +42,10 @@ type Querier interface {
42 GetDailyVisitCount(ctx context.Context, date interface{}) ([]GetDailyVisitCountRow, error)42 GetDailyVisitCount(ctx context.Context, date interface{}) ([]GetDailyVisitCountRow, error)
43 GetDomainStats(ctx context.Context, limit int64) ([]GetDomainStatsRow, error)43 GetDomainStats(ctx context.Context, limit int64) ([]GetDomainStatsRow, error)
44 GetFavicon(ctx context.Context, key string) (Favicon, error)44 GetFavicon(ctx context.Context, key string) (Favicon, error)
45- GetFavoriteByID(ctx context.Context, id int64) (Favorite, error)45+ GetFavoriteByID(ctx context.Context, id int64) (GetFavoriteByIDRow, error)
46- GetFavoriteByShortcut(ctx context.Context, shortcutKey sql.NullInt64) (Favorite, error)46+ GetFavoriteByShortcut(ctx context.Context, shortcutKey sql.NullInt64) (GetFavoriteByShortcutRow, error)
47- GetFavoriteByURL(ctx context.Context, url string) (Favorite, error)47+ GetFavoriteByURL(ctx context.Context, url string) (GetFavoriteByURLRow, error)
48- GetFavoritesByTag(ctx context.Context, tagID int64) ([]Favorite, error)48+ GetFavoritesByTag(ctx context.Context, tagID int64) ([]GetFavoritesByTagRow, error)
49 GetHistoryByURL(ctx context.Context, url string) (History, error)49 GetHistoryByURL(ctx context.Context, url string) (History, error)
50 GetHistoryStats(ctx context.Context) (GetHistoryStatsRow, error)50 GetHistoryStats(ctx context.Context) (GetHistoryStatsRow, error)
51 GetHourlyDistribution(ctx context.Context) ([]GetHourlyDistributionRow, error)51 GetHourlyDistribution(ctx context.Context) ([]GetHourlyDistributionRow, error)
M internal/ui/systemviews/components_templ.go +0 -1
@@ -1,6 +1,5 @@
11 // Code generated by templ - DO NOT EDIT.
22
3-// templ: version: v0.3.1020
43 package systemviews
54
65 //lint:file-ignore SA4006 This context is only used if a nested component is present.
@@ -1,6 +1,5 @@
1 // Code generated by templ - DO NOT EDIT.1 // Code generated by templ - DO NOT EDIT.
2 2
3-// templ: version: v0.3.1020
4 package systemviews3 package systemviews
5 4
6 //lint:file-ignore SA4006 This context is only used if a nested component is present.5 //lint:file-ignore SA4006 This context is only used if a nested component is present.
M internal/ui/systemviews/config_templ.go +0 -1 generated file: collapsed
M internal/ui/systemviews/favorites_templ.go +0 -1 generated file: collapsed
M internal/ui/systemviews/history_templ.go +0 -1 generated file: collapsed
M internal/ui/systemviews/icons_templ.go +0 -1 generated file: collapsed

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