Files
CableGUI/internal/db/excalidraw_ids.go
mAi 275cb5a55a feat(backend): slice 8 — export scene to mxdrw
- internal/exporter: pure BuildScene + 21-char base62 IDs, port ellipses,
  device rect+text pairs, IO diamonds, arrow bindings, legend texts.
  Bundles intentionally omitted per design §4.1.
- internal/db: PersistExcalidrawIDs idempotent updater per project.
- internal/server: POST /api/projects/:pid/sync/export — loads snapshot,
  mints/reuses excalidraw_ids, PUTs scene to mxdrw with bearer auth.
  Returns viewer URL + element_count + mxdrw response.

Roundtrip hand-tested against mxdrw.msbls.de: scene saved, IDs stable
across re-exports.
2026-05-16 01:35:46 +02:00

61 lines
1.5 KiB
Go

package db
import (
"database/sql"
)
// PersistExcalidrawIDs writes the assignments returned by the exporter
// back onto the corresponding rows. Idempotent: only updates rows whose
// excalidraw_id is currently NULL (the first export "owns" the id; later
// exports reuse it so mxdrw's collab cursors / undo history survive).
//
// Caller passes one map per kind; keys are the in-project row ids,
// values are the 21-char Excalidraw element ids the exporter minted.
func (s *Store) PersistExcalidrawIDs(projectID int64,
frames, devices, ports, ios, cables map[int64]string,
) error {
tx, err := s.db.Begin()
if err != nil {
return err
}
defer tx.Rollback()
if err := updateExIDs(tx, "frames", projectID, frames); err != nil {
return err
}
if err := updateExIDs(tx, "devices", projectID, devices); err != nil {
return err
}
if err := updateExIDs(tx, "ports", projectID, ports); err != nil {
return err
}
if err := updateExIDs(tx, "io_markers", projectID, ios); err != nil {
return err
}
if err := updateExIDs(tx, "cables", projectID, cables); err != nil {
return err
}
return tx.Commit()
}
func updateExIDs(tx *sql.Tx, table string, projectID int64, m map[int64]string) error {
if len(m) == 0 {
return nil
}
stmt, err := tx.Prepare(
`UPDATE ` + table + `
SET excalidraw_id = ?
WHERE id = ? AND project_id = ? AND excalidraw_id IS NULL`,
)
if err != nil {
return err
}
defer stmt.Close()
for id, exID := range m {
if _, err := stmt.Exec(exID, id, projectID); err != nil {
return err
}
}
return nil
}