odbc_iter/
thread_local.rs1use log::debug;
2use std::cell::RefCell;
3
4use crate::query::Connection;
5use crate::{Odbc, OdbcError};
6
7thread_local! {
8 static DB: RefCell<Option<Connection>> = RefCell::new(None);
9}
10
11pub fn connection_with<O, F>(
19 connection_string: &str,
20 f: F
21) -> O where F: Fn(Result<Connection, OdbcError>) -> (Option<Connection>, O) {
22 initialized_connection_with(connection_string, |_| Ok(()), f)
23}
24
25pub fn initialized_connection_with<O, E, I, F>(
32 connection_string: &str,
33 init: I,
34 f: F
35) -> O where E: From<OdbcError>, I: Fn(&mut Connection) -> Result<(), E>, F: Fn(Result<Connection, E>) -> (Option<Connection>, O) {
36 DB.with(|db| {
37 let connection;
38
39 let conn = db.borrow_mut().take();
40 match conn {
41 Some(conn) => connection = conn,
42 None => {
43 let id = std::thread::current().id();
44 debug!("[{:?}] Connecting to database: {}", id, &connection_string);
45
46 match Odbc::connect(&connection_string)
47 .map_err(Into::into)
48 .and_then(|mut conn| init(&mut conn).map(|_| conn)) {
49 Ok(conn) => {
50 connection = conn;
51 }
52 Err(err) => return f(Err(err)).1,
53 }
54 }
55 }
56
57 let (connection, o) = f(Ok(connection));
58 *db.borrow_mut() = connection;
59 o
60 })
61}
62
63#[cfg(test)]
64mod tests {
65 #[allow(unused_imports)]
66 use super::*;
67 #[allow(unused_imports)]
68 use crate::*;
69 #[allow(unused_imports)]
70 use assert_matches::assert_matches;
71
72 #[cfg(feature = "test-monetdb")]
73 #[test]
74 fn test_connection_with() {
75 connection_with(
76 crate::tests::monetdb_connection_string().as_str(),
77 |result| {
78 let mut monetdb = result.expect("connect to MonetDB");
79 let data = monetdb
80 .handle()
81 .query::<ValueRow>("SELECT 'foo'")
82 .expect("failed to run query")
83 .collect::<Result<Vec<_>, _>>()
84 .expect("fetch data");
85
86 assert_matches!(data[0][0], Some(Value::String(ref string)) => assert_eq!(string, "foo"));
87 (Some(monetdb), ())
88 },
89 )
90 }
91
92 #[cfg(feature = "test-monetdb")]
93 #[test]
94 fn test_connection_with_reconnect() {
95 connection_with(
96 crate::tests::monetdb_connection_string().as_str(),
97 |result| {
98 let mut monetdb = result.expect("connect to MonetDB");
99 let data = monetdb
100 .handle()
101 .query::<ValueRow>("SELECT 'foo'")
102 .expect("failed to run query")
103 .collect::<Result<Vec<_>, _>>()
104 .expect("fetch data");
105
106 assert_matches!(data[0][0], Some(Value::String(ref string)) => assert_eq!(string, "foo"));
107 (None, ())
108 },
109 );
110
111 connection_with(
112 crate::tests::monetdb_connection_string().as_str(),
113 |result| {
114 let mut monetdb = result.expect("connect to MonetDB");
115 let data = monetdb
116 .handle()
117 .query::<ValueRow>("SELECT 'foo'")
118 .expect("failed to run query")
119 .collect::<Result<Vec<_>, _>>()
120 .expect("fetch data");
121
122 assert_matches!(data[0][0], Some(Value::String(ref string)) => assert_eq!(string, "foo"));
123 (None, ())
124 },
125 )
126 }
127
128 #[cfg(feature = "test-monetdb")]
129 #[test]
130 fn test_connection_with_nested() {
131 connection_with(
132 crate::tests::monetdb_connection_string().as_str(),
133 |result| {
134 let mut monetdb = result.expect("connect to MonetDB");
135 let data = monetdb
136 .handle()
137 .query::<ValueRow>("SELECT 'foo'")
138 .expect("failed to run query")
139 .collect::<Result<Vec<_>, _>>()
140 .expect("fetch data");
141
142 assert_matches!(data[0][0], Some(Value::String(ref string)) => assert_eq!(string, "foo"));
143
144 connection_with(
145 crate::tests::monetdb_connection_string().as_str(),
146 |result| {
147 let mut monetdb = result.expect("connect to MonetDB");
148 let data = monetdb
149 .handle()
150 .query::<ValueRow>("SELECT 'foo'")
151 .expect("failed to run query")
152 .collect::<Result<Vec<_>, _>>()
153 .expect("fetch data");
154
155 assert_matches!(data[0][0], Some(Value::String(ref string)) => assert_eq!(string, "foo"));
156 (Some(monetdb), ())
157 },
158 );
159
160 (Some(monetdb), ())
161 },
162 )
163 }
164}