1pub use stack_ids::{EntityId, Scope, ScopeKey};
12
13use serde::{Deserialize, Serialize};
14
15#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
23pub struct ProjectionId {
24 pub kind: ProjectionKind,
26 pub key: String,
28 pub scope: ScopeKey,
30}
31
32impl ProjectionId {
33 pub fn new(kind: ProjectionKind, key: impl Into<String>, scope: ScopeKey) -> Self {
34 Self {
35 kind,
36 key: key.into(),
37 scope,
38 }
39 }
40}
41
42impl std::fmt::Display for ProjectionId {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 write!(f, "{}:{}@{}", self.kind.as_str(), self.key, self.scope)
45 }
46}
47
48#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
50#[serde(rename_all = "snake_case")]
51pub enum ProjectionKind {
52 Entity,
54 Temporal,
56 RouteStats,
58 Custom(String),
60}
61
62impl ProjectionKind {
63 pub fn as_str(&self) -> &str {
64 match self {
65 Self::Entity => "entity",
66 Self::Temporal => "temporal",
67 Self::RouteStats => "route_stats",
68 Self::Custom(s) => s.as_str(),
69 }
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn scope_key_equality() {
79 let s1 = Scope::new("ns").with_repo("repo-a");
80 let s2 = Scope::new("ns").with_repo("repo-a");
81 assert_eq!(s1.key(), s2.key());
82 }
83
84 #[test]
85 fn scope_key_inequality_different_repo() {
86 let s1 = Scope::new("ns").with_repo("repo-a");
87 let s2 = Scope::new("ns").with_repo("repo-b");
88 assert_ne!(s1.key(), s2.key());
89 }
90
91 #[test]
92 fn scope_key_display() {
93 let s = Scope::new("prod")
94 .with_domain("code")
95 .with_workspace("ws1")
96 .with_repo("myrepo");
97 assert_eq!(s.key().to_string(), "prod/code@ws1#myrepo");
98 }
99
100 #[test]
101 fn projection_id_includes_scope() {
102 let sk = ScopeKey::namespace_only("ns");
103 let pid = ProjectionId::new(ProjectionKind::Entity, "test", sk);
104 let display = pid.to_string();
105 assert!(display.contains("entity"));
106 assert!(display.contains("test"));
107 assert!(display.contains("ns"));
108 }
109}