diff options
Diffstat (limited to 'internal/db/bundb/user.go')
-rw-r--r-- | internal/db/bundb/user.go | 175 |
1 files changed, 93 insertions, 82 deletions
diff --git a/internal/db/bundb/user.go b/internal/db/bundb/user.go index aa2f4c2c8..d9b281a6f 100644 --- a/internal/db/bundb/user.go +++ b/internal/db/bundb/user.go @@ -22,7 +22,7 @@ import ( "context" "time" - "github.com/superseriousbusiness/gotosocial/internal/cache" + "codeberg.org/gruf/go-cache/v3/result" "github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" "github.com/uptrace/bun" @@ -30,111 +30,121 @@ import ( type userDB struct { conn *DBConn - cache *cache.UserCache + cache *result.Cache[*gtsmodel.User] } -func (u *userDB) newUserQ(user *gtsmodel.User) *bun.SelectQuery { - return u.conn. - NewSelect(). - Model(user). - Relation("Account") +func (u *userDB) init() { + // Initialize user result cache + u.cache = result.NewSized([]result.Lookup{ + {Name: "ID"}, + {Name: "AccountID"}, + {Name: "Email"}, + {Name: "ConfirmationToken"}, + }, func(u1 *gtsmodel.User) *gtsmodel.User { + u2 := new(gtsmodel.User) + *u2 = *u1 + return u2 + }, 1000) + + // Set cache TTL and start sweep routine + u.cache.SetTTL(time.Minute*5, false) + u.cache.Start(time.Second * 10) } -func (u *userDB) getUser(ctx context.Context, cacheGet func() (*gtsmodel.User, bool), dbQuery func(*gtsmodel.User) error) (*gtsmodel.User, db.Error) { - // Attempt to fetch cached user - user, cached := cacheGet() +func (u *userDB) GetUserByID(ctx context.Context, id string) (*gtsmodel.User, db.Error) { + return u.cache.Load("ID", func() (*gtsmodel.User, error) { + var user gtsmodel.User - if !cached { - user = >smodel.User{} + q := u.conn. + NewSelect(). + Model(&user). + Relation("Account"). + Where("? = ?", bun.Ident("user.id"), id) - // Not cached! Perform database query - err := dbQuery(user) - if err != nil { + if err := q.Scan(ctx); err != nil { return nil, u.conn.ProcessError(err) } - // Place in the cache - u.cache.Put(user) - } - - return user, nil -} - -func (u *userDB) GetUserByID(ctx context.Context, id string) (*gtsmodel.User, db.Error) { - return u.getUser( - ctx, - func() (*gtsmodel.User, bool) { - return u.cache.GetByID(id) - }, - func(user *gtsmodel.User) error { - return u.newUserQ(user).Where("? = ?", bun.Ident("user.id"), id).Scan(ctx) - }, - ) + return &user, nil + }, id) } func (u *userDB) GetUserByAccountID(ctx context.Context, accountID string) (*gtsmodel.User, db.Error) { - return u.getUser( - ctx, - func() (*gtsmodel.User, bool) { - return u.cache.GetByAccountID(accountID) - }, - func(user *gtsmodel.User) error { - return u.newUserQ(user).Where("? = ?", bun.Ident("user.account_id"), accountID).Scan(ctx) - }, - ) + return u.cache.Load("AccountID", func() (*gtsmodel.User, error) { + var user gtsmodel.User + + q := u.conn. + NewSelect(). + Model(&user). + Relation("Account"). + Where("? = ?", bun.Ident("user.account_id"), accountID) + + if err := q.Scan(ctx); err != nil { + return nil, u.conn.ProcessError(err) + } + + return &user, nil + }, accountID) } func (u *userDB) GetUserByEmailAddress(ctx context.Context, emailAddress string) (*gtsmodel.User, db.Error) { - return u.getUser( - ctx, - func() (*gtsmodel.User, bool) { - return u.cache.GetByEmail(emailAddress) - }, - func(user *gtsmodel.User) error { - return u.newUserQ(user).Where("? = ?", bun.Ident("user.email"), emailAddress).Scan(ctx) - }, - ) + return u.cache.Load("Email", func() (*gtsmodel.User, error) { + var user gtsmodel.User + + q := u.conn. + NewSelect(). + Model(&user). + Relation("Account"). + Where("? = ?", bun.Ident("user.email"), emailAddress) + + if err := q.Scan(ctx); err != nil { + return nil, u.conn.ProcessError(err) + } + + return &user, nil + }, emailAddress) } func (u *userDB) GetUserByConfirmationToken(ctx context.Context, confirmationToken string) (*gtsmodel.User, db.Error) { - return u.getUser( - ctx, - func() (*gtsmodel.User, bool) { - return u.cache.GetByConfirmationToken(confirmationToken) - }, - func(user *gtsmodel.User) error { - return u.newUserQ(user).Where("? = ?", bun.Ident("user.confirmation_token"), confirmationToken).Scan(ctx) - }, - ) -} + return u.cache.Load("ConfirmationToken", func() (*gtsmodel.User, error) { + var user gtsmodel.User -func (u *userDB) PutUser(ctx context.Context, user *gtsmodel.User) (*gtsmodel.User, db.Error) { - if _, err := u.conn. - NewInsert(). - Model(user). - Exec(ctx); err != nil { - return nil, u.conn.ProcessError(err) - } + q := u.conn. + NewSelect(). + Model(&user). + Relation("Account"). + Where("? = ?", bun.Ident("user.confirmation_token"), confirmationToken) - u.cache.Put(user) - return user, nil + if err := q.Scan(ctx); err != nil { + return nil, u.conn.ProcessError(err) + } + + return &user, nil + }, confirmationToken) } -func (u *userDB) UpdateUser(ctx context.Context, user *gtsmodel.User, columns ...string) (*gtsmodel.User, db.Error) { +func (u *userDB) PutUser(ctx context.Context, user *gtsmodel.User) db.Error { + return u.cache.Store(user, func() error { + _, err := u.conn. + NewInsert(). + Model(user). + Exec(ctx) + return u.conn.ProcessError(err) + }) +} + +func (u *userDB) UpdateUser(ctx context.Context, user *gtsmodel.User) db.Error { // Update the user's last-updated user.UpdatedAt = time.Now() - if _, err := u.conn. - NewUpdate(). - Model(user). - Where("? = ?", bun.Ident("user.id"), user.ID). - Column(columns...). - Exec(ctx); err != nil { - return nil, u.conn.ProcessError(err) - } - - u.cache.Invalidate(user.ID) - return user, nil + return u.cache.Store(user, func() error { + _, err := u.conn. + NewUpdate(). + Model(user). + Where("? = ?", bun.Ident("user.id"), user.ID). + Exec(ctx) + return u.conn.ProcessError(err) + }) } func (u *userDB) DeleteUserByID(ctx context.Context, userID string) db.Error { @@ -146,6 +156,7 @@ func (u *userDB) DeleteUserByID(ctx context.Context, userID string) db.Error { return u.conn.ProcessError(err) } - u.cache.Invalidate(userID) + // Invalidate user from cache + u.cache.Invalidate("ID", userID) return nil } |