1use std::collections::HashMap;
2use std::sync::{Arc, Mutex};
3
4use crate::protocol::binary::client_ops::{
5 BinaryTypeCache, fetch_binary_type, register_binary_type,
6};
7use crate::protocol::binary::metadata::BinaryType;
8use crate::protocol::handshake::HandshakeRequest;
9use crate::protocol::messages::{
10 SqlFieldsRequest, decode_cache_names_response, decode_tx_start_response,
11 encode_cache_create_with_config, encode_cache_get_names, encode_tx_start,
12};
13use crate::protocol::{IgniteValue, StatementType, TxConcurrency, TxIsolation, cache_id, op_code};
14use crate::transport::{IgniteConnection, next_request_id};
15
16use crate::affinity::AffinityContext;
17use crate::cache::{IgniteCache, destroy_cache_by_name, get_or_create_cache_by_name};
18use crate::channel::ChannelRegistry;
19use crate::error::{IgniteError, Result};
20use crate::pool::IgniteClientConfig;
21use crate::query::{QueryResult, UpdateResult};
22use crate::stream::{self, QueryStream};
23use crate::transaction::{Transaction, execute_sql_fields, extract_rows_affected};
24
25#[derive(Clone)]
28pub struct IgniteClient {
29 registry: Arc<ChannelRegistry>,
30 affinity: Arc<AffinityContext>,
31 config: Arc<IgniteClientConfig>,
32 binary_types: Arc<BinaryTypeCache>,
36}
37
38impl IgniteClient {
39 pub fn new(config: IgniteClientConfig) -> Self {
43 let config = Arc::new(config);
44 let registry = Arc::new(ChannelRegistry::new(config.clone()));
45 let enabled = config
46 .partition_awareness
47 .unwrap_or(registry.node_count() >= 2);
48 let affinity = Arc::new(AffinityContext::new(enabled));
49 Self {
50 registry,
51 affinity,
52 config,
53 binary_types: Arc::new(Mutex::new(HashMap::new())),
54 }
55 }
56
57 pub async fn query(&self, sql: &str, params: Vec<IgniteValue>) -> Result<QueryResult> {
74 let conn_obj = self.registry.get(None).await?;
75 let mut req = SqlFieldsRequest::new(sql, params);
76 req.page_size = self.config.page_size as i32;
77 execute_sql_fields(&conn_obj, req).await
78 }
79
80 pub async fn query_stream(&self, sql: &str, params: Vec<IgniteValue>) -> Result<QueryStream> {
90 use crate::protocol::messages::SqlFieldsFirstPage;
91 use crate::protocol::op_code;
92
93 let conn_obj = self.registry.get(None).await?;
94 let conn = Arc::new(conn_obj.clone());
97 drop(conn_obj);
98
99 let mut req = SqlFieldsRequest::new(sql, params);
100 req.page_size = self.config.page_size as i32;
101 let req_id = next_request_id();
102 let payload = req.encode(op_code::QUERY_SQL_FIELDS, req_id);
103
104 let mut resp = conn
105 .request(req_id, payload)
106 .await
107 .map_err(IgniteError::Transport)?;
108
109 let first = SqlFieldsFirstPage::decode(&mut resp, req.include_field_names)
110 .map_err(IgniteError::Protocol)?;
111
112 Ok(stream::build_stream(conn, first))
113 }
114
115 #[must_use = "futures do nothing unless you `.await` them"]
117 pub async fn execute(&self, sql: &str, params: Vec<IgniteValue>) -> Result<UpdateResult> {
118 let conn_obj = self.registry.get(None).await?;
119 let req = SqlFieldsRequest {
120 statement_type: StatementType::Update,
121 ..SqlFieldsRequest::new(sql, params)
122 };
123 let result = execute_sql_fields(&conn_obj, req).await?;
124 Ok(UpdateResult {
125 rows_affected: extract_rows_affected(&result),
126 })
127 }
128
129 pub async fn begin_transaction(&self) -> Result<Transaction> {
131 self.begin_transaction_with(TxConcurrency::Pessimistic, TxIsolation::ReadCommitted, 0)
132 .await
133 }
134
135 pub async fn begin_transaction_with(
141 &self,
142 concurrency: TxConcurrency,
143 isolation: TxIsolation,
144 timeout_ms: i64,
145 ) -> Result<Transaction> {
146 let hs = HandshakeRequest::new(self.config.username.clone(), self.config.password.clone());
148 let tls = if self.config.use_tls {
149 Some(
150 crate::transport::build_tls_config(self.config.tls_accept_invalid_certs)
151 .map_err(IgniteError::Transport)?,
152 )
153 } else {
154 None
155 };
156 let conn = IgniteConnection::connect(
157 &self.config.address,
158 hs,
159 Some(self.config.connect_timeout),
160 Some(self.config.request_timeout),
161 tls,
162 )
163 .await
164 .map_err(IgniteError::Transport)?;
165
166 let req_id = next_request_id();
167 let payload = encode_tx_start(
168 op_code::TX_START,
169 req_id,
170 concurrency,
171 isolation,
172 timeout_ms,
173 None,
174 );
175
176 let mut response = conn
177 .request(req_id, payload)
178 .await
179 .map_err(IgniteError::Transport)?;
180
181 let tx_id = decode_tx_start_response(&mut response).map_err(IgniteError::Protocol)?;
182
183 Ok(Transaction::new(
184 tx_id,
185 Arc::new(conn),
186 self.config.page_size as i32,
187 ))
188 }
189
190 pub async fn with_transaction<F, Fut, T>(&self, f: F) -> Result<T>
193 where
194 F: FnOnce(Transaction) -> Fut,
195 Fut: std::future::Future<Output = Result<(Transaction, T)>>,
196 {
197 let tx = self.begin_transaction().await?;
198 match f(tx).await {
199 Ok((tx, result)) => {
200 tx.commit().await?;
201 Ok(result)
202 }
203 Err(e) => Err(e),
204 }
205 }
206
207 pub fn pool_status(&self) -> deadpool::managed::Status {
209 self.registry.primary_status()
210 }
211
212 pub fn cache(&self, name: &str) -> IgniteCache {
217 IgniteCache::new(
218 cache_id(name),
219 self.registry.clone(),
220 self.affinity.clone(),
221 self.binary_types.clone(),
222 )
223 }
224
225 pub async fn get_or_create_cache(&self, name: &str) -> Result<IgniteCache> {
228 get_or_create_cache_by_name(name, &self.registry, &self.affinity, &self.binary_types).await
229 }
230
231 pub async fn get_or_create_transactional_cache(&self, name: &str) -> Result<IgniteCache> {
237 let req_id = next_request_id();
238 let payload = encode_cache_create_with_config(
239 op_code::CACHE_GET_OR_CREATE_WITH_CONFIGURATION,
240 req_id,
241 name,
242 true, );
244 let conn = self.registry.get(None).await?;
245 conn.request(req_id, payload)
246 .await
247 .map_err(IgniteError::Transport)?;
248 Ok(IgniteCache::new(
250 cache_id(name),
251 self.registry.clone(),
252 self.affinity.clone(),
253 self.binary_types.clone(),
254 ))
255 }
256
257 pub async fn destroy_cache(&self, name: &str) -> Result<()> {
259 destroy_cache_by_name(name, &self.registry).await
260 }
261
262 pub async fn cache_names(&self) -> Result<Vec<String>> {
264 let req_id = next_request_id();
265 let payload = encode_cache_get_names(op_code::CACHE_GET_NAMES, req_id);
266 let conn = self.registry.get(None).await?;
267 let mut resp = conn
268 .request(req_id, payload)
269 .await
270 .map_err(IgniteError::Transport)?;
271 decode_cache_names_response(&mut resp).map_err(IgniteError::Protocol)
272 }
273
274 pub async fn binary_type(&self, type_id: i32) -> Result<Option<Arc<BinaryType>>> {
285 fetch_binary_type(&self.registry, &self.binary_types, type_id).await
286 }
287
288 pub async fn register_binary_type(&self, t: &BinaryType) -> Result<()> {
298 register_binary_type(&self.registry, &self.binary_types, t).await
299 }
300}