Skip to main content

things3_cloud/wire/
checklist.rs

1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6use crate::{
7    ids::ThingsId,
8    wire::{deserialize_default_on_null, deserialize_vec_or_single, task::TaskStatus},
9};
10
11fn is_false(v: &bool) -> bool {
12    !*v
13}
14
15/// Checklist item wire properties.
16#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
17pub struct ChecklistItemProps {
18    /// `tt`: checklist item title.
19    #[serde(rename = "tt", default)]
20    pub title: String,
21
22    /// `ss`: checklist item status.
23    #[serde(rename = "ss", default)]
24    pub status: TaskStatus,
25
26    /// `sp`: completion/cancellation timestamp.
27    #[serde(rename = "sp", default, skip_serializing_if = "Option::is_none")]
28    pub stop_date: Option<f64>,
29
30    /// `ts`: parent task IDs (normally a single task UUID).
31    #[serde(rename = "ts", default, deserialize_with = "deserialize_vec_or_single")]
32    pub task_ids: Vec<ThingsId>,
33
34    /// `ix`: sort index within checklist.
35    #[serde(rename = "ix", default)]
36    pub sort_index: i32,
37
38    /// `cd`: creation timestamp.
39    #[serde(rename = "cd", default, skip_serializing_if = "Option::is_none")]
40    pub creation_date: Option<f64>,
41
42    /// `md`: modification timestamp.
43    #[serde(rename = "md", default, skip_serializing_if = "Option::is_none")]
44    pub modification_date: Option<f64>,
45
46    /// `lt`: leaves tombstone on delete.
47    #[serde(
48        rename = "lt",
49        default,
50        deserialize_with = "deserialize_default_on_null",
51        skip_serializing_if = "is_false"
52    )]
53    pub leaves_tombstone: bool,
54
55    /// `xx`: conflict override metadata.
56    #[serde(rename = "xx", default, skip_serializing_if = "Option::is_none")]
57    pub conflict_overrides: Option<Value>,
58}
59
60/// Sparse patch fields for ChecklistItem `t=1` updates.
61#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
62pub struct ChecklistItemPatch {
63    /// `tt`: title.
64    #[serde(rename = "tt", skip_serializing_if = "Option::is_none")]
65    pub title: Option<String>,
66
67    /// `ss`: status.
68    #[serde(rename = "ss", skip_serializing_if = "Option::is_none")]
69    pub status: Option<TaskStatus>,
70
71    /// `ts`: parent task IDs.
72    #[serde(rename = "ts", skip_serializing_if = "Option::is_none")]
73    pub task_ids: Option<Vec<ThingsId>>,
74
75    /// `ix`: sort index.
76    #[serde(rename = "ix", skip_serializing_if = "Option::is_none")]
77    pub sort_index: Option<i32>,
78
79    /// `cd`: creation timestamp.
80    #[serde(rename = "cd", skip_serializing_if = "Option::is_none")]
81    pub creation_date: Option<f64>,
82
83    /// `md`: modification timestamp.
84    #[serde(rename = "md", skip_serializing_if = "Option::is_none")]
85    pub modification_date: Option<f64>,
86}
87
88impl ChecklistItemPatch {
89    pub fn is_empty(&self) -> bool {
90        self.title.is_none()
91            && self.status.is_none()
92            && self.task_ids.is_none()
93            && self.sort_index.is_none()
94            && self.creation_date.is_none()
95            && self.modification_date.is_none()
96    }
97
98    pub fn into_properties(self) -> BTreeMap<String, Value> {
99        match serde_json::to_value(self) {
100            Ok(Value::Object(map)) => map.into_iter().collect(),
101            _ => BTreeMap::new(),
102        }
103    }
104}