chore: release v0.26.2
This commit is contained in:
+38
-2
@@ -2301,7 +2301,7 @@ func (r *Repo) IterateAll(ctx context.Context, fn func(QSO) error) error {
|
||||
const awardCols = `id, callsign, qso_date, band, freq_hz, mode, ` +
|
||||
`grid, vucc_grids, country, state, cnty, cont, cqz, ituz, dxcc, iota, sota_ref, pota_ref, ` +
|
||||
`name, qth, address, comment, notes, ` +
|
||||
`qsl_rcvd, lotw_rcvd, eqsl_rcvd, extras_json`
|
||||
`qsl_rcvd, lotw_rcvd, eqsl_rcvd, extras_json, award_refs`
|
||||
|
||||
// IterateForAwards streams a lightweight projection of every QSO — only the
|
||||
// fields award computation reads (see awardCols). All other QSO fields are left
|
||||
@@ -2326,6 +2326,37 @@ func (r *Repo) IterateForAwards(ctx context.Context, fn func(QSO) error) error {
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
// IterateForAwardsWithRef streams only the QSOs whose stored award_refs already
|
||||
// mention one award code.
|
||||
//
|
||||
// For a change that RELABELS an award rather than re-matching it — the grid
|
||||
// column switching from the reference to its description — the rows that can
|
||||
// possibly change are exactly these. On a 30 000-QSO log with 2 488 French
|
||||
// departments in it, that is the difference between reading the whole logbook
|
||||
// and reading a twelfth of it.
|
||||
//
|
||||
// Matched with LIKE on the JSON key, which is exact enough: award_refs is a
|
||||
// compact object written by us, so a code appears as "DDFM": and nowhere else.
|
||||
func (r *Repo) IterateForAwardsWithRef(ctx context.Context, code string, fn func(QSO) error) error {
|
||||
like := "%\"" + strings.ToUpper(strings.TrimSpace(code)) + "\":%"
|
||||
rows, err := r.db.QueryContext(ctx,
|
||||
`SELECT `+awardCols+` FROM qso WHERE award_refs LIKE ? ORDER BY qso_date ASC, id ASC`, like)
|
||||
if err != nil {
|
||||
return fmt.Errorf("query qso (awards, one code): %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
q, err := scanAwardQSO(rows)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fn(q); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
// scanAwardQSO reads one row produced by awardCols into a QSO, populating only
|
||||
// the award-relevant fields. Column order MUST match awardCols.
|
||||
func scanAwardQSO(s scanner) (QSO, error) {
|
||||
@@ -2341,16 +2372,21 @@ func scanAwardQSO(s scanner) (QSO, error) {
|
||||
comment, notes sql.NullString
|
||||
qslRcvd, lotwRcvd, eqslRcvd sql.NullString
|
||||
extrasJSON sql.NullString
|
||||
awardRefs sql.NullString
|
||||
)
|
||||
if err := s.Scan(
|
||||
&q.ID, &q.Callsign, &qsoDateStr, &q.Band, &freqHz, &q.Mode,
|
||||
&grid, &vucc, &country, &state, &cnty, &cont, &cqz, &ituz, &dxcc, &iotaRef, &sota, &pota,
|
||||
&name, &qth, &address, &comment, ¬es,
|
||||
&qslRcvd, &lotwRcvd, &eqslRcvd, &extrasJSON,
|
||||
&qslRcvd, &lotwRcvd, &eqslRcvd, &extrasJSON, &awardRefs,
|
||||
); err != nil {
|
||||
return QSO{}, fmt.Errorf("scan qso (awards): %w", err)
|
||||
}
|
||||
q.QSODate = parseTimeLoose(qsoDateStr)
|
||||
// award_refs rides along so a recompute can compare what it produced against
|
||||
// what is stored WITHOUT falling back to the full-record scan — the whole
|
||||
// point of this projection.
|
||||
q.AwardRefs = awardRefs.String
|
||||
if freqHz.Valid {
|
||||
v := freqHz.Int64
|
||||
q.FreqHz = &v
|
||||
|
||||
Reference in New Issue
Block a user