package db import ( "context" "database/sql" "fmt" "slices" "strings" "time" "github.com/bluesky-social/indigo/atproto/syntax" "tangled.org/core/appview/models" "tangled.org/core/consts" "tangled.org/core/orm" ) // RecentSpindles suggests spindles for the spindle picker: ones this user already // pointed a repo at, most recently created first, plus the default spindle. func RecentSpindles(ctx context.Context, e Execer, user syntax.DID) ([]string, error) { rows, err := e.QueryContext(ctx, ` select spindle from repos where did = ? and coalesce(spindle, '') != '' group by spindle order by max(id) desc limit 5 `, user) if err != nil { return nil, err } defer rows.Close() var spindles []string for rows.Next() { var spindle string if err := rows.Scan(&spindle); err != nil { return nil, err } spindles = append(spindles, spindle) } if err := rows.Err(); err != nil { return nil, err } // a fresh account owns no repos, and a bare text input gives it nothing to go on if !slices.Contains(spindles, consts.DefaultSpindle) { spindles = append(spindles, consts.DefaultSpindle) } return spindles, nil } func GetSpindles(ctx context.Context, e Execer, filters ...orm.Filter) ([]models.Spindle, error) { var spindles []models.Spindle var conditions []string var args []any for _, filter := range filters { conditions = append(conditions, filter.Condition()) args = append(args, filter.Arg()...) } whereClause := "" if conditions != nil { whereClause = " where " + strings.Join(conditions, " and ") } query := fmt.Sprintf( `select id, owner, instance, verified, created, needs_upgrade from spindles %s order by created `, whereClause, ) rows, err := e.QueryContext(ctx, query, args...) if err != nil { return nil, err } defer rows.Close() for rows.Next() { var spindle models.Spindle var createdAt string var verified sql.NullString var needsUpgrade int if err := rows.Scan( &spindle.Id, &spindle.Owner, &spindle.Instance, &verified, &createdAt, &needsUpgrade, ); err != nil { return nil, err } spindle.Created, err = time.Parse(time.RFC3339, createdAt) if err != nil { spindle.Created = time.Now() } if verified.Valid { t, err := time.Parse(time.RFC3339, verified.String) if err != nil { now := time.Now() spindle.Verified = &now } spindle.Verified = &t } if needsUpgrade != 0 { spindle.NeedsUpgrade = true } spindles = append(spindles, spindle) } return spindles, nil } func VerifySpindle(e Execer, filters ...orm.Filter) (int64, error) { var conditions []string var args []any for _, filter := range filters { conditions = append(conditions, filter.Condition()) args = append(args, filter.Arg()...) } whereClause := "" if conditions != nil { whereClause = " where " + strings.Join(conditions, " and ") } query := fmt.Sprintf(`update spindles set verified = strftime('%%Y-%%m-%%dT%%H:%%M:%%SZ', 'now'), needs_upgrade = 0 %s`, whereClause) res, err := e.Exec(query, args...) if err != nil { return 0, err } return res.RowsAffected() }