Revision history: change sets + revisions + revert — the undo substrate (#48) (#61)
Build image / build-and-push (push) Successful in 5s

Co-authored-by: Steve Dudenhoeffer <[email protected]>
This commit was merged in pull request #61.
This commit is contained in:
2026-07-21 05:07:30 +00:00
committed by steve
parent 653f381c4b
commit f208da94d6
16 changed files with 2169 additions and 19 deletions
+27
View File
@@ -61,6 +61,33 @@ func (d *DB) CreateObject(ctx context.Context, o *domain.GardenObject) (*domain.
return created, nil
}
// RestoreObject re-inserts a deleted object under its ORIGINAL id, preserving
// version and timestamps — the inverse of a delete, for reverting a change set
// (#48). SQLite allows an explicit INTEGER PRIMARY KEY insert once the row is
// gone; if the id has been taken again the insert fails on the primary key, which
// is the correct outcome (the service checks first and reports a conflict).
//
// Deliberately not routed through objectInsert: that omits id/version/timestamps
// because a normal create must let the database assign them.
func (d *DB) RestoreObject(ctx context.Context, o *domain.GardenObject) (*domain.GardenObject, error) {
restored, err := scanObject(d.sql.QueryRowContext(ctx,
`INSERT INTO garden_objects
(id, garden_id, kind, name, shape, points, x_cm, y_cm, width_cm, height_cm,
rotation_deg, z_index, plantable, color, props, grid_size_cm, snap_to_grid, notes,
version, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
RETURNING `+objectColumns,
o.ID, o.GardenID, o.Kind, o.Name, o.Shape, o.Points, o.XCM, o.YCM, o.WidthCM, o.HeightCM,
o.RotationDeg, o.ZIndex, boolToInt(o.Plantable), o.Color, o.Props,
o.GridSizeCM, boolToInt(o.SnapToGrid), o.Notes, o.Version, o.CreatedAt,
))
if err != nil {
return nil, fmt.Errorf("store: restore object: %w", err)
}
return restored, nil
}
// GetObject returns the object with the given id, or domain.ErrNotFound.
func (d *DB) GetObject(ctx context.Context, id int64) (*domain.GardenObject, error) {
o, err := scanObject(d.sql.QueryRowContext(ctx,