mongodb/change_stream/event.rs
1//! Contains the types related to a `ChangeStream` event.
2#[cfg(test)]
3use std::convert::TryInto;
4
5#[cfg(test)]
6use crate::{bson::Bson, bson_compat::RawError};
7use crate::{
8 bson::{DateTime, Document, RawBson, RawDocumentBuf, Timestamp},
9 cursor::common::CursorSpecification,
10 options::ChangeStreamOptions,
11};
12
13use serde::{Deserialize, Serialize};
14use serde_with::skip_serializing_none;
15
16/// An opaque token used for resuming an interrupted
17/// [`ChangeStream`](crate::change_stream::ChangeStream).
18///
19/// When starting a new change stream,
20/// [`crate::action::Watch::start_after`] and
21/// [`crate::action::Watch::resume_after`] fields can be specified
22/// with instances of `ResumeToken`.
23///
24/// See the documentation
25/// [here](https://www.mongodb.com/docs/manual/changeStreams/#change-stream-resume-token) for more
26/// information on resume tokens.
27#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
28pub struct ResumeToken(pub(crate) RawBson);
29
30impl ResumeToken {
31 pub(crate) fn initial(
32 options: Option<&ChangeStreamOptions>,
33 spec: &CursorSpecification,
34 ) -> Option<ResumeToken> {
35 match &spec.post_batch_resume_token {
36 // Token from initial response from `aggregate`
37 Some(token) if spec.is_empty => Some(token.clone()),
38 // Token from options passed to `watch`
39 _ => options
40 .and_then(|o| o.start_after.as_ref().or(o.resume_after.as_ref()))
41 .cloned(),
42 }
43 }
44
45 pub(crate) fn from_raw(doc: Option<RawDocumentBuf>) -> Option<ResumeToken> {
46 doc.map(|doc| ResumeToken(RawBson::Document(doc)))
47 }
48
49 #[cfg(test)]
50 pub(crate) fn parsed(self) -> std::result::Result<Bson, RawError> {
51 self.0.try_into()
52 }
53}
54
55/// A `ChangeStreamEvent` represents a
56/// [change event](https://www.mongodb.com/docs/manual/reference/change-events/) in the associated change stream.
57#[skip_serializing_none]
58#[derive(Debug, Serialize, Deserialize, PartialEq)]
59#[serde(rename_all = "camelCase")]
60#[non_exhaustive]
61pub struct ChangeStreamEvent<T> {
62 /// An opaque token for use when resuming an interrupted `ChangeStream`.
63 ///
64 /// See the documentation
65 /// [here](https://www.mongodb.com/docs/manual/changeStreams/#change-stream-resume-token) for
66 /// more information on resume tokens.
67 ///
68 /// Also see the documentation on [resuming a change
69 /// stream](https://www.mongodb.com/docs/manual/changeStreams/#resume-a-change-stream).
70 #[serde(rename = "_id")]
71 pub id: ResumeToken,
72
73 /// Describes the type of operation represented in this change notification.
74 pub operation_type: OperationType,
75
76 /// Identifies the collection or database on which the event occurred.
77 pub ns: Option<ChangeNamespace>,
78
79 /// The type of the newly created object. Only included for `OperationType::Create`.
80 pub ns_type: Option<ChangeNamespaceType>,
81
82 /// The new name for the `ns` collection. Only included for `OperationType::Rename`.
83 pub to: Option<ChangeNamespace>,
84
85 /// The identifier for the session associated with the transaction.
86 /// Only present if the operation is part of a multi-document transaction.
87 pub lsid: Option<Document>,
88
89 /// Together with the lsid, a number that helps uniquely identify a transaction.
90 /// Only present if the operation is part of a multi-document transaction.
91 pub txn_number: Option<i64>,
92
93 /// A `Document` that contains the `_id` of the document created or modified by the `insert`,
94 /// `replace`, `delete`, `update` operations (i.e. CRUD operations). For sharded collections,
95 /// also displays the full shard key for the document. The `_id` field is not repeated if it is
96 /// already a part of the shard key.
97 pub document_key: Option<Document>,
98
99 /// A description of the fields that were updated or removed by the update operation.
100 /// Only specified if `operation_type` is `OperationType::Update`.
101 pub update_description: Option<UpdateDescription>,
102
103 /// The cluster time at which the change occurred.
104 pub cluster_time: Option<Timestamp>,
105
106 /// The wall time from the mongod that the change event originated from.
107 pub wall_time: Option<DateTime>,
108
109 /// The `Document` created or modified by the `insert`, `replace`, `delete`, `update`
110 /// operations (i.e. CRUD operations).
111 ///
112 /// For `insert` and `replace` operations, this represents the new document created by the
113 /// operation. For `delete` operations, this field is `None`.
114 ///
115 /// For `update` operations, this field only appears if you configured the change stream with
116 /// [`full_document`](crate::action::Watch::full_document) set to
117 /// [`UpdateLookup`](crate::options::FullDocumentType::UpdateLookup). This field then
118 /// represents the most current majority-committed version of the document modified by the
119 /// update operation.
120 pub full_document: Option<T>,
121
122 /// Contains the pre-image of the modified or deleted document if the pre-image is available
123 /// for the change event and either `Required` or `WhenAvailable` was specified for the
124 /// [`full_document_before_change`](
125 /// crate::action::Watch::full_document_before_change) option when creating the
126 /// change stream. If `WhenAvailable` was specified but the pre-image is unavailable, this
127 /// will be explicitly set to `None`.
128 pub full_document_before_change: Option<T>,
129}
130
131/// Describes which fields have been updated or removed from a document.
132#[skip_serializing_none]
133#[derive(Debug, Serialize, Deserialize, PartialEq)]
134#[serde(rename_all = "camelCase")]
135#[non_exhaustive]
136pub struct UpdateDescription {
137 /// A `Document` containing key:value pairs of names of the fields that were changed, and the
138 /// new value for those fields.
139 pub updated_fields: Document,
140
141 /// An array of field names that were removed from the `Document`.
142 pub removed_fields: Vec<String>,
143
144 /// Arrays that were truncated in the `Document`.
145 pub truncated_arrays: Option<Vec<TruncatedArray>>,
146
147 /// When an update event reports changes involving ambiguous fields, the disambiguatedPaths
148 /// document provides the path key with an array listing each path component.
149 /// Note: The disambiguatedPaths field is only available on change streams started with the
150 /// `show_expanded_events` option.
151 pub disambiguated_paths: Option<Document>,
152}
153
154/// Describes an array that has been truncated.
155#[derive(Debug, Serialize, Deserialize, PartialEq)]
156#[serde(rename_all = "camelCase")]
157#[non_exhaustive]
158pub struct TruncatedArray {
159 /// The field path of the array.
160 pub field: String,
161
162 /// The new size of the array.
163 pub new_size: i32,
164}
165
166/// The operation type represented in a given change notification.
167#[derive(Debug, Clone, PartialEq, Eq)]
168#[non_exhaustive]
169pub enum OperationType {
170 /// See [insert-event](https://www.mongodb.com/docs/manual/reference/change-events/#insert-event)
171 Insert,
172
173 /// See [update-event](https://www.mongodb.com/docs/manual/reference/change-events/#update-event)
174 Update,
175
176 /// See [replace-event](https://www.mongodb.com/docs/manual/reference/change-events/#replace-event)
177 Replace,
178
179 /// See [delete-event](https://www.mongodb.com/docs/manual/reference/change-events/#delete-event)
180 Delete,
181
182 /// See [drop-event](https://www.mongodb.com/docs/manual/reference/change-events/#drop-event)
183 Drop,
184
185 /// See [rename-event](https://www.mongodb.com/docs/manual/reference/change-events/#rename-event)
186 Rename,
187
188 /// See [dropdatabase-event](https://www.mongodb.com/docs/manual/reference/change-events/#dropdatabase-event)
189 DropDatabase,
190
191 /// See [invalidate-event](https://www.mongodb.com/docs/manual/reference/change-events/#invalidate-event)
192 Invalidate,
193
194 /// A catch-all for future event types.
195 Other(String),
196}
197
198#[derive(Serialize, Deserialize)]
199#[serde(rename_all = "camelCase")]
200enum OperationTypeHelper {
201 Insert,
202 Update,
203 Replace,
204 Delete,
205 Drop,
206 Rename,
207 DropDatabase,
208 Invalidate,
209}
210
211#[derive(Serialize, Deserialize)]
212#[serde(untagged)]
213enum OperationTypeWrapper<'a> {
214 Known(OperationTypeHelper),
215 Unknown(&'a str),
216}
217
218impl<'a> From<&'a OperationType> for OperationTypeWrapper<'a> {
219 fn from(src: &'a OperationType) -> Self {
220 match src {
221 OperationType::Insert => Self::Known(OperationTypeHelper::Insert),
222 OperationType::Update => Self::Known(OperationTypeHelper::Update),
223 OperationType::Replace => Self::Known(OperationTypeHelper::Replace),
224 OperationType::Delete => Self::Known(OperationTypeHelper::Delete),
225 OperationType::Drop => Self::Known(OperationTypeHelper::Drop),
226 OperationType::Rename => Self::Known(OperationTypeHelper::Rename),
227 OperationType::DropDatabase => Self::Known(OperationTypeHelper::DropDatabase),
228 OperationType::Invalidate => Self::Known(OperationTypeHelper::Invalidate),
229 OperationType::Other(s) => Self::Unknown(s),
230 }
231 }
232}
233
234impl From<OperationTypeWrapper<'_>> for OperationType {
235 fn from(src: OperationTypeWrapper) -> Self {
236 match src {
237 OperationTypeWrapper::Known(h) => match h {
238 OperationTypeHelper::Insert => Self::Insert,
239 OperationTypeHelper::Update => Self::Update,
240 OperationTypeHelper::Replace => Self::Replace,
241 OperationTypeHelper::Delete => Self::Delete,
242 OperationTypeHelper::Drop => Self::Drop,
243 OperationTypeHelper::Rename => Self::Rename,
244 OperationTypeHelper::DropDatabase => Self::DropDatabase,
245 OperationTypeHelper::Invalidate => Self::Invalidate,
246 },
247 OperationTypeWrapper::Unknown(s) => Self::Other(s.to_string()),
248 }
249 }
250}
251
252impl<'de> Deserialize<'de> for OperationType {
253 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
254 where
255 D: serde::Deserializer<'de>,
256 {
257 OperationTypeWrapper::deserialize(deserializer).map(OperationType::from)
258 }
259}
260
261impl Serialize for OperationType {
262 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
263 where
264 S: serde::Serializer,
265 {
266 OperationTypeWrapper::serialize(&self.into(), serializer)
267 }
268}
269
270/// Identifies the collection or database on which an event occurred.
271#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
272#[non_exhaustive]
273pub struct ChangeNamespace {
274 /// The name of the database in which the change occurred.
275 pub db: String,
276
277 /// The name of the collection in which the change occurred.
278 pub coll: Option<String>,
279}
280
281/// Identifies the type of object for a `create` event.
282#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
283#[non_exhaustive]
284pub enum ChangeNamespaceType {
285 /// A collection with no special options set.
286 Collection,
287 /// A timeseries collection.
288 Timeseries,
289 /// A view collection.
290 View,
291 /// Forward compatibility fallthrough.
292 #[serde(untagged)]
293 Other(String),
294}