feat: extract workflow runtime phase 3 foundation

This commit is contained in:
2026-04-07 09:09:40 +02:00
parent 56ee5fc5bf
commit e3cda1c9f7
7 changed files with 732 additions and 284 deletions
+83 -73
View File
@@ -32,6 +32,70 @@ def _get_engine():
return _engine
def resolve_template_for_session(
session: Session,
category_key: str | None = None,
output_type_id: str | None = None,
) -> RenderTemplate | None:
"""Find the best matching active render template on an existing sync session."""
active = RenderTemplate.is_active == True # noqa: E712
def _has_ot(ot_id):
return exists(
select(render_template_output_types.c.template_id).where(and_(
render_template_output_types.c.template_id == RenderTemplate.id,
render_template_output_types.c.output_type_id == ot_id,
))
)
_no_ots = ~exists(
select(render_template_output_types.c.template_id).where(
render_template_output_types.c.template_id == RenderTemplate.id,
)
)
if category_key and output_type_id:
row = session.execute(
select(RenderTemplate).where(and_(
active,
RenderTemplate.category_key == category_key,
_has_ot(output_type_id),
))
).unique().scalar_one_or_none()
if row:
return row
if category_key:
row = session.execute(
select(RenderTemplate).where(and_(
active,
RenderTemplate.category_key == category_key,
_no_ots,
))
).unique().scalar_one_or_none()
if row:
return row
if output_type_id:
row = session.execute(
select(RenderTemplate).where(and_(
active,
RenderTemplate.category_key.is_(None),
_has_ot(output_type_id),
))
).unique().scalar_one_or_none()
if row:
return row
return session.execute(
select(RenderTemplate).where(and_(
active,
RenderTemplate.category_key.is_(None),
_no_ots,
))
).scalar_one_or_none()
def resolve_template(
category_key: str | None = None,
output_type_id: str | None = None,
@@ -43,69 +107,29 @@ def resolve_template(
"""
engine = _get_engine()
with Session(engine) as session:
active = RenderTemplate.is_active == True # noqa: E712
# Helper: subquery checking if a template is linked to a specific OT
def _has_ot(ot_id):
return exists(
select(render_template_output_types.c.template_id).where(and_(
render_template_output_types.c.template_id == RenderTemplate.id,
render_template_output_types.c.output_type_id == ot_id,
))
)
# Helper: subquery checking if a template has NO linked OTs
_no_ots = ~exists(
select(render_template_output_types.c.template_id).where(
render_template_output_types.c.template_id == RenderTemplate.id,
)
return resolve_template_for_session(
session,
category_key=category_key,
output_type_id=output_type_id,
)
# 1. Exact match: category_key + output_type in M2M
if category_key and output_type_id:
row = session.execute(
select(RenderTemplate).where(and_(
active,
RenderTemplate.category_key == category_key,
_has_ot(output_type_id),
))
).unique().scalar_one_or_none()
if row:
return row
# 2. Category only: category_key + no OTs linked
if category_key:
row = session.execute(
select(RenderTemplate).where(and_(
active,
RenderTemplate.category_key == category_key,
_no_ots,
))
).unique().scalar_one_or_none()
if row:
return row
def get_material_library_path_for_session(session: Session) -> str | None:
"""Return the active material library path on an existing sync session."""
from app.domains.materials.models import AssetLibrary
# 3. OT only: no category_key + output_type in M2M
if output_type_id:
row = session.execute(
select(RenderTemplate).where(and_(
active,
RenderTemplate.category_key.is_(None),
_has_ot(output_type_id),
))
).unique().scalar_one_or_none()
if row:
return row
row = session.execute(
select(AssetLibrary).where(AssetLibrary.is_active == True).limit(1) # noqa: E712
).scalar_one_or_none()
if row and row.blend_file_path:
return row.blend_file_path
# 4. Global fallback: no category_key + no OTs linked
row = session.execute(
select(RenderTemplate).where(and_(
active,
RenderTemplate.category_key.is_(None),
_no_ots,
))
).scalar_one_or_none()
return row
row = session.execute(
select(SystemSetting).where(SystemSetting.key == "material_library_path")
).scalar_one_or_none()
if row and row.value and row.value.strip():
return row.value.strip()
return None
def get_material_library_path() -> str | None:
@@ -115,18 +139,4 @@ def get_material_library_path() -> str | None:
"""
engine = _get_engine()
with Session(engine) as session:
# Prefer active AssetLibrary
from app.domains.materials.models import AssetLibrary
row = session.execute(
select(AssetLibrary).where(AssetLibrary.is_active == True).limit(1) # noqa: E712
).scalar_one_or_none()
if row and row.blend_file_path:
return row.blend_file_path
# Fallback to legacy system setting
row = session.execute(
select(SystemSetting).where(SystemSetting.key == "material_library_path")
).scalar_one_or_none()
if row and row.value and row.value.strip():
return row.value.strip()
return None
return get_material_library_path_for_session(session)