1use super::{
16 Error, JsonSnafu, Model, ModelListParams, Schema, SchemaAllowCreate, SchemaAllowEdit,
17 SchemaType, SchemaView, SqlxSnafu, format_datetime,
18};
19use serde::{Deserialize, Serialize};
20use snafu::ResultExt;
21use sqlx::FromRow;
22use sqlx::{Pool, Postgres, QueryBuilder};
23use std::collections::HashMap;
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>, params: serde_json::Value) -> Result<u64> {
162 let params: DetectorGroupInsertParams =
163 serde_json::from_value(params).context(JsonSnafu)?;
164 let row: (i64,) = sqlx::query_as(
165 r#"INSERT INTO detector_groups (name, code, owner_id, created_by, status, remark) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id"#,
166 )
167 .bind(params.name)
168 .bind(params.code)
169 .bind(params.owner_id as i64)
170 .bind(params.created_by as i64)
171 .bind(params.status)
172 .bind(params.remark)
173 .fetch_one(pool)
174 .await
175 .context(SqlxSnafu)?;
176
177 Ok(row.0 as u64)
178 }
179
180 async fn get_by_id(&self, pool: &Pool<Postgres>, id: u64) -> Result<Option<Self::Output>> {
181 let result = sqlx::query_as::<_, DetectorGroupSchema>(
182 r#"SELECT * FROM detector_groups WHERE id = $1 AND deleted_at IS NULL"#,
183 )
184 .bind(id as i64)
185 .fetch_optional(pool)
186 .await
187 .context(SqlxSnafu)?;
188
189 Ok(result.map(|schema| schema.into()))
190 }
191
192 async fn delete_by_id(&self, pool: &Pool<Postgres>, id: u64) -> Result<()> {
193 sqlx::query(r#"UPDATE detector_groups SET deleted_at = NOW() WHERE id = $1"#)
194 .bind(id as i64)
195 .execute(pool)
196 .await
197 .context(SqlxSnafu)?;
198
199 Ok(())
200 }
201
202 async fn update_by_id(
203 &self,
204 pool: &Pool<Postgres>,
205 id: u64,
206 params: serde_json::Value,
207 ) -> Result<()> {
208 let params: DetectorGroupUpdateParams =
209 serde_json::from_value(params).context(JsonSnafu)?;
210
211 let _ = sqlx::query(
212 r#"UPDATE detector_groups SET name = COALESCE($1, name), owner_id = COALESCE($2, owner_id), status = COALESCE($3, status), remark = COALESCE($4, remark) WHERE id = $5 AND deleted_at IS NULL"#,
213 )
214 .bind(params.name)
215 .bind(params.owner_id.map(|v| v as i64))
216 .bind(params.status)
217 .bind(params.remark)
218 .bind(id as i64)
219 .execute(pool)
220 .await
221 .context(SqlxSnafu)?;
222
223 Ok(())
224 }
225
226 async fn count(&self, pool: &Pool<Postgres>, params: &ModelListParams) -> Result<i64> {
227 let mut qb = QueryBuilder::new("SELECT COUNT(*) FROM detector_groups");
228 self.push_conditions(&mut qb, params)?;
229 let count = qb
230 .build_query_scalar::<i64>()
231 .fetch_one(pool)
232 .await
233 .context(SqlxSnafu)?;
234 Ok(count)
235 }
236
237 async fn list(
238 &self,
239 pool: &Pool<Postgres>,
240 params: &ModelListParams,
241 ) -> Result<Vec<Self::Output>> {
242 let mut qb = QueryBuilder::new("SELECT * FROM detector_groups");
243 self.push_conditions(&mut qb, params)?;
244 params.push_pagination(&mut qb);
245 let groups = qb
246 .build_query_as::<DetectorGroupSchema>()
247 .fetch_all(pool)
248 .await
249 .context(SqlxSnafu)?;
250 Ok(groups.into_iter().map(|s| s.into()).collect())
251 }
252}