This commit is contained in:
2026-05-26 00:56:08 +02:00
parent 7ace2cc602
commit 7e518ddba3
10 changed files with 51169 additions and 51 deletions
+33
View File
@@ -807,6 +807,39 @@ func (r *Repo) Count(ctx context.Context) (int64, error) {
return n, err
}
// ExistingDedupeKeys returns a set of every QSO key currently in the DB,
// used by the ADIF importer to skip records that would re-create the
// same contact. The key is callsign|YYYY-MM-DDTHH:MM|band|mode — minute
// precision so two loggers that wrote a few seconds apart still match.
//
// On a 25k-row table this returns ~25k strings (~2MB RAM) in one pass —
// far cheaper than N exists-queries during the import loop.
func (r *Repo) ExistingDedupeKeys(ctx context.Context) (map[string]struct{}, error) {
rows, err := r.db.QueryContext(ctx, `
SELECT callsign, strftime('%Y-%m-%dT%H:%M', qso_date), band, mode
FROM qso`)
if err != nil {
return nil, err
}
defer rows.Close()
out := make(map[string]struct{}, 1024)
for rows.Next() {
var call, when, band, mode string
if err := rows.Scan(&call, &when, &band, &mode); err != nil {
return nil, err
}
out[DedupeKey(call, when, band, mode)] = struct{}{}
}
return out, rows.Err()
}
// DedupeKey is the canonical dedupe identity for a QSO. Exposed so the
// importer can compute the key from in-flight records and check against
// the same map ExistingDedupeKeys returns.
func DedupeKey(callsign, qsoDateMinute, band, mode string) string {
return strings.ToUpper(callsign) + "|" + qsoDateMinute + "|" + strings.ToLower(band) + "|" + strings.ToUpper(mode)
}
// scanner is what both *sql.Row and *sql.Rows satisfy for our needs.
type scanner interface {
Scan(dest ...any) error