Skip to content

Commit d8a5b80

Browse files
committed
feat: add with_roles to Client, Query, Insert{er}
1 parent 476d846 commit d8a5b80

File tree

4 files changed

+65
-89
lines changed

4 files changed

+65
-89
lines changed

src/insert.rs

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ impl InsertState {
9595
}
9696
}
9797

98+
#[inline]
9899
fn expect_client_mut(&mut self) -> &mut Client {
99100
let Self::NotStarted { client, .. } = self else {
100101
panic!("cannot modify client options while an insert is in-progress")
@@ -182,29 +183,19 @@ impl<T> Insert<T> {
182183
self
183184
}
184185

185-
/// Set the [role] to use when executing `INSERT` statements.
186+
/// Configure the [roles] to use when executing `INSERT` statements.
186187
///
187-
/// Overrides any role previously set by [`Client::with_role()`] or [`Client::with_option()`].
188+
/// Overrides any roles previously set by this method, [`Insert::with_option`],
189+
/// [`Client::with_roles`] or [`Client::with_option`].
188190
///
189-
/// [role]: https://clickhouse.com/docs/operations/access-rights#role-management
191+
/// An empty iterator may be passed to clear the set roles.
190192
///
191-
/// # Panics
192-
/// If called after the request is started, e.g., after [`Insert::write`].
193-
pub fn with_role(mut self, role: impl Into<String>) -> Self {
194-
self.state.expect_client_mut().set_role(Some(role.into()));
195-
self
196-
}
197-
198-
/// Perform inserts without any explicit [role] set.
199-
///
200-
/// Overrides any role previously set by [`Client::with_role()`] or [`Client::with_option()`].
201-
///
202-
/// [role]: https://clickhouse.com/docs/operations/access-rights#role-management
193+
/// [roles]: https://clickhouse.com/docs/operations/access-rights#role-management
203194
///
204195
/// # Panics
205196
/// If called after the request is started, e.g., after [`Insert::write`].
206-
pub fn with_default_role(mut self) -> Self {
207-
self.state.expect_client_mut().set_role(None);
197+
pub fn with_roles(mut self, roles: impl IntoIterator<Item = impl Into<String>>) -> Self {
198+
self.state.expect_client_mut().set_roles(roles);
208199
self
209200
}
210201

src/inserter.rs

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -161,41 +161,30 @@ where
161161
self
162162
}
163163

164-
/// Set the [role] to use when executing `INSERT` statements.
164+
/// Set the [roles] to use when executing `INSERT` statements.
165165
///
166-
/// Overrides any role previously set by [`Client::with_role()`] or [`Client::with_option()`].
166+
/// Overrides any roles previously set by this method, [`Inserter::with_option`],
167+
/// [`Client::with_roles`] or [`Client::with_option`].
167168
///
168-
/// This does not take effect until the next `INSERT` statement begins
169-
/// if one is already in-progress.
170-
///
171-
/// If you have already begun writing data, you may call [`.force_commit()`][Self::force_commit]
172-
/// to end the current `INSERT` so this takes effect on the next call to [`.write()`][Self::write].
173-
///
174-
/// [role]: https://clickhouse.com/docs/operations/access-rights#role-management
175-
pub fn with_role(mut self, role: impl Into<String>) -> Self {
176-
self.client.set_role(Some(role.into()));
177-
self
178-
}
179-
180-
/// Perform inserts without any explicit [role] set.
181-
///
182-
/// Overrides any role previously set by [`Client::with_role()`] or [`Client::with_option()`].
169+
/// An empty iterator may be passed to clear the set roles.
183170
///
171+
/// # Note
184172
/// This does not take effect until the next `INSERT` statement begins
185173
/// if one is already in-progress.
186174
///
187175
/// If you have already begun writing data, you may call [`.force_commit()`][Self::force_commit]
188176
/// to end the current `INSERT` so this takes effect on the next call to [`.write()`][Self::write].
189177
///
190-
/// [role]: https://clickhouse.com/docs/operations/access-rights#role-management
191-
pub fn with_default_role(mut self) -> Self {
192-
self.client.set_role(None);
178+
/// [roles]: https://clickhouse.com/docs/operations/access-rights#role-management
179+
pub fn with_roles(mut self, roles: impl IntoIterator<Item = impl Into<String>>) -> Self {
180+
self.client.set_roles(roles);
193181
self
194182
}
195183

196184
/// Similar to [`Client::with_option`], but for the INSERT statements
197185
/// generated by this [`Inserter`] only.
198186
///
187+
/// # Note
199188
/// This does not take effect until the next `INSERT` statement begins
200189
/// if one is already in-progress.
201190
///

src/lib.rs

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub use clickhouse_macros::Row;
1616
use clickhouse_types::{Column, DataTypeNode};
1717

1818
use crate::_priv::row_insert_metadata_query;
19-
use std::borrow::Cow;
19+
use std::collections::HashSet;
2020
use std::{collections::HashMap, fmt::Display, sync::Arc};
2121
use tokio::sync::RwLock;
2222

@@ -58,7 +58,8 @@ pub struct Client {
5858
database: Option<String>,
5959
authentication: Authentication,
6060
compression: Compression,
61-
options: HashMap<Cow<'static, str>, String>,
61+
roles: HashSet<String>,
62+
options: HashMap<String, String>,
6263
headers: HashMap<String, String>,
6364
products_info: Vec<ProductInfo>,
6465
validation: bool,
@@ -122,6 +123,7 @@ impl Client {
122123
database: None,
123124
authentication: Authentication::default(),
124125
compression: Compression::default(),
126+
roles: HashSet::new(),
125127
options: HashMap::new(),
126128
headers: HashMap::new(),
127129
products_info: Vec::default(),
@@ -228,27 +230,32 @@ impl Client {
228230
self
229231
}
230232

231-
/// Set the [role] to use when executing statements with this `Client` instance.
233+
/// Configure the [roles] to use when executing statements with this `Client` instance.
232234
///
233-
/// Overrides any role previously set by [`Client::with_role()`] or [`Client::with_option()`].
235+
/// Overrides any roles previously set by this method or [`Client::with_option`].
236+
///
237+
/// An empty iterator may be passed to clear the set roles.
234238
///
235239
/// This setting is copied into cloned clients.
236240
///
237-
/// [role]: https://clickhouse.com/docs/operations/access-rights#role-management
238-
pub fn with_role(mut self, role: impl Into<String>) -> Self {
239-
self.set_role(Some(role.into()));
240-
self
241-
}
242-
243-
/// Execute subsequent statements with this `Client` instance without any explicit [role] set.
241+
/// [roles]: https://clickhouse.com/docs/operations/access-rights#role-management
244242
///
245-
/// Overrides any role previously set by [`Client::with_role()`] or [`Client::with_option()`].
243+
/// # Examples
246244
///
247-
/// This setting is copied into cloned clients.
245+
/// ```
246+
/// # use clickhouse::Client;
247+
///
248+
/// # Single role
249+
/// let client = Client::default().with_roles(["foo"]);
248250
///
249-
/// [role]: https://clickhouse.com/docs/operations/access-rights#role-management
250-
pub fn with_default_role(mut self) -> Self {
251-
self.set_role(None);
251+
/// # Multiple roles
252+
/// let client = Client::default().with_roles(["foo", "bar", "baz"]);
253+
///
254+
/// # Clear all previously set roles
255+
/// let client = Client::default().with_roles([]);
256+
/// ```
257+
pub fn with_roles(mut self, roles: impl IntoIterator<Item = impl Into<String>>) -> Self {
258+
self.set_roles(roles);
252259
self
253260
}
254261

@@ -303,7 +310,7 @@ impl Client {
303310
/// Client::default().with_option("allow_nondeterministic_mutations", "1");
304311
/// ```
305312
pub fn with_option(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
306-
self.options.insert(Cow::Owned(name.into()), value.into());
313+
self.options.insert(name.into(), value.into());
307314
self
308315
}
309316

@@ -472,22 +479,15 @@ impl Client {
472479
/// Used internally to modify the options map of an _already cloned_
473480
/// [`Client`] instance.
474481
pub(crate) fn add_option(&mut self, name: impl Into<String>, value: impl Into<String>) {
475-
self.options.insert(Cow::Owned(name.into()), value.into());
482+
self.options.insert(name.into(), value.into());
476483
}
477484

478-
pub(crate) fn set_role(&mut self, role: Option<String>) {
479-
// By setting the role via `options`, we can be sure we've overwritten any role
480-
// manually set by the user with `with_option()`.
481-
let key = Cow::Borrowed("role");
485+
pub(crate) fn set_roles(&mut self, roles: impl IntoIterator<Item = impl Into<String>>) {
486+
// Make sure we overwrite any role manually set by the user via `with_option()`.
487+
self.options.remove("role");
482488

483-
match role {
484-
Some(role) => {
485-
self.options.insert(key, role);
486-
}
487-
None => {
488-
self.options.remove(&key);
489-
}
490-
}
489+
self.roles.clear();
490+
self.roles.extend(roles.into_iter().map(Into::into));
491491
}
492492

493493
/// Use a mock server for testing purposes.

src/query.rs

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -39,28 +39,6 @@ impl Query {
3939
&self.sql
4040
}
4141

42-
/// Perform this query with the given [role] set.
43-
///
44-
/// Overrides any role previously set
45-
///
46-
/// [role]: https://clickhouse.com/docs/operations/access-rights#role-management
47-
pub fn with_role(self, role: impl Into<String>) -> Self {
48-
Self {
49-
client: self.client.with_role(role),
50-
..self
51-
}
52-
}
53-
54-
/// Perform this query without any explicit [role] set.
55-
///
56-
/// [role]: https://clickhouse.com/docs/operations/access-rights#role-management
57-
pub fn with_default_role(self) -> Self {
58-
Self {
59-
client: self.client.with_default_role(),
60-
..self
61-
}
62-
}
63-
6442
/// Binds `value` to the next `?` in the query.
6543
///
6644
/// The `value`, which must either implement [`Serialize`] or be an
@@ -211,6 +189,9 @@ impl Query {
211189
for (name, value) in &self.client.options {
212190
pairs.append_pair(name, value);
213191
}
192+
193+
pairs.extend_pairs(self.client.roles.iter().map(|role| ("role", role)));
194+
214195
drop(pairs);
215196

216197
let mut builder = Request::builder().method(method).uri(url.as_str());
@@ -231,6 +212,21 @@ impl Query {
231212
Ok(Response::new(future, self.client.compression))
232213
}
233214

215+
/// Configure the [roles] to use when executing this query.
216+
///
217+
/// Overrides any roles previously set by this method, [`Query::with_option`],
218+
/// [`Client::with_roles`] or [`Client::with_option`].
219+
///
220+
/// An empty iterator may be passed to clear the set roles.
221+
///
222+
/// [roles]: https://clickhouse.com/docs/operations/access-rights#role-management
223+
pub fn with_roles(self, roles: impl IntoIterator<Item = impl Into<String>>) -> Self {
224+
Self {
225+
client: self.client.with_roles(roles),
226+
..self
227+
}
228+
}
229+
234230
/// Similar to [`Client::with_option`], but for this particular query only.
235231
pub fn with_option(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
236232
self.client.add_option(name, value);

0 commit comments

Comments
 (0)