Implement 'likes sort order' for Likes tab

This commit is contained in:
Alessio 2023-10-12 15:34:24 -03:00
parent 9aff2b8a93
commit dc1bde2fe6
4 changed files with 62 additions and 12 deletions

View File

@ -155,13 +155,40 @@ func TestUserLikesFeed(t *testing.T) {
// Fetch @Peter_Nimitz user feed while logged in as @MysteryGrove // Fetch @Peter_Nimitz user feed while logged in as @MysteryGrove
c := persistence.NewUserFeedLikesCursor(UserHandle("MysteryGrove")) c := persistence.NewUserFeedLikesCursor(UserHandle("MysteryGrove"))
require.Equal(c.SortOrder, persistence.SORT_ORDER_LIKED_AT)
c.PageSize = 2
feed, err := profile.NextPage(c, UserID(0)) feed, err := profile.NextPage(c, UserID(0))
require.NoError(err) require.NoError(err)
// Should have "liked" 1 tweet require.Len(feed.Tweets, 2)
require.Len(feed.Tweets, 1) for i, expected_tweet_id := range []TweetID{1698765208393576891, 1426669666928414720} {
_, is_ok := feed.Tweets[1413646595493568516] assert.Equal(feed.Items[i].TweetID, expected_tweet_id)
_, is_ok := feed.Tweets[expected_tweet_id]
assert.True(is_ok) assert.True(is_ok)
}
require.Equal(feed.CursorBottom.CursorValue, 4)
feed, err = profile.NextPage(feed.CursorBottom, UserID(0))
require.NoError(err)
require.Len(feed.Tweets, 2)
for i, expected_tweet_id := range []TweetID{1343633011364016128, 1513313535480287235} {
assert.Equal(feed.Items[i].TweetID, expected_tweet_id)
_, is_ok := feed.Tweets[expected_tweet_id]
assert.True(is_ok)
}
assert.Equal(feed.CursorBottom.CursorValue, 2)
feed, err = profile.NextPage(feed.CursorBottom, UserID(0))
require.NoError(err)
require.Len(feed.Tweets, 1)
for i, expected_tweet_id := range []TweetID{1413646595493568516} {
assert.Equal(feed.Items[i].TweetID, expected_tweet_id)
_, is_ok := feed.Tweets[expected_tweet_id]
assert.True(is_ok)
}
assert.Equal(feed.CursorBottom.CursorPosition, persistence.CURSOR_END)
} }
func TestTweetDetailWithReplies(t *testing.T) { func TestTweetDetailWithReplies(t *testing.T) {

View File

@ -16,6 +16,7 @@ const (
SORT_ORDER_OLDEST SORT_ORDER_OLDEST
SORT_ORDER_MOST_LIKES SORT_ORDER_MOST_LIKES
SORT_ORDER_MOST_RETWEETS SORT_ORDER_MOST_RETWEETS
SORT_ORDER_LIKED_AT
) )
func (o SortOrder) OrderByClause() string { func (o SortOrder) OrderByClause() string {
@ -28,6 +29,8 @@ func (o SortOrder) OrderByClause() string {
return "order by num_likes desc" return "order by num_likes desc"
case SORT_ORDER_MOST_RETWEETS: case SORT_ORDER_MOST_RETWEETS:
return "order by num_retweets desc" return "order by num_retweets desc"
case SORT_ORDER_LIKED_AT:
return "order by likes_sort_order desc"
default: default:
panic(fmt.Sprintf("Invalid sort order: %d", o)) panic(fmt.Sprintf("Invalid sort order: %d", o))
} }
@ -42,6 +45,8 @@ func (o SortOrder) PaginationWhereClause() string {
return "num_likes < ?" return "num_likes < ?"
case SORT_ORDER_MOST_RETWEETS: case SORT_ORDER_MOST_RETWEETS:
return "num_retweets < ?" return "num_retweets < ?"
case SORT_ORDER_LIKED_AT:
return "likes_sort_order < ?"
default: default:
panic(fmt.Sprintf("Invalid sort order: %d", o)) panic(fmt.Sprintf("Invalid sort order: %d", o))
} }
@ -56,6 +61,8 @@ func (o SortOrder) NextCursorValue(r CursorResult) int {
return r.NumLikes return r.NumLikes
case SORT_ORDER_MOST_RETWEETS: case SORT_ORDER_MOST_RETWEETS:
return r.NumRetweets return r.NumRetweets
case SORT_ORDER_LIKED_AT:
return r.LikeSortOrder
default: default:
panic(fmt.Sprintf("Invalid sort order: %d", o)) panic(fmt.Sprintf("Invalid sort order: %d", o))
} }
@ -95,6 +102,7 @@ type CursorResult struct {
scraper.Tweet scraper.Tweet
scraper.Retweet scraper.Retweet
Chrono int `db:"chrono"` Chrono int `db:"chrono"`
LikeSortOrder int `db:"likes_sort_order"`
ByUserID scraper.UserID `db:"by_user_id"` ByUserID scraper.UserID `db:"by_user_id"`
} }
@ -181,7 +189,7 @@ func NewUserFeedLikesCursor(h scraper.UserHandle) Cursor {
UntilTimestamp: scraper.TimestampFromUnix(0), UntilTimestamp: scraper.TimestampFromUnix(0),
CursorPosition: CURSOR_START, CursorPosition: CURSOR_START,
CursorValue: 0, CursorValue: 0,
SortOrder: SORT_ORDER_NEWEST, SortOrder: SORT_ORDER_LIKED_AT,
PageSize: 50, PageSize: 50,
LikedByUserHandle: h, LikedByUserHandle: h,
@ -255,6 +263,8 @@ func (c *Cursor) apply_token(token string) error {
c.ToUserHandles = append(c.ToUserHandles, scraper.UserHandle(parts[1])) c.ToUserHandles = append(c.ToUserHandles, scraper.UserHandle(parts[1]))
case "retweeted_by": case "retweeted_by":
c.RetweetedByUserHandle = scraper.UserHandle(parts[1]) c.RetweetedByUserHandle = scraper.UserHandle(parts[1])
case "liked_by":
c.LikedByUserHandle = scraper.UserHandle(parts[1])
case "since": case "since":
c.SinceTimestamp.Time, err = time.Parse("2006-01-02", parts[1]) c.SinceTimestamp.Time, err = time.Parse("2006-01-02", parts[1])
case "until": case "until":
@ -396,10 +406,16 @@ func (p Profile) NextPage(c Cursor, current_user_id scraper.UserID) (Feed, error
} }
liked_by_filter_join_clause := "" liked_by_filter_join_clause := ""
likes_sort_order_field := ""
if c.LikedByUserHandle != "" { if c.LikedByUserHandle != "" {
liked_by_filter_join_clause = " join likes filter_likes on tweets.id = filter_likes.tweet_id " liked_by_filter_join_clause = " join likes filter_likes on tweets.id = filter_likes.tweet_id "
where_clauses = append(where_clauses, "filter_likes.user_id = (select id from users where handle like ?) ") where_clauses = append(where_clauses, "filter_likes.user_id = (select id from users where handle like ?) ")
bind_values = append(bind_values, c.LikedByUserHandle) bind_values = append(bind_values, c.LikedByUserHandle)
likes_sort_order_field = ", coalesce(filter_likes.sort_order, -1) likes_sort_order "
// Don't include retweets on "liked by" searches because it doesn't distinguish which retweet
// version was the "liked" one
where_clauses = append(where_clauses, "retweet_id = 0")
} }
// Pagination // Pagination
@ -414,7 +430,7 @@ func (p Profile) NextPage(c Cursor, current_user_id scraper.UserID) (Feed, error
} }
q := `select * from ( q := `select * from (
select ` + TWEETS_ALL_SQL_FIELDS + `, select ` + TWEETS_ALL_SQL_FIELDS + likes_sort_order_field + `,
0 tweet_id, 0 retweet_id, 0 retweeted_by, 0 retweeted_at, 0 tweet_id, 0 retweet_id, 0 retweeted_by, 0 retweeted_at,
posted_at chrono, tweets.user_id by_user_id posted_at chrono, tweets.user_id by_user_id
from tweets from tweets
@ -427,7 +443,7 @@ func (p Profile) NextPage(c Cursor, current_user_id scraper.UserID) (Feed, error
union union
select * from ( select * from (
select ` + TWEETS_ALL_SQL_FIELDS + `, select ` + TWEETS_ALL_SQL_FIELDS + likes_sort_order_field + `,
retweets.tweet_id, retweet_id, retweeted_by, retweeted_at, retweets.tweet_id, retweet_id, retweeted_by, retweeted_at,
retweeted_at chrono, retweeted_by by_user_id retweeted_at chrono, retweeted_by by_user_id
from retweets from retweets

View File

@ -190,10 +190,6 @@ create table hashtags (rowid integer primary key,
foreign key(tweet_id) references tweets(id) foreign key(tweet_id) references tweets(id)
); );
create table database_version(rowid integer primary key,
version_number integer not null unique
);
create table likes(rowid integer primary key, create table likes(rowid integer primary key,
sort_order integer unique not null, sort_order integer unique not null,
user_id integer not null, user_id integer not null,
@ -202,6 +198,12 @@ create table likes(rowid integer primary key,
foreign key(user_id) references users(id) foreign key(user_id) references users(id)
foreign key(tweet_id) references tweets(id) foreign key(tweet_id) references tweets(id)
); );
create index if not exists index_likes_user_id on likes (user_id);
create index if not exists index_likes_tweet_id on likes (tweet_id);
create table fake_user_sequence(latest_fake_id integer not null); create table fake_user_sequence(latest_fake_id integer not null);
insert into fake_user_sequence values(0x4000000000000000); insert into fake_user_sequence values(0x4000000000000000);
create table database_version(rowid integer primary key,
version_number integer not null unique
);

View File

@ -307,6 +307,11 @@ create table likes(rowid integer primary key,
foreign key(tweet_id) references tweets(id) foreign key(tweet_id) references tweets(id)
); );
insert into likes values(1, 1, 1178839081222115328, 1413646595493568516); insert into likes values(1, 1, 1178839081222115328, 1413646595493568516);
insert into likes values(2, 2, 1178839081222115328, 1513313535480287235);
insert into likes values(3, 3, 1178839081222115328, 1343633011364016128);
insert into likes values(4, 4, 1178839081222115328, 1426669666928414720);
insert into likes values(5, 5, 1178839081222115328, 1698765208393576891);
create table fake_user_sequence(latest_fake_id integer not null); create table fake_user_sequence(latest_fake_id integer not null);
insert into fake_user_sequence values(0x4000000000000000); insert into fake_user_sequence values(0x4000000000000000);