slicer_pipeline.py 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. """Model for a Slicing/Printing Pipeline definition (#1425).
  2. A pipeline bundles the four slot picks a user normally makes in the SliceModal
  3. (printer / process / filament(s) / bed type) under a named, reusable preset.
  4. This is PR A — bundle definitions only. Run state and dispatch live in
  5. ``pipeline_runs`` / ``pipeline_jobs`` (PR B + PR C).
  6. The target_* and fanout_strategy columns are materialised now to avoid a
  7. second migration when PR B / PR C land; PR A's API accepts the defaults and
  8. the UI doesn't expose them yet.
  9. """
  10. from datetime import datetime
  11. from sqlalchemy import Boolean, DateTime, ForeignKey, Integer, String, Text, func
  12. from sqlalchemy.orm import Mapped, mapped_column
  13. from backend.app.core.database import Base
  14. class SlicerPipeline(Base):
  15. """A named slicer preset bundle (printer + process + filament[s] + bed)."""
  16. __tablename__ = "slicer_pipelines"
  17. id: Mapped[int] = mapped_column(primary_key=True)
  18. name: Mapped[str] = mapped_column(String(200))
  19. description: Mapped[str | None] = mapped_column(String(1000))
  20. # Preset slots. ``*_source`` mirrors PresetRef.source semantics
  21. # (orca_cloud / cloud / local / standard); ``*_id`` is the opaque
  22. # source-specific id the slicer pipeline uses to resolve content.
  23. printer_preset_source: Mapped[str] = mapped_column(String(20))
  24. printer_preset_id: Mapped[str] = mapped_column(String(200))
  25. process_preset_source: Mapped[str] = mapped_column(String(20))
  26. process_preset_id: Mapped[str] = mapped_column(String(200))
  27. # JSON array of {"source": ..., "id": ...} entries — one per AMS slot the
  28. # source plate is expected to use. Stored as JSON text per Bambuddy's
  29. # convention (see LocalPreset.compatible_printers).
  30. filament_presets_json: Mapped[str] = mapped_column(Text)
  31. bed_type: Mapped[str | None] = mapped_column(String(64))
  32. # Target — PR B+ wiring; PR A treats every pipeline as a bundle without
  33. # an active target. Kept materialised so PR B is code-only, not a
  34. # migration. ``target_kind`` ∈ {"specific_printer", "printer_class"}.
  35. target_kind: Mapped[str] = mapped_column(String(20), default="printer_class")
  36. target_printer_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("printers.id", ondelete="SET NULL"))
  37. target_model_class: Mapped[str | None] = mapped_column(String(20))
  38. # Fanout strategy for PR C multi-copy runs. PR A defaults it; the UI
  39. # doesn't expose it yet. Values: max_parallel / fill_one_first / round_robin.
  40. fanout_strategy: Mapped[str] = mapped_column(String(20), default="max_parallel")
  41. # Audit fields. created_by is nullable so pipelines survive user deletes
  42. # and so installs without auth enabled (current_user is None) still work.
  43. created_by: Mapped[int | None] = mapped_column(Integer, ForeignKey("users.id", ondelete="SET NULL"))
  44. is_deleted: Mapped[bool] = mapped_column(Boolean, default=False, server_default="0")
  45. created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
  46. updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now())