package checkin import ( "context" "database/sql" "time" "github.com/bluesky-social/indigo/atproto/syntax" ) // ImportFromPDS caches a set of quest.atmo.checkin records (as returned by // ListFromPDS) into the local checkins table for did, so the user reads as // checked in locally. // // Check-ins whose referenced event isn't cached locally are skipped: the // checkins.event_uri foreign key requires the event row to exist, and we only // know about events that have been imported. Idempotent — rows that already // exist (by record_uri) are left untouched. // // Returns how many rows were newly imported and how many were skipped (event // not present locally, already cached, or malformed). func ImportFromPDS(ctx context.Context, db *sql.DB, did syntax.DID, entries []PDSEntry) (imported, skipped int, err error) { for _, e := range entries { if e.RecordURI == "" || e.EventURI == "" { skipped++ continue } // The FK requires the event to be cached locally first. var exists int scanErr := db.QueryRowContext(ctx, `SELECT 1 FROM events WHERE uri = ?`, e.EventURI).Scan(&exists) if scanErr == sql.ErrNoRows { skipped++ continue } if scanErr != nil { return imported, skipped, scanErr } at := e.CheckedInAt if at.IsZero() { at = time.Now().UTC() } res, execErr := db.ExecContext(ctx, ` INSERT INTO checkins (record_uri, did, event_uri, checked_in_at, cached_at) VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP) ON CONFLICT(record_uri) DO NOTHING `, e.RecordURI, did.String(), e.EventURI, at.UTC()) if execErr != nil { return imported, skipped, execErr } if n, _ := res.RowsAffected(); n > 0 { imported++ } else { skipped++ // already cached } } return imported, skipped, nil }