icydb_core/model/
index.rs1use std::fmt::{self, Display};
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
18pub struct IndexModel {
19 name: &'static str,
21 store: &'static str,
22 fields: &'static [&'static str],
23 unique: bool,
24 predicate: Option<&'static str>,
25}
26
27impl IndexModel {
28 #[must_use]
29 pub const fn new(
30 name: &'static str,
31 store: &'static str,
32 fields: &'static [&'static str],
33 unique: bool,
34 ) -> Self {
35 Self::new_with_predicate(name, store, fields, unique, None)
36 }
37
38 #[must_use]
40 pub const fn new_with_predicate(
41 name: &'static str,
42 store: &'static str,
43 fields: &'static [&'static str],
44 unique: bool,
45 predicate: Option<&'static str>,
46 ) -> Self {
47 Self {
48 name,
49 store,
50 fields,
51 unique,
52 predicate,
53 }
54 }
55
56 #[must_use]
58 pub const fn name(&self) -> &'static str {
59 self.name
60 }
61
62 #[must_use]
64 pub const fn store(&self) -> &'static str {
65 self.store
66 }
67
68 #[must_use]
70 pub const fn fields(&self) -> &'static [&'static str] {
71 self.fields
72 }
73
74 #[must_use]
76 pub const fn is_unique(&self) -> bool {
77 self.unique
78 }
79
80 #[must_use]
82 pub const fn predicate(&self) -> Option<&'static str> {
83 self.predicate
84 }
85
86 #[must_use]
88 pub fn is_prefix_of(&self, other: &Self) -> bool {
89 self.fields().len() < other.fields().len() && other.fields().starts_with(self.fields())
90 }
91}
92
93impl Display for IndexModel {
94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95 let fields = self.fields().join(", ");
96 if self.is_unique() {
97 if let Some(predicate) = self.predicate() {
98 write!(
99 f,
100 "{}: UNIQUE {}({}) WHERE {}",
101 self.name(),
102 self.store(),
103 fields,
104 predicate
105 )
106 } else {
107 write!(f, "{}: UNIQUE {}({})", self.name(), self.store(), fields)
108 }
109 } else if let Some(predicate) = self.predicate() {
110 write!(
111 f,
112 "{}: {}({}) WHERE {}",
113 self.name(),
114 self.store(),
115 fields,
116 predicate
117 )
118 } else {
119 write!(f, "{}: {}({})", self.name(), self.store(), fields)
120 }
121 }
122}
123
124#[cfg(test)]
129mod tests {
130 use crate::model::index::IndexModel;
131
132 #[test]
133 fn index_model_with_predicate_exposes_predicate_metadata() {
134 let model = IndexModel::new_with_predicate(
135 "users|email|active",
136 "users::index",
137 &["email"],
138 false,
139 Some("active = true"),
140 );
141
142 assert_eq!(model.predicate(), Some("active = true"));
143 assert_eq!(
144 model.to_string(),
145 "users|email|active: users::index(email) WHERE active = true"
146 );
147 }
148
149 #[test]
150 fn index_model_without_predicate_preserves_legacy_display_shape() {
151 let model = IndexModel::new("users|email", "users::index", &["email"], true);
152
153 assert_eq!(model.predicate(), None);
154 assert_eq!(model.to_string(), "users|email: UNIQUE users::index(email)");
155 }
156}