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 RELATED_ADD: &str = "related_add";
20 pub const RELATED_REMOVE: &str = "related_remove";
21 pub const EPIC_LINK_ADD: &str = "epic_link_add";
22 pub const EPIC_LINK_REMOVE: &str = "epic_link_remove";
23 pub const ATTACHMENT_ADD: &str = "attachment_add";
24 pub const ATTACHMENT_DELETE: &str = "attachment_delete";
25 pub const CREATE_PROJECT: &str = "create_project";
26 pub const SET_PROJECT_METADATA: &str = "set_project_metadata";
27 pub const PROJECT_DELETE: &str = "project_delete";
28 pub const CREATE_LABEL: &str = "create_label";
29 pub const SET_LABEL_NAME: &str = "set_label_name";
30 pub const LABEL_DELETE: &str = "label_delete";
31 pub const LABEL_RESTORE: &str = "label_restore";
32 pub const CREATE_WORKSPACE: &str = "create_workspace";
33 pub const SET_WORKSPACE_FIELD: &str = "set_workspace_field";
34 pub const CREATE_RECURRENCE_SERIES: &str = "create_recurrence_series";
35 pub const UPDATE_RECURRENCE_TEMPLATE: &str = "update_recurrence_template";
36 pub const PROJECT_RECURRENCE_OCCURRENCE: &str = "project_recurrence_occurrence";
37 pub const RESOLVE_RECURRENCE_OCCURRENCE: &str = "resolve_recurrence_occurrence";
38 pub const SET_RECURRENCE_STATE: &str = "set_recurrence_state";
39 pub const CREATE_METADATA_FIELD: &str = "create_metadata_field";
40 pub const SET_METADATA_FIELD: &str = "set_metadata_field";
41 pub const SET_TASK_METADATA: &str = "set_task_metadata";
42 pub const REMOVE_TASK_METADATA: &str = "remove_task_metadata";
43 pub const SET_RECURRENCE_METADATA: &str = "set_recurrence_metadata";
44 pub const REMOVE_RECURRENCE_METADATA: &str = "remove_recurrence_metadata";
45 pub const OPEN_RECURRENCE_PAUSE: &str = "open_recurrence_pause";
46 pub const CLOSE_RECURRENCE_PAUSE: &str = "close_recurrence_pause";
47 pub const STOP_RECURRENCE_SERIES: &str = "stop_recurrence_series";
48}
49
50pub enum ChangeEntity {
51 Task,
52 Project,
53 Label,
54 MetadataField,
55 #[allow(dead_code)]
56 Workspace,
57 RecurrenceSeries,
58}
59
60impl ChangeEntity {
61 pub const fn as_str(&self) -> &'static str {
62 match self {
63 Self::Task => "task",
64 Self::Project => "project",
65 Self::Label => "label",
66 Self::MetadataField => "metadata_field",
67 Self::Workspace => "workspace",
68 Self::RecurrenceSeries => "recurrence_series",
69 }
70 }
71}
72
73pub struct ChangePayload {
86 map: serde_json::Map<String, serde_json::Value>,
87}
88
89impl ChangePayload {
90 pub fn workspace(workspace: &Workspace) -> Self {
91 let mut map = serde_json::Map::new();
92 map.insert(
93 "workspace_id".to_string(),
94 Value::String(workspace.id.to_string()),
95 );
96 map.insert(
97 "workspace_key".to_string(),
98 Value::String(workspace.key.clone()),
99 );
100 Self { map }
101 }
102
103 pub fn set(mut self, key: &str, value: impl serde::Serialize) -> Self {
104 self.map.insert(
105 key.to_string(),
106 serde_json::to_value(value).expect("change payload value serialization"),
107 );
108 self
109 }
110
111 pub fn into_value(self) -> Value {
112 Value::Object(self.map)
113 }
114}
115
116pub(crate) async fn append_change(
122 conn: &mut SqliteConnection,
123 entity: ChangeEntity,
124 entity_id: &str,
125 field: Option<&str>,
126 op_type: &'static str,
127 payload: ChangePayload,
128) -> Result<String> {
129 insert_change(
130 conn,
131 entity.as_str(),
132 entity_id,
133 field,
134 op_type,
135 payload.into_value(),
136 None,
137 )
138 .await
139}