anderson-ufrj commited on
Commit
bba32be
·
1 Parent(s): 4e91d62

fix(models): add Investigation model to repository

Browse files

Add missing Investigation SQLAlchemy model required by investigation_service.
The model was not tracked due to models/ being in .gitignore, but src/models/
should be tracked. This model is essential for database operations.

Files changed (1) hide show
  1. src/models/investigation.py +108 -0
src/models/investigation.py ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Investigation models for database persistence.
3
+ """
4
+
5
+ from datetime import datetime
6
+ from typing import Optional, Dict, Any, List
7
+ from sqlalchemy import Column, String, DateTime, Integer, Float, Text, Index, JSON
8
+ from sqlalchemy.sql import func
9
+ from src.models.base import BaseModel
10
+
11
+
12
+ class Investigation(BaseModel):
13
+ """
14
+ Investigation database model.
15
+
16
+ Stores complete investigation data for frontend consumption.
17
+ """
18
+
19
+ __tablename__ = "investigations"
20
+
21
+ # User identification
22
+ user_id = Column(String(255), nullable=False, index=True)
23
+ session_id = Column(String(255), nullable=True, index=True)
24
+
25
+ # Investigation details
26
+ query = Column(Text, nullable=False)
27
+ data_source = Column(String(100), nullable=False, index=True)
28
+
29
+ # Status tracking
30
+ status = Column(
31
+ String(50),
32
+ nullable=False,
33
+ default="pending",
34
+ index=True,
35
+ )
36
+ current_phase = Column(String(100), nullable=True)
37
+ progress = Column(Float, default=0.0)
38
+
39
+ # Results summary
40
+ anomalies_found = Column(Integer, default=0)
41
+ total_records_analyzed = Column(Integer, default=0)
42
+ confidence_score = Column(Float, nullable=True)
43
+
44
+ # JSON data (stored as TEXT in SQLite, JSONB in PostgreSQL)
45
+ filters = Column(JSON, default={})
46
+ anomaly_types = Column(JSON, default=[])
47
+ results = Column(JSON, default=[])
48
+ investigation_metadata = Column(JSON, default={})
49
+
50
+ # Text fields
51
+ summary = Column(Text, nullable=True)
52
+ error_message = Column(Text, nullable=True)
53
+
54
+ # Timing
55
+ started_at = Column(DateTime, nullable=True)
56
+ completed_at = Column(DateTime, nullable=True)
57
+ processing_time_ms = Column(Integer, nullable=True)
58
+
59
+ # Indexes for performance
60
+ __table_args__ = (
61
+ Index('idx_investigations_user_status', 'user_id', 'status'),
62
+ Index('idx_investigations_created_at', 'created_at'),
63
+ )
64
+
65
+ def to_dict(self, include_results: bool = True) -> Dict[str, Any]:
66
+ """Convert to dictionary for API responses."""
67
+ data = {
68
+ "id": self.id,
69
+ "user_id": self.user_id,
70
+ "session_id": self.session_id,
71
+ "query": self.query,
72
+ "data_source": self.data_source,
73
+ "status": self.status,
74
+ "current_phase": self.current_phase,
75
+ "progress": self.progress,
76
+ "anomalies_found": self.anomalies_found,
77
+ "total_records_analyzed": self.total_records_analyzed,
78
+ "confidence_score": self.confidence_score,
79
+ "filters": self.filters or {},
80
+ "anomaly_types": self.anomaly_types or [],
81
+ "summary": self.summary,
82
+ "error_message": self.error_message,
83
+ "created_at": self.created_at.isoformat() if self.created_at else None,
84
+ "updated_at": self.updated_at.isoformat() if self.updated_at else None,
85
+ "started_at": self.started_at.isoformat() if self.started_at else None,
86
+ "completed_at": self.completed_at.isoformat() if self.completed_at else None,
87
+ "processing_time_ms": self.processing_time_ms,
88
+ "metadata": self.investigation_metadata or {},
89
+ }
90
+
91
+ if include_results:
92
+ data["results"] = self.results or []
93
+ else:
94
+ data["results_count"] = len(self.results) if self.results else 0
95
+
96
+ return data
97
+
98
+ def to_status_dict(self) -> Dict[str, Any]:
99
+ """Lightweight status response."""
100
+ return {
101
+ "investigation_id": self.id,
102
+ "status": self.status,
103
+ "progress": self.progress,
104
+ "current_phase": self.current_phase,
105
+ "records_processed": self.total_records_analyzed,
106
+ "anomalies_detected": self.anomalies_found,
107
+ "estimated_completion": None,
108
+ }