mirror of
https://github.com/usememos/memos.git
synced 2025-04-02 12:00:21 +02:00
feat: update store cache (#1066)
* feat: update store cache * chore: update
This commit is contained in:
parent
6e5be6ba75
commit
3590d3f8b6
3
go.mod
3
go.mod
@ -14,7 +14,6 @@ require (
|
|||||||
require github.com/labstack/echo/v4 v4.9.0
|
require github.com/labstack/echo/v4 v4.9.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/VictoriaMetrics/fastcache v1.10.0
|
|
||||||
github.com/gorilla/feeds v1.1.1
|
github.com/gorilla/feeds v1.1.1
|
||||||
github.com/gorilla/sessions v1.2.1
|
github.com/gorilla/sessions v1.2.1
|
||||||
github.com/labstack/echo-contrib v0.13.0
|
github.com/labstack/echo-contrib v0.13.0
|
||||||
@ -22,10 +21,8 @@ require (
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
|
||||||
github.com/gorilla/context v1.1.1 // indirect
|
github.com/gorilla/context v1.1.1 // indirect
|
||||||
github.com/gorilla/securecookie v1.1.1 // indirect
|
github.com/gorilla/securecookie v1.1.1 // indirect
|
||||||
github.com/kr/pretty v0.3.1 // indirect
|
github.com/kr/pretty v0.3.1 // indirect
|
||||||
|
9
go.sum
9
go.sum
@ -1,20 +1,12 @@
|
|||||||
github.com/VictoriaMetrics/fastcache v1.10.0 h1:5hDJnLsKLpnUEToub7ETuRu8RCkb40woBZAUiKonXzY=
|
|
||||||
github.com/VictoriaMetrics/fastcache v1.10.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8=
|
|
||||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
|
|
||||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
|
||||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
|
||||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
|
||||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
||||||
@ -88,7 +80,6 @@ golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
|||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
||||||
|
@ -13,48 +13,6 @@ import (
|
|||||||
"github.com/usememos/memos/api"
|
"github.com/usememos/memos/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
func generateRSSFromMemoList(memoList []*api.Memo, baseURL string, profile *api.CustomizedProfile) (string, error) {
|
|
||||||
feed := &feeds.Feed{
|
|
||||||
Title: profile.Name,
|
|
||||||
Link: &feeds.Link{Href: baseURL},
|
|
||||||
Description: profile.Description,
|
|
||||||
Created: time.Now(),
|
|
||||||
}
|
|
||||||
|
|
||||||
feed.Items = make([]*feeds.Item, len(memoList))
|
|
||||||
for i, memo := range memoList {
|
|
||||||
var useTitle = strings.HasPrefix(memo.Content, "# ")
|
|
||||||
|
|
||||||
var title string
|
|
||||||
if useTitle {
|
|
||||||
title = strings.Split(memo.Content, "\n")[0][2:]
|
|
||||||
} else {
|
|
||||||
title = memo.Creator.Username + "-memos-" + strconv.Itoa(memo.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
var description string
|
|
||||||
if useTitle {
|
|
||||||
var firstLineEnd = strings.Index(memo.Content, "\n")
|
|
||||||
description = memo.Content[firstLineEnd+1:]
|
|
||||||
} else {
|
|
||||||
description = memo.Content
|
|
||||||
}
|
|
||||||
|
|
||||||
feed.Items[i] = &feeds.Item{
|
|
||||||
Title: title,
|
|
||||||
Link: &feeds.Link{Href: baseURL + "/m/" + strconv.Itoa(memo.ID)},
|
|
||||||
Description: description,
|
|
||||||
Created: time.Unix(memo.CreatedTs, 0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rss, err := feed.ToRss()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return rss, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) registerRSSRoutes(g *echo.Group) {
|
func (s *Server) registerRSSRoutes(g *echo.Group) {
|
||||||
g.GET("/explore/rss.xml", func(c echo.Context) error {
|
g.GET("/explore/rss.xml", func(c echo.Context) error {
|
||||||
ctx := c.Request().Context()
|
ctx := c.Request().Context()
|
||||||
@ -123,6 +81,48 @@ func (s *Server) registerRSSRoutes(g *echo.Group) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func generateRSSFromMemoList(memoList []*api.Memo, baseURL string, profile *api.CustomizedProfile) (string, error) {
|
||||||
|
feed := &feeds.Feed{
|
||||||
|
Title: profile.Name,
|
||||||
|
Link: &feeds.Link{Href: baseURL},
|
||||||
|
Description: profile.Description,
|
||||||
|
Created: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
feed.Items = make([]*feeds.Item, len(memoList))
|
||||||
|
for i, memo := range memoList {
|
||||||
|
var useTitle = strings.HasPrefix(memo.Content, "# ")
|
||||||
|
|
||||||
|
var title string
|
||||||
|
if useTitle {
|
||||||
|
title = strings.Split(memo.Content, "\n")[0][2:]
|
||||||
|
} else {
|
||||||
|
title = memo.Creator.Username + "-memos-" + strconv.Itoa(memo.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
var description string
|
||||||
|
if useTitle {
|
||||||
|
var firstLineEnd = strings.Index(memo.Content, "\n")
|
||||||
|
description = memo.Content[firstLineEnd+1:]
|
||||||
|
} else {
|
||||||
|
description = memo.Content
|
||||||
|
}
|
||||||
|
|
||||||
|
feed.Items[i] = &feeds.Item{
|
||||||
|
Title: title,
|
||||||
|
Link: &feeds.Link{Href: baseURL + "/m/" + strconv.Itoa(memo.ID)},
|
||||||
|
Description: description,
|
||||||
|
Created: time.Unix(memo.CreatedTs, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rss, err := feed.ToRss()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return rss, nil
|
||||||
|
}
|
||||||
|
|
||||||
func getSystemCustomizedProfile(ctx context.Context, s *Server) (api.CustomizedProfile, error) {
|
func getSystemCustomizedProfile(ctx context.Context, s *Server) (api.CustomizedProfile, error) {
|
||||||
systemStatus := api.SystemStatus{
|
systemStatus := api.SystemStatus{
|
||||||
CustomizedProfile: api.CustomizedProfile{
|
CustomizedProfile: api.CustomizedProfile{
|
||||||
|
@ -1,82 +1,15 @@
|
|||||||
package store
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"encoding/gob"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/VictoriaMetrics/fastcache"
|
"github.com/usememos/memos/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func getUserSettingCacheKey(userSetting userSettingRaw) string {
|
||||||
// 64 MiB.
|
return fmt.Sprintf("%d-%s", userSetting.UserID, userSetting.Key.String())
|
||||||
cacheSize = 1024 * 1024 * 64
|
|
||||||
)
|
|
||||||
|
|
||||||
// CacheService implements a cache.
|
|
||||||
type CacheService struct {
|
|
||||||
cache *fastcache.Cache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CacheNamespace is the type of a cache.
|
func getUserSettingFindCacheKey(userSettingFind *api.UserSettingFind) string {
|
||||||
type CacheNamespace string
|
return fmt.Sprintf("%d-%s", userSettingFind.UserID, userSettingFind.Key.String())
|
||||||
|
|
||||||
const (
|
|
||||||
// UserCache is the cache type of users.
|
|
||||||
UserCache CacheNamespace = "u"
|
|
||||||
// MemoCache is the cache type of memos.
|
|
||||||
MemoCache CacheNamespace = "m"
|
|
||||||
// ShortcutCache is the cache type of shortcuts.
|
|
||||||
ShortcutCache CacheNamespace = "s"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewCacheService creates a cache service.
|
|
||||||
func NewCacheService() *CacheService {
|
|
||||||
return &CacheService{
|
|
||||||
cache: fastcache.New(cacheSize),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FindCache finds the value in cache.
|
|
||||||
func (s *CacheService) FindCache(namespace CacheNamespace, id int, entry interface{}) (bool, error) {
|
|
||||||
buf1 := []byte{0, 0, 0, 0, 0, 0, 0, 0}
|
|
||||||
binary.LittleEndian.PutUint64(buf1, uint64(id))
|
|
||||||
|
|
||||||
buf2, has := s.cache.HasGet(nil, append([]byte(namespace), buf1...))
|
|
||||||
if has {
|
|
||||||
dec := gob.NewDecoder(bytes.NewReader(buf2))
|
|
||||||
if err := dec.Decode(entry); err != nil {
|
|
||||||
return false, fmt.Errorf("failed to decode entry for cache namespace: %s, error: %w", namespace, err)
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpsertCache upserts the value to cache.
|
|
||||||
func (s *CacheService) UpsertCache(namespace CacheNamespace, id int, entry interface{}) error {
|
|
||||||
buf1 := []byte{0, 0, 0, 0, 0, 0, 0, 0}
|
|
||||||
binary.LittleEndian.PutUint64(buf1, uint64(id))
|
|
||||||
|
|
||||||
var buf2 bytes.Buffer
|
|
||||||
enc := gob.NewEncoder(&buf2)
|
|
||||||
if err := enc.Encode(entry); err != nil {
|
|
||||||
return fmt.Errorf("failed to encode entry for cache namespace: %s, error: %w", namespace, err)
|
|
||||||
}
|
|
||||||
s.cache.Set(append([]byte(namespace), buf1...), buf2.Bytes())
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteCache deletes the cache.
|
|
||||||
func (s *CacheService) DeleteCache(namespace CacheNamespace, id int) {
|
|
||||||
buf1 := []byte{0, 0, 0, 0, 0, 0, 0, 0}
|
|
||||||
binary.LittleEndian.PutUint64(buf1, uint64(id))
|
|
||||||
|
|
||||||
_, has := s.cache.HasGet(nil, append([]byte(namespace), buf1...))
|
|
||||||
if has {
|
|
||||||
s.cache.Del(append([]byte(namespace), buf1...))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ type memoRaw struct {
|
|||||||
// Domain specific fields
|
// Domain specific fields
|
||||||
Content string
|
Content string
|
||||||
Visibility api.Visibility
|
Visibility api.Visibility
|
||||||
|
Pinned bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// toMemo creates an instance of Memo based on the memoRaw.
|
// toMemo creates an instance of Memo based on the memoRaw.
|
||||||
@ -43,24 +44,15 @@ func (raw *memoRaw) toMemo() *api.Memo {
|
|||||||
Content: raw.Content,
|
Content: raw.Content,
|
||||||
Visibility: raw.Visibility,
|
Visibility: raw.Visibility,
|
||||||
DisplayTs: raw.CreatedTs,
|
DisplayTs: raw.CreatedTs,
|
||||||
|
Pinned: raw.Pinned,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) ComposeMemo(ctx context.Context, memo *api.Memo) (*api.Memo, error) {
|
func (s *Store) ComposeMemo(ctx context.Context, memo *api.Memo) (*api.Memo, error) {
|
||||||
memoOrganizer, err := s.FindMemoOrganizer(ctx, &api.MemoOrganizerFind{
|
if err := s.ComposeMemoCreator(ctx, memo); err != nil {
|
||||||
MemoID: memo.ID,
|
|
||||||
UserID: memo.CreatorID,
|
|
||||||
})
|
|
||||||
if err != nil && common.ErrorCode(err) != common.NotFound {
|
|
||||||
return nil, err
|
|
||||||
} else if memoOrganizer != nil {
|
|
||||||
memo.Pinned = memoOrganizer.Pinned
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = s.ComposeMemoCreator(ctx, memo); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err = s.ComposeMemoResourceList(ctx, memo); err != nil {
|
if err := s.ComposeMemoResourceList(ctx, memo); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,10 +94,7 @@ func (s *Store) CreateMemo(ctx context.Context, create *api.MemoCreate) (*api.Me
|
|||||||
return nil, FormatError(err)
|
return nil, FormatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.cache.UpsertCache(MemoCache, memoRaw.ID, memoRaw); err != nil {
|
s.memoCache.Store(memoRaw.ID, memoRaw)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
memo, err := s.ComposeMemo(ctx, memoRaw.toMemo())
|
memo, err := s.ComposeMemo(ctx, memoRaw.toMemo())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -130,10 +119,7 @@ func (s *Store) PatchMemo(ctx context.Context, patch *api.MemoPatch) (*api.Memo,
|
|||||||
return nil, FormatError(err)
|
return nil, FormatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.cache.UpsertCache(MemoCache, memoRaw.ID, memoRaw); err != nil {
|
s.memoCache.Store(memoRaw.ID, memoRaw)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
memo, err := s.ComposeMemo(ctx, memoRaw.toMemo())
|
memo, err := s.ComposeMemo(ctx, memoRaw.toMemo())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -169,12 +155,8 @@ func (s *Store) FindMemoList(ctx context.Context, find *api.MemoFind) ([]*api.Me
|
|||||||
|
|
||||||
func (s *Store) FindMemo(ctx context.Context, find *api.MemoFind) (*api.Memo, error) {
|
func (s *Store) FindMemo(ctx context.Context, find *api.MemoFind) (*api.Memo, error) {
|
||||||
if find.ID != nil {
|
if find.ID != nil {
|
||||||
memoRaw := &memoRaw{}
|
if memo, ok := s.memoCache.Load(*find.ID); ok {
|
||||||
has, err := s.cache.FindCache(MemoCache, *find.ID, memoRaw)
|
memoRaw := memo.(*memoRaw)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if has {
|
|
||||||
memo, err := s.ComposeMemo(ctx, memoRaw.toMemo())
|
memo, err := s.ComposeMemo(ctx, memoRaw.toMemo())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -199,10 +181,7 @@ func (s *Store) FindMemo(ctx context.Context, find *api.MemoFind) (*api.Memo, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
memoRaw := list[0]
|
memoRaw := list[0]
|
||||||
if err := s.cache.UpsertCache(MemoCache, memoRaw.ID, memoRaw); err != nil {
|
s.memoCache.Store(memoRaw.ID, memoRaw)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
memo, err := s.ComposeMemo(ctx, memoRaw.toMemo())
|
memo, err := s.ComposeMemo(ctx, memoRaw.toMemo())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -229,8 +208,7 @@ func (s *Store) DeleteMemo(ctx context.Context, delete *api.MemoDelete) error {
|
|||||||
return FormatError(err)
|
return FormatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.cache.DeleteCache(MemoCache, delete.ID)
|
s.memoCache.Delete(delete.ID)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,19 +287,19 @@ func findMemoRawList(ctx context.Context, tx *sql.Tx, find *api.MemoFind) ([]*me
|
|||||||
where, args := []string{"1 = 1"}, []interface{}{}
|
where, args := []string{"1 = 1"}, []interface{}{}
|
||||||
|
|
||||||
if v := find.ID; v != nil {
|
if v := find.ID; v != nil {
|
||||||
where, args = append(where, "id = ?"), append(args, *v)
|
where, args = append(where, "memo.id = ?"), append(args, *v)
|
||||||
}
|
}
|
||||||
if v := find.CreatorID; v != nil {
|
if v := find.CreatorID; v != nil {
|
||||||
where, args = append(where, "creator_id = ?"), append(args, *v)
|
where, args = append(where, "memo.creator_id = ?"), append(args, *v)
|
||||||
}
|
}
|
||||||
if v := find.RowStatus; v != nil {
|
if v := find.RowStatus; v != nil {
|
||||||
where, args = append(where, "row_status = ?"), append(args, *v)
|
where, args = append(where, "memo.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, "memo_organizer.pinned = 1")
|
||||||
}
|
}
|
||||||
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, "memo.content LIKE ?"), append(args, "%"+*v+"%")
|
||||||
}
|
}
|
||||||
if v := find.VisibilityList; len(v) != 0 {
|
if v := find.VisibilityList; len(v) != 0 {
|
||||||
list := []string{}
|
list := []string{}
|
||||||
@ -329,21 +307,23 @@ func findMemoRawList(ctx context.Context, tx *sql.Tx, find *api.MemoFind) ([]*me
|
|||||||
list = append(list, fmt.Sprintf("$%d", len(args)+1))
|
list = append(list, fmt.Sprintf("$%d", len(args)+1))
|
||||||
args = append(args, visibility)
|
args = append(args, visibility)
|
||||||
}
|
}
|
||||||
where = append(where, fmt.Sprintf("visibility in (%s)", strings.Join(list, ",")))
|
where = append(where, fmt.Sprintf("memo.visibility in (%s)", strings.Join(list, ",")))
|
||||||
}
|
}
|
||||||
|
|
||||||
query := `
|
query := `
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
memo.id,
|
||||||
creator_id,
|
memo.creator_id,
|
||||||
created_ts,
|
memo.created_ts,
|
||||||
updated_ts,
|
memo.updated_ts,
|
||||||
row_status,
|
memo.row_status,
|
||||||
content,
|
memo.content,
|
||||||
visibility
|
memo.visibility,
|
||||||
|
memo_organizer.pinned
|
||||||
FROM memo
|
FROM memo
|
||||||
|
LEFT JOIN memo_organizer ON memo_organizer.memo_id = memo.id
|
||||||
WHERE ` + strings.Join(where, " AND ") + `
|
WHERE ` + strings.Join(where, " AND ") + `
|
||||||
ORDER BY created_ts DESC
|
ORDER BY memo.created_ts DESC
|
||||||
`
|
`
|
||||||
rows, err := tx.QueryContext(ctx, query, args...)
|
rows, err := tx.QueryContext(ctx, query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -354,6 +334,7 @@ func findMemoRawList(ctx context.Context, tx *sql.Tx, find *api.MemoFind) ([]*me
|
|||||||
memoRawList := make([]*memoRaw, 0)
|
memoRawList := make([]*memoRaw, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var memoRaw memoRaw
|
var memoRaw memoRaw
|
||||||
|
var pinned sql.NullBool
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
&memoRaw.ID,
|
&memoRaw.ID,
|
||||||
&memoRaw.CreatorID,
|
&memoRaw.CreatorID,
|
||||||
@ -362,10 +343,14 @@ func findMemoRawList(ctx context.Context, tx *sql.Tx, find *api.MemoFind) ([]*me
|
|||||||
&memoRaw.RowStatus,
|
&memoRaw.RowStatus,
|
||||||
&memoRaw.Content,
|
&memoRaw.Content,
|
||||||
&memoRaw.Visibility,
|
&memoRaw.Visibility,
|
||||||
|
&pinned,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, FormatError(err)
|
return nil, FormatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if pinned.Valid {
|
||||||
|
memoRaw.Pinned = pinned.Bool
|
||||||
|
}
|
||||||
memoRawList = append(memoRawList, &memoRaw)
|
memoRawList = append(memoRawList, &memoRaw)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,10 +56,7 @@ func (s *Store) CreateShortcut(ctx context.Context, create *api.ShortcutCreate)
|
|||||||
return nil, FormatError(err)
|
return nil, FormatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.cache.UpsertCache(ShortcutCache, shortcutRaw.ID, shortcutRaw); err != nil {
|
s.shortcutCache.Store(shortcutRaw.ID, shortcutRaw)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
shortcut := shortcutRaw.toShortcut()
|
shortcut := shortcutRaw.toShortcut()
|
||||||
|
|
||||||
return shortcut, nil
|
return shortcut, nil
|
||||||
@ -81,10 +78,7 @@ func (s *Store) PatchShortcut(ctx context.Context, patch *api.ShortcutPatch) (*a
|
|||||||
return nil, FormatError(err)
|
return nil, FormatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.cache.UpsertCache(ShortcutCache, shortcutRaw.ID, shortcutRaw); err != nil {
|
s.shortcutCache.Store(shortcutRaw.ID, shortcutRaw)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
shortcut := shortcutRaw.toShortcut()
|
shortcut := shortcutRaw.toShortcut()
|
||||||
|
|
||||||
return shortcut, nil
|
return shortcut, nil
|
||||||
@ -112,13 +106,8 @@ func (s *Store) FindShortcutList(ctx context.Context, find *api.ShortcutFind) ([
|
|||||||
|
|
||||||
func (s *Store) FindShortcut(ctx context.Context, find *api.ShortcutFind) (*api.Shortcut, error) {
|
func (s *Store) FindShortcut(ctx context.Context, find *api.ShortcutFind) (*api.Shortcut, error) {
|
||||||
if find.ID != nil {
|
if find.ID != nil {
|
||||||
shortcutRaw := &shortcutRaw{}
|
if shortcut, ok := s.shortcutCache.Load(*find.ID); ok {
|
||||||
has, err := s.cache.FindCache(ShortcutCache, *find.ID, shortcutRaw)
|
return shortcut.(*shortcutRaw).toShortcut(), nil
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if has {
|
|
||||||
return shortcutRaw.toShortcut(), nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,11 +127,7 @@ func (s *Store) FindShortcut(ctx context.Context, find *api.ShortcutFind) (*api.
|
|||||||
}
|
}
|
||||||
|
|
||||||
shortcutRaw := list[0]
|
shortcutRaw := list[0]
|
||||||
|
s.shortcutCache.Store(shortcutRaw.ID, shortcutRaw)
|
||||||
if err := s.cache.UpsertCache(ShortcutCache, shortcutRaw.ID, shortcutRaw); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
shortcut := shortcutRaw.toShortcut()
|
shortcut := shortcutRaw.toShortcut()
|
||||||
|
|
||||||
return shortcut, nil
|
return shortcut, nil
|
||||||
@ -164,8 +149,7 @@ func (s *Store) DeleteShortcut(ctx context.Context, delete *api.ShortcutDelete)
|
|||||||
return FormatError(err)
|
return FormatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.cache.DeleteCache(ShortcutCache, *delete.ID)
|
s.shortcutCache.Delete(*delete.ID)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package store
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/usememos/memos/server/profile"
|
"github.com/usememos/memos/server/profile"
|
||||||
)
|
)
|
||||||
@ -11,17 +12,18 @@ import (
|
|||||||
type Store struct {
|
type Store struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
profile *profile.Profile
|
profile *profile.Profile
|
||||||
cache *CacheService
|
|
||||||
|
userCache sync.Map // map[int]*userRaw
|
||||||
|
userSettingCache sync.Map // map[string]*userSettingRaw
|
||||||
|
memoCache sync.Map // map[int]*memoRaw
|
||||||
|
shortcutCache sync.Map // map[int]*shortcutRaw
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new instance of Store.
|
// New creates a new instance of Store.
|
||||||
func New(db *sql.DB, profile *profile.Profile) *Store {
|
func New(db *sql.DB, profile *profile.Profile) *Store {
|
||||||
cacheService := NewCacheService()
|
|
||||||
|
|
||||||
return &Store{
|
return &Store{
|
||||||
db: db,
|
db: db,
|
||||||
profile: profile,
|
profile: profile,
|
||||||
cache: cacheService,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,10 +58,8 @@ func (s *Store) ComposeMemoCreator(ctx context.Context, memo *api.Memo) error {
|
|||||||
user.OpenID = ""
|
user.OpenID = ""
|
||||||
user.UserSettingList = nil
|
user.UserSettingList = nil
|
||||||
memo.Creator = user
|
memo.Creator = user
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) CreateUser(ctx context.Context, create *api.UserCreate) (*api.User, error) {
|
func (s *Store) CreateUser(ctx context.Context, create *api.UserCreate) (*api.User, error) {
|
||||||
tx, err := s.db.BeginTx(ctx, nil)
|
tx, err := s.db.BeginTx(ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -78,12 +76,8 @@ func (s *Store) CreateUser(ctx context.Context, create *api.UserCreate) (*api.Us
|
|||||||
return nil, FormatError(err)
|
return nil, FormatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.cache.UpsertCache(UserCache, userRaw.ID, userRaw); err != nil {
|
s.userCache.Store(userRaw.ID, userRaw)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
user := userRaw.toUser()
|
user := userRaw.toUser()
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,12 +97,8 @@ func (s *Store) PatchUser(ctx context.Context, patch *api.UserPatch) (*api.User,
|
|||||||
return nil, FormatError(err)
|
return nil, FormatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.cache.UpsertCache(UserCache, userRaw.ID, userRaw); err != nil {
|
s.userCache.Store(userRaw.ID, userRaw)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
user := userRaw.toUser()
|
user := userRaw.toUser()
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,13 +124,8 @@ func (s *Store) FindUserList(ctx context.Context, find *api.UserFind) ([]*api.Us
|
|||||||
|
|
||||||
func (s *Store) FindUser(ctx context.Context, find *api.UserFind) (*api.User, error) {
|
func (s *Store) FindUser(ctx context.Context, find *api.UserFind) (*api.User, error) {
|
||||||
if find.ID != nil {
|
if find.ID != nil {
|
||||||
userRaw := &userRaw{}
|
if user, ok := s.userCache.Load(*find.ID); ok {
|
||||||
has, err := s.cache.FindCache(UserCache, *find.ID, userRaw)
|
return user.(*userRaw).toUser(), nil
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if has {
|
|
||||||
return userRaw.toUser(), nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,13 +145,8 @@ func (s *Store) FindUser(ctx context.Context, find *api.UserFind) (*api.User, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
userRaw := list[0]
|
userRaw := list[0]
|
||||||
|
s.userCache.Store(userRaw.ID, userRaw)
|
||||||
if err := s.cache.UpsertCache(UserCache, userRaw.ID, userRaw); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
user := userRaw.toUser()
|
user := userRaw.toUser()
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,8 +168,7 @@ func (s *Store) DeleteUser(ctx context.Context, delete *api.UserDelete) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.cache.DeleteCache(UserCache, delete.ID)
|
s.userCache.Delete(delete.ID)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ func (s *Store) UpsertUserSetting(ctx context.Context, upsert *api.UserSettingUp
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.userSettingCache.Store(getUserSettingCacheKey(*userSettingRaw), userSettingRaw)
|
||||||
userSetting := userSettingRaw.toUserSetting()
|
userSetting := userSettingRaw.toUserSetting()
|
||||||
|
|
||||||
return userSetting, nil
|
return userSetting, nil
|
||||||
@ -57,6 +58,7 @@ func (s *Store) FindUserSettingList(ctx context.Context, find *api.UserSettingFi
|
|||||||
|
|
||||||
list := []*api.UserSetting{}
|
list := []*api.UserSetting{}
|
||||||
for _, raw := range userSettingRawList {
|
for _, raw := range userSettingRawList {
|
||||||
|
s.userSettingCache.Store(getUserSettingCacheKey(*raw), raw)
|
||||||
list = append(list, raw.toUserSetting())
|
list = append(list, raw.toUserSetting())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +66,13 @@ func (s *Store) FindUserSettingList(ctx context.Context, find *api.UserSettingFi
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) FindUserSetting(ctx context.Context, find *api.UserSettingFind) (*api.UserSetting, error) {
|
func (s *Store) FindUserSetting(ctx context.Context, find *api.UserSettingFind) (*api.UserSetting, error) {
|
||||||
|
if userSetting, ok := s.userSettingCache.Load(getUserSettingFindCacheKey(find)); ok {
|
||||||
|
if userSetting == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return userSetting.(*userSettingRaw).toUserSetting(), nil
|
||||||
|
}
|
||||||
|
|
||||||
tx, err := s.db.BeginTx(ctx, nil)
|
tx, err := s.db.BeginTx(ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, FormatError(err)
|
return nil, FormatError(err)
|
||||||
@ -76,12 +85,13 @@ func (s *Store) FindUserSetting(ctx context.Context, find *api.UserSettingFind)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(list) == 0 {
|
if len(list) == 0 {
|
||||||
|
s.userSettingCache.Store(getUserSettingFindCacheKey(find), nil)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
userSetting := list[0].toUserSetting()
|
userSettingRaw := list[0]
|
||||||
|
s.userSettingCache.Store(getUserSettingCacheKey(*userSettingRaw), userSettingRaw)
|
||||||
return userSetting, nil
|
return userSettingRaw.toUserSetting(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func upsertUserSetting(ctx context.Context, tx *sql.Tx, upsert *api.UserSettingUpsert) (*userSettingRaw, error) {
|
func upsertUserSetting(ctx context.Context, tx *sql.Tx, upsert *api.UserSettingUpsert) (*userSettingRaw, error) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user