offline-twitter/pkg/persistence/notification_queries.go

134 lines
3.9 KiB
Go

package persistence
import (
"database/sql"
"errors"
"fmt"
. "gitlab.com/offline-twitter/twitter_offline_engine/pkg/scraper"
)
func (p Profile) SaveNotification(n Notification) {
tx, err := p.DB.Beginx()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
panic(r) // Re-raise the panic
}
}()
if err != nil {
panic(err)
}
// Save the Notification
_, err = tx.NamedExec(`
insert into notifications(id, type, sent_at, sort_index, user_id, action_user_id, action_tweet_id, action_retweet_id,
has_detail, last_scraped_at)
values (:id, :type, :sent_at, :sort_index, :user_id, nullif(:action_user_id, 0), nullif(:action_tweet_id, 0),
nullif(:action_retweet_id, 0), :has_detail, :last_scraped_at)
on conflict do update
set sent_at = max(sent_at, :sent_at),
sort_index = max(sort_index, :sort_index),
action_user_id = nullif(:action_user_id, 0),
action_tweet_id = nullif(:action_tweet_id, 0),
has_detail = has_detail or :has_detail,
last_scraped_at = max(last_scraped_at, :last_scraped_at)
`, n)
if err != nil {
fmt.Printf("failed to save notification %#v\n", n)
panic(err)
}
// Save relevant users and tweets
for _, u_id := range n.UserIDs {
_, err = tx.Exec(`
insert into notification_users(notification_id, user_id) values (?, ?) on conflict do nothing
`, n.ID, u_id)
if err != nil {
panic(err)
}
}
for _, t_id := range n.TweetIDs {
_, err = tx.Exec(`
insert into notification_tweets(notification_id, tweet_id) values (?, ?) on conflict do nothing
`, n.ID, t_id)
if err != nil {
fmt.Printf("failed to save notification %#v\n", n)
panic(err)
}
}
for _, r_id := range n.RetweetIDs {
_, err = tx.Exec(`
insert into notification_retweets(notification_id, retweet_id) values (?, ?) on conflict do nothing
`, n.ID, r_id)
if err != nil {
fmt.Printf("failed to save notification %#v\n", n)
panic(err)
}
}
err = tx.Commit()
if err != nil {
panic(err)
}
}
func (p Profile) GetNotification(id NotificationID) Notification {
var ret Notification
err := p.DB.Get(&ret,
`select id, type, sent_at, sort_index, user_id, ifnull(action_user_id, 0) action_user_id,
ifnull(action_tweet_id, 0) action_tweet_id, ifnull(action_retweet_id, 0) action_retweet_id, has_detail, last_scraped_at
from notifications where id = ?`,
id)
if err != nil {
panic(err)
}
err = p.DB.Select(&ret.UserIDs, `select user_id from notification_users where notification_id = ?`, id)
if err != nil {
panic(err)
}
err = p.DB.Select(&ret.TweetIDs, `select tweet_id from notification_tweets where notification_id = ?`, id)
if err != nil {
panic(err)
}
err = p.DB.Select(&ret.RetweetIDs, `select retweet_id from notification_retweets where notification_id = ?`, id)
if err != nil {
panic(err)
}
return ret
}
func (p Profile) CheckNotificationScrapesNeeded(trove TweetTrove) []NotificationID {
ret := []NotificationID{}
for n_id, notification := range trove.Notifications {
// If there's no detail page, skip
if !notification.HasDetail {
continue
}
// Check its last-scraped
var last_scraped_at Timestamp
err := p.DB.Get(&last_scraped_at, `select last_scraped_at from notifications where id = ?`, n_id)
if errors.Is(err, sql.ErrNoRows) {
// It's not scraped at all yet
ret = append(ret, n_id)
continue
} else if err != nil {
panic(err)
}
// If the latest scrape is not fresh (older than the notification sent-at time), add it
if last_scraped_at.Time.Before(notification.SentAt.Time) {
ret = append(ret, n_id)
}
}
return ret
}
func (p Profile) GetUnreadNotificationsCount(u_id UserID, since_sort_index int64) int {
var ret int
err := p.DB.Get(&ret, `select count(*) from notifications where sort_index > ? and user_id = ?`, since_sort_index, u_id)
if err != nil {
panic(err)
}
return ret
}