sylvia_iot_broker/models/
device.rs

1//! Traits and structs for devices.
2
3use std::error::Error as StdError;
4
5use async_trait::async_trait;
6use chrono::{DateTime, Utc};
7use serde_json::{Map, Value};
8
9/// The item content.
10#[derive(Debug, PartialEq)]
11pub struct Device {
12    pub device_id: String,
13    pub unit_id: String,           // Associated device unit.
14    pub unit_code: Option<String>, // Associated network's unit.
15    pub network_id: String,
16    pub network_code: String,
17    pub network_addr: String,
18    pub created_at: DateTime<Utc>,
19    pub modified_at: DateTime<Utc>,
20    pub profile: String,
21    pub name: String,
22    pub info: Map<String, Value>,
23}
24
25// The device cache item.
26#[derive(Clone)]
27pub struct DeviceCacheItem {
28    pub device_id: String,
29    pub profile: String,
30}
31
32/// The sort keys for the list operation.
33pub enum SortKey {
34    CreatedAt,
35    ModifiedAt,
36    NetworkCode,
37    NetworkAddr,
38    Profile,
39    Name,
40}
41
42/// The sort condition for the list operation.
43pub struct SortCond {
44    pub key: SortKey,
45    pub asc: bool,
46}
47
48/// The list operation options.
49pub struct ListOptions<'a> {
50    /// The query conditions.
51    pub cond: &'a ListQueryCond<'a>,
52    /// The data offset.
53    pub offset: Option<u64>,
54    /// The maximum number to query.
55    pub limit: Option<u64>,
56    /// The sort conditions.
57    pub sort: Option<&'a [SortCond]>,
58    /// The maximum number items one time the `list()` returns.
59    ///
60    /// Use cursors until reaching `limit` or all data.
61    pub cursor_max: Option<u64>,
62}
63
64/// The query condition to get item(s).
65#[derive(Default)]
66pub struct QueryCond<'a> {
67    pub unit_id: Option<&'a str>,
68    pub device_id: Option<&'a str>,
69    pub network_id: Option<&'a str>,
70    pub network_addrs: Option<&'a Vec<&'a str>>,
71    pub device: Option<QueryOneCond<'a>>,
72}
73
74/// The query condition for the exact one device.
75#[derive(Clone)]
76pub struct QueryOneCond<'a> {
77    pub unit_code: Option<&'a str>,
78    pub network_code: &'a str,
79    pub network_addr: &'a str,
80}
81
82/// The query condition for the get cache operation.
83pub enum GetCacheQueryCond<'a> {
84    CodeAddr(QueryOneCond<'a>),
85}
86
87/// The query condition for the delete cache operation.
88pub struct DelCacheQueryCond<'a> {
89    /// To delete devices of the specified network unit code. Empty for public network.
90    pub unit_code: &'a str,
91    /// To delete devices of the specified network code.
92    pub network_code: Option<&'a str>,
93    /// To delete a device of the specified network address.
94    pub network_addr: Option<&'a str>,
95}
96
97/// The query condition for the list operation.
98#[derive(Default)]
99pub struct ListQueryCond<'a> {
100    /// To get devices of the specified unit.
101    pub unit_id: Option<&'a str>,
102    /// To get the specified device.
103    pub device_id: Option<&'a str>,
104    /// To get devices of the specified network.
105    pub network_id: Option<&'a str>,
106    /// To get devices of the specified network code.
107    pub network_code: Option<&'a str>,
108    /// To get devices of the specified network address.
109    /// This has priorier than `network_addrs`.
110    pub network_addr: Option<&'a str>,
111    /// To get devices of the specified network addresses.
112    pub network_addrs: Option<&'a Vec<&'a str>>,
113    /// To get devices with the specified profile.
114    pub profile: Option<&'a str>,
115    /// To get unit that their **name** contains the specified (partial) word.
116    pub name_contains: Option<&'a str>,
117}
118
119/// The query condition for the update operation.
120pub struct UpdateQueryCond<'a> {
121    /// The specified device.
122    pub device_id: &'a str,
123}
124
125/// The update fields by using [`Some`]s.
126#[derive(Default)]
127pub struct Updates<'a> {
128    /// The (network_id, network_code) tuple.
129    pub network: Option<(&'a str, &'a str)>,
130    pub network_addr: Option<&'a str>,
131    pub modified_at: Option<DateTime<Utc>>,
132    pub profile: Option<&'a str>,
133    pub name: Option<&'a str>,
134    pub info: Option<&'a Map<String, Value>>,
135}
136
137/// Model operations.
138#[async_trait]
139pub trait DeviceModel: Sync {
140    /// To create and initialize the table/collection.
141    async fn init(&self) -> Result<(), Box<dyn StdError>>;
142
143    /// To get item count for the query condition.
144    ///
145    /// **Note**: this may take a long time.
146    async fn count(&self, cond: &ListQueryCond) -> Result<u64, Box<dyn StdError>>;
147
148    /// To get item list. The maximum number of returned items will be controlled by the
149    /// `cursor_max` of the list option.
150    ///
151    /// For the first time, `cursor` MUST use `None`. If one cursor is returned, it means that
152    /// there are more items to get. Use the returned cursor to get more data items.
153    ///
154    /// **Note**: using cursors is recommended to prevent exhausting memory.
155    async fn list(
156        &self,
157        opts: &ListOptions,
158        cursor: Option<Box<dyn Cursor>>,
159    ) -> Result<(Vec<Device>, Option<Box<dyn Cursor>>), Box<dyn StdError>>;
160
161    /// To get an item.
162    async fn get(&self, cond: &QueryCond) -> Result<Option<Device>, Box<dyn StdError>>;
163
164    /// To add an item.
165    async fn add(&self, device: &Device) -> Result<(), Box<dyn StdError>>;
166
167    /// To add items in bulk. Duplicate items will be skipped without errors.
168    async fn add_bulk(&self, devices: &Vec<Device>) -> Result<(), Box<dyn StdError>>;
169
170    /// To delete one or more items.
171    async fn del(&self, cond: &QueryCond) -> Result<(), Box<dyn StdError>>;
172
173    /// To update one or more items.
174    async fn update(
175        &self,
176        cond: &UpdateQueryCond,
177        updates: &Updates,
178    ) -> Result<(), Box<dyn StdError>>;
179}
180
181/// The operations for cursors.
182///
183/// All functions are private to let programs to pass them as arguments directly without any
184/// operation.
185#[async_trait]
186pub trait Cursor: Send {
187    async fn try_next(&mut self) -> Result<Option<Device>, Box<dyn StdError>>;
188
189    fn offset(&self) -> u64;
190}
191
192/// Cache operations.
193#[async_trait]
194pub trait DeviceCache: Sync {
195    /// To clear all devices.
196    async fn clear(&self) -> Result<(), Box<dyn StdError>>;
197
198    /// To get device.
199    async fn get(
200        &self,
201        cond: &GetCacheQueryCond,
202    ) -> Result<Option<DeviceCacheItem>, Box<dyn StdError>>;
203
204    /// To set device.
205    async fn set(
206        &self,
207        cond: &GetCacheQueryCond,
208        value: Option<&DeviceCacheItem>,
209    ) -> Result<(), Box<dyn StdError>>;
210
211    /// To delete device.
212    async fn del(&self, cond: &DelCacheQueryCond) -> Result<(), Box<dyn StdError>>;
213}