firebase_rs_sdk/firestore/model/
field_path.rs1use crate::firestore::error::{invalid_argument, FirestoreResult};
2
3#[derive(Clone, Debug, PartialEq, Eq, Hash)]
4pub struct FieldPath {
5 segments: Vec<String>,
6}
7
8impl FieldPath {
9 pub fn new<S, I>(segments: I) -> FirestoreResult<Self>
10 where
11 S: Into<String>,
12 I: IntoIterator<Item = S>,
13 {
14 let segments: Vec<String> = segments.into_iter().map(Into::into).collect();
15 if segments.is_empty() {
16 return Err(invalid_argument(
17 "FieldPath must contain at least one segment",
18 ));
19 }
20 Ok(Self { segments })
21 }
22
23 pub fn from_dot_separated(path: &str) -> FirestoreResult<Self> {
24 if path.trim().is_empty() {
25 return Err(invalid_argument("FieldPath string cannot be empty"));
26 }
27 FieldPath::new(path.split('.'))
28 }
29
30 pub fn last_segment(&self) -> &str {
31 self.segments
32 .last()
33 .expect("FieldPath always has at least one segment")
34 .as_str()
35 }
36
37 pub fn segments(&self) -> &[String] {
38 &self.segments
39 }
40
41 pub fn canonical_string(&self) -> String {
42 self.segments.join(".")
43 }
44
45 pub fn to_vec(&self) -> Vec<String> {
46 self.segments.clone()
47 }
48
49 pub fn document_id() -> Self {
50 Self {
51 segments: vec!["__name__".to_string()],
52 }
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 #[test]
61 fn from_dot_path() {
62 let field = FieldPath::from_dot_separated("foo.bar").unwrap();
63 assert_eq!(field.segments(), &["foo", "bar"]);
64 }
65
66 #[test]
67 fn rejects_empty() {
68 let err = FieldPath::from_dot_separated("").unwrap_err();
69 assert_eq!(err.code_str(), "firestore/invalid-argument");
70 }
71}