plc_control/src/service/control.rs

304 lines
8.4 KiB
Rust

use crate::model::{ControlUnit, EventRecord};
use sqlx::{PgPool, QueryBuilder};
use uuid::Uuid;
pub async fn get_units_count(pool: &PgPool, keyword: Option<&str>) -> Result<i64, sqlx::Error> {
match keyword {
Some(keyword) => {
let like = format!("%{}%", keyword);
sqlx::query_scalar::<_, i64>(
r#"
SELECT COUNT(*)
FROM unit
WHERE code ILIKE $1 OR name ILIKE $1
"#,
)
.bind(like)
.fetch_one(pool)
.await
}
None => sqlx::query_scalar::<_, i64>(r#"SELECT COUNT(*) FROM unit"#)
.fetch_one(pool)
.await,
}
}
pub async fn get_units_paginated(
pool: &PgPool,
keyword: Option<&str>,
page_size: i32,
offset: u32,
) -> Result<Vec<ControlUnit>, sqlx::Error> {
match keyword {
Some(keyword) => {
let like = format!("%{}%", keyword);
if page_size == -1 {
sqlx::query_as::<_, ControlUnit>(
r#"
SELECT *
FROM unit
WHERE code ILIKE $1 OR name ILIKE $1
ORDER BY created_at
"#,
)
.bind(like)
.fetch_all(pool)
.await
} else {
sqlx::query_as::<_, ControlUnit>(
r#"
SELECT *
FROM unit
WHERE code ILIKE $1 OR name ILIKE $1
ORDER BY created_at
LIMIT $2 OFFSET $3
"#,
)
.bind(like)
.bind(page_size as i64)
.bind(offset as i64)
.fetch_all(pool)
.await
}
}
None => {
if page_size == -1 {
sqlx::query_as::<_, ControlUnit>(r#"SELECT * FROM unit ORDER BY created_at"#)
.fetch_all(pool)
.await
} else {
sqlx::query_as::<_, ControlUnit>(
r#"
SELECT *
FROM unit
ORDER BY created_at
LIMIT $1 OFFSET $2
"#,
)
.bind(page_size as i64)
.bind(offset as i64)
.fetch_all(pool)
.await
}
}
}
}
pub async fn get_unit_by_id(
pool: &PgPool,
unit_id: Uuid,
) -> Result<Option<ControlUnit>, sqlx::Error> {
sqlx::query_as::<_, ControlUnit>(r#"SELECT * FROM unit WHERE id = $1"#)
.bind(unit_id)
.fetch_optional(pool)
.await
}
pub async fn get_unit_by_code(
pool: &PgPool,
code: &str,
) -> Result<Option<ControlUnit>, sqlx::Error> {
sqlx::query_as::<_, ControlUnit>(r#"SELECT * FROM unit WHERE code = $1"#)
.bind(code)
.fetch_optional(pool)
.await
}
pub struct CreateUnitParams<'a> {
pub code: &'a str,
pub name: &'a str,
pub description: Option<&'a str>,
pub enabled: bool,
pub run_time_sec: i32,
pub stop_time_sec: i32,
pub acc_time_sec: i32,
pub bl_time_sec: i32,
pub require_manual_ack_after_fault: bool,
}
pub async fn create_unit(
pool: &PgPool,
params: CreateUnitParams<'_>,
) -> Result<Uuid, sqlx::Error> {
let unit_id = Uuid::new_v4();
sqlx::query(
r#"
INSERT INTO unit (
id, code, name, description, enabled,
run_time_sec, stop_time_sec, acc_time_sec, bl_time_sec,
require_manual_ack_after_fault
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
"#,
)
.bind(unit_id)
.bind(params.code)
.bind(params.name)
.bind(params.description)
.bind(params.enabled)
.bind(params.run_time_sec)
.bind(params.stop_time_sec)
.bind(params.acc_time_sec)
.bind(params.bl_time_sec)
.bind(params.require_manual_ack_after_fault)
.execute(pool)
.await?;
Ok(unit_id)
}
pub struct UpdateUnitParams<'a> {
pub code: Option<&'a str>,
pub name: Option<&'a str>,
pub description: Option<&'a str>,
pub enabled: Option<bool>,
pub run_time_sec: Option<i32>,
pub stop_time_sec: Option<i32>,
pub acc_time_sec: Option<i32>,
pub bl_time_sec: Option<i32>,
pub require_manual_ack_after_fault: Option<bool>,
}
pub async fn update_unit(
pool: &PgPool,
unit_id: Uuid,
params: UpdateUnitParams<'_>,
) -> Result<(), sqlx::Error> {
let mut updates = Vec::new();
let mut param_count = 1;
if params.code.is_some() {
updates.push(format!("code = ${}", param_count));
param_count += 1;
}
if params.name.is_some() {
updates.push(format!("name = ${}", param_count));
param_count += 1;
}
if params.description.is_some() {
updates.push(format!("description = ${}", param_count));
param_count += 1;
}
if params.enabled.is_some() {
updates.push(format!("enabled = ${}", param_count));
param_count += 1;
}
if params.run_time_sec.is_some() {
updates.push(format!("run_time_sec = ${}", param_count));
param_count += 1;
}
if params.stop_time_sec.is_some() {
updates.push(format!("stop_time_sec = ${}", param_count));
param_count += 1;
}
if params.acc_time_sec.is_some() {
updates.push(format!("acc_time_sec = ${}", param_count));
param_count += 1;
}
if params.bl_time_sec.is_some() {
updates.push(format!("bl_time_sec = ${}", param_count));
param_count += 1;
}
if params.require_manual_ack_after_fault.is_some() {
updates.push(format!(
"require_manual_ack_after_fault = ${}",
param_count
));
param_count += 1;
}
updates.push("updated_at = NOW()".to_string());
let sql = format!(
r#"UPDATE unit SET {} WHERE id = ${}"#,
updates.join(", "),
param_count
);
let mut query = sqlx::query(&sql);
if let Some(code) = params.code {
query = query.bind(code);
}
if let Some(name) = params.name {
query = query.bind(name);
}
if let Some(description) = params.description {
query = query.bind(description);
}
if let Some(enabled) = params.enabled {
query = query.bind(enabled);
}
if let Some(run_time_sec) = params.run_time_sec {
query = query.bind(run_time_sec);
}
if let Some(stop_time_sec) = params.stop_time_sec {
query = query.bind(stop_time_sec);
}
if let Some(acc_time_sec) = params.acc_time_sec {
query = query.bind(acc_time_sec);
}
if let Some(bl_time_sec) = params.bl_time_sec {
query = query.bind(bl_time_sec);
}
if let Some(require_manual_ack_after_fault) = params.require_manual_ack_after_fault {
query = query.bind(require_manual_ack_after_fault);
}
query.bind(unit_id).execute(pool).await?;
Ok(())
}
pub async fn delete_unit(pool: &PgPool, unit_id: Uuid) -> Result<bool, sqlx::Error> {
let result = sqlx::query(r#"DELETE FROM unit WHERE id = $1"#)
.bind(unit_id)
.execute(pool)
.await?;
Ok(result.rows_affected() > 0)
}
pub async fn get_events_count(
pool: &PgPool,
unit_id: Option<Uuid>,
event_type: Option<&str>,
) -> Result<i64, sqlx::Error> {
let mut qb =
QueryBuilder::new("SELECT COUNT(*)::BIGINT FROM event WHERE 1 = 1");
if let Some(unit_id) = unit_id {
qb.push(" AND unit_id = ").push_bind(unit_id);
}
if let Some(event_type) = event_type {
qb.push(" AND event_type = ").push_bind(event_type);
}
qb.build_query_scalar().fetch_one(pool).await
}
pub async fn get_events_paginated(
pool: &PgPool,
unit_id: Option<Uuid>,
event_type: Option<&str>,
page_size: i32,
offset: u32,
) -> Result<Vec<EventRecord>, sqlx::Error> {
let mut qb = QueryBuilder::new("SELECT * FROM event WHERE 1 = 1");
if let Some(unit_id) = unit_id {
qb.push(" AND unit_id = ").push_bind(unit_id);
}
if let Some(event_type) = event_type {
qb.push(" AND event_type = ").push_bind(event_type);
}
qb.push(" ORDER BY created_at DESC");
if page_size != -1 {
qb.push(" LIMIT ").push_bind(page_size as i64);
qb.push(" OFFSET ").push_bind(offset as i64);
}
qb.build_query_as::<EventRecord>().fetch_all(pool).await
}