From a6a621b540b218cc22210199fc00f777d6060402 Mon Sep 17 00:00:00 2001 From: vwency Date: Mon, 1 Dec 2025 02:59:55 +0600 Subject: [PATCH 1/4] feat(query): readonly configuration method added --- src/query.rs | 6 ++++++ tests/it/query_readonly.rs | 20 ++++++++++---------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/query.rs b/src/query.rs index 25f21af..5b794f3 100644 --- a/src/query.rs +++ b/src/query.rs @@ -239,6 +239,12 @@ impl Query { self.client.add_option(name, value); self } + + /// Set read-only option for this query. + pub fn readonly(self, enabled: bool) -> Self { + let value = if enabled { "1" } else { "0" }; + self.with_option("readonly", value) + } /// Specify server side parameter for query. /// diff --git a/tests/it/query_readonly.rs b/tests/it/query_readonly.rs index a4de5e6..da4f9bd 100644 --- a/tests/it/query_readonly.rs +++ b/tests/it/query_readonly.rs @@ -45,14 +45,14 @@ async fn test_fetch(client: &Client) { "initial `fetch` readonly setting value should be 1" ); - let query = select_readonly_setting_query(client).with_option("readonly", "0"); + let query = select_readonly_setting_query(client).readonly(false); let disabled_readonly_row = run_fetch(query).await; assert_eq!( disabled_readonly_row.value, "0", "`fetch` modified readonly setting value should be 0" ); - let query = select_readonly_setting_query(client).with_option("readonly", "1"); + let query = select_readonly_setting_query(client).readonly(true); let same_readonly_row = run_fetch(query).await; assert_eq!( same_readonly_row.value, "1", @@ -68,14 +68,14 @@ async fn test_fetch_bytes(client: &Client) { "initial `fetch_bytes` readonly setting value should be 1" ); - let query = select_readonly_setting_query(client).with_option("readonly", "0"); + let query = select_readonly_setting_query(client).readonly(false); let disabled_readonly_value = run_fetch_bytes(query).await; assert_eq!( disabled_readonly_value, b"0\n", "`fetch_bytes` modified readonly setting value should be 0" ); - let query = select_readonly_setting_query(client).with_option("readonly", "1"); + let query = select_readonly_setting_query(client).readonly(true); let same_readonly_value = run_fetch_bytes(query).await; assert_eq!( same_readonly_value, b"1\n", @@ -91,14 +91,14 @@ async fn test_fetch_one(client: &Client) { "initial `fetch_one` readonly setting value should be 1" ); - let query = select_readonly_setting_query(client).with_option("readonly", "0"); + let query = select_readonly_setting_query(client).readonly(false); let disabled_readonly_value: String = run_fetch_one(query).await; assert_eq!( disabled_readonly_value, "0", "`fetch_one` modified readonly setting value should be 0" ); - let query = select_readonly_setting_query(client).with_option("readonly", "1"); + let query = select_readonly_setting_query(client).readonly(true); let same_readonly_value: String = run_fetch_one(query).await; assert_eq!( same_readonly_value, "1", @@ -115,7 +115,7 @@ async fn test_fetch_optional(client: &Client) { "initial `fetch_optional` readonly setting value should be 1" ); - let query = select_readonly_setting_query(client).with_option("readonly", "0"); + let query = select_readonly_setting_query(client).readonly(false); let disabled_readonly_value: Option = run_fetch_optional(query).await; assert_eq!( disabled_readonly_value.as_deref(), @@ -123,7 +123,7 @@ async fn test_fetch_optional(client: &Client) { "`fetch_optional` modified readonly setting value should be 0" ); - let query = select_readonly_setting_query(client).with_option("readonly", "1"); + let query = select_readonly_setting_query(client).readonly(true); let same_readonly_value: Option = run_fetch_optional(query).await; assert_eq!( same_readonly_value.as_deref(), @@ -141,7 +141,7 @@ async fn test_fetch_all(client: &Client) { "initial `fetch_all` readonly setting value should be 1" ); - let query = select_readonly_setting_query(client).with_option("readonly", "0"); + let query = select_readonly_setting_query(client).readonly(false); let disabled_readonly_value: Vec = run_fetch_all(query).await; assert_eq!( disabled_readonly_value, @@ -149,7 +149,7 @@ async fn test_fetch_all(client: &Client) { "`fetch_all` modified readonly setting value should be 0" ); - let query = select_readonly_setting_query(client).with_option("readonly", "1"); + let query = select_readonly_setting_query(client).readonly(true); let same_readonly_value: Vec = run_fetch_all(query).await; assert_eq!( same_readonly_value, From f232454e8144e5fe5309305fe497113dad7f5ee9 Mon Sep 17 00:00:00 2001 From: vwency Date: Tue, 2 Dec 2025 17:53:31 +0600 Subject: [PATCH 2/4] refactor(query::readonly): removed using with_options directly insert in options --- src/query.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/query.rs b/src/query.rs index 5b794f3..c515bac 100644 --- a/src/query.rs +++ b/src/query.rs @@ -171,12 +171,8 @@ impl Query { // Normally, we enforce `readonly` for all `fetch_*` operations. // However, we still allow overriding it to support several niche use-cases, // e.g., temporary tables usage. See https://github.com/ClickHouse/clickhouse-rs/issues/230 - if readonly { - let readonly_value = match self.client.options.get(settings::READONLY) { - None => "1", - Some(value) => value, - }; - pairs.append_pair(settings::READONLY, readonly_value); + if readonly && !self.client.options.contains_key(settings::READONLY) { + pairs.append_pair(settings::READONLY, "1"); } if self.client.compression.is_lz4() { @@ -241,9 +237,10 @@ impl Query { } /// Set read-only option for this query. - pub fn readonly(self, enabled: bool) -> Self { + pub fn readonly(mut self, enabled: bool) -> Self { let value = if enabled { "1" } else { "0" }; - self.with_option("readonly", value) + self.client.options.insert(settings::READONLY.to_string(), value.to_string()); + self } /// Specify server side parameter for query. From e9e5033f54043608fa51faa9c32ad14886d95434 Mon Sep 17 00:00:00 2001 From: vwency Date: Tue, 2 Dec 2025 17:56:13 +0600 Subject: [PATCH 3/4] refactor(codestyle): back code design for default readonly value --- src/query.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/query.rs b/src/query.rs index c515bac..7254e1c 100644 --- a/src/query.rs +++ b/src/query.rs @@ -171,8 +171,12 @@ impl Query { // Normally, we enforce `readonly` for all `fetch_*` operations. // However, we still allow overriding it to support several niche use-cases, // e.g., temporary tables usage. See https://github.com/ClickHouse/clickhouse-rs/issues/230 - if readonly && !self.client.options.contains_key(settings::READONLY) { - pairs.append_pair(settings::READONLY, "1"); + if readonly { + let readonly_value = match self.client.options.get(settings::READONLY) { + None => "1", + Some(value) => value, + }; + pairs.append_pair(settings::READONLY, readonly_value); } if self.client.compression.is_lz4() { From 2ee30598ed41b1a8570070ea146c54abe5eda3a2 Mon Sep 17 00:00:00 2001 From: vwency Date: Tue, 2 Dec 2025 17:59:49 +0600 Subject: [PATCH 4/4] chore(changelog): update set readonly method --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7e0cba..cdc1ebd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Optimize `RowCursor` by reusing buffer capacity where possible. ([#340]) * All `Query::fetch*` methods will always use POST instead of GET. It is now allowed to change `readonly` value via - `Query::with_option`. ([#342]) + `Query::readonly`. ([#342]) * In case of a schema mismatch, the client now emits `clickhouse::error::Error::SchemaMismatch` instead of panicking. ([#346]) * Removed [replace_with], [static_assertions], and [sealed] from the crate dependencies. ([#353])