dmsc/database/orm/
py_repository.rs1use crate::core::DMSCResult;
19use crate::database::{DMSCDatabase, DMSCDatabasePool};
20use pyo3::prelude::*;
21use pyo3::types::{PyDict, PyList};
22use tokio::runtime::Runtime;
23
24#[pyclass]
25pub struct DMSCPyORMRepository {
26 pool: DMSCDatabasePool,
27 table_name: String,
28 rt: Runtime,
29}
30
31#[pymethods]
32impl DMSCPyORMRepository {
33 #[new]
34 #[pyo3(signature = (pool, table_name))]
35 pub fn new(pool: DMSCDatabasePool, table_name: &str) -> PyResult<Self> {
36 let rt = Runtime::new().map_err(|e| pyo3::PyErr::from(crate::core::DMSCError::Other(e.to_string())))?;
37 Ok(Self {
38 pool,
39 table_name: table_name.to_string(),
40 rt,
41 })
42 }
43
44 pub fn get_table_name(&self) -> &str {
45 &self.table_name
46 }
47
48 pub fn find_all(&self, py: Python) -> PyResult<Py<PyList>> {
49 let result = self.rt.block_on(async {
50 self.find_all_impl().await
51 }).map_err(|e| pyo3::PyErr::from(e))?;
52 let list = PyList::empty(py);
53 for value in result {
54 let dict = PyDict::new(py);
55 if let serde_json::Value::Object(map) = value {
56 for (k, v) in map {
57 Self::json_to_py(py, k, v, &dict);
58 }
59 }
60 list.append(dict).map_err(|e| pyo3::PyErr::from(e))?;
61 }
62 Ok(list.into())
63 }
64
65 pub fn find_by_id(&self, id: &str, py: Python) -> PyResult<Option<Py<PyDict>>> {
66 let result = self.rt.block_on(async {
67 self.find_by_id_impl(id).await
68 }).map_err(|e| pyo3::PyErr::from(e))?;
69 match result {
70 Some(value) => {
71 let dict = PyDict::new(py);
72 if let serde_json::Value::Object(map) = value {
73 for (k, v) in map {
74 Self::json_to_py(py, k, v, &dict);
75 }
76 }
77 Ok(Some(dict.into()))
78 }
79 None => Ok(None),
80 }
81 }
82
83 pub fn count(&self) -> PyResult<u64> {
84 self.rt.block_on(async {
85 self.count_impl().await
86 }).map_err(|e| pyo3::PyErr::from(e))
87 }
88
89 pub fn exists(&self, id: &str) -> PyResult<bool> {
90 self.rt.block_on(async {
91 self.exists_impl(id).await
92 }).map_err(|e| pyo3::PyErr::from(e))
93 }
94
95 pub fn delete(&self, id: &str) -> PyResult<()> {
96 self.rt.block_on(async {
97 self.delete_impl(id).await
98 }).map_err(|e| pyo3::PyErr::from(e))
99 }
100}
101
102impl DMSCPyORMRepository {
103 fn json_to_py(py: Python, key: String, value: serde_json::Value, dict: &Bound<PyDict>) {
104 match value {
105 serde_json::Value::Null => {},
106 serde_json::Value::Bool(b) => { let _ = dict.set_item(key, b); },
107 serde_json::Value::Number(n) => {
108 if let Some(i) = n.as_i64() {
109 let _ = dict.set_item(key, i);
110 } else if let Some(f) = n.as_f64() {
111 let _ = dict.set_item(key, f);
112 } else {
113 let _ = dict.set_item(key, n.to_string());
114 }
115 }
116 serde_json::Value::String(s) => { let _ = dict.set_item(key, s); },
117 serde_json::Value::Array(arr) => {
118 let list = PyList::empty(py);
119 for (idx, v) in arr.into_iter().enumerate() {
120 let item = PyDict::new(py);
121 Self::json_to_py(py, idx.to_string(), v, &item);
122 let _ = list.append(item);
123 }
124 let _ = dict.set_item(key, list);
125 }
126 serde_json::Value::Object(map) => {
127 let nested = PyDict::new(py);
128 for (k, v) in map {
129 Self::json_to_py(py, k, v, &nested);
130 }
131 let _ = dict.set_item(key, nested);
132 }
133 }
134 }
135
136 async fn find_all_impl(&self) -> DMSCResult<Vec<serde_json::Value>> {
137 let db = self.pool.get().await?;
138 let sql = format!("SELECT * FROM {}", self.table_name);
139 let result = db.query(&sql).await?;
140 let mut entities = Vec::new();
141 for row in result {
142 let json_value = serde_json::to_value(row.to_map())?;
143 entities.push(json_value);
144 }
145 Ok(entities)
146 }
147
148 async fn find_by_id_impl(&self, id: &str) -> DMSCResult<Option<serde_json::Value>> {
149 let db = self.pool.get().await?;
150 let sql = format!("SELECT * FROM {} WHERE id = ?", self.table_name);
151 let result = db.query_with_params(&sql, &[serde_json::json!(id)]).await?;
152 if let Some(row) = result.first() {
153 let json_value = serde_json::to_value(row.to_map())?;
154 Ok(Some(json_value))
155 } else {
156 Ok(None)
157 }
158 }
159
160 async fn count_impl(&self) -> DMSCResult<u64> {
161 let db = self.pool.get().await?;
162 let sql = format!("SELECT COUNT(*) as total FROM {}", self.table_name);
163 if let Some(row) = db.query_one(&sql).await? {
164 Ok(row.get::<i64>("total").map(|v| v as u64).unwrap_or(0))
165 } else {
166 Ok(0)
167 }
168 }
169
170 async fn exists_impl(&self, id: &str) -> DMSCResult<bool> {
171 let db = self.pool.get().await?;
172 let sql = format!("SELECT 1 FROM {} WHERE id = ? LIMIT 1", self.table_name);
173 let result = db.query_with_params(&sql, &[serde_json::json!(id)]).await?;
174 Ok(!result.is_empty())
175 }
176
177 async fn delete_impl(&self, id: &str) -> DMSCResult<()> {
178 let db = self.pool.get().await?;
179 let sql = format!("DELETE FROM {} WHERE id = ?", self.table_name);
180 db.execute_with_params(&sql, &[serde_json::json!(id)]).await?;
181 Ok(())
182 }
183}