Seed provenance + inventory: source links and seed lots (#50) (#64)
Build image / build-and-push (push) Successful in 8s

Co-authored-by: Steve Dudenhoeffer <[email protected]>
This commit was merged in pull request #64.
This commit is contained in:
2026-07-21 05:39:24 +00:00
committed by steve
parent 2a8fe24766
commit 78a04672b5
18 changed files with 1511 additions and 31 deletions
+21
View File
@@ -1,6 +1,7 @@
package api
import (
"encoding/json"
"errors"
"log/slog"
"net/http"
@@ -69,6 +70,26 @@ func writeVersionConflict(c *gin.Context, current any) {
})
}
// parseNullable decodes any JSON value into (value, present) for a nullable
// column: absent → (nil, false); explicit null → (nil, true); anything else →
// the decoded value. That three-way distinction is what lets a PATCH tell "clear
// this to NULL" apart from "leave it alone", and every nullable field in the API
// needs it, so it lives here rather than in whichever file happened to want it
// first.
func parseNullable[T any](raw json.RawMessage) (*T, bool, error) {
if len(raw) == 0 {
return nil, false, nil
}
if string(raw) == "null" {
return nil, true, nil
}
var v T
if err := json.Unmarshal(raw, &v); err != nil {
return nil, false, err
}
return &v, true, nil
}
// intQuery reads a non-negative integer query parameter, falling back to def on
// an absent or malformed value.
func intQuery(c *gin.Context, name string, def int) int {