Skip to main content

allsource_core/application/dto/
event_dto.rs

1use crate::domain::entities::Event;
2use chrono::{DateTime, Utc};
3use serde::{Deserialize, Serialize};
4use uuid::Uuid;
5
6/// DTO for ingesting a new event
7#[derive(Debug, Deserialize)]
8pub struct IngestEventRequest {
9    pub event_type: String,
10    pub entity_id: String,
11    pub tenant_id: Option<String>, // Optional, defaults to "default"
12    pub payload: serde_json::Value,
13    pub metadata: Option<serde_json::Value>,
14}
15
16/// DTO for event ingestion response
17#[derive(Debug, Serialize)]
18pub struct IngestEventResponse {
19    pub event_id: Uuid,
20    pub timestamp: DateTime<Utc>,
21}
22
23impl IngestEventResponse {
24    pub fn from_event(event: &Event) -> Self {
25        Self {
26            event_id: event.id(),
27            timestamp: event.timestamp(),
28        }
29    }
30}
31
32/// DTO for querying events
33#[derive(Debug, Default, Deserialize)]
34pub struct QueryEventsRequest {
35    /// Filter by entity ID
36    pub entity_id: Option<String>,
37
38    /// Filter by event type
39    pub event_type: Option<String>,
40
41    /// Tenant ID (required for multi-tenancy)
42    pub tenant_id: Option<String>,
43
44    /// Time-travel: get events as of this timestamp
45    pub as_of: Option<DateTime<Utc>>,
46
47    /// Get events since this timestamp
48    pub since: Option<DateTime<Utc>>,
49
50    /// Get events until this timestamp
51    pub until: Option<DateTime<Utc>>,
52
53    /// Limit number of results
54    pub limit: Option<usize>,
55
56    /// Filter by event type prefix (e.g., "index." matches "index.created", "index.updated")
57    pub event_type_prefix: Option<String>,
58
59    /// Filter by payload fields (JSON string, e.g., `{"user_id":"abc-123"}`).
60    /// Matches events where payload contains ALL specified key-value pairs.
61    pub payload_filter: Option<String>,
62}
63
64/// DTO for query response
65#[derive(Debug, Serialize)]
66pub struct QueryEventsResponse {
67    pub events: Vec<EventDto>,
68    pub count: usize,
69    pub total_count: usize,
70    pub has_more: bool,
71}
72
73/// DTO for a single event in responses
74#[derive(Debug, Serialize, Deserialize, Clone)]
75pub struct EventDto {
76    pub id: Uuid,
77    pub event_type: String,
78    pub entity_id: String,
79    pub tenant_id: String,
80    pub payload: serde_json::Value,
81    pub timestamp: DateTime<Utc>,
82    pub metadata: Option<serde_json::Value>,
83    pub version: i64,
84}
85
86impl From<&Event> for EventDto {
87    fn from(event: &Event) -> Self {
88        Self {
89            id: event.id(),
90            event_type: event.event_type().to_string(),
91            entity_id: event.entity_id().to_string(),
92            tenant_id: event.tenant_id().to_string(),
93            payload: event.payload().clone(),
94            timestamp: event.timestamp(),
95            metadata: event.metadata().cloned(),
96            version: event.version(),
97        }
98    }
99}
100
101impl From<Event> for EventDto {
102    fn from(event: Event) -> Self {
103        EventDto::from(&event)
104    }
105}
106
107/// Request parameters for listing entities
108#[derive(Debug, Deserialize)]
109pub struct ListEntitiesRequest {
110    /// Filter entities by event type prefix
111    pub event_type_prefix: Option<String>,
112    /// Filter by payload fields (JSON string)
113    pub payload_filter: Option<String>,
114    /// Limit number of entities returned
115    pub limit: Option<usize>,
116    /// Offset for pagination
117    pub offset: Option<usize>,
118}
119
120/// A single entity summary in the list response
121#[derive(Debug, Serialize)]
122pub struct EntitySummary {
123    pub entity_id: String,
124    pub event_count: usize,
125    pub last_event_type: String,
126    pub last_event_at: DateTime<Utc>,
127}
128
129/// Response from listing entities
130#[derive(Debug, Serialize)]
131pub struct ListEntitiesResponse {
132    pub entities: Vec<EntitySummary>,
133    pub total: usize,
134    pub has_more: bool,
135}
136
137/// Request parameters for detecting duplicate entities
138#[derive(Debug, Deserialize)]
139pub struct DetectDuplicatesRequest {
140    /// Required: event type prefix to scope the search (no full-store scans)
141    pub event_type_prefix: String,
142    /// Comma-separated list of payload field names to group by (e.g., "name,user_id")
143    pub group_by: String,
144    /// Limit number of duplicate groups returned
145    pub limit: Option<usize>,
146    /// Offset for pagination
147    pub offset: Option<usize>,
148}
149
150/// A group of entities that share the same payload field values
151#[derive(Debug, Serialize)]
152pub struct DuplicateGroup {
153    /// The shared field values that define this group
154    pub key: serde_json::Value,
155    /// Entity IDs in this group
156    pub entity_ids: Vec<String>,
157    /// Number of entities in this group
158    pub count: usize,
159}
160
161/// Response from duplicate entity detection
162#[derive(Debug, Serialize)]
163pub struct DetectDuplicatesResponse {
164    /// Groups where count > 1
165    pub duplicates: Vec<DuplicateGroup>,
166    /// Total number of duplicate groups found
167    pub total: usize,
168    /// Whether more results are available
169    pub has_more: bool,
170}
171
172/// DTO for batch ingesting multiple events
173#[derive(Debug, Deserialize)]
174pub struct IngestEventsBatchRequest {
175    pub events: Vec<IngestEventRequest>,
176}
177
178/// DTO for batch ingestion response
179#[derive(Debug, Serialize)]
180pub struct IngestEventsBatchResponse {
181    /// Total number of events submitted
182    pub total: usize,
183    /// Number of events successfully ingested
184    pub ingested: usize,
185    /// Individual results for each event
186    pub events: Vec<IngestEventResponse>,
187}