ns_indexer/db/
model_service_state.rs1use ns_axum_web::erring::HTTPError;
2use ns_scylla_orm::{ColumnsMap, ToCqlVal};
3use ns_scylla_orm_macros::CqlOrm;
4
5use ns_protocol::state;
6
7use crate::db::scylladb;
8
9#[derive(Debug, Default, Clone, CqlOrm, PartialEq)]
10pub struct ServiceState {
11 pub name: String,
12 pub code: i64,
13 pub sequence: i64,
14 pub data: Vec<u8>,
15
16 pub _fields: Vec<String>, }
18
19impl ServiceState {
20 pub fn with_pk(name: String, code: i64) -> Self {
21 Self {
22 name,
23 code,
24 ..Default::default()
25 }
26 }
27
28 pub fn from_index(value: &state::ServiceState) -> anyhow::Result<Self> {
29 let data = state::to_bytes(&value.data)?;
30 Ok(Self {
31 name: value.name.clone(),
32 code: value.code as i64,
33 sequence: value.sequence as i64,
34 data,
35 _fields: Self::fields(),
36 })
37 }
38
39 pub fn to_index(&self) -> anyhow::Result<state::ServiceState> {
40 let data = state::from_bytes(&self.data)?;
41 Ok(state::ServiceState {
42 name: self.name.clone(),
43 code: self.code as u64,
44 sequence: self.sequence as u64,
45 data,
46 })
47 }
48
49 pub fn select_fields(select_fields: Vec<String>, with_pk: bool) -> anyhow::Result<Vec<String>> {
50 if select_fields.is_empty() {
51 return Ok(Self::fields());
52 }
53
54 let fields = Self::fields();
55 let mut select_fields = select_fields;
56 for field in &select_fields {
57 if !fields.contains(field) {
58 return Err(HTTPError::new(400, format!("Invalid field: {}", field)).into());
59 }
60 }
61
62 let field = "sequence".to_string();
63 if !select_fields.contains(&field) {
64 select_fields.push(field);
65 }
66
67 if with_pk {
68 let field = "name".to_string();
69 if !select_fields.contains(&field) {
70 select_fields.push(field);
71 }
72 let field = "code".to_string();
73 if !select_fields.contains(&field) {
74 select_fields.push(field);
75 }
76 }
77
78 Ok(select_fields)
79 }
80
81 pub async fn get_one(
82 &mut self,
83 db: &scylladb::ScyllaDB,
84 select_fields: Vec<String>,
85 ) -> anyhow::Result<()> {
86 let fields = Self::select_fields(select_fields, false)?;
87 self._fields = fields.clone();
88
89 let query = format!(
90 "SELECT {} FROM service_state WHERE name=? AND code=? LIMIT 1",
91 fields.join(",")
92 );
93 let params = (self.name.to_cql(), self.code.to_cql());
94 let res = db.execute(query, params).await?.single_row()?;
95
96 let mut cols = ColumnsMap::with_capacity(fields.len());
97 cols.fill(res, &fields)?;
98 self.fill(&cols);
99
100 Ok(())
101 }
102
103 pub async fn list_by_name(
104 db: &scylladb::ScyllaDB,
105 name: &String,
106 select_fields: Vec<String>,
107 ) -> anyhow::Result<Vec<Self>> {
108 let fields = Self::select_fields(select_fields, true)?;
109
110 let query = format!(
111 "SELECT {} FROM service_state WHERE name=? USING TIMEOUT 3s",
112 fields.clone().join(",")
113 );
114 let params = (name.to_cql(),);
115 let rows = db.execute_iter(query, params).await?;
116
117 let mut res: Vec<Self> = Vec::with_capacity(rows.len());
118 for row in rows {
119 let mut doc = Self::default();
120 let mut cols = ColumnsMap::with_capacity(fields.len());
121 cols.fill(row, &fields)?;
122 doc.fill(&cols);
123 doc._fields = fields.clone();
124 res.push(doc);
125 }
126
127 Ok(res)
128 }
129}