appview/db: split star subjects #824

merged
opened by boltless.me targeting master from sl/uzmtowmlwkvz

renamed starred_by_did column to did

remove foreign key constraints from repo_at column to support targetting non-ingested repository or sh.tangled.string. the column isn't renamed yet because I'm afraid to break somewhere with that rename. We really need some test code here.

Signed-off-by: Seongmin Lee git@boltless.me

Changed files
+80 -34
appview
db
models
notify
db
posthog
pages
templates
timeline
fragments
state
+41
appview/db/db.go
···
return err
})
+
// remove the foreign key constraints from stars.
+
// using same column names for backwards compatibility, but now `repo_at`
+
// column can represent literally anything.
+
runMigration(conn, logger, "generalize-stars-subject", func(tx *sql.Tx) error {
+
_, err := tx.Exec(`
+
create table stars_new (
+
id integer primary key autoincrement,
+
did text not null,
+
rkey text not null,
+
+
repo_at text not null,
+
+
created text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
+
unique(did, rkey),
+
unique(did, repo_at)
+
);
+
+
insert into stars_new (
+
id,
+
did,
+
rkey,
+
repo_at,
+
created
+
)
+
select
+
id,
+
starred_by_did,
+
rkey,
+
repo_at,
+
created
+
from stars;
+
+
drop table stars;
+
alter table stars_new rename to stars;
+
+
create index if not exists idx_stars_created on stars(created);
+
create index if not exists idx_stars_repo_at_created on stars(repo_at, created);
+
`)
+
return err
+
})
+
return &DB{
db,
logger,
+17 -17
appview/db/star.go
···
)
func AddStar(e Execer, star *models.Star) error {
-
query := `insert or ignore into stars (starred_by_did, repo_at, rkey) values (?, ?, ?)`
+
query := `insert or ignore into stars (did, repo_at, rkey) values (?, ?, ?)`
_, err := e.Exec(
query,
-
star.StarredByDid,
+
star.Did,
star.RepoAt.String(),
star.Rkey,
)
···
}
// Get a star record
-
func GetStar(e Execer, starredByDid string, repoAt syntax.ATURI) (*models.Star, error) {
+
func GetStar(e Execer, did string, repoAt syntax.ATURI) (*models.Star, error) {
query := `
-
select starred_by_did, repo_at, created, rkey
+
select did, repo_at, created, rkey
from stars
-
where starred_by_did = ? and repo_at = ?`
-
row := e.QueryRow(query, starredByDid, repoAt)
+
where did = ? and repo_at = ?`
+
row := e.QueryRow(query, did, repoAt)
var star models.Star
var created string
-
err := row.Scan(&star.StarredByDid, &star.RepoAt, &created, &star.Rkey)
+
err := row.Scan(&star.Did, &star.RepoAt, &created, &star.Rkey)
if err != nil {
return nil, err
}
···
}
// Remove a star
-
func DeleteStar(e Execer, starredByDid string, repoAt syntax.ATURI) error {
-
_, err := e.Exec(`delete from stars where starred_by_did = ? and repo_at = ?`, starredByDid, repoAt)
+
func DeleteStar(e Execer, did string, repoAt syntax.ATURI) error {
+
_, err := e.Exec(`delete from stars where did = ? and repo_at = ?`, did, repoAt)
return err
}
// Remove a star
-
func DeleteStarByRkey(e Execer, starredByDid string, rkey string) error {
-
_, err := e.Exec(`delete from stars where starred_by_did = ? and rkey = ?`, starredByDid, rkey)
+
func DeleteStarByRkey(e Execer, did string, rkey string) error {
+
_, err := e.Exec(`delete from stars where did = ? and rkey = ?`, did, rkey)
return err
}
func GetStarCount(e Execer, repoAt syntax.ATURI) (int, error) {
stars := 0
err := e.QueryRow(
-
`select count(starred_by_did) from stars where repo_at = ?`, repoAt).Scan(&stars)
+
`select count(did) from stars where repo_at = ?`, repoAt).Scan(&stars)
if err != nil {
return 0, err
}
···
query := fmt.Sprintf(`
SELECT repo_at
FROM stars
-
WHERE starred_by_did = ? AND repo_at IN (%s)
+
WHERE did = ? AND repo_at IN (%s)
`, strings.Join(placeholders, ","))
rows, err := e.Query(query, args...)
···
}
repoQuery := fmt.Sprintf(
-
`select starred_by_did, repo_at, created, rkey
+
`select did, repo_at, created, rkey
from stars
%s
order by created desc
···
for rows.Next() {
var star models.Star
var created string
-
err := rows.Scan(&star.StarredByDid, &star.RepoAt, &created, &star.Rkey)
+
err := rows.Scan(&star.Did, &star.RepoAt, &created, &star.Rkey)
if err != nil {
return nil, err
}
···
rows, err := e.Query(`
select
-
s.starred_by_did,
+
s.did,
s.repo_at,
s.rkey,
s.created,
···
var starCreatedAt, repoCreatedAt string
if err := rows.Scan(
-
&star.StarredByDid,
+
&star.Did,
&star.RepoAt,
&star.Rkey,
&starCreatedAt,
+1 -1
appview/db/timeline.go
···
func getTimelineStars(e Execer, limit int, loggedInUserDid string, userIsFollowing []string) ([]models.TimelineEvent, error) {
filters := make([]filter, 0)
if userIsFollowing != nil {
-
filters = append(filters, FilterIn("starred_by_did", userIsFollowing))
+
filters = append(filters, FilterIn("did", userIsFollowing))
}
stars, err := GetStars(e, limit, filters...)
+3 -3
appview/ingester.go
···
return err
}
err = db.AddStar(i.Db, &models.Star{
-
StarredByDid: did,
-
RepoAt: subjectUri,
-
Rkey: e.Commit.RKey,
+
Did: did,
+
RepoAt: subjectUri,
+
Rkey: e.Commit.RKey,
})
case jmodels.CommitOperationDelete:
err = db.DeleteStarByRkey(i.Db, did, e.Commit.RKey)
+4 -4
appview/models/star.go
···
)
type Star struct {
-
StarredByDid string
-
RepoAt syntax.ATURI
-
Created time.Time
-
Rkey string
+
Did string
+
RepoAt syntax.ATURI
+
Created time.Time
+
Rkey string
// optionally, populate this when querying for reverse mappings
Repo *Repo
+6 -1
appview/notify/db/db.go
···
"slices"
"github.com/bluesky-social/indigo/atproto/syntax"
+
"tangled.org/core/api/tangled"
"tangled.org/core/appview/db"
"tangled.org/core/appview/models"
"tangled.org/core/appview/notify"
···
}
func (n *databaseNotifier) NewStar(ctx context.Context, star *models.Star) {
+
if star.RepoAt.Collection().String() != tangled.RepoNSID {
+
// skip string stars for now
+
return
+
}
var err error
repo, err := db.GetRepo(n.db, db.FilterEq("at_uri", string(star.RepoAt)))
if err != nil {
···
return
}
-
actorDid := syntax.DID(star.StarredByDid)
+
actorDid := syntax.DID(star.Did)
recipients := []syntax.DID{syntax.DID(repo.Did)}
eventType := models.NotificationTypeRepoStarred
entityType := "repo"
+2 -2
appview/notify/posthog/notifier.go
···
func (n *posthogNotifier) NewStar(ctx context.Context, star *models.Star) {
err := n.client.Enqueue(posthog.Capture{
-
DistinctId: star.StarredByDid,
+
DistinctId: star.Did,
Event: "star",
Properties: posthog.Properties{"repo_at": star.RepoAt.String()},
})
···
func (n *posthogNotifier) DeleteStar(ctx context.Context, star *models.Star) {
err := n.client.Enqueue(posthog.Capture{
-
DistinctId: star.StarredByDid,
+
DistinctId: star.Did,
Event: "unstar",
Properties: posthog.Properties{"repo_at": star.RepoAt.String()},
})
+1 -1
appview/pages/templates/timeline/fragments/timeline.html
···
{{ $event := index . 1 }}
{{ $star := $event.Star }}
{{ with $star }}
-
{{ $starrerHandle := resolve .StarredByDid }}
+
{{ $starrerHandle := resolve .Did }}
{{ $repoOwnerHandle := resolve .Repo.Did }}
<div class="pl-6 py-2 bg-white dark:bg-gray-800 text-gray-600 dark:text-gray-300 flex flex-wrap items-center gap-2 text-sm">
{{ template "user/fragments/picHandleLink" $starrerHandle }}
+2 -2
appview/state/profile.go
···
return nil, fmt.Errorf("failed to get string count: %w", err)
}
-
starredCount, err := db.CountStars(s.db, db.FilterEq("starred_by_did", did))
+
starredCount, err := db.CountStars(s.db, db.FilterEq("did", did))
if err != nil {
return nil, fmt.Errorf("failed to get starred repo count: %w", err)
}
···
}
l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle)
-
stars, err := db.GetStars(s.db, 0, db.FilterEq("starred_by_did", profile.UserDid))
+
stars, err := db.GetStars(s.db, 0, db.FilterEq("did", profile.UserDid))
if err != nil {
l.Error("failed to get stars", "err", err)
s.pages.Error500(w)
+3 -3
appview/state/star.go
···
log.Println("created atproto record: ", resp.Uri)
star := &models.Star{
-
StarredByDid: currentUser.Did,
-
RepoAt: subjectUri,
-
Rkey: rkey,
+
Did: currentUser.Did,
+
RepoAt: subjectUri,
+
Rkey: rkey,
}
err = db.AddStar(s.db, star)