Season view: filter the editor to a year (#54) (#66)
Build image / build-and-push (push) Successful in 17s
Build image / build-and-push (push) Successful in 17s
Co-authored-by: Steve Dudenhoeffer <[email protected]>
This commit was merged in pull request #66.
This commit is contained in:
@@ -62,6 +62,68 @@ func queryPlantings(ctx context.Context, q queryer, query string, args ...any) (
|
||||
return plantings, nil
|
||||
}
|
||||
|
||||
// ListPlantingsForGardenYear returns every plop in a garden whose time in the
|
||||
// ground overlaps the given calendar year — the season view (#54).
|
||||
//
|
||||
// The interval is [planted_at, removed_at]: planted before the year ended, and
|
||||
// either still in the ground or removed after the year began. Garlic planted in
|
||||
// October and pulled the following July therefore appears in BOTH years, which
|
||||
// is what actually happened.
|
||||
//
|
||||
// Undated plantings are always included. Every planting that predates this
|
||||
// feature has a null planted_at, and a rule that excluded them would empty every
|
||||
// existing garden the moment a year was selected — an unhelpful way to be
|
||||
// technically correct.
|
||||
func (d *DB) ListPlantingsForGardenYear(ctx context.Context, gardenID int64, year int) ([]domain.Planting, error) {
|
||||
start := fmt.Sprintf("%04d-01-01", year)
|
||||
end := fmt.Sprintf("%04d-12-31", year)
|
||||
return queryPlantings(ctx, d.sql,
|
||||
`SELECT `+qualifyColumns("pl", plantingColumns)+` FROM plantings pl
|
||||
JOIN garden_objects o ON o.id = pl.object_id
|
||||
WHERE o.garden_id = ?
|
||||
AND (pl.planted_at IS NULL OR pl.planted_at <= ?)
|
||||
AND (pl.removed_at IS NULL OR pl.removed_at >= ?)
|
||||
ORDER BY pl.id`,
|
||||
gardenID, end, start)
|
||||
}
|
||||
|
||||
// GardenPlantingYears lists the calendar years a garden has planting data for,
|
||||
// newest first — every year touched by a [planted_at, removed_at] interval.
|
||||
//
|
||||
// Undated plantings contribute no year, deliberately: they belong to every year
|
||||
// the selector offers, so adding one here would be noise.
|
||||
func (d *DB) GardenPlantingYears(ctx context.Context, gardenID int64) ([]int, error) {
|
||||
rows, err := d.sql.QueryContext(ctx,
|
||||
`SELECT DISTINCT CAST(substr(y, 1, 4) AS INTEGER) AS year FROM (
|
||||
SELECT pl.planted_at AS y FROM plantings pl
|
||||
JOIN garden_objects o ON o.id = pl.object_id
|
||||
WHERE o.garden_id = ? AND pl.planted_at IS NOT NULL
|
||||
UNION
|
||||
SELECT pl.removed_at AS y FROM plantings pl
|
||||
JOIN garden_objects o ON o.id = pl.object_id
|
||||
WHERE o.garden_id = ? AND pl.removed_at IS NOT NULL
|
||||
)
|
||||
ORDER BY year DESC`,
|
||||
gardenID, gardenID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("store: garden planting years: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
years := []int{}
|
||||
for rows.Next() {
|
||||
var y int
|
||||
if err := rows.Scan(&y); err != nil {
|
||||
return nil, fmt.Errorf("store: scan planting year: %w", err)
|
||||
}
|
||||
years = append(years, y)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, fmt.Errorf("store: iterate planting years: %w", err)
|
||||
}
|
||||
return years, nil
|
||||
}
|
||||
|
||||
// ListActivePlantingsForObject returns an object's currently-planted plops
|
||||
// (removed_at IS NULL). Always a non-nil slice. Used by FillRegion to avoid
|
||||
// stacking new plops inside existing ones.
|
||||
|
||||
Reference in New Issue
Block a user