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 SET_FIELD: &str = "set_field";
11 pub const RESOLVE_FIELD: &str = "resolve_field";
12 pub const LABEL_ADD: &str = "label_add";
13 pub const LABEL_REMOVE: &str = "label_remove";
14 pub const NOTE_ADD: &str = "note_add";
15 pub const NOTE_EDIT: &str = "note_edit";
16 pub const NOTE_DELETE: &str = "note_delete";
17 pub const DEPENDENCY_ADD: &str = "dependency_add";
18 pub const DEPENDENCY_REMOVE: &str = "dependency_remove";
19 pub const EPIC_LINK_ADD: &str = "epic_link_add";
20 pub const EPIC_LINK_REMOVE: &str = "epic_link_remove";
21 pub const ATTACHMENT_ADD: &str = "attachment_add";
22 pub const ATTACHMENT_DELETE: &str = "attachment_delete";
23 pub const CREATE_PROJECT: &str = "create_project";
24 pub const SET_PROJECT_METADATA: &str = "set_project_metadata";
25 pub const PROJECT_DELETE: &str = "project_delete";
26 pub const CREATE_LABEL: &str = "create_label";
27 pub const SET_LABEL_NAME: &str = "set_label_name";
28 pub const LABEL_DELETE: &str = "label_delete";
29 pub const LABEL_RESTORE: &str = "label_restore";
30 pub const CREATE_WORKSPACE: &str = "create_workspace";
31 pub const SET_WORKSPACE_FIELD: &str = "set_workspace_field";
32 pub const CREATE_RECURRENCE_SERIES: &str = "create_recurrence_series";
33 pub const UPDATE_RECURRENCE_TEMPLATE: &str = "update_recurrence_template";
34 pub const PROJECT_RECURRENCE_OCCURRENCE: &str = "project_recurrence_occurrence";
35 pub const RESOLVE_RECURRENCE_OCCURRENCE: &str = "resolve_recurrence_occurrence";
36 pub const SET_RECURRENCE_STATE: &str = "set_recurrence_state";
37 pub const OPEN_RECURRENCE_PAUSE: &str = "open_recurrence_pause";
38 pub const CLOSE_RECURRENCE_PAUSE: &str = "close_recurrence_pause";
39 pub const STOP_RECURRENCE_SERIES: &str = "stop_recurrence_series";
40}
41
42pub enum ChangeEntity {
43 Task,
44 Project,
45 Label,
46 #[allow(dead_code)]
47 Workspace,
48 RecurrenceSeries,
49}
50
51impl ChangeEntity {
52 pub const fn as_str(&self) -> &'static str {
53 match self {
54 Self::Task => "task",
55 Self::Project => "project",
56 Self::Label => "label",
57 Self::Workspace => "workspace",
58 Self::RecurrenceSeries => "recurrence_series",
59 }
60 }
61}
62
63pub struct ChangePayload {
76 map: serde_json::Map<String, serde_json::Value>,
77}
78
79impl ChangePayload {
80 pub fn workspace(workspace: &Workspace) -> Self {
81 let mut map = serde_json::Map::new();
82 map.insert(
83 "workspace_id".to_string(),
84 Value::String(workspace.id.to_string()),
85 );
86 map.insert(
87 "workspace_key".to_string(),
88 Value::String(workspace.key.clone()),
89 );
90 Self { map }
91 }
92
93 pub fn set(mut self, key: &str, value: impl serde::Serialize) -> Self {
94 self.map.insert(
95 key.to_string(),
96 serde_json::to_value(value).expect("change payload value serialization"),
97 );
98 self
99 }
100
101 pub fn into_value(self) -> Value {
102 Value::Object(self.map)
103 }
104}
105
106pub(crate) async fn append_change(
112 conn: &mut SqliteConnection,
113 entity: ChangeEntity,
114 entity_id: &str,
115 field: Option<&str>,
116 op_type: &'static str,
117 payload: ChangePayload,
118) -> Result<String> {
119 insert_change(
120 conn,
121 entity.as_str(),
122 entity_id,
123 field,
124 op_type,
125 payload.into_value(),
126 None,
127 )
128 .await
129}