Skip to main content

force_sync/
identity.rs

1//! Canonical identity types for synced records.
2
3use crate::error::ForceSyncError;
4
5/// Canonical identity for a synced record.
6#[derive(Debug, Clone, PartialEq, Eq, Hash)]
7pub struct SyncKey {
8    tenant: String,
9    object_name: String,
10    external_id: String,
11}
12
13impl SyncKey {
14    /// Creates a canonical identity from non-empty tenant, object, and external ID parts.
15    ///
16    /// # Errors
17    ///
18    /// Returns an error when any part is empty.
19    pub fn new(
20        tenant: impl Into<String>,
21        object_name: impl Into<String>,
22        external_id: impl Into<String>,
23    ) -> Result<Self, ForceSyncError> {
24        let tenant = tenant.into();
25        let object_name = object_name.into();
26        let external_id = external_id.into();
27
28        if tenant.is_empty() {
29            return Err(ForceSyncError::EmptySyncKeyPart { part: "tenant" });
30        }
31
32        if object_name.is_empty() {
33            return Err(ForceSyncError::EmptySyncKeyPart {
34                part: "object_name",
35            });
36        }
37
38        if external_id.is_empty() {
39            return Err(ForceSyncError::EmptySyncKeyPart {
40                part: "external_id",
41            });
42        }
43
44        Ok(Self {
45            tenant,
46            object_name,
47            external_id,
48        })
49    }
50
51    /// Returns the tenant identifier.
52    #[must_use]
53    pub fn tenant(&self) -> &str {
54        &self.tenant
55    }
56
57    /// Returns the synced object name.
58    #[must_use]
59    pub fn object_name(&self) -> &str {
60        &self.object_name
61    }
62
63    /// Returns the canonical external ID.
64    #[must_use]
65    pub fn external_id(&self) -> &str {
66        &self.external_id
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::SyncKey;
73
74    #[test]
75    fn sync_key_requires_non_empty_parts() {
76        let Err(err) = SyncKey::new("", "Account", "abc") else {
77            panic!("empty tenant should fail");
78        };
79
80        assert!(err.to_string().contains("tenant"));
81    }
82}