1use anyhow::Result;
2use serde_json::Value;
3use sqlx::SqliteConnection;
4
5use crate::db::insert_change;
6use crate::workspaces::Workspace;
7
8pub mod op_type {
9 pub const CREATE_TASK: &str = "create_task";
10 pub const MOVE_TASKS: &str = "move_tasks";
11 pub const SET_FIELD: &str = "set_field";
12 pub const RESOLVE_FIELD: &str = "resolve_field";
13 pub const LABEL_ADD: &str = "label_add";
14 pub const LABEL_REMOVE: &str = "label_remove";
15 pub const NOTE_ADD: &str = "note_add";
16 pub const NOTE_EDIT: &str = "note_edit";
17 pub const NOTE_DELETE: &str = "note_delete";
18 pub const DEPENDENCY_ADD: &str = "dependency_add";
19 pub const DEPENDENCY_REMOVE: &str = "dependency_remove";
20 pub const RELATED_ADD: &str = "related_add";
21 pub const RELATED_REMOVE: &str = "related_remove";
22 pub const EPIC_LINK_ADD: &str = "epic_link_add";
23 pub const EPIC_LINK_REMOVE: &str = "epic_link_remove";
24 pub const ATTACHMENT_ADD: &str = "attachment_add";
25 pub const ATTACHMENT_DELETE: &str = "attachment_delete";
26 pub const CREATE_PROJECT: &str = "create_project";
27 pub const SET_PROJECT_METADATA: &str = "set_project_metadata";
28 pub const PROJECT_DELETE: &str = "project_delete";
29 pub const CREATE_LABEL: &str = "create_label";
30 pub const SET_LABEL_NAME: &str = "set_label_name";
31 pub const LABEL_DELETE: &str = "label_delete";
32 pub const LABEL_RESTORE: &str = "label_restore";
33 pub const CREATE_WORKSPACE: &str = "create_workspace";
34 pub const SET_WORKSPACE_FIELD: &str = "set_workspace_field";
35 pub const CREATE_RECURRENCE_SERIES: &str = "create_recurrence_series";
36 pub const UPDATE_RECURRENCE_TEMPLATE: &str = "update_recurrence_template";
37 pub const PROJECT_RECURRENCE_OCCURRENCE: &str = "project_recurrence_occurrence";
38 pub const RESOLVE_RECURRENCE_OCCURRENCE: &str = "resolve_recurrence_occurrence";
39 pub const SET_RECURRENCE_STATE: &str = "set_recurrence_state";
40 pub const CREATE_METADATA_FIELD: &str = "create_metadata_field";
41 pub const SET_METADATA_FIELD: &str = "set_metadata_field";
42 pub const SET_TASK_METADATA: &str = "set_task_metadata";
43 pub const REMOVE_TASK_METADATA: &str = "remove_task_metadata";
44 pub const SET_RECURRENCE_METADATA: &str = "set_recurrence_metadata";
45 pub const REMOVE_RECURRENCE_METADATA: &str = "remove_recurrence_metadata";
46 pub const OPEN_RECURRENCE_PAUSE: &str = "open_recurrence_pause";
47 pub const CLOSE_RECURRENCE_PAUSE: &str = "close_recurrence_pause";
48 pub const STOP_RECURRENCE_SERIES: &str = "stop_recurrence_series";
49 pub const PUBLISH_DEVICE_LABEL: &str = "publish_device_label";
50}
51
52pub enum ChangeEntity {
53 Task,
54 TaskMove,
55 Project,
56 Label,
57 MetadataField,
58 #[allow(dead_code)]
59 Workspace,
60 RecurrenceSeries,
61}
62
63impl ChangeEntity {
64 pub const fn as_str(&self) -> &'static str {
65 match self {
66 Self::Task => "task",
67 Self::TaskMove => "task_move",
68 Self::Project => "project",
69 Self::Label => "label",
70 Self::MetadataField => "metadata_field",
71 Self::Workspace => "workspace",
72 Self::RecurrenceSeries => "recurrence_series",
73 }
74 }
75}
76
77pub struct ChangePayload {
90 map: serde_json::Map<String, serde_json::Value>,
91}
92
93impl ChangePayload {
94 pub fn workspace(workspace: &Workspace) -> Self {
95 let mut map = serde_json::Map::new();
96 map.insert(
97 "workspace_id".to_string(),
98 Value::String(workspace.id.to_string()),
99 );
100 map.insert(
101 "workspace_key".to_string(),
102 Value::String(workspace.key.clone()),
103 );
104 Self { map }
105 }
106
107 pub fn set(mut self, key: &str, value: impl serde::Serialize) -> Self {
108 self.map.insert(
109 key.to_string(),
110 serde_json::to_value(value).expect("change payload value serialization"),
111 );
112 self
113 }
114
115 pub fn into_value(self) -> Value {
116 Value::Object(self.map)
117 }
118}
119
120pub(crate) async fn append_change(
126 conn: &mut SqliteConnection,
127 entity: ChangeEntity,
128 entity_id: &str,
129 field: Option<&str>,
130 op_type: &'static str,
131 payload: ChangePayload,
132) -> Result<String> {
133 insert_change(
134 conn,
135 entity.as_str(),
136 entity_id,
137 field,
138 op_type,
139 payload.into_value(),
140 None,
141 )
142 .await
143}