Initial commit
CI / test (push) Canceled after 0s

This commit is contained in:
2026-09-12 22:22:17 +02:00
commit 904d14b64c
314 changed files with 31884 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
package storage
import (
"encoding/json"
"strings"
"time"
"gardomatic.kleiax.de/internal/platform/validate"
)
// LocationModelInterface persists hierarchical locations within a garden.
type LocationModelInterface interface {
Insert(location Location) (Location, error)
Get(gardenID, id int) (Location, error)
GetAllForGarden(gardenID int) ([]Location, error)
Update(gardenID int, location Location) (Location, error)
Delete(gardenID, id int) error
}
// ValidateLocation applies persistence-independent location validation rules.
func ValidateLocation(v *validate.Validator, location Location) {
v.Check(strings.TrimSpace(location.Name) != "", "name", "must be provided")
v.Check(len(location.Name) <= 500, "name", "must not be more than 500 bytes long")
v.Check(len(location.Description) <= 10_000, "description", "must not be more than 10000 bytes long")
v.Check(len(location.Kind) <= 100, "kind", "must not be more than 100 bytes long")
v.Check(len(location.Attributes) == 0 || json.Valid(location.Attributes), "attributes", "must be valid JSON")
if location.ParentID != nil {
v.Check(*location.ParentID > 0, "parent_id", "must be a positive integer")
v.Check(*location.ParentID != location.ID, "parent_id", "must not refer to the location itself")
}
if location.AreaSQM != nil {
v.Check(*location.AreaSQM >= 0, "area_sqm", "must be zero or greater")
}
validateOptionalEnum(v, "sun_exposure", location.SunExposure, "sunny", "partial_shade", "shade")
validateOptionalEnum(v, "soil_condition", location.SoilCondition, "dry", "moist", "boggy")
validateOptionalEnum(v, "soil_reaction", location.SoilReaction, "alkaline", "acidic", "neutral")
}
// Location describes a physical place where plants can be assigned.
type Location struct {
ID int `json:"id"`
GardenID int `json:"garden_id"`
ParentID *int `json:"parent_id,omitempty"`
Name string `json:"name"`
Description string `json:"description"`
ImageData string `json:"image_data,omitempty"`
ImageID *int `json:"image_id,omitempty"`
Kind string `json:"kind"`
AreaSQM *float64 `json:"area_sqm,omitempty"`
SunExposure *string `json:"sun_exposure,omitempty"`
SoilCondition *string `json:"soil_condition,omitempty"`
SoilReaction *string `json:"soil_reaction,omitempty"`
Attributes json.RawMessage `json:"attributes"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Version int `json:"version"`
CreatedBy int `json:"created_by"`
UpdatedBy int `json:"updated_by"`
}