mirror of
https://github.com/usememos/memos.git
synced 2024-11-28 05:53:14 +03:00
feat: vacuum records manually (#420)
This commit is contained in:
parent
4f10c12092
commit
dc5d705f8c
@ -90,5 +90,5 @@ type MemoFind struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MemoDelete struct {
|
type MemoDelete struct {
|
||||||
ID int `json:"id"`
|
ID int
|
||||||
}
|
}
|
||||||
|
@ -19,3 +19,8 @@ type MemoOrganizerUpsert struct {
|
|||||||
UserID int
|
UserID int
|
||||||
Pinned bool `json:"pinned"`
|
Pinned bool `json:"pinned"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MemoOrganizerDelete struct {
|
||||||
|
MemoID *int
|
||||||
|
UserID *int
|
||||||
|
}
|
||||||
|
@ -19,6 +19,6 @@ type MemoResourceFind struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MemoResourceDelete struct {
|
type MemoResourceDelete struct {
|
||||||
MemoID int
|
MemoID *int
|
||||||
ResourceID *int
|
ResourceID *int
|
||||||
}
|
}
|
||||||
|
@ -40,18 +40,16 @@ type ResourceFind struct {
|
|||||||
MemoID *int
|
MemoID *int
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResourceDelete struct {
|
|
||||||
ID int
|
|
||||||
|
|
||||||
// Standard fields
|
|
||||||
CreatorID int
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResourcePatch struct {
|
type ResourcePatch struct {
|
||||||
ID int
|
ID int
|
||||||
|
|
||||||
// Standard fields
|
// Standard fields
|
||||||
UpdatedTs *int64
|
UpdatedTs *int64
|
||||||
|
|
||||||
|
// Domain specific fields
|
||||||
Filename *string `json:"filename"`
|
Filename *string `json:"filename"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ResourceDelete struct {
|
||||||
|
ID int
|
||||||
|
}
|
||||||
|
@ -46,5 +46,8 @@ type ShortcutFind struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ShortcutDelete struct {
|
type ShortcutDelete struct {
|
||||||
ID int
|
ID *int
|
||||||
|
|
||||||
|
// Standard fields
|
||||||
|
CreatorID *int
|
||||||
}
|
}
|
||||||
|
@ -156,3 +156,7 @@ type UserSettingFind struct {
|
|||||||
|
|
||||||
Key *UserSettingKey `json:"key"`
|
Key *UserSettingKey `json:"key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserSettingDelete struct {
|
||||||
|
UserID int
|
||||||
|
}
|
||||||
|
@ -500,7 +500,7 @@ func (s *Server) registerMemoRoutes(g *echo.Group) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
memoResourceDelete := &api.MemoResourceDelete{
|
memoResourceDelete := &api.MemoResourceDelete{
|
||||||
MemoID: memoID,
|
MemoID: &memoID,
|
||||||
ResourceID: &resourceID,
|
ResourceID: &resourceID,
|
||||||
}
|
}
|
||||||
if err := s.Store.DeleteMemoResource(ctx, memoResourceDelete); err != nil {
|
if err := s.Store.DeleteMemoResource(ctx, memoResourceDelete); err != nil {
|
||||||
|
@ -170,9 +170,19 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
|
|||||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("resourceId"))).SetInternal(err)
|
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("resourceId"))).SetInternal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resource, err := s.Store.FindResource(ctx, &api.ResourceFind{
|
||||||
|
ID: &resourceID,
|
||||||
|
CreatorID: &userID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find resource").SetInternal(err)
|
||||||
|
}
|
||||||
|
if resource == nil {
|
||||||
|
return echo.NewHTTPError(http.StatusNotFound, "Not find resource").SetInternal(err)
|
||||||
|
}
|
||||||
|
|
||||||
resourceDelete := &api.ResourceDelete{
|
resourceDelete := &api.ResourceDelete{
|
||||||
ID: resourceID,
|
ID: resourceID,
|
||||||
CreatorID: userID,
|
|
||||||
}
|
}
|
||||||
if err := s.Store.DeleteResource(ctx, resourceDelete); err != nil {
|
if err := s.Store.DeleteResource(ctx, resourceDelete); err != nil {
|
||||||
if common.ErrorCode(err) == common.NotFound {
|
if common.ErrorCode(err) == common.NotFound {
|
||||||
|
@ -128,7 +128,7 @@ func (s *Server) registerShortcutRoutes(g *echo.Group) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
shortcutDelete := &api.ShortcutDelete{
|
shortcutDelete := &api.ShortcutDelete{
|
||||||
ID: shortcutID,
|
ID: &shortcutID,
|
||||||
}
|
}
|
||||||
if err := s.Store.DeleteShortcut(ctx, shortcutDelete); err != nil {
|
if err := s.Store.DeleteShortcut(ctx, shortcutDelete); err != nil {
|
||||||
if common.ErrorCode(err) == common.NotFound {
|
if common.ErrorCode(err) == common.NotFound {
|
||||||
|
@ -221,13 +221,8 @@ func (s *Store) DeleteMemo(ctx context.Context, delete *api.MemoDelete) error {
|
|||||||
if err := deleteMemo(ctx, tx, delete); err != nil {
|
if err := deleteMemo(ctx, tx, delete); err != nil {
|
||||||
return FormatError(err)
|
return FormatError(err)
|
||||||
}
|
}
|
||||||
|
if err := vacuum(ctx, tx); err != nil {
|
||||||
resourceDelete := &api.MemoResourceDelete{
|
return err
|
||||||
MemoID: delete.ID,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := deleteMemoResource(ctx, tx, resourceDelete); err != nil {
|
|
||||||
return FormatError(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tx.Commit(); err != nil {
|
if err := tx.Commit(); err != nil {
|
||||||
@ -323,7 +318,7 @@ func findMemoRawList(ctx context.Context, tx *sql.Tx, find *api.MemoFind) ([]*me
|
|||||||
where, args = append(where, "row_status = ?"), append(args, *v)
|
where, args = append(where, "row_status = ?"), append(args, *v)
|
||||||
}
|
}
|
||||||
if v := find.Pinned; v != nil {
|
if v := find.Pinned; v != nil {
|
||||||
where = append(where, "id in (SELECT memo_id FROM memo_organizer WHERE pinned = 1 AND user_id = memo.creator_id)")
|
where = append(where, "id IN (SELECT memo_id FROM memo_organizer WHERE pinned = 1 AND user_id = memo.creator_id)")
|
||||||
}
|
}
|
||||||
if v := find.ContentSearch; v != nil {
|
if v := find.ContentSearch; v != nil {
|
||||||
where, args = append(where, "content LIKE ?"), append(args, "%"+*v+"%")
|
where, args = append(where, "content LIKE ?"), append(args, "%"+*v+"%")
|
||||||
@ -382,16 +377,36 @@ func findMemoRawList(ctx context.Context, tx *sql.Tx, find *api.MemoFind) ([]*me
|
|||||||
}
|
}
|
||||||
|
|
||||||
func deleteMemo(ctx context.Context, tx *sql.Tx, delete *api.MemoDelete) error {
|
func deleteMemo(ctx context.Context, tx *sql.Tx, delete *api.MemoDelete) error {
|
||||||
result, err := tx.ExecContext(ctx, `
|
where, args := []string{"id = ?"}, []interface{}{delete.ID}
|
||||||
DELETE FROM memo WHERE id = ?
|
|
||||||
`, delete.ID)
|
stmt := `DELETE FROM memo WHERE ` + strings.Join(where, " AND ")
|
||||||
|
result, err := tx.ExecContext(ctx, stmt, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FormatError(err)
|
return FormatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, _ := result.RowsAffected()
|
rows, _ := result.RowsAffected()
|
||||||
if rows == 0 {
|
if rows == 0 {
|
||||||
return &common.Error{Code: common.NotFound, Err: fmt.Errorf("memo ID not found: %d", delete.ID)}
|
return &common.Error{Code: common.NotFound, Err: fmt.Errorf("memo not found")}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func vacuumMemo(ctx context.Context, tx *sql.Tx) error {
|
||||||
|
stmt := `
|
||||||
|
DELETE FROM
|
||||||
|
memo
|
||||||
|
WHERE
|
||||||
|
creator_id NOT IN (
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
user
|
||||||
|
)`
|
||||||
|
_, err := tx.ExecContext(ctx, stmt)
|
||||||
|
if err != nil {
|
||||||
|
return FormatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/usememos/memos/api"
|
"github.com/usememos/memos/api"
|
||||||
"github.com/usememos/memos/common"
|
"github.com/usememos/memos/common"
|
||||||
@ -65,6 +66,24 @@ func (s *Store) UpsertMemoOrganizer(ctx context.Context, upsert *api.MemoOrganiz
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) DeleteMemoOrganizer(ctx context.Context, delete *api.MemoOrganizerDelete) error {
|
||||||
|
tx, err := s.db.BeginTx(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return FormatError(err)
|
||||||
|
}
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
if err := deleteMemoOrganizer(ctx, tx, delete); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.Commit(); err != nil {
|
||||||
|
return FormatError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func findMemoOrganizer(ctx context.Context, tx *sql.Tx, find *api.MemoOrganizerFind) (*memoOrganizerRaw, error) {
|
func findMemoOrganizer(ctx context.Context, tx *sql.Tx, find *api.MemoOrganizerFind) (*memoOrganizerRaw, error) {
|
||||||
query := `
|
query := `
|
||||||
SELECT
|
SELECT
|
||||||
@ -127,3 +146,52 @@ func upsertMemoOrganizer(ctx context.Context, tx *sql.Tx, upsert *api.MemoOrgani
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func deleteMemoOrganizer(ctx context.Context, tx *sql.Tx, delete *api.MemoOrganizerDelete) error {
|
||||||
|
where, args := []string{}, []interface{}{}
|
||||||
|
|
||||||
|
if v := delete.MemoID; v != nil {
|
||||||
|
where, args = append(where, "memo_id = ?"), append(args, *v)
|
||||||
|
}
|
||||||
|
if v := delete.UserID; v != nil {
|
||||||
|
where, args = append(where, "user_id = ?"), append(args, *v)
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt := `DELETE FROM memo_organizer WHERE ` + strings.Join(where, " AND ")
|
||||||
|
result, err := tx.ExecContext(ctx, stmt, args...)
|
||||||
|
if err != nil {
|
||||||
|
return FormatError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, _ := result.RowsAffected()
|
||||||
|
if rows == 0 {
|
||||||
|
return &common.Error{Code: common.NotFound, Err: fmt.Errorf("memo organizer not found")}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func vacuumMemoOrganizer(ctx context.Context, tx *sql.Tx) error {
|
||||||
|
stmt := `
|
||||||
|
DELETE FROM
|
||||||
|
memo_organizer
|
||||||
|
WHERE
|
||||||
|
memo_id NOT IN (
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
memo
|
||||||
|
)
|
||||||
|
OR user_id NOT IN (
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
user
|
||||||
|
)`
|
||||||
|
_, err := tx.ExecContext(ctx, stmt)
|
||||||
|
if err != nil {
|
||||||
|
return FormatError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -188,14 +188,17 @@ func upsertMemoResource(ctx context.Context, tx *sql.Tx, upsert *api.MemoResourc
|
|||||||
}
|
}
|
||||||
|
|
||||||
func deleteMemoResource(ctx context.Context, tx *sql.Tx, delete *api.MemoResourceDelete) error {
|
func deleteMemoResource(ctx context.Context, tx *sql.Tx, delete *api.MemoResourceDelete) error {
|
||||||
where, args := []string{"memo_id = ?"}, []interface{}{delete.MemoID}
|
where, args := []string{}, []interface{}{}
|
||||||
|
|
||||||
|
if v := delete.MemoID; v != nil {
|
||||||
|
where, args = append(where, "memo_id = ?"), append(args, *v)
|
||||||
|
}
|
||||||
if v := delete.ResourceID; v != nil {
|
if v := delete.ResourceID; v != nil {
|
||||||
where, args = append(where, "resource_id = ?"), append(args, *v)
|
where, args = append(where, "resource_id = ?"), append(args, *v)
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := tx.ExecContext(ctx, `
|
stmt := `DELETE FROM memo_resource WHERE ` + strings.Join(where, " AND ")
|
||||||
DELETE FROM memo_resource WHERE `+strings.Join(where, " AND "), args...)
|
result, err := tx.ExecContext(ctx, stmt, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FormatError(err)
|
return FormatError(err)
|
||||||
}
|
}
|
||||||
@ -207,3 +210,28 @@ func deleteMemoResource(ctx context.Context, tx *sql.Tx, delete *api.MemoResourc
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func vacuumMemoResource(ctx context.Context, tx *sql.Tx) error {
|
||||||
|
stmt := `
|
||||||
|
DELETE FROM
|
||||||
|
memo_resource
|
||||||
|
WHERE
|
||||||
|
memo_id NOT IN (
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
memo
|
||||||
|
)
|
||||||
|
OR resource_id NOT IN (
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
resource
|
||||||
|
)`
|
||||||
|
_, err := tx.ExecContext(ctx, stmt)
|
||||||
|
if err != nil {
|
||||||
|
return FormatError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -169,8 +169,10 @@ func (s *Store) DeleteResource(ctx context.Context, delete *api.ResourceDelete)
|
|||||||
}
|
}
|
||||||
defer tx.Rollback()
|
defer tx.Rollback()
|
||||||
|
|
||||||
err = deleteResource(ctx, tx, delete)
|
if err := deleteResource(ctx, tx, delete); err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
|
}
|
||||||
|
if err := vacuum(ctx, tx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,11 +180,6 @@ func (s *Store) DeleteResource(ctx context.Context, delete *api.ResourceDelete)
|
|||||||
return FormatError(err)
|
return FormatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vacuum sqlite database file size after deleting resource.
|
|
||||||
if _, err := s.db.Exec("VACUUM"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
s.cache.DeleteCache(api.ResourceCache, delete.ID)
|
s.cache.DeleteCache(api.ResourceCache, delete.ID)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -340,16 +337,36 @@ func findResourceList(ctx context.Context, tx *sql.Tx, find *api.ResourceFind) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func deleteResource(ctx context.Context, tx *sql.Tx, delete *api.ResourceDelete) error {
|
func deleteResource(ctx context.Context, tx *sql.Tx, delete *api.ResourceDelete) error {
|
||||||
result, err := tx.ExecContext(ctx, `
|
where, args := []string{"id = ?"}, []interface{}{delete.ID}
|
||||||
DELETE FROM resource WHERE id = ? AND creator_id = ?
|
|
||||||
`, delete.ID, delete.CreatorID)
|
stmt := `DELETE FROM resource WHERE ` + strings.Join(where, " AND ")
|
||||||
|
result, err := tx.ExecContext(ctx, stmt, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FormatError(err)
|
return FormatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, _ := result.RowsAffected()
|
rows, _ := result.RowsAffected()
|
||||||
if rows == 0 {
|
if rows == 0 {
|
||||||
return &common.Error{Code: common.NotFound, Err: fmt.Errorf("resource ID not found: %d", delete.ID)}
|
return &common.Error{Code: common.NotFound, Err: fmt.Errorf("resource not found")}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func vacuumResource(ctx context.Context, tx *sql.Tx) error {
|
||||||
|
stmt := `
|
||||||
|
DELETE FROM
|
||||||
|
resource
|
||||||
|
WHERE
|
||||||
|
creator_id NOT IN (
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
user
|
||||||
|
)`
|
||||||
|
_, err := tx.ExecContext(ctx, stmt)
|
||||||
|
if err != nil {
|
||||||
|
return FormatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -164,7 +164,7 @@ func (s *Store) DeleteShortcut(ctx context.Context, delete *api.ShortcutDelete)
|
|||||||
return FormatError(err)
|
return FormatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.cache.DeleteCache(api.ShortcutCache, delete.ID)
|
s.cache.DeleteCache(api.ShortcutCache, *delete.ID)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -292,16 +292,43 @@ func findShortcutList(ctx context.Context, tx *sql.Tx, find *api.ShortcutFind) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func deleteShortcut(ctx context.Context, tx *sql.Tx, delete *api.ShortcutDelete) error {
|
func deleteShortcut(ctx context.Context, tx *sql.Tx, delete *api.ShortcutDelete) error {
|
||||||
result, err := tx.ExecContext(ctx, `
|
where, args := []string{}, []interface{}{}
|
||||||
DELETE FROM shortcut WHERE id = ?
|
|
||||||
`, delete.ID)
|
if v := delete.ID; v != nil {
|
||||||
|
where, args = append(where, "id = ?"), append(args, *v)
|
||||||
|
}
|
||||||
|
if v := delete.CreatorID; v != nil {
|
||||||
|
where, args = append(where, "creator_id = ?"), append(args, *v)
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt := `DELETE FROM shortcut WHERE ` + strings.Join(where, " AND ")
|
||||||
|
result, err := tx.ExecContext(ctx, stmt, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FormatError(err)
|
return FormatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, _ := result.RowsAffected()
|
rows, _ := result.RowsAffected()
|
||||||
if rows == 0 {
|
if rows == 0 {
|
||||||
return &common.Error{Code: common.NotFound, Err: fmt.Errorf("shortcut ID not found: %d", delete.ID)}
|
return &common.Error{Code: common.NotFound, Err: fmt.Errorf("shortcut not found")}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func vacuumShortcut(ctx context.Context, tx *sql.Tx) error {
|
||||||
|
stmt := `
|
||||||
|
DELETE FROM
|
||||||
|
shortcut
|
||||||
|
WHERE
|
||||||
|
creator_id NOT IN (
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
user
|
||||||
|
)`
|
||||||
|
_, err := tx.ExecContext(ctx, stmt)
|
||||||
|
if err != nil {
|
||||||
|
return FormatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package store
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
||||||
"github.com/usememos/memos/api"
|
"github.com/usememos/memos/api"
|
||||||
@ -24,3 +25,51 @@ func New(db *sql.DB, profile *profile.Profile) *Store {
|
|||||||
cache: cacheService,
|
cache: cacheService,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) Vacuum(ctx context.Context) error {
|
||||||
|
tx, err := s.db.BeginTx(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return FormatError(err)
|
||||||
|
}
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
if err := vacuum(ctx, tx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.Commit(); err != nil {
|
||||||
|
return FormatError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vacuum sqlite database file size after deleting resource.
|
||||||
|
if _, err := s.db.Exec("VACUUM"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exec vacuum records in a transcation.
|
||||||
|
func vacuum(ctx context.Context, tx *sql.Tx) error {
|
||||||
|
if err := vacuumMemo(ctx, tx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := vacuumResource(ctx, tx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := vacuumShortcut(ctx, tx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := vacuumUserSetting(ctx, tx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := vacuumMemoOrganizer(ctx, tx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := vacuumMemoResource(ctx, tx); err != nil {
|
||||||
|
// Prevent revive warning.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -175,13 +175,15 @@ func (s *Store) DeleteUser(ctx context.Context, delete *api.UserDelete) error {
|
|||||||
}
|
}
|
||||||
defer tx.Rollback()
|
defer tx.Rollback()
|
||||||
|
|
||||||
err = deleteUser(ctx, tx, delete)
|
if err := deleteUser(ctx, tx, delete); err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return FormatError(err)
|
}
|
||||||
|
if err := vacuum(ctx, tx); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tx.Commit(); err != nil {
|
if err := tx.Commit(); err != nil {
|
||||||
return FormatError(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.cache.DeleteCache(api.UserCache, delete.ID)
|
s.cache.DeleteCache(api.UserCache, delete.ID)
|
||||||
@ -364,7 +366,7 @@ func deleteUser(ctx context.Context, tx *sql.Tx, delete *api.UserDelete) error {
|
|||||||
|
|
||||||
rows, _ := result.RowsAffected()
|
rows, _ := result.RowsAffected()
|
||||||
if rows == 0 {
|
if rows == 0 {
|
||||||
return &common.Error{Code: common.NotFound, Err: fmt.Errorf("user ID not found: %d", delete.ID)}
|
return &common.Error{Code: common.NotFound, Err: fmt.Errorf("user not found")}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -149,3 +149,22 @@ func findUserSettingList(ctx context.Context, tx *sql.Tx, find *api.UserSettingF
|
|||||||
|
|
||||||
return userSettingRawList, nil
|
return userSettingRawList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func vacuumUserSetting(ctx context.Context, tx *sql.Tx) error {
|
||||||
|
stmt := `
|
||||||
|
DELETE FROM
|
||||||
|
user_setting
|
||||||
|
WHERE
|
||||||
|
user_id NOT IN (
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
user
|
||||||
|
)`
|
||||||
|
_, err := tx.ExecContext(ctx, stmt)
|
||||||
|
if err != nil {
|
||||||
|
return FormatError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user