1use serde::{Deserialize, Serialize};
16use snafu::ResultExt;
17use sqlx::FromRow;
18use sqlx::{Pool, Postgres, QueryBuilder};
19use std::collections::HashMap;
20use tibba_model::{
21 Error, JsonSnafu, Model, ModelListParams, Schema, SchemaAllowCreate, SchemaAllowEdit,
22 SchemaType, SchemaView, SqlxSnafu, format_datetime,
23};
24use time::PrimitiveDateTime;
25
26type Result<T> = std::result::Result<T, Error>;
27
28#[derive(FromRow)]
29struct DetectorGroupSchema {
30 id: i64,
31 name: String,
32 code: String,
33 owner_id: i64,
34 status: i16,
35 remark: String,
36 created_by: i64,
37 created: PrimitiveDateTime,
38 modified: PrimitiveDateTime,
39}
40
41#[derive(Deserialize, Serialize, Clone, Debug)]
42pub struct DetectorGroup {
43 pub id: i64,
44 pub name: String,
45 pub code: String,
46 pub owner_id: i64,
47 pub status: i16,
48 pub created_by: i64,
49 pub remark: String,
50 pub created: String,
51 pub modified: String,
52}
53
54impl From<DetectorGroupSchema> for DetectorGroup {
55 fn from(schema: DetectorGroupSchema) -> Self {
56 Self {
57 id: schema.id,
58 name: schema.name,
59 code: schema.code,
60 owner_id: schema.owner_id,
61 status: schema.status,
62 created_by: schema.created_by,
63 remark: schema.remark,
64 created: format_datetime(schema.created),
65 modified: format_datetime(schema.modified),
66 }
67 }
68}
69
70#[derive(Debug, Clone, Deserialize, Default)]
71pub struct DetectorGroupInsertParams {
72 pub name: String,
73 pub code: String,
74 pub owner_id: u64,
75 pub created_by: u64,
76 pub status: i16,
77 pub remark: String,
78}
79
80#[derive(Debug, Clone, Deserialize, Default)]
81pub struct DetectorGroupUpdateParams {
82 pub name: Option<String>,
83 pub owner_id: Option<u64>,
84 pub status: Option<i16>,
85 pub remark: Option<String>,
86}
87
88pub struct DetectorGroupModel {}
89
90impl DetectorGroupModel {
91 pub async fn list_enabled(&self, pool: &Pool<Postgres>) -> Result<Vec<DetectorGroup>> {
92 let groups = sqlx::query_as::<_, DetectorGroupSchema>(
93 r#"SELECT * FROM detector_groups WHERE deleted_at IS NULL AND status = 1"#,
94 )
95 .fetch_all(pool)
96 .await
97 .context(SqlxSnafu)?;
98
99 Ok(groups.into_iter().map(|schema| schema.into()).collect())
100 }
101}
102
103impl Model for DetectorGroupModel {
104 type Output = DetectorGroup;
105 fn new() -> Self {
106 Self {}
107 }
108 async fn schema_view(&self, _pool: &Pool<Postgres>) -> SchemaView {
109 SchemaView {
110 schemas: vec![
111 Schema::new_id(),
112 Schema {
113 name: "code".to_string(),
114 category: SchemaType::String,
115 required: true,
116 fixed: true,
117 ..Default::default()
118 },
119 Schema {
120 name: "name".to_string(),
121 category: SchemaType::String,
122 required: true,
123 ..Default::default()
124 },
125 Schema {
126 name: "owner_id".to_string(),
127 category: SchemaType::Number,
128 read_only: true,
129 auto_create: true,
130 ..Default::default()
131 },
132 Schema::new_status(),
133 Schema::new_remark(),
134 Schema::new_created(),
135 Schema::new_modified(),
136 ],
137 allow_edit: SchemaAllowEdit {
138 owner: true,
139 roles: vec!["*".to_string()],
140 ..Default::default()
141 },
142 allow_create: SchemaAllowCreate {
143 roles: vec!["*".to_string()],
144 ..Default::default()
145 },
146 }
147 }
148
149 fn push_filter_conditions<'args>(
150 &self,
151 qb: &mut QueryBuilder<'args, Postgres>,
152 filters: &HashMap<String, String>,
153 ) -> Result<()> {
154 if let Some(status) = filters.get("status").and_then(|s| s.parse::<i16>().ok()) {
155 qb.push(" AND status = ");
156 qb.push_bind(status);
157 }
158 Ok(())
159 }
160
161 async fn insert(&self, pool: &Pool<Postgres>, mut params: serde_json::Value) -> Result<u64> {
162 if let Some(obj) = params.as_object_mut() {
164 if !obj.contains_key("owner_id") {
165 if let Some(created_by) = obj.get("created_by").cloned() {
166 obj.insert("owner_id".to_string(), created_by);
167 }
168 }
169 }
170 let params: DetectorGroupInsertParams =
171 serde_json::from_value(params).context(JsonSnafu)?;
172 let row: (i64,) = sqlx::query_as(
173 r#"INSERT INTO detector_groups (name, code, owner_id, created_by, status, remark) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id"#,
174 )
175 .bind(params.name)
176 .bind(params.code)
177 .bind(params.owner_id as i64)
178 .bind(params.created_by as i64)
179 .bind(params.status)
180 .bind(params.remark)
181 .fetch_one(pool)
182 .await
183 .context(SqlxSnafu)?;
184
185 Ok(row.0 as u64)
186 }
187
188 async fn get_by_id(&self, pool: &Pool<Postgres>, id: u64) -> Result<Option<Self::Output>> {
189 let result = sqlx::query_as::<_, DetectorGroupSchema>(
190 r#"SELECT * FROM detector_groups WHERE id = $1 AND deleted_at IS NULL"#,
191 )
192 .bind(id as i64)
193 .fetch_optional(pool)
194 .await
195 .context(SqlxSnafu)?;
196
197 Ok(result.map(|schema| schema.into()))
198 }
199
200 async fn delete_by_id(&self, pool: &Pool<Postgres>, id: u64) -> Result<()> {
201 sqlx::query(
202 r#"UPDATE detector_groups SET deleted_at = NOW(), modified = NOW() WHERE id = $1"#,
203 )
204 .bind(id as i64)
205 .execute(pool)
206 .await
207 .context(SqlxSnafu)?;
208
209 Ok(())
210 }
211
212 async fn update_by_id(
213 &self,
214 pool: &Pool<Postgres>,
215 id: u64,
216 params: serde_json::Value,
217 ) -> Result<()> {
218 let params: DetectorGroupUpdateParams =
219 serde_json::from_value(params).context(JsonSnafu)?;
220
221 let _ = sqlx::query(
222 r#"UPDATE detector_groups SET name = COALESCE($1, name), owner_id = COALESCE($2, owner_id), status = COALESCE($3, status), remark = COALESCE($4, remark), modified = NOW() WHERE id = $5 AND deleted_at IS NULL"#,
223 )
224 .bind(params.name)
225 .bind(params.owner_id.map(|v| v as i64))
226 .bind(params.status)
227 .bind(params.remark)
228 .bind(id as i64)
229 .execute(pool)
230 .await
231 .context(SqlxSnafu)?;
232
233 Ok(())
234 }
235
236 async fn count(&self, pool: &Pool<Postgres>, params: &ModelListParams) -> Result<i64> {
237 let mut qb = QueryBuilder::new("SELECT COUNT(*) FROM detector_groups");
238 self.push_conditions(&mut qb, params)?;
239 let count = qb
240 .build_query_scalar::<i64>()
241 .fetch_one(pool)
242 .await
243 .context(SqlxSnafu)?;
244 Ok(count)
245 }
246
247 async fn list(
248 &self,
249 pool: &Pool<Postgres>,
250 params: &ModelListParams,
251 ) -> Result<Vec<Self::Output>> {
252 let mut qb = QueryBuilder::new("SELECT * FROM detector_groups");
253 self.push_conditions(&mut qb, params)?;
254 params.push_pagination(&mut qb);
255 let groups = qb
256 .build_query_as::<DetectorGroupSchema>()
257 .fetch_all(pool)
258 .await
259 .context(SqlxSnafu)?;
260 Ok(groups.into_iter().map(|s| s.into()).collect())
261 }
262}