feat: extract workflow runtime phase 3 foundation
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user