From efe7a989515966a65a3e1711abe1900549caa0b1 Mon Sep 17 00:00:00 2001 From: Pierre Merlin Date: Wed, 24 Jun 2026 14:10:26 +0200 Subject: [PATCH] Add adhoc option to control prepared-statement caching Default adhoc to true in N1ql.config to preserve current behavior (queries are not cached). When set to false, Couchbase will cache the parameterized query plan, improving performance for repeated queries. The option is forwarded to Couchbase::Options::Query in both n1ql and relation query paths. Co-Authored-By: Claude Opus 4.6 --- lib/couchbase-orm/n1ql.rb | 8 +++++--- lib/couchbase-orm/relation.rb | 2 ++ spec/n1ql_spec.rb | 8 ++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index 2b2e999..9d8c706 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -23,7 +23,8 @@ def self.sanitize(value) def self.config(new_config = nil) Thread.current['__couchbaseorm_n1ql_config__'] = new_config if new_config Thread.current['__couchbaseorm_n1ql_config__'] || { - scan_consistency: DEFAULT_SCAN_CONSISTENCY + scan_consistency: DEFAULT_SCAN_CONSISTENCY, + adhoc: true } end @@ -130,10 +131,11 @@ def run_query(keys, values, query_fn, custom_order: nil, descending: false, limi limit = build_limit(limit) n1ql_query = "select raw meta().id from `#{bucket_name}` where #{where} order by #{order} #{limit}" - query_options = options.merge(positional_parameters: params) + adhoc = options.delete(:adhoc) { CouchbaseOrm::N1ql.config[:adhoc] } + query_options = options.merge(positional_parameters: params, adhoc: adhoc) result = cluster.query(n1ql_query, Couchbase::Options::Query.new(**query_options)) CouchbaseOrm.logger.debug { - "N1QL query: #{n1ql_query} params: #{params.inspect} return #{result.rows.to_a.length} rows with scan_consistency: #{options[:scan_consistency]}" + "N1QL query: #{n1ql_query} params: #{params.inspect} return #{result.rows.to_a.length} rows with scan_consistency: #{options[:scan_consistency]} adhoc: #{adhoc}" } N1qlProxy.new(result) end diff --git a/lib/couchbase-orm/relation.rb b/lib/couchbase-orm/relation.rb index 9735aaf..094334d 100644 --- a/lib/couchbase-orm/relation.rb +++ b/lib/couchbase-orm/relation.rb @@ -236,6 +236,8 @@ def build_update_with_params(params, **cond) def build_query_options(positional_parameters: []) opts = { scan_consistency: CouchbaseOrm::N1ql.config[:scan_consistency] } opts[:positional_parameters] = positional_parameters unless positional_parameters.empty? + adhoc = CouchbaseOrm::N1ql.config[:adhoc] + opts[:adhoc] = adhoc unless adhoc.nil? Couchbase::Options::Query.new(**opts) end diff --git a/spec/n1ql_spec.rb b/spec/n1ql_spec.rb index 15dacdd..45d8f8c 100644 --- a/spec/n1ql_spec.rb +++ b/spec/n1ql_spec.rb @@ -174,25 +174,25 @@ class N1QLTest < CouchbaseOrm::Base N1QLTest.by_rating_reverse() expect(CouchbaseOrm.logger).to have_received(:debug).at_least(:once) do |&block| msg = block ? block.call : nil - msg == "N1QL query: select raw meta().id from `#{CouchbaseOrm::Connection.bucket.name}` where type=$1 order by name DESC params: [\"n1_ql_test\"] return 0 rows with scan_consistency: #{described_class::DEFAULT_SCAN_CONSISTENCY}" + msg == "N1QL query: select raw meta().id from `#{CouchbaseOrm::Connection.bucket.name}` where type=$1 order by name DESC params: [\"n1_ql_test\"] return 0 rows with scan_consistency: #{described_class::DEFAULT_SCAN_CONSISTENCY} adhoc: true" end end it "should log the set scan_consistency when n1ql query is executed with a specific scan_consistency" do allow(CouchbaseOrm.logger).to receive(:debug) default_n1ql_config = CouchbaseOrm::N1ql.config - CouchbaseOrm::N1ql.config({ scan_consistency: :not_bounded }) + CouchbaseOrm::N1ql.config({ scan_consistency: :not_bounded, adhoc: true }) N1QLTest.by_rating_reverse() expect(CouchbaseOrm.logger).to have_received(:debug).at_least(:once) do |&block| msg = block ? block.call : nil - msg == "N1QL query: select raw meta().id from `#{CouchbaseOrm::Connection.bucket.name}` where type=$1 order by name DESC params: [\"n1_ql_test\"] return 0 rows with scan_consistency: not_bounded" + msg == "N1QL query: select raw meta().id from `#{CouchbaseOrm::Connection.bucket.name}` where type=$1 order by name DESC params: [\"n1_ql_test\"] return 0 rows with scan_consistency: not_bounded adhoc: true" end CouchbaseOrm::N1ql.config(default_n1ql_config) N1QLTest.by_rating_reverse() expect(CouchbaseOrm.logger).to have_received(:debug).at_least(:once) do |&block| msg = block ? block.call : nil - msg == "N1QL query: select raw meta().id from `#{CouchbaseOrm::Connection.bucket.name}` where type=$1 order by name DESC params: [\"n1_ql_test\"] return 0 rows with scan_consistency: #{described_class::DEFAULT_SCAN_CONSISTENCY}" + msg == "N1QL query: select raw meta().id from `#{CouchbaseOrm::Connection.bucket.name}` where type=$1 order by name DESC params: [\"n1_ql_test\"] return 0 rows with scan_consistency: #{described_class::DEFAULT_SCAN_CONSISTENCY} adhoc: true" end end