Configurable grid + snap-to-grid in the layout system (#45)
Build image / build-and-push (push) Successful in 7s
Build image / build-and-push (push) Successful in 7s
Closes #44. Two independent grids (garden + per-bed), each with a size and a snap toggle; snapping defaults off. See PR #45 for details. Co-authored-by: Steve Dudenhoeffer <[email protected]>
This commit was merged in pull request #45.
This commit is contained in:
@@ -10,29 +10,37 @@ import (
|
||||
)
|
||||
|
||||
// gardenColumns lists the gardens columns in the fixed order scanGarden expects.
|
||||
const gardenColumns = `id, owner_id, name, width_cm, height_cm, unit_pref, notes, version, created_at, updated_at`
|
||||
const gardenColumns = `id, owner_id, name, width_cm, height_cm, unit_pref, notes, grid_size_cm, snap_to_grid, version, created_at, updated_at`
|
||||
|
||||
func scanGarden(s scanner) (*domain.Garden, error) {
|
||||
var g domain.Garden
|
||||
var (
|
||||
g domain.Garden
|
||||
snap int64
|
||||
)
|
||||
if err := s.Scan(
|
||||
&g.ID, &g.OwnerID, &g.Name, &g.WidthCM, &g.HeightCM,
|
||||
&g.UnitPref, &g.Notes, &g.Version, &g.CreatedAt, &g.UpdatedAt,
|
||||
&g.UnitPref, &g.Notes, &g.GridSizeCM, &snap, &g.Version, &g.CreatedAt, &g.UpdatedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g.SnapToGrid = snap != 0
|
||||
return &g, nil
|
||||
}
|
||||
|
||||
// scanGardenWithRole reads a garden row plus a trailing my_role column into the
|
||||
// computed Garden.MyRole field (used by the actor-scoped list).
|
||||
func scanGardenWithRole(s scanner) (*domain.Garden, error) {
|
||||
var g domain.Garden
|
||||
var (
|
||||
g domain.Garden
|
||||
snap int64
|
||||
)
|
||||
if err := s.Scan(
|
||||
&g.ID, &g.OwnerID, &g.Name, &g.WidthCM, &g.HeightCM,
|
||||
&g.UnitPref, &g.Notes, &g.Version, &g.CreatedAt, &g.UpdatedAt, &g.MyRole,
|
||||
&g.UnitPref, &g.Notes, &g.GridSizeCM, &snap, &g.Version, &g.CreatedAt, &g.UpdatedAt, &g.MyRole,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g.SnapToGrid = snap != 0
|
||||
return &g, nil
|
||||
}
|
||||
|
||||
@@ -45,10 +53,10 @@ const maxGardensListed = 1000
|
||||
// set and validated by the service) and returns the stored row.
|
||||
func (d *DB) CreateGarden(ctx context.Context, g *domain.Garden) (*domain.Garden, error) {
|
||||
created, err := scanGarden(d.sql.QueryRowContext(ctx,
|
||||
`INSERT INTO gardens (owner_id, name, width_cm, height_cm, unit_pref, notes)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
`INSERT INTO gardens (owner_id, name, width_cm, height_cm, unit_pref, notes, grid_size_cm, snap_to_grid)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
RETURNING `+gardenColumns,
|
||||
g.OwnerID, g.Name, g.WidthCM, g.HeightCM, g.UnitPref, g.Notes,
|
||||
g.OwnerID, g.Name, g.WidthCM, g.HeightCM, g.UnitPref, g.Notes, g.GridSizeCM, boolToInt(g.SnapToGrid),
|
||||
))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("store: insert garden: %w", err)
|
||||
@@ -117,11 +125,12 @@ func (d *DB) UpdateGarden(ctx context.Context, g *domain.Garden) (*domain.Garden
|
||||
updated, err := scanGarden(d.sql.QueryRowContext(ctx,
|
||||
`UPDATE gardens
|
||||
SET name = ?, width_cm = ?, height_cm = ?, unit_pref = ?, notes = ?,
|
||||
grid_size_cm = ?, snap_to_grid = ?,
|
||||
version = version + 1,
|
||||
updated_at = strftime('%Y-%m-%dT%H:%M:%SZ', 'now')
|
||||
WHERE id = ? AND version = ?
|
||||
RETURNING `+gardenColumns,
|
||||
g.Name, g.WidthCM, g.HeightCM, g.UnitPref, g.Notes, g.ID, g.Version,
|
||||
g.Name, g.WidthCM, g.HeightCM, g.UnitPref, g.Notes, g.GridSizeCM, boolToInt(g.SnapToGrid), g.ID, g.Version,
|
||||
))
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
// No row matched: distinguish "gone" from "stale version".
|
||||
|
||||
Reference in New Issue
Block a user