Address Gadfly review on #10: clearable color/props, column lists, dedup
Build image / build-and-push (push) Successful in 7s
Build image / build-and-push (push) Successful in 7s
Fixes from the PR #28 adversarial review (considered; not graded). Correctness / API - PATCH /objects/:id can now clear nullable color/props back to NULL: the request takes them as json.RawMessage, and ObjectPatch carries an explicit Set flag so an explicit `null` (clear) is distinguished from an absent field (unchanged) — the strongest cross-model finding (6 hits). New test. Maintainability - store/plantings.go + plants.go use explicit qualified column lists (qualifyColumns helper) instead of SELECT *, matching gardens/objects and surviving a future column add. - Consolidated objectKinds + plantableByDefault into one kind→traits map. - objectForRole factors the fetch-then-authorize shared by UpdateObject and DeleteObject; dropped the redundant kind check in CreateObject (finalizeObject is the single validation point). - Request→service mapping via toInput()/toPatch() methods (matches gardens). - Renamed handler gardenFull → getGardenFull (verbNoun); test helper decodeGarden → decodeMap; generic bind-error messages. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01JdQpdYYsTgtkJBxbcpAszi
This commit is contained in:
@@ -7,9 +7,10 @@ import (
|
||||
"gitea.stevedudenhoeffer.com/steve/pansy/internal/domain"
|
||||
)
|
||||
|
||||
// scanPlant reads a plants row in table-declared column order (id, owner_id,
|
||||
// name, category, spacing_cm, color, icon, days_to_maturity, notes, version,
|
||||
// created_at, updated_at) — the order SELECT p.* yields.
|
||||
// plantColumns lists plants columns in the order scanPlant expects.
|
||||
const plantColumns = `id, owner_id, name, category, spacing_cm, color, icon,
|
||||
days_to_maturity, notes, version, created_at, updated_at`
|
||||
|
||||
func scanPlant(s scanner) (*domain.Plant, error) {
|
||||
var p domain.Plant
|
||||
if err := s.Scan(
|
||||
@@ -26,9 +27,8 @@ func scanPlant(s scanner) (*domain.Plant, error) {
|
||||
// non-nil slice (empty until plantings exist, #14). Full plant CRUD/seeding is
|
||||
// #12; this is only the /full read side.
|
||||
func (d *DB) ListReferencedPlants(ctx context.Context, gardenID int64) ([]domain.Plant, error) {
|
||||
// p.* returns the plants columns in table-declared order, matching scanPlant.
|
||||
rows, err := d.sql.QueryContext(ctx,
|
||||
`SELECT DISTINCT p.* FROM plants p
|
||||
`SELECT DISTINCT `+qualifyColumns("p", plantColumns)+` FROM plants p
|
||||
JOIN plantings pl ON pl.plant_id = p.id
|
||||
JOIN garden_objects o ON o.id = pl.object_id
|
||||
WHERE o.garden_id = ? AND pl.removed_at IS NULL
|
||||
|
||||
Reference in New Issue
Block a user