diff options
author | 2024-03-06 11:18:57 +0100 | |
---|---|---|
committer | 2024-03-06 11:18:57 +0100 | |
commit | b22e213e15a7bc64773e626d76305bd860e6301c (patch) | |
tree | bdc0f14481b144f8e4e45a380ea3b7cf78490041 /internal/db/bundb/move.go | |
parent | [feature] Filters v1 (#2594) (diff) | |
download | gotosocial-b22e213e15a7bc64773e626d76305bd860e6301c.tar.xz |
[feature/chore] Add Move database functions + cache (#2647)
* [feature/chore] Add Move database functions + cache
* add move mem ratio to envparsing.sh
* update comment
Diffstat (limited to 'internal/db/bundb/move.go')
-rw-r--r-- | internal/db/bundb/move.go | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/internal/db/bundb/move.go b/internal/db/bundb/move.go new file mode 100644 index 000000000..a66b9dea5 --- /dev/null +++ b/internal/db/bundb/move.go @@ -0,0 +1,236 @@ +// GoToSocial +// Copyright (C) GoToSocial Authors admin@gotosocial.org +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +package bundb + +import ( + "context" + "errors" + "fmt" + "net/url" + "time" + + "github.com/superseriousbusiness/gotosocial/internal/db" + "github.com/superseriousbusiness/gotosocial/internal/gtscontext" + "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" + "github.com/superseriousbusiness/gotosocial/internal/state" + "github.com/uptrace/bun" +) + +type moveDB struct { + db *bun.DB + state *state.State +} + +func (m *moveDB) GetMoveByID( + ctx context.Context, + id string, +) (*gtsmodel.Move, error) { + return m.getMove( + ctx, + "ID", + func(move *gtsmodel.Move) error { + return m.db. + NewSelect(). + Model(move). + Where("? = ?", bun.Ident("move.id"), id). + Scan(ctx) + }, + id, + ) +} + +func (m *moveDB) GetMoveByURI( + ctx context.Context, + uri string, +) (*gtsmodel.Move, error) { + return m.getMove( + ctx, + "URI", + func(move *gtsmodel.Move) error { + return m.db. + NewSelect(). + Model(move). + Where("? = ?", bun.Ident("move.uri"), uri). + Scan(ctx) + }, + uri, + ) +} + +func (m *moveDB) GetMoveByOriginTarget( + ctx context.Context, + originURI string, + targetURI string, +) (*gtsmodel.Move, error) { + return m.getMove( + ctx, + "OriginURI,TargetURI", + func(move *gtsmodel.Move) error { + return m.db. + NewSelect(). + Model(move). + Where("? = ?", bun.Ident("move.origin_uri"), originURI). + Where("? = ?", bun.Ident("move.target_uri"), targetURI). + Scan(ctx) + }, + originURI, targetURI, + ) +} + +func (m *moveDB) GetLatestMoveSuccessInvolvingURIs( + ctx context.Context, + uri1 string, + uri2 string, +) (time.Time, error) { + // Get at most 1 latest Move + // involving the provided URIs. + var moves []*gtsmodel.Move + err := m.db. + NewSelect(). + Model(&moves). + Column("succeeded_at"). + Where("? = ?", bun.Ident("move.origin_uri"), uri1). + WhereOr("? = ?", bun.Ident("move.origin_uri"), uri2). + WhereOr("? = ?", bun.Ident("move.target_uri"), uri1). + WhereOr("? = ?", bun.Ident("move.target_uri"), uri2). + Order("id DESC"). + Limit(1). + Scan(ctx) + if err != nil && !errors.Is(err, db.ErrNoEntries) { + return time.Time{}, err + } + + if len(moves) != 1 { + return time.Time{}, nil + } + + return moves[0].SucceededAt, nil +} + +func (m *moveDB) GetLatestMoveAttemptInvolvingURIs( + ctx context.Context, + uri1 string, + uri2 string, +) (time.Time, error) { + // Get at most 1 latest Move + // involving the provided URIs. + var moves []*gtsmodel.Move + err := m.db. + NewSelect(). + Model(&moves). + Column("attempted_at"). + Where("? = ?", bun.Ident("move.origin_uri"), uri1). + WhereOr("? = ?", bun.Ident("move.origin_uri"), uri2). + WhereOr("? = ?", bun.Ident("move.target_uri"), uri1). + WhereOr("? = ?", bun.Ident("move.target_uri"), uri2). + Order("id DESC"). + Limit(1). + Scan(ctx) + if err != nil && !errors.Is(err, db.ErrNoEntries) { + return time.Time{}, err + } + + if len(moves) != 1 { + return time.Time{}, nil + } + + return moves[0].AttemptedAt, nil +} + +func (m *moveDB) getMove( + ctx context.Context, + lookup string, + dbQuery func(*gtsmodel.Move) error, + keyParts ...any, +) (*gtsmodel.Move, error) { + move, err := m.state.Caches.GTS.Move.LoadOne(lookup, func() (*gtsmodel.Move, error) { + var move gtsmodel.Move + + // Not cached! Perform database query. + if err := dbQuery(&move); err != nil { + return nil, err + } + + return &move, nil + }, keyParts...) + if err != nil { + return nil, err + } + + if gtscontext.Barebones(ctx) { + return move, nil + } + + // Populate the Move by parsing out the URIs. + if move.Origin == nil { + move.Origin, err = url.Parse(move.OriginURI) + if err != nil { + return nil, fmt.Errorf("error parsing Move originURI: %w", err) + } + } + + if move.Target == nil { + move.Target, err = url.Parse(move.TargetURI) + if err != nil { + return nil, fmt.Errorf("error parsing Move originURI: %w", err) + } + } + + return move, nil +} + +func (m *moveDB) PutMove(ctx context.Context, move *gtsmodel.Move) error { + return m.state.Caches.GTS.Move.Store(move, func() error { + _, err := m.db. + NewInsert(). + Model(move). + Exec(ctx) + return err + }) +} + +func (m *moveDB) UpdateMove(ctx context.Context, move *gtsmodel.Move, columns ...string) error { + move.UpdatedAt = time.Now() + if len(columns) > 0 { + // If we're updating by column, + // ensure "updated_at" is included. + columns = append(columns, "updated_at") + } + + return m.state.Caches.GTS.Move.Store(move, func() error { + _, err := m.db. + NewUpdate(). + Model(move). + Column(columns...). + Where("? = ?", bun.Ident("move.id"), move.ID). + Exec(ctx) + return err + }) +} + +func (m *moveDB) DeleteMoveByID(ctx context.Context, id string) error { + defer m.state.Caches.GTS.Move.Invalidate("ID", id) + + _, err := m.db. + NewDelete(). + TableExpr("? AS ?", bun.Ident("moves"), bun.Ident("move")). + Where("? = ?", bun.Ident("move.id"), id). + Exec(ctx) + + return err +} |