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