ump_ngx/server/sqlsrv/
utils.rs

1//! Integration utilities for creating sqlsrv handlers.
2
3use super::{r2d2, ConnPool, WrConn};
4
5
6use threadpool::ThreadPool;
7
8use ump_ng::ReplyContext;
9
10// Re-export rusqlite from sqlsrv
11pub use sqlsrv::rusqlite;
12
13use rusqlite::Connection;
14
15pub enum Error<E> {
16  R2D2(r2d2::Error),
17  App(E)
18}
19
20
21/// Given an [`ConnPool`] and a [`ReplyContext`], run a closure (presumably
22/// performing read-only database operations).
23///
24/// Translates the closure's `Result<T, E>` into a `ReplyContext::reply()` on
25/// `Ok` and `ReplyContext::fail()` on `Err`.
26///
27/// # Errors
28/// [`r2d2::Error`] is returned if a read-only connection could not be
29/// acquired from the connection pool.
30pub fn proc_rodb_req<R, E, F>(
31  cpool: &ConnPool,
32  rctx: ReplyContext<R, E>,
33  f: F
34) -> Result<(), r2d2::Error>
35where
36  R: Send + 'static,
37  E: std::error::Error + Send + 'static,
38  F: FnOnce(&Connection) -> Result<R, E> + Send + 'static
39{
40  let roconn = cpool.reader()?;
41
42  let res = match f(&roconn) {
43    Ok(reply) => rctx.reply(reply),
44    Err(e) => rctx.fail(e)
45  };
46  if let Err(e) = res {
47    eprintln!("Reply message pass failed; {e}");
48  }
49
50  Ok(())
51}
52
53/// Process a requested read-only database message on a thread pool.
54///
55/// The read-only database connection will be acquired from the connection pool
56/// `cpool`.  The tread will be launched on the thread pool `tpool`.
57///
58/// The closure `f` returns a `Result<T, E>`, where the `Ok(T)` case will pass
59/// the `T` to the `rctx`'s [`reply()`](ReplyContext::reply), and `Err(E)` will
60/// pass the `E` to [`fail()`](ReplyContext::fail).
61///
62/// # Errors
63/// [`r2d2::Error`] is returned if a read-only connection could not be
64/// acquired from the connection pool.
65pub fn proc_rodb_req_thrd<R, E, F>(
66  cpool: &ConnPool,
67  tpool: &ThreadPool,
68  rctx: ReplyContext<R, E>,
69  f: F
70) -> Result<(), r2d2::Error>
71where
72  R: Send + 'static,
73  E: std::error::Error + Send + 'static,
74  F: FnOnce(&Connection) -> Result<R, E> + Send + 'static
75{
76  let roconn = cpool.reader()?;
77
78  tpool.execute(move || {
79    let res = match f(&roconn) {
80      Ok(reply) => rctx.reply(reply),
81      Err(e) => rctx.fail(e)
82    };
83    if let Err(e) = res {
84      eprintln!("Reply message pass failed; {e}");
85    }
86  });
87
88  Ok(())
89}
90
91/// Process a requested read/write database message.
92pub fn proc_rwdb_req<R, E, F>(cpool: &ConnPool, rctx: ReplyContext<R, E>, f: F)
93where
94  R: Send + 'static,
95  E: std::error::Error + Send + 'static,
96  F: FnOnce(&mut WrConn) -> Result<R, E> + Send + 'static
97{
98  let mut conn = cpool.writer();
99
100  let res = match f(&mut conn) {
101    Ok(reply) => rctx.reply(reply),
102    Err(e) => rctx.fail(e)
103  };
104  if let Err(e) = res {
105    eprintln!("Reply message pass failed; {e}");
106  }
107}
108
109/// Process a requested read/write database message on a thread pool.
110///
111/// The read/write database connection will be acquired from the connection
112/// pool `cpool`.  The tread will be launched on the thread pool `tpool`.
113///
114/// The closure `f` returns a `Result<T, E>`, where the `Ok(T)` case will pass
115/// the `T` to the `rctx`'s [`reply()`](ReplyContext::reply), and `Err(E)` will
116/// pass the `E` to [`fail()`](ReplyContext::fail).
117pub fn proc_rwdb_req_thrd<R, E, F>(
118  cpool: &ConnPool,
119  tpool: &ThreadPool,
120  rctx: ReplyContext<R, E>,
121  f: F
122) where
123  R: Send + 'static,
124  E: std::error::Error + Send + 'static,
125  F: FnOnce(&mut WrConn) -> Result<R, E> + Send + 'static
126{
127  let mut rwconn = cpool.writer();
128
129  tpool.execute(move || {
130    let res = match f(&mut rwconn) {
131      Ok(reply) => rctx.reply(reply),
132      Err(e) => rctx.fail(e)
133    };
134    if let Err(e) = res {
135      eprintln!("Reply message pass failed; {e}");
136    }
137  });
138}
139
140// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :