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 CREATE_METADATA_FIELD: &str = "create_metadata_field";
38 pub const SET_METADATA_FIELD: &str = "set_metadata_field";
39 pub const SET_TASK_METADATA: &str = "set_task_metadata";
40 pub const REMOVE_TASK_METADATA: &str = "remove_task_metadata";
41 pub const SET_RECURRENCE_METADATA: &str = "set_recurrence_metadata";
42 pub const REMOVE_RECURRENCE_METADATA: &str = "remove_recurrence_metadata";
43 pub const OPEN_RECURRENCE_PAUSE: &str = "open_recurrence_pause";
44 pub const CLOSE_RECURRENCE_PAUSE: &str = "close_recurrence_pause";
45 pub const STOP_RECURRENCE_SERIES: &str = "stop_recurrence_series";
46}
47
48pub enum ChangeEntity {
49 Task,
50 Project,
51 Label,
52 MetadataField,
53 #[allow(dead_code)]
54 Workspace,
55 RecurrenceSeries,
56}
57
58impl ChangeEntity {
59 pub const fn as_str(&self) -> &'static str {
60 match self {
61 Self::Task => "task",
62 Self::Project => "project",
63 Self::Label => "label",
64 Self::MetadataField => "metadata_field",
65 Self::Workspace => "workspace",
66 Self::RecurrenceSeries => "recurrence_series",
67 }
68 }
69}
70
71pub struct ChangePayload {
84 map: serde_json::Map<String, serde_json::Value>,
85}
86
87impl ChangePayload {
88 pub fn workspace(workspace: &Workspace) -> Self {
89 let mut map = serde_json::Map::new();
90 map.insert(
91 "workspace_id".to_string(),
92 Value::String(workspace.id.to_string()),
93 );
94 map.insert(
95 "workspace_key".to_string(),
96 Value::String(workspace.key.clone()),
97 );
98 Self { map }
99 }
100
101 pub fn set(mut self, key: &str, value: impl serde::Serialize) -> Self {
102 self.map.insert(
103 key.to_string(),
104 serde_json::to_value(value).expect("change payload value serialization"),
105 );
106 self
107 }
108
109 pub fn into_value(self) -> Value {
110 Value::Object(self.map)
111 }
112}
113
114pub(crate) async fn append_change(
120 conn: &mut SqliteConnection,
121 entity: ChangeEntity,
122 entity_id: &str,
123 field: Option<&str>,
124 op_type: &'static str,
125 payload: ChangePayload,
126) -> Result<String> {
127 insert_change(
128 conn,
129 entity.as_str(),
130 entity_id,
131 field,
132 op_type,
133 payload.into_value(),
134 None,
135 )
136 .await
137}