Skip to main content

tibba_model/
detector_group.rs

1// Copyright 2025 Tree xie.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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}