firebase_rs_sdk/database/
on_disconnect.rs1use serde_json::{Map as JsonMap, Value};
2
3use crate::database::api::{normalize_path, pack_with_priority, validate_priority_value};
4use crate::database::error::{invalid_argument, DatabaseResult};
5use crate::database::DatabaseReference;
6
7#[derive(Clone, Debug)]
16pub struct OnDisconnect {
17 reference: DatabaseReference,
18}
19
20impl OnDisconnect {
21 pub(crate) fn new(reference: DatabaseReference) -> Self {
22 Self { reference }
23 }
24
25 pub async fn set<V>(&self, value: V) -> DatabaseResult<()>
31 where
32 V: Into<Value>,
33 {
34 let resolved = self
35 .reference
36 .resolve_for_current_path(value.into())
37 .await?;
38 self.reference
39 .database()
40 .repo()
41 .on_disconnect_put(self.reference.path_segments(), resolved)
42 .await
43 }
44
45 pub async fn set_with_priority<V, P>(&self, value: V, priority: P) -> DatabaseResult<()>
47 where
48 V: Into<Value>,
49 P: Into<Value>,
50 {
51 let priority = priority.into();
52 validate_priority_value(&priority)?;
53 if matches!(self.reference.key(), Some(".length" | ".keys")) {
54 return Err(invalid_argument(
55 "set_with_priority failed: read-only child key",
56 ));
57 }
58
59 let resolved = self
60 .reference
61 .resolve_for_current_path(value.into())
62 .await?;
63 let payload = pack_with_priority(resolved, priority);
64 self.reference
65 .database()
66 .repo()
67 .on_disconnect_put(self.reference.path_segments(), payload)
68 .await
69 }
70
71 pub async fn update(&self, updates: JsonMap<String, Value>) -> DatabaseResult<()> {
73 if updates.is_empty() {
74 return Ok(());
75 }
76
77 let base_path = self.reference.path_segments();
78 let mut payload = JsonMap::with_capacity(updates.len());
79
80 for (key, value) in updates {
81 if key.trim().is_empty() {
82 return Err(invalid_argument("OnDisconnect.update keys cannot be empty"));
83 }
84 let relative_segments = normalize_path(&key)?;
85 if relative_segments.is_empty() {
86 return Err(invalid_argument(
87 "OnDisconnect.update path cannot reference the current location",
88 ));
89 }
90
91 let mut absolute = base_path.clone();
92 absolute.extend(relative_segments.clone());
93 let resolved = self
94 .reference
95 .resolve_for_absolute_path(&absolute, value)
96 .await?;
97 let canonical = relative_segments.join("/");
98 payload.insert(canonical, resolved);
99 }
100
101 self.reference
102 .database()
103 .repo()
104 .on_disconnect_merge(base_path, Value::Object(payload))
105 .await
106 }
107
108 pub async fn remove(&self) -> DatabaseResult<()> {
110 self.set(Value::Null).await
111 }
112
113 pub async fn cancel(&self) -> DatabaseResult<()> {
115 self.reference
116 .database()
117 .repo()
118 .on_disconnect_cancel(self.reference.path_segments())
119 .await
120 }
121}