feat(domain): add session purge entity and repository methods
- commit
- de0b075a54b685d9a17074ece46251ce211918fa
- author
- brice · · 2025-12-25 10:16 UTC
- parent
- b375737
- signature
- unsigned
7 files · +103 -0
M internal/domain/entity/purge.go +6 -0
| @@ -30,3 +30,9 @@ type PurgeResult struct { | |||
| 30 | 30 | Success bool | |
| 31 | 31 | Error error | |
| 32 | 32 | } | |
| 33 | + | ||
| 34 | + | // SessionPurgeItem represents an inactive session in the purge selection UI. | |
| 35 | + | type SessionPurgeItem struct { | |
| 36 | + | Info SessionInfo | |
| 37 | + | Selected bool | |
| 38 | + | } | |
| @@ -30,3 +30,9 @@ type PurgeResult struct { | |||||
| 30 | Success bool | 30 | Success bool | ||
| 31 | Error error | 31 | Error error | ||
| 32 | } | 32 | } | ||
| 33 | + | ||||
| 34 | + | // SessionPurgeItem represents an inactive session in the purge selection UI. | |||
| 35 | + | type SessionPurgeItem struct { | |||
| 36 | + | Info SessionInfo | |||
| 37 | + | Selected bool | |||
| 38 | + | } | |||
M internal/domain/repository/mocks/mocks.go +60 -0
| @@ -3335,6 +3335,66 @@ func (_c *MockSessionStateRepository_GetSnapshot_Call) RunAndReturn(run func(ctx | |||
| 3335 | 3335 | return _c | |
| 3336 | 3336 | } | |
| 3337 | 3337 | ||
| 3338 | + | // GetTotalSnapshotsSize provides a mock function for the type MockSessionStateRepository | |
| 3339 | + | func (_mock *MockSessionStateRepository) GetTotalSnapshotsSize(ctx context.Context) (int64, error) { | |
| 3340 | + | ret := _mock.Called(ctx) | |
| 3341 | + | ||
| 3342 | + | if len(ret) == 0 { | |
| 3343 | + | panic("no return value specified for GetTotalSnapshotsSize") | |
| 3344 | + | } | |
| 3345 | + | ||
| 3346 | + | var r0 int64 | |
| 3347 | + | var r1 error | |
| 3348 | + | if returnFunc, ok := ret.Get(0).(func(context.Context) (int64, error)); ok { | |
| 3349 | + | return returnFunc(ctx) | |
| 3350 | + | } | |
| 3351 | + | if returnFunc, ok := ret.Get(0).(func(context.Context) int64); ok { | |
| 3352 | + | r0 = returnFunc(ctx) | |
| 3353 | + | } else { | |
| 3354 | + | r0 = ret.Get(0).(int64) | |
| 3355 | + | } | |
| 3356 | + | if returnFunc, ok := ret.Get(1).(func(context.Context) error); ok { | |
| 3357 | + | r1 = returnFunc(ctx) | |
| 3358 | + | } else { | |
| 3359 | + | r1 = ret.Error(1) | |
| 3360 | + | } | |
| 3361 | + | return r0, r1 | |
| 3362 | + | } | |
| 3363 | + | ||
| 3364 | + | // MockSessionStateRepository_GetTotalSnapshotsSize_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTotalSnapshotsSize' | |
| 3365 | + | type MockSessionStateRepository_GetTotalSnapshotsSize_Call struct { | |
| 3366 | + | *mock.Call | |
| 3367 | + | } | |
| 3368 | + | ||
| 3369 | + | // GetTotalSnapshotsSize is a helper method to define mock.On call | |
| 3370 | + | // - ctx context.Context | |
| 3371 | + | func (_e *MockSessionStateRepository_Expecter) GetTotalSnapshotsSize(ctx interface{}) *MockSessionStateRepository_GetTotalSnapshotsSize_Call { | |
| 3372 | + | return &MockSessionStateRepository_GetTotalSnapshotsSize_Call{Call: _e.mock.On("GetTotalSnapshotsSize", ctx)} | |
| 3373 | + | } | |
| 3374 | + | ||
| 3375 | + | func (_c *MockSessionStateRepository_GetTotalSnapshotsSize_Call) Run(run func(ctx context.Context)) *MockSessionStateRepository_GetTotalSnapshotsSize_Call { | |
| 3376 | + | _c.Call.Run(func(args mock.Arguments) { | |
| 3377 | + | var arg0 context.Context | |
| 3378 | + | if args[0] != nil { | |
| 3379 | + | arg0 = args[0].(context.Context) | |
| 3380 | + | } | |
| 3381 | + | run( | |
| 3382 | + | arg0, | |
| 3383 | + | ) | |
| 3384 | + | }) | |
| 3385 | + | return _c | |
| 3386 | + | } | |
| 3387 | + | ||
| 3388 | + | func (_c *MockSessionStateRepository_GetTotalSnapshotsSize_Call) Return(n int64, err error) *MockSessionStateRepository_GetTotalSnapshotsSize_Call { | |
| 3389 | + | _c.Call.Return(n, err) | |
| 3390 | + | return _c | |
| 3391 | + | } | |
| 3392 | + | ||
| 3393 | + | func (_c *MockSessionStateRepository_GetTotalSnapshotsSize_Call) RunAndReturn(run func(ctx context.Context) (int64, error)) *MockSessionStateRepository_GetTotalSnapshotsSize_Call { | |
| 3394 | + | _c.Call.Return(run) | |
| 3395 | + | return _c | |
| 3396 | + | } | |
| 3397 | + | ||
| 3338 | 3398 | // SaveSnapshot provides a mock function for the type MockSessionStateRepository | |
| 3339 | 3399 | func (_mock *MockSessionStateRepository) SaveSnapshot(ctx context.Context, state *entity.SessionState) error { | |
| 3340 | 3400 | ret := _mock.Called(ctx, state) | |
| @@ -3335,6 +3335,66 @@ func (_c *MockSessionStateRepository_GetSnapshot_Call) RunAndReturn(run func(ctx | |||||
| 3335 | return _c | 3335 | return _c | ||
| 3336 | } | 3336 | } | ||
| 3337 | 3337 | ||||
| 3338 | + | // GetTotalSnapshotsSize provides a mock function for the type MockSessionStateRepository | |||
| 3339 | + | func (_mock *MockSessionStateRepository) GetTotalSnapshotsSize(ctx context.Context) (int64, error) { | |||
| 3340 | + | ret := _mock.Called(ctx) | |||
| 3341 | + | ||||
| 3342 | + | if len(ret) == 0 { | |||
| 3343 | + | panic("no return value specified for GetTotalSnapshotsSize") | |||
| 3344 | + | } | |||
| 3345 | + | ||||
| 3346 | + | var r0 int64 | |||
| 3347 | + | var r1 error | |||
| 3348 | + | if returnFunc, ok := ret.Get(0).(func(context.Context) (int64, error)); ok { | |||
| 3349 | + | return returnFunc(ctx) | |||
| 3350 | + | } | |||
| 3351 | + | if returnFunc, ok := ret.Get(0).(func(context.Context) int64); ok { | |||
| 3352 | + | r0 = returnFunc(ctx) | |||
| 3353 | + | } else { | |||
| 3354 | + | r0 = ret.Get(0).(int64) | |||
| 3355 | + | } | |||
| 3356 | + | if returnFunc, ok := ret.Get(1).(func(context.Context) error); ok { | |||
| 3357 | + | r1 = returnFunc(ctx) | |||
| 3358 | + | } else { | |||
| 3359 | + | r1 = ret.Error(1) | |||
| 3360 | + | } | |||
| 3361 | + | return r0, r1 | |||
| 3362 | + | } | |||
| 3363 | + | ||||
| 3364 | + | // MockSessionStateRepository_GetTotalSnapshotsSize_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTotalSnapshotsSize' | |||
| 3365 | + | type MockSessionStateRepository_GetTotalSnapshotsSize_Call struct { | |||
| 3366 | + | *mock.Call | |||
| 3367 | + | } | |||
| 3368 | + | ||||
| 3369 | + | // GetTotalSnapshotsSize is a helper method to define mock.On call | |||
| 3370 | + | // - ctx context.Context | |||
| 3371 | + | func (_e *MockSessionStateRepository_Expecter) GetTotalSnapshotsSize(ctx interface{}) *MockSessionStateRepository_GetTotalSnapshotsSize_Call { | |||
| 3372 | + | return &MockSessionStateRepository_GetTotalSnapshotsSize_Call{Call: _e.mock.On("GetTotalSnapshotsSize", ctx)} | |||
| 3373 | + | } | |||
| 3374 | + | ||||
| 3375 | + | func (_c *MockSessionStateRepository_GetTotalSnapshotsSize_Call) Run(run func(ctx context.Context)) *MockSessionStateRepository_GetTotalSnapshotsSize_Call { | |||
| 3376 | + | _c.Call.Run(func(args mock.Arguments) { | |||
| 3377 | + | var arg0 context.Context | |||
| 3378 | + | if args[0] != nil { | |||
| 3379 | + | arg0 = args[0].(context.Context) | |||
| 3380 | + | } | |||
| 3381 | + | run( | |||
| 3382 | + | arg0, | |||
| 3383 | + | ) | |||
| 3384 | + | }) | |||
| 3385 | + | return _c | |||
| 3386 | + | } | |||
| 3387 | + | ||||
| 3388 | + | func (_c *MockSessionStateRepository_GetTotalSnapshotsSize_Call) Return(n int64, err error) *MockSessionStateRepository_GetTotalSnapshotsSize_Call { | |||
| 3389 | + | _c.Call.Return(n, err) | |||
| 3390 | + | return _c | |||
| 3391 | + | } | |||
| 3392 | + | ||||
| 3393 | + | func (_c *MockSessionStateRepository_GetTotalSnapshotsSize_Call) RunAndReturn(run func(ctx context.Context) (int64, error)) *MockSessionStateRepository_GetTotalSnapshotsSize_Call { | |||
| 3394 | + | _c.Call.Return(run) | |||
| 3395 | + | return _c | |||
| 3396 | + | } | |||
| 3397 | + | ||||
| 3338 | // SaveSnapshot provides a mock function for the type MockSessionStateRepository | 3398 | // SaveSnapshot provides a mock function for the type MockSessionStateRepository | ||
| 3339 | func (_mock *MockSessionStateRepository) SaveSnapshot(ctx context.Context, state *entity.SessionState) error { | 3399 | func (_mock *MockSessionStateRepository) SaveSnapshot(ctx context.Context, state *entity.SessionState) error { | ||
| 3340 | ret := _mock.Called(ctx, state) | 3400 | ret := _mock.Called(ctx, state) | ||
M internal/domain/repository/session_state.go +3 -0
| @@ -20,4 +20,7 @@ type SessionStateRepository interface { | |||
| 20 | 20 | // GetAllSnapshots returns all snapshots with summary info. | |
| 21 | 21 | // Used by ListSessionsUseCase. | |
| 22 | 22 | GetAllSnapshots(ctx context.Context) ([]*entity.SessionState, error) | |
| 23 | + | ||
| 24 | + | // GetTotalSnapshotsSize returns the total size of all session snapshots in bytes. | |
| 25 | + | GetTotalSnapshotsSize(ctx context.Context) (int64, error) | |
| 23 | 26 | } | |
| @@ -20,4 +20,7 @@ type SessionStateRepository interface { | |||||
| 20 | // GetAllSnapshots returns all snapshots with summary info. | 20 | // GetAllSnapshots returns all snapshots with summary info. | ||
| 21 | // Used by ListSessionsUseCase. | 21 | // Used by ListSessionsUseCase. | ||
| 22 | GetAllSnapshots(ctx context.Context) ([]*entity.SessionState, error) | 22 | GetAllSnapshots(ctx context.Context) ([]*entity.SessionState, error) | ||
| 23 | + | ||||
| 24 | + | // GetTotalSnapshotsSize returns the total size of all session snapshots in bytes. | |||
| 25 | + | GetTotalSnapshotsSize(ctx context.Context) (int64, error) | |||
| 23 | } | 26 | } | ||
M internal/infrastructure/persistence/sqlite/queries/session_states.sql +4 -0
| @@ -30,3 +30,7 @@ LEFT JOIN session_states ss ON s.id = ss.session_id | |||
| 30 | 30 | WHERE s.type = 'browser' | |
| 31 | 31 | ORDER BY s.started_at DESC | |
| 32 | 32 | LIMIT ?; | |
| 33 | + | ||
| 34 | + | -- name: GetTotalSessionStatesSize :one | |
| 35 | + | SELECT COALESCE(SUM(LENGTH(state_json)), 0) as total_size | |
| 36 | + | FROM session_states; | |
| @@ -30,3 +30,7 @@ LEFT JOIN session_states ss ON s.id = ss.session_id | |||||
| 30 | WHERE s.type = 'browser' | 30 | WHERE s.type = 'browser' | ||
| 31 | ORDER BY s.started_at DESC | 31 | ORDER BY s.started_at DESC | ||
| 32 | LIMIT ?; | 32 | LIMIT ?; | ||
| 33 | + | ||||
| 34 | + | -- name: GetTotalSessionStatesSize :one | |||
| 35 | + | SELECT COALESCE(SUM(LENGTH(state_json)), 0) as total_size | |||
| 36 | + | FROM session_states; | |||
M internal/infrastructure/persistence/sqlite/session_state_repo.go +17 -0
| @@ -99,3 +99,20 @@ func (r *sessionStateRepo) GetAllSnapshots(ctx context.Context) ([]*entity.Sessi | |||
| 99 | 99 | ||
| 100 | 100 | return states, nil | |
| 101 | 101 | } | |
| 102 | + | ||
| 103 | + | // GetTotalSnapshotsSize returns the total size of all session snapshots in bytes. | |
| 104 | + | func (r *sessionStateRepo) GetTotalSnapshotsSize(ctx context.Context) (int64, error) { | |
| 105 | + | result, err := r.queries.GetTotalSessionStatesSize(ctx) | |
| 106 | + | if err != nil { | |
| 107 | + | return 0, err | |
| 108 | + | } | |
| 109 | + | // SQLite returns int64 for SUM, but COALESCE wraps it as interface{} | |
| 110 | + | switch v := result.(type) { | |
| 111 | + | case int64: | |
| 112 | + | return v, nil | |
| 113 | + | case float64: | |
| 114 | + | return int64(v), nil | |
| 115 | + | default: | |
| 116 | + | return 0, nil | |
| 117 | + | } | |
| 118 | + | } | |
| @@ -99,3 +99,20 @@ func (r *sessionStateRepo) GetAllSnapshots(ctx context.Context) ([]*entity.Sessi | |||||
| 99 | 99 | ||||
| 100 | return states, nil | 100 | return states, nil | ||
| 101 | } | 101 | } | ||
| 102 | + | ||||
| 103 | + | // GetTotalSnapshotsSize returns the total size of all session snapshots in bytes. | |||
| 104 | + | func (r *sessionStateRepo) GetTotalSnapshotsSize(ctx context.Context) (int64, error) { | |||
| 105 | + | result, err := r.queries.GetTotalSessionStatesSize(ctx) | |||
| 106 | + | if err != nil { | |||
| 107 | + | return 0, err | |||
| 108 | + | } | |||
| 109 | + | // SQLite returns int64 for SUM, but COALESCE wraps it as interface{} | |||
| 110 | + | switch v := result.(type) { | |||
| 111 | + | case int64: | |||
| 112 | + | return v, nil | |||
| 113 | + | case float64: | |||
| 114 | + | return int64(v), nil | |||
| 115 | + | default: | |||
| 116 | + | return 0, nil | |||
| 117 | + | } | |||
| 118 | + | } | |||
M internal/infrastructure/persistence/sqlite/sqlc/querier.go +1 -0
| @@ -52,6 +52,7 @@ type Querier interface { | |||
| 52 | 52 | GetTagByID(ctx context.Context, id int64) (FavoriteTag, error) | |
| 53 | 53 | GetTagByName(ctx context.Context, name string) (FavoriteTag, error) | |
| 54 | 54 | GetTagsForFavorite(ctx context.Context, favoriteID int64) ([]FavoriteTag, error) | |
| 55 | + | GetTotalSessionStatesSize(ctx context.Context) (interface{}, error) | |
| 55 | 56 | GetZoomLevel(ctx context.Context, domain string) (ZoomLevel, error) | |
| 56 | 57 | IncrementVisitCount(ctx context.Context, url string) error | |
| 57 | 58 | InsertSession(ctx context.Context, arg InsertSessionParams) error | |
| @@ -52,6 +52,7 @@ type Querier interface { | |||||
| 52 | GetTagByID(ctx context.Context, id int64) (FavoriteTag, error) | 52 | GetTagByID(ctx context.Context, id int64) (FavoriteTag, error) | ||
| 53 | GetTagByName(ctx context.Context, name string) (FavoriteTag, error) | 53 | GetTagByName(ctx context.Context, name string) (FavoriteTag, error) | ||
| 54 | GetTagsForFavorite(ctx context.Context, favoriteID int64) ([]FavoriteTag, error) | 54 | GetTagsForFavorite(ctx context.Context, favoriteID int64) ([]FavoriteTag, error) | ||
| 55 | + | GetTotalSessionStatesSize(ctx context.Context) (interface{}, error) | |||
| 55 | GetZoomLevel(ctx context.Context, domain string) (ZoomLevel, error) | 56 | GetZoomLevel(ctx context.Context, domain string) (ZoomLevel, error) | ||
| 56 | IncrementVisitCount(ctx context.Context, url string) error | 57 | IncrementVisitCount(ctx context.Context, url string) error | ||
| 57 | InsertSession(ctx context.Context, arg InsertSessionParams) error | 58 | InsertSession(ctx context.Context, arg InsertSessionParams) error | ||
M internal/infrastructure/persistence/sqlite/sqlc/session_states.sql.go +12 -0
| @@ -130,6 +130,18 @@ func (q *Queries) GetSessionsWithState(ctx context.Context, limit int64) ([]GetS | |||
| 130 | 130 | return items, nil | |
| 131 | 131 | } | |
| 132 | 132 | ||
| 133 | + | const GetTotalSessionStatesSize = `-- name: GetTotalSessionStatesSize :one | |
| 134 | + | SELECT COALESCE(SUM(LENGTH(state_json)), 0) as total_size | |
| 135 | + | FROM session_states | |
| 136 | + | ` | |
| 137 | + | ||
| 138 | + | func (q *Queries) GetTotalSessionStatesSize(ctx context.Context) (interface{}, error) { | |
| 139 | + | row := q.db.QueryRowContext(ctx, GetTotalSessionStatesSize) | |
| 140 | + | var total_size interface{} | |
| 141 | + | err := row.Scan(&total_size) | |
| 142 | + | return total_size, err | |
| 143 | + | } | |
| 144 | + | ||
| 133 | 145 | const UpsertSessionState = `-- name: UpsertSessionState :exec | |
| 134 | 146 | INSERT INTO session_states (session_id, state_json, version, tab_count, pane_count, updated_at) | |
| 135 | 147 | VALUES (?, ?, ?, ?, ?, ?) | |
| @@ -130,6 +130,18 @@ func (q *Queries) GetSessionsWithState(ctx context.Context, limit int64) ([]GetS | |||||
| 130 | return items, nil | 130 | return items, nil | ||
| 131 | } | 131 | } | ||
| 132 | 132 | ||||
| 133 | + | const GetTotalSessionStatesSize = `-- name: GetTotalSessionStatesSize :one | |||
| 134 | + | SELECT COALESCE(SUM(LENGTH(state_json)), 0) as total_size | |||
| 135 | + | FROM session_states | |||
| 136 | + | ` | |||
| 137 | + | ||||
| 138 | + | func (q *Queries) GetTotalSessionStatesSize(ctx context.Context) (interface{}, error) { | |||
| 139 | + | row := q.db.QueryRowContext(ctx, GetTotalSessionStatesSize) | |||
| 140 | + | var total_size interface{} | |||
| 141 | + | err := row.Scan(&total_size) | |||
| 142 | + | return total_size, err | |||
| 143 | + | } | |||
| 144 | + | ||||
| 133 | const UpsertSessionState = `-- name: UpsertSessionState :exec | 145 | const UpsertSessionState = `-- name: UpsertSessionState :exec | ||
| 134 | INSERT INTO session_states (session_id, state_json, version, tab_count, pane_count, updated_at) | 146 | INSERT INTO session_states (session_id, state_json, version, tab_count, pane_count, updated_at) | ||
| 135 | VALUES (?, ?, ?, ?, ?, ?) | 147 | VALUES (?, ?, ?, ?, ?, ?) | ||