dittolive_ditto/store/query_builder/
subscription.rs

1//! [`Subscription`]s are used to register interest in receiving updates
2//! for specified [`DittoDocument`]s.
3
4#![allow(deprecated)]
5
6use_prelude!();
7
8use std::sync::{Arc, Weak};
9
10use ffi_sdk::COrderByParam;
11
12use crate::error::{DittoError, ErrorKind};
13
14/// Use [`cursor_op.subscribe()`] or [`id_op.subscribe()`] to sync documents from remote peers.
15///
16/// Holding a `Subscription` will cause documents matching the query to continue to sync
17/// from remote peers.
18///
19/// Dropping a `Subscription` will cancel the sync of this query's documents from remote peers.
20///
21/// [`cursor_op.subscribe()`]: crate::store::query_builder::PendingCursorOperation::subscribe
22/// [`id_op.subscribe()`]: crate::store::query_builder::PendingIdSpecificOperation::subscribe
23#[must_use = "Dropping a `Subscription` will cancel it"]
24#[deprecated(
25    since = "4.14.4",
26    note = "Will be removed in SDK 5.0. Use DQL queries instead"
27)]
28pub struct Subscription {
29    pub(super) ditto: Weak<BoxedDitto>,
30    pub(super) collection_name: char_p::Box,
31    pub(super) query: char_p::Box,
32    pub(super) query_args: Option<Vec<u8>>,
33    pub(super) order_by: Vec<(String, QuerySortDirection)>,
34    pub(super) limit: i32,
35    pub(super) offset: u32,
36}
37
38impl Subscription {
39    #[allow(clippy::too_many_arguments)]
40    pub(crate) fn new(
41        ditto: Arc<BoxedDitto>,
42        collection_name: char_p::Box,
43        query: &str,
44        query_args: Option<Vec<u8>>,
45        order_by: &'_ [COrderByParam<'_>],
46        limit: i32,
47        offset: u32,
48    ) -> Self {
49        let query = char_p::new(query);
50        {
51            let code = ffi_sdk::ditto_add_subscription(
52                &ditto,
53                collection_name.as_ref(),
54                query.as_ref(),
55                query_args.as_ref().map(|qa| (&qa[..]).into()),
56                order_by.into(),
57                limit,
58                offset,
59            );
60            if code != 0 {
61                error!(
62                    collection = %collection_name,
63                    %query,
64                    error = %DittoError::from_ffi(ErrorKind::InvalidInput),
65                    "error adding subscription",
66                );
67            }
68        };
69        let order_by: Vec<(String, QuerySortDirection)> = order_by
70            .iter()
71            // TODO: Doing `o.query_c_str.to_owned().into_string()` fails with
72            // an InvalidNulTerminator error, but AFAICT it should be equivalent
73            // to the below?
74            .map(|o| (o.query_c_str.to_str_with_null().to_string(), o.direction))
75            .collect();
76
77        Subscription {
78            ditto: Arc::downgrade(&ditto),
79            collection_name,
80            query,
81            query_args,
82            order_by,
83            limit,
84            offset,
85        }
86    }
87}
88
89#[allow(deprecated)]
90impl crate::observer::Observer for Subscription {}
91
92impl Drop for Subscription {
93    fn drop(&mut self) {
94        debug!(
95            collection = %self.collection_name,
96            query = %self.query,
97            "dropping subscription",
98        );
99        if let Some(ditto) = self.ditto.upgrade() {
100            {
101                let order_by = self
102                    .order_by
103                    .iter()
104                    .map(|query_and_direction| COrderByParam {
105                        query_c_str: query_and_direction
106                            .0
107                            .as_str()
108                            .try_into()
109                            .expect("valid string"),
110                        direction: query_and_direction.1,
111                    })
112                    .collect::<Vec<COrderByParam<'_>>>();
113
114                let code = ffi_sdk::ditto_remove_subscription(
115                    &ditto,
116                    self.collection_name.as_ref(),
117                    self.query.as_ref(),
118                    self.query_args.as_ref().map(|qa| (&qa[..]).into()),
119                    order_by[..].into(),
120                    self.limit,
121                    self.offset,
122                );
123                if code != 0 {
124                    error!(
125                        collection = %self.collection_name,
126                        query = %self.query,
127                        error = %DittoError::from_ffi(ErrorKind::InvalidInput),
128                        "error removing subscription",
129                    );
130                }
131            }
132        }
133    }
134}