Snapshot now populates frames + devices from the DB (slice 1 left them as empty arrays). Frame store: - CreateFrame requires positive width/height; rejects empty name; UNIQUE (project_id, name) collisions surface as ErrConflict via mapWriteErr. - GetFrame is project-scoped — wrong-project read returns ErrNotFound. - UpdateFrame applies a partial; project_id is not exposed (moving a frame across projects would orphan its devices). - DeleteFrame relies on the schema's ON DELETE SET NULL to drop devices' frame_id refs cleanly; verified by test. Device store: - CreateDevice defaults color to #1e1e1e if blank; rejects empty name, non-positive size; validates frame_id is in the same project (returns ErrInvalidInput on cross-project ref). - UpdateDevice uses a FrameRef tri-state for frame_id so callers can distinguish "leave alone" from "clear to NULL" from "move to frame X". - Cross-project frame_id on PATCH is rejected with ErrInvalidInput. - ListDevices supports an optional frame_id filter. 13 new table-driven tests, all green with -race.
65 lines
2.2 KiB
Go
65 lines
2.2 KiB
Go
package db
|
|
|
|
// Project is the top-level entity. One project ↔ one .excalidraw drawing.
|
|
type Project struct {
|
|
ID int64 `json:"id"`
|
|
Name string `json:"name"`
|
|
DrawingName string `json:"drawing_name"`
|
|
Description string `json:"description"`
|
|
CreatedAt string `json:"created_at"`
|
|
UpdatedAt string `json:"updated_at"`
|
|
}
|
|
|
|
// CableType is global. Renaming/recolouring affects every project.
|
|
type CableType struct {
|
|
ID int64 `json:"id"`
|
|
Name string `json:"name"`
|
|
Color string `json:"color"`
|
|
CreatedAt string `json:"created_at"`
|
|
UpdatedAt string `json:"updated_at"`
|
|
}
|
|
|
|
// Frame is a sub-zone inside a project (`desk`, `rack`, …).
|
|
type Frame struct {
|
|
ID int64 `json:"id"`
|
|
ProjectID int64 `json:"project_id"`
|
|
Name string `json:"name"`
|
|
X float64 `json:"x"`
|
|
Y float64 `json:"y"`
|
|
Width float64 `json:"width"`
|
|
Height float64 `json:"height"`
|
|
ExcalidrawID *string `json:"excalidraw_id,omitempty"`
|
|
CreatedAt string `json:"created_at"`
|
|
UpdatedAt string `json:"updated_at"`
|
|
}
|
|
|
|
// Device is a hardware item inside a project, optionally inside a frame.
|
|
type Device struct {
|
|
ID int64 `json:"id"`
|
|
ProjectID int64 `json:"project_id"`
|
|
FrameID *int64 `json:"frame_id"` // nullable: device "outside" any frame
|
|
Name string `json:"name"`
|
|
Color string `json:"color"`
|
|
X float64 `json:"x"`
|
|
Y float64 `json:"y"`
|
|
Width float64 `json:"width"`
|
|
Height float64 `json:"height"`
|
|
ExcalidrawID *string `json:"excalidraw_id,omitempty"`
|
|
CreatedAt string `json:"created_at"`
|
|
UpdatedAt string `json:"updated_at"`
|
|
}
|
|
|
|
// Snapshot is the editor's one-shot loader payload for a single project.
|
|
// Arrays for collections still gated by future slices stay non-nil [] so
|
|
// JSON encodes as [] not null.
|
|
type Snapshot struct {
|
|
Project Project `json:"project"`
|
|
Frames []Frame `json:"frames"`
|
|
Devices []Device `json:"devices"`
|
|
Ports []any `json:"ports"`
|
|
Cables []any `json:"cables"`
|
|
IOMarkers []any `json:"io_markers"`
|
|
Bundles []any `json:"bundles"`
|
|
CableTypes []CableType `json:"cable_types"`
|
|
}
|