alternative method of selecting home timeline
This commit is contained in:
parent
5da8160d31
commit
054f286cae
|
@ -19,7 +19,6 @@ package bundb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -31,6 +30,7 @@ import (
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/log"
|
"github.com/superseriousbusiness/gotosocial/internal/log"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/state"
|
"github.com/superseriousbusiness/gotosocial/internal/state"
|
||||||
"github.com/uptrace/bun"
|
"github.com/uptrace/bun"
|
||||||
|
"github.com/uptrace/bun/dialect"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -103,38 +103,67 @@ func (t *timelineDB) GetHomeTimeline(ctx context.Context, accountID string, maxI
|
||||||
q = q.Order("status.id ASC")
|
q = q.Order("status.id ASC")
|
||||||
}
|
}
|
||||||
|
|
||||||
// As this is the home timeline, it should be
|
// Create a temp table containing just the
|
||||||
// populated by statuses from accounts followed
|
// IDs of accounts that accountID follows.
|
||||||
// by accountID, and posts from accountID itself.
|
var (
|
||||||
//
|
tempTableName = "#temp_follows_" + id.NewULID()
|
||||||
// So, begin by seeing who accountID follows.
|
err error
|
||||||
// It should be a little cheaper to do this in
|
|
||||||
// a separate query like this, rather than using
|
|
||||||
// a join, since followIDs are cached in memory.
|
|
||||||
follows, err := t.state.DB.GetAccountFollows(
|
|
||||||
gtscontext.SetBarebones(ctx),
|
|
||||||
accountID,
|
|
||||||
)
|
)
|
||||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
|
||||||
return nil, gtserror.Newf("db error getting follows for account %s: %w", accountID, err)
|
switch t.db.Dialect().Name() {
|
||||||
|
case dialect.PG:
|
||||||
|
_, err = t.db.NewRaw(
|
||||||
|
"SELECT ? INTO ? FROM ? AS ? WHERE ? = ?",
|
||||||
|
bun.Ident("follow.target_account_id"),
|
||||||
|
bun.Ident(tempTableName),
|
||||||
|
bun.Ident("follows"), bun.Ident("follow"),
|
||||||
|
bun.Ident("follow.account_id"), accountID,
|
||||||
|
).Exec(ctx)
|
||||||
|
case dialect.SQLite:
|
||||||
|
_, err = t.db.NewRaw(
|
||||||
|
"CREATE TABLE ? AS SELECT ? FROM ? AS ? WHERE ? = ?",
|
||||||
|
bun.Ident(tempTableName),
|
||||||
|
bun.Ident("follow.target_account_id"),
|
||||||
|
bun.Ident("follows"), bun.Ident("follow"),
|
||||||
|
bun.Ident("follow.account_id"), accountID,
|
||||||
|
).Exec(ctx)
|
||||||
|
default:
|
||||||
|
log.Panic(ctx, "db dialect was neither pg nor sqlite")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract just the accountID from each follow.
|
if err != nil {
|
||||||
targetAccountIDs := make([]string, len(follows)+1)
|
return nil, gtserror.Newf("db error creating temp follows table: %w", err)
|
||||||
for i, f := range follows {
|
|
||||||
targetAccountIDs[i] = f.TargetAccountID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean up temp
|
||||||
|
// table on exit.
|
||||||
|
defer func() {
|
||||||
|
if _, err := t.db.
|
||||||
|
NewDropTable().
|
||||||
|
Table(tempTableName).
|
||||||
|
IfExists().
|
||||||
|
Exec(ctx); err != nil {
|
||||||
|
log.Errorf(ctx, "db error dropping temp follows table: %q", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// Add accountID itself as a pseudo follow so that
|
// Add accountID itself as a pseudo follow so that
|
||||||
// accountID can see its own posts in the timeline.
|
// accountID can see its own posts in the timeline.
|
||||||
targetAccountIDs[len(targetAccountIDs)-1] = accountID
|
if _, err := t.db.
|
||||||
|
NewRaw(
|
||||||
|
"INSERT INTO ? VALUES (?)",
|
||||||
|
bun.Ident(tempTableName), accountID,
|
||||||
|
).
|
||||||
|
Exec(ctx); err != nil {
|
||||||
|
return nil, gtserror.Newf("db error inserting accountID into temp follows table: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Select only statuses authored by
|
// Select only statuses authored by
|
||||||
// accounts with IDs in the slice.
|
// accounts with IDs in the slice.
|
||||||
q = q.Where(
|
q = q.Where(
|
||||||
"? IN (?)",
|
"? IN (?)",
|
||||||
bun.Ident("status.account_id"),
|
bun.Ident("status.account_id"),
|
||||||
bun.In(targetAccountIDs),
|
t.db.NewSelect().Table(tempTableName),
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := q.Scan(ctx, &statusIDs); err != nil {
|
if err := q.Scan(ctx, &statusIDs); err != nil {
|
||||||
|
|
Loading…
Reference in New Issue