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}
30
31pub enum ChangeEntity {
32 Task,
33 Project,
34 Label,
35 #[allow(dead_code)]
36 Workspace,
37}
38
39impl ChangeEntity {
40 pub const fn as_str(&self) -> &'static str {
41 match self {
42 Self::Task => "task",
43 Self::Project => "project",
44 Self::Label => "label",
45 Self::Workspace => "workspace",
46 }
47 }
48}
49
50pub struct ChangePayload {
63 map: serde_json::Map<String, serde_json::Value>,
64}
65
66impl ChangePayload {
67 pub fn workspace(workspace: &Workspace) -> Self {
68 let mut map = serde_json::Map::new();
69 map.insert(
70 "workspace_id".to_string(),
71 Value::String(workspace.id.to_string()),
72 );
73 map.insert(
74 "workspace_key".to_string(),
75 Value::String(workspace.key.clone()),
76 );
77 Self { map }
78 }
79
80 pub fn set(mut self, key: &str, value: impl serde::Serialize) -> Self {
81 self.map.insert(
82 key.to_string(),
83 serde_json::to_value(value).expect("change payload value serialization"),
84 );
85 self
86 }
87
88 pub fn into_value(self) -> Value {
89 Value::Object(self.map)
90 }
91}
92
93pub(crate) async fn append_change(
99 conn: &mut SqliteConnection,
100 entity: ChangeEntity,
101 entity_id: &str,
102 field: Option<&str>,
103 op_type: &'static str,
104 payload: ChangePayload,
105) -> Result<String> {
106 insert_change(
107 conn,
108 entity.as_str(),
109 entity_id,
110 field,
111 op_type,
112 payload.into_value(),
113 None,
114 )
115 .await
116}