Files
AICyclingCoach/tui/services/rule_service.py
2025-09-12 09:08:10 -07:00

244 lines
8.6 KiB
Python

"""
Rule service for TUI application.
Manages training rules without HTTP dependencies.
"""
from typing import Dict, List, Optional
from sqlalchemy import select, desc
from sqlalchemy.ext.asyncio import AsyncSession
from backend.app.models.rule import Rule
class RuleService:
"""Service for training rule operations."""
def __init__(self, db: AsyncSession):
self.db = db
async def get_rules(self) -> List[Dict]:
"""Get all training rules."""
try:
result = await self.db.execute(
select(Rule).order_by(desc(Rule.created_at))
)
rules = result.scalars().all()
return [
{
"id": r.id,
"name": r.name,
"description": r.description,
"user_defined": r.user_defined,
"rule_text": r.rule_text,
"version": r.version,
"parent_rule_id": r.parent_rule_id,
"created_at": r.created_at.isoformat() if r.created_at else None
} for r in rules
]
except Exception as e:
raise Exception(f"Error fetching rules: {str(e)}")
async def get_rule(self, rule_id: int) -> Optional[Dict]:
"""Get a specific rule by ID."""
try:
rule = await self.db.get(Rule, rule_id)
if not rule:
return None
return {
"id": rule.id,
"name": rule.name,
"description": rule.description,
"user_defined": rule.user_defined,
"rule_text": rule.rule_text,
"version": rule.version,
"parent_rule_id": rule.parent_rule_id,
"created_at": rule.created_at.isoformat() if rule.created_at else None
}
except Exception as e:
raise Exception(f"Error fetching rule {rule_id}: {str(e)}")
async def create_rule(
self,
name: str,
rule_text: str,
description: Optional[str] = None,
user_defined: bool = True,
version: int = 1,
parent_rule_id: Optional[int] = None
) -> Dict:
"""Create a new training rule."""
try:
db_rule = Rule(
name=name,
description=description,
user_defined=user_defined,
rule_text=rule_text,
version=version,
parent_rule_id=parent_rule_id
)
self.db.add(db_rule)
await self.db.commit()
await self.db.refresh(db_rule)
return {
"id": db_rule.id,
"name": db_rule.name,
"description": db_rule.description,
"user_defined": db_rule.user_defined,
"rule_text": db_rule.rule_text,
"version": db_rule.version,
"parent_rule_id": db_rule.parent_rule_id,
"created_at": db_rule.created_at.isoformat() if db_rule.created_at else None
}
except Exception as e:
raise Exception(f"Error creating rule: {str(e)}")
async def update_rule(
self,
rule_id: int,
name: Optional[str] = None,
rule_text: Optional[str] = None,
description: Optional[str] = None,
version: Optional[int] = None
) -> Dict:
"""Update an existing rule."""
try:
db_rule = await self.db.get(Rule, rule_id)
if not db_rule:
raise Exception("Rule not found")
if name is not None:
db_rule.name = name
if rule_text is not None:
db_rule.rule_text = rule_text
if description is not None:
db_rule.description = description
if version is not None:
db_rule.version = version
await self.db.commit()
await self.db.refresh(db_rule)
return {
"id": db_rule.id,
"name": db_rule.name,
"description": db_rule.description,
"user_defined": db_rule.user_defined,
"rule_text": db_rule.rule_text,
"version": db_rule.version,
"parent_rule_id": db_rule.parent_rule_id,
"created_at": db_rule.created_at.isoformat() if db_rule.created_at else None
}
except Exception as e:
raise Exception(f"Error updating rule: {str(e)}")
async def delete_rule(self, rule_id: int) -> Dict:
"""Delete a rule."""
try:
rule = await self.db.get(Rule, rule_id)
if not rule:
raise Exception("Rule not found")
await self.db.delete(rule)
await self.db.commit()
return {"message": "Rule deleted successfully"}
except Exception as e:
raise Exception(f"Error deleting rule: {str(e)}")
async def get_user_defined_rules(self) -> List[Dict]:
"""Get only user-defined rules."""
try:
result = await self.db.execute(
select(Rule)
.where(Rule.user_defined == True)
.order_by(desc(Rule.created_at))
)
rules = result.scalars().all()
return [
{
"id": r.id,
"name": r.name,
"description": r.description,
"rule_text": r.rule_text,
"version": r.version,
"created_at": r.created_at.isoformat() if r.created_at else None
} for r in rules
]
except Exception as e:
raise Exception(f"Error fetching user-defined rules: {str(e)}")
async def get_system_rules(self) -> List[Dict]:
"""Get only system-defined rules."""
try:
result = await self.db.execute(
select(Rule)
.where(Rule.user_defined == False)
.order_by(desc(Rule.created_at))
)
rules = result.scalars().all()
return [
{
"id": r.id,
"name": r.name,
"description": r.description,
"rule_text": r.rule_text,
"version": r.version,
"created_at": r.created_at.isoformat() if r.created_at else None
} for r in rules
]
except Exception as e:
raise Exception(f"Error fetching system rules: {str(e)}")
async def create_rule_version(self, parent_rule_id: int, rule_text: str, description: Optional[str] = None) -> Dict:
"""Create a new version of an existing rule."""
try:
parent_rule = await self.db.get(Rule, parent_rule_id)
if not parent_rule:
raise Exception("Parent rule not found")
# Get the highest version number for this rule family
result = await self.db.execute(
select(Rule.version)
.where(Rule.parent_rule_id == parent_rule_id)
.order_by(desc(Rule.version))
.limit(1)
)
max_version = result.scalar_one_or_none() or parent_rule.version
new_version = max_version + 1
new_rule = Rule(
name=parent_rule.name,
description=description or parent_rule.description,
user_defined=parent_rule.user_defined,
rule_text=rule_text,
version=new_version,
parent_rule_id=parent_rule_id
)
self.db.add(new_rule)
await self.db.commit()
await self.db.refresh(new_rule)
return {
"id": new_rule.id,
"name": new_rule.name,
"description": new_rule.description,
"user_defined": new_rule.user_defined,
"rule_text": new_rule.rule_text,
"version": new_rule.version,
"parent_rule_id": new_rule.parent_rule_id,
"created_at": new_rule.created_at.isoformat() if new_rule.created_at else None
}
except Exception as e:
raise Exception(f"Error creating rule version: {str(e)}")