feat(db): fill in the distances nothing ever recorded
The published page derives a distance as it renders, which fixed the empty column there but not the cause: the field is empty in the database, so it goes out empty in every ADIF export and leaves the same gap in whoever imports it. BackfillDistances computes it from the two locators for QSOs that have both. Only where it is EMPTY: a stored distance came from the log that recorded the contact, which knew the real positions, and two four-character squares are a worse answer that must not overwrite a better one. Whole kilometres, for the same reason the published column is. In the Database panel rather than beside the county backfill, which lives under US Counties: this one touches the whole logbook, whatever country the QSOs are in.
This commit is contained in:
@@ -10337,6 +10337,63 @@ func (a *App) DownloadULSCounties() error {
|
||||
}
|
||||
|
||||
// BackfillUSCountiesResult summarises a bulk county/grid backfill over the log.
|
||||
// BackfillDistancesResult reports what a distance backfill did.
|
||||
type BackfillDistancesResult struct {
|
||||
Scanned int `json:"scanned"` // QSOs examined
|
||||
Filled int `json:"filled"` // QSOs that gained a distance
|
||||
NoGrid int `json:"no_grid"` // skipped: one of the two locators is missing
|
||||
}
|
||||
|
||||
// BackfillDistances computes DISTANCE for past QSOs that have both locators and
|
||||
// no distance recorded.
|
||||
//
|
||||
// Nothing has ever computed it when logging — the column is only filled by an
|
||||
// ADIF import that carried one — so a log made in OpsLog has it empty
|
||||
// throughout. The published web page works around that by deriving the distance
|
||||
// as it renders, but the column still travels empty into every ADIF export, and
|
||||
// that is what leaves the gap in someone else's log.
|
||||
//
|
||||
// Only fills what is EMPTY. A stored distance came from the log that recorded
|
||||
// the contact, which knew the real positions; two four-character squares are a
|
||||
// worse answer and must not overwrite a better one.
|
||||
func (a *App) BackfillDistances() (BackfillDistancesResult, error) {
|
||||
var res BackfillDistancesResult
|
||||
if a.qso == nil {
|
||||
return res, fmt.Errorf("db not initialized")
|
||||
}
|
||||
rows, err := a.qso.List(a.ctx, qso.ListFilter{Limit: 1_000_000})
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
for i := range rows {
|
||||
q := rows[i]
|
||||
res.Scanned++
|
||||
if q.Distance != nil && *q.Distance > 0 {
|
||||
continue
|
||||
}
|
||||
km, ok := geo.DistanceBetweenGrids(q.MyGrid, q.Grid)
|
||||
if !ok || km <= 0 {
|
||||
res.NoGrid++
|
||||
continue
|
||||
}
|
||||
// Whole kilometres: the squares are tens of kilometres across and a
|
||||
// decimal would assert an accuracy the grids do not carry.
|
||||
v := math.Round(km)
|
||||
q.Distance = &v
|
||||
if err := a.qso.Update(a.ctx, q); err != nil {
|
||||
applog.Printf("backfill distance: QSO %d: %v", q.ID, err)
|
||||
continue
|
||||
}
|
||||
res.Filled++
|
||||
}
|
||||
applog.Printf("backfill distance: %d scanned, %d filled, %d without both grids",
|
||||
res.Scanned, res.Filled, res.NoGrid)
|
||||
if res.Filled > 0 {
|
||||
a.invalidateAwardStats()
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
type BackfillUSCountiesResult struct {
|
||||
Scanned int `json:"scanned"` // US QSOs examined
|
||||
County int `json:"county"` // QSOs that gained a county
|
||||
|
||||
Reference in New Issue
Block a user