couchbase-orm 3.1.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +4 -12
- data/couchbase-orm.gemspec +1 -1
- data/docusaurus/docs/tutorial-ruby-couchbase-orm/07-sqlpp-queries.md +41 -0
- data/lib/couchbase-orm/n1ql.rb +9 -4
- data/lib/couchbase-orm/relation.rb +9 -4
- data/lib/couchbase-orm/version.rb +1 -1
- data/spec/n1ql_spec.rb +19 -0
- data/spec/relation_spec.rb +33 -0
- metadata +4 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 253e0ee05a3522f641294d615724214c6b03ebfd189f008544e9a41f0e671916
|
|
4
|
+
data.tar.gz: 7628e1f89db8f7649dd6795145b238a06af87cb1901e30337670c3f15b87378c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: af199f51fb0fd808ac4920ca8eb16d50b8d6afa89a23cd311d5e39e92df87f93914368267afd373e7d8d282e50e517b892039008f3a2d234ef5bf1ea2b63bb83
|
|
7
|
+
data.tar.gz: b0703729ad90b504026467377aecdeaed17434010f044ede50d0645ef1e51d9dadef595c31ad1f1990d7366ba7f4101c934c716f4f8cb2152a70d0f846ad7e88
|
data/.github/workflows/test.yml
CHANGED
|
@@ -20,23 +20,15 @@ jobs:
|
|
|
20
20
|
- ruby: '3.3'
|
|
21
21
|
active-model: '7.2'
|
|
22
22
|
couchbase: '7.2.3'
|
|
23
|
-
- ruby: '3.2'
|
|
24
|
-
active-model: '7.2.0'
|
|
25
|
-
couchbase: '7.1.1'
|
|
26
|
-
- ruby: '3.2'
|
|
27
|
-
active-model: '7.1.0'
|
|
28
|
-
couchbase: '6.6.5'
|
|
29
|
-
- ruby: '3.1'
|
|
30
|
-
active-model: '7.1.0'
|
|
31
|
-
couchbase: '7.1.0'
|
|
32
23
|
fail-fast: false
|
|
33
24
|
runs-on: ubuntu-24.04
|
|
34
25
|
name: ${{ matrix.ruby }} rails-${{ matrix.active-model }} couchbase-${{ matrix.couchbase }}
|
|
35
26
|
steps:
|
|
36
27
|
- uses: actions/checkout@v3
|
|
37
|
-
- run:
|
|
38
|
-
|
|
39
|
-
|
|
28
|
+
- run: |
|
|
29
|
+
sudo apt-get update
|
|
30
|
+
sudo apt-get install -y libevent-dev libev-dev python3-httplib2
|
|
31
|
+
sudo apt-get install -y libtinfo5 || sudo apt-get install -y libtinfo6
|
|
40
32
|
- uses: ruby/setup-ruby@v1
|
|
41
33
|
with:
|
|
42
34
|
ruby-version: ${{ matrix.ruby }}
|
data/couchbase-orm.gemspec
CHANGED
|
@@ -15,7 +15,7 @@ Gem::Specification.new do |gem|
|
|
|
15
15
|
gem.summary = 'Couchbase ORM for Rails'
|
|
16
16
|
gem.description = 'A Couchbase ORM for Rails'
|
|
17
17
|
|
|
18
|
-
gem.required_ruby_version = '>= 3.
|
|
18
|
+
gem.required_ruby_version = '>= 3.3.0'
|
|
19
19
|
gem.require_paths = ['lib']
|
|
20
20
|
|
|
21
21
|
gem.add_runtime_dependency 'activemodel', ENV['ACTIVE_MODEL_VERSION'] || '>= 7.1'
|
|
@@ -147,6 +147,47 @@ docs = N1QLTest.by_custom_rating_values(key: [[1, 2]]).collect { |ob| ob.name }
|
|
|
147
147
|
|
|
148
148
|
In the above examples, the `collect` method is used to extract the `name` attribute from each document in the result set.
|
|
149
149
|
|
|
150
|
+
## 7.8 Prepared Statement Plan Caching
|
|
151
|
+
|
|
152
|
+
Couchbase Server can cache the query execution plan for a SQL++ query so that subsequent executions skip the planning step. This is controlled by the `adhoc` query option: `adhoc: false` tells the server to prepare and cache the plan on first execution and reuse it on subsequent ones.
|
|
153
|
+
|
|
154
|
+
### Default behaviour
|
|
155
|
+
|
|
156
|
+
By default CouchbaseOrm runs queries with `adhoc: true` (the Couchbase SDK default), meaning no plan caching. This preserves the existing behaviour — you opt into plan caching explicitly.
|
|
157
|
+
|
|
158
|
+
### Enabling caching for a specific call
|
|
159
|
+
|
|
160
|
+
Pass `adhoc: false` directly to the query method to prepare and cache the plan (useful for frequently repeated queries):
|
|
161
|
+
|
|
162
|
+
```ruby
|
|
163
|
+
# Cache the plan for this query
|
|
164
|
+
N1QLTest.by_rating(key: 1, adhoc: false)
|
|
165
|
+
|
|
166
|
+
# Relation query with plan caching
|
|
167
|
+
User.where(country: 'FR').with(adhoc: false).to_a
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Enabling caching for a specific `n1ql` definition
|
|
171
|
+
|
|
172
|
+
Set `adhoc: false` in the macro options to always cache the plan for that particular query:
|
|
173
|
+
|
|
174
|
+
```ruby
|
|
175
|
+
n1ql :by_stable_filter, emit_key: [:name], adhoc: false
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Changing the global default
|
|
179
|
+
|
|
180
|
+
Override the thread-local config to change the default for all queries in the current thread:
|
|
181
|
+
|
|
182
|
+
```ruby
|
|
183
|
+
# Enable plan caching for all queries in this thread
|
|
184
|
+
CouchbaseOrm::N1ql.config(adhoc: false)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Override priority
|
|
188
|
+
|
|
189
|
+
From highest to lowest: **per-call kwarg** > **per-`n1ql`-definition option** > **`N1ql.config`** > **default (`true`)**.
|
|
190
|
+
|
|
150
191
|
## 7.7 Indexing for SQL++
|
|
151
192
|
|
|
152
193
|
To optimize the performance of SQL++ queries, it's important to create appropriate indexes on the fields used in the query conditions. Couchbase Server provides a way to create indexes using the Index service.
|
data/lib/couchbase-orm/n1ql.rb
CHANGED
|
@@ -9,6 +9,7 @@ module CouchbaseOrm
|
|
|
9
9
|
extend ActiveSupport::Concern
|
|
10
10
|
NO_VALUE = :no_value_specified
|
|
11
11
|
DEFAULT_SCAN_CONSISTENCY = :request_plus
|
|
12
|
+
DEFAULT_ADHOC = true
|
|
12
13
|
# sanitize for injection query
|
|
13
14
|
def self.sanitize(value)
|
|
14
15
|
if value.is_a?(String)
|
|
@@ -22,9 +23,10 @@ module CouchbaseOrm
|
|
|
22
23
|
|
|
23
24
|
def self.config(new_config = nil)
|
|
24
25
|
Thread.current['__couchbaseorm_n1ql_config__'] = new_config if new_config
|
|
25
|
-
|
|
26
|
-
scan_consistency: DEFAULT_SCAN_CONSISTENCY
|
|
27
|
-
|
|
26
|
+
{
|
|
27
|
+
scan_consistency: DEFAULT_SCAN_CONSISTENCY,
|
|
28
|
+
adhoc: DEFAULT_ADHOC
|
|
29
|
+
}.merge(Thread.current['__couchbaseorm_n1ql_config__'] || {})
|
|
28
30
|
end
|
|
29
31
|
|
|
30
32
|
module ClassMethods
|
|
@@ -57,7 +59,10 @@ module CouchbaseOrm
|
|
|
57
59
|
@indexes[name] = method_opts
|
|
58
60
|
|
|
59
61
|
singleton_class.__send__(:define_method, name) do |key: NO_VALUE, **opts, &result_modifier|
|
|
60
|
-
opts = options.merge(opts).reverse_merge(
|
|
62
|
+
opts = options.merge(opts).reverse_merge(
|
|
63
|
+
scan_consistency: CouchbaseOrm::N1ql.config[:scan_consistency],
|
|
64
|
+
adhoc: CouchbaseOrm::N1ql.config[:adhoc]
|
|
65
|
+
)
|
|
61
66
|
values = key == NO_VALUE ? NO_VALUE : convert_values(method_opts[:emit_key], key)
|
|
62
67
|
current_query = run_query(method_opts[:emit_key], values, query_fn, custom_order: custom_order, **opts.except(:include_docs, :key))
|
|
63
68
|
if result_modifier
|
|
@@ -3,7 +3,7 @@ module CouchbaseOrm
|
|
|
3
3
|
extend ActiveSupport::Concern
|
|
4
4
|
|
|
5
5
|
class CouchbaseOrm_Relation
|
|
6
|
-
def initialize(model:, where: where = nil, order: order = nil, limit: limit = nil, _not: _not = false, strict_loading: strict_loading = false)
|
|
6
|
+
def initialize(model:, where: where = nil, order: order = nil, limit: limit = nil, _not: _not = false, strict_loading: strict_loading = false, query_options: query_options = {})
|
|
7
7
|
CouchbaseOrm::logger.debug "CouchbaseOrm_Relation init: #{model} where:#{where.inspect} not:#{_not.inspect} order:#{order.inspect} limit: #{limit} strict_loading: #{strict_loading}"
|
|
8
8
|
@model = model
|
|
9
9
|
@limit = limit
|
|
@@ -12,6 +12,7 @@ module CouchbaseOrm
|
|
|
12
12
|
@order = merge_order(**order) if order
|
|
13
13
|
@where = merge_where(where, _not) if where
|
|
14
14
|
@strict_loading = strict_loading
|
|
15
|
+
@query_options = query_options || {}
|
|
15
16
|
CouchbaseOrm::logger.debug "- #{to_s}"
|
|
16
17
|
end
|
|
17
18
|
|
|
@@ -70,6 +71,10 @@ module CouchbaseOrm
|
|
|
70
71
|
!!@strict_loading
|
|
71
72
|
end
|
|
72
73
|
|
|
74
|
+
def with(opts = {})
|
|
75
|
+
CouchbaseOrm_Relation.new(**initializer_arguments.merge(query_options: @query_options.merge(opts)))
|
|
76
|
+
end
|
|
77
|
+
|
|
73
78
|
def first
|
|
74
79
|
n1ql_query, params = self.limit(1).to_n1ql_with_params
|
|
75
80
|
result = @model.cluster.query(n1ql_query, build_query_options(positional_parameters: params))
|
|
@@ -168,7 +173,7 @@ module CouchbaseOrm
|
|
|
168
173
|
end
|
|
169
174
|
|
|
170
175
|
def initializer_arguments
|
|
171
|
-
{ model: @model, order: @order, where: @where, limit: @limit, strict_loading: @strict_loading }
|
|
176
|
+
{ model: @model, order: @order, where: @where, limit: @limit, strict_loading: @strict_loading, query_options: @query_options }
|
|
172
177
|
end
|
|
173
178
|
|
|
174
179
|
def merge_order(*lorder, **horder)
|
|
@@ -238,7 +243,7 @@ module CouchbaseOrm
|
|
|
238
243
|
end
|
|
239
244
|
|
|
240
245
|
def build_query_options(positional_parameters: [])
|
|
241
|
-
opts =
|
|
246
|
+
opts = CouchbaseOrm::N1ql.config.merge(@query_options)
|
|
242
247
|
opts[:positional_parameters] = positional_parameters unless positional_parameters.empty?
|
|
243
248
|
Couchbase::Options::Query.new(**opts)
|
|
244
249
|
end
|
|
@@ -261,7 +266,7 @@ module CouchbaseOrm
|
|
|
261
266
|
|
|
262
267
|
delegate :ids, :update_all, :delete_all, :count, :empty?, :filter, :reduce, :find_by, to: :all
|
|
263
268
|
|
|
264
|
-
delegate :where, :not, :order, :limit, :all, :strict_loading, :strict_loading?, to: :relation
|
|
269
|
+
delegate :where, :not, :order, :limit, :all, :strict_loading, :strict_loading?, :with, to: :relation
|
|
265
270
|
end
|
|
266
271
|
end
|
|
267
272
|
end
|
data/spec/n1ql_spec.rb
CHANGED
|
@@ -196,6 +196,25 @@ describe CouchbaseOrm::N1ql do
|
|
|
196
196
|
end
|
|
197
197
|
end
|
|
198
198
|
|
|
199
|
+
it "should use adhoc: true by default (no prepared statement plan caching)" do
|
|
200
|
+
expect(Couchbase::Options::Query).to receive(:new).with(hash_including(adhoc: true)).and_call_original
|
|
201
|
+
N1QLTest.by_rating_reverse()
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
it "should allow overriding adhoc per call to enable plan caching" do
|
|
205
|
+
expect(Couchbase::Options::Query).to receive(:new).with(hash_including(adhoc: false)).and_call_original
|
|
206
|
+
N1QLTest.by_rating_reverse(adhoc: false)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
it "should respect N1ql.config adhoc setting" do
|
|
210
|
+
default_config = CouchbaseOrm::N1ql.config
|
|
211
|
+
CouchbaseOrm::N1ql.config({ adhoc: false })
|
|
212
|
+
expect(Couchbase::Options::Query).to receive(:new).with(hash_including(adhoc: false)).and_call_original
|
|
213
|
+
N1QLTest.by_rating_reverse()
|
|
214
|
+
ensure
|
|
215
|
+
CouchbaseOrm::N1ql.config(default_config)
|
|
216
|
+
end
|
|
217
|
+
|
|
199
218
|
after(:all) do
|
|
200
219
|
N1QLTest.delete_all
|
|
201
220
|
end
|
data/spec/relation_spec.rb
CHANGED
|
@@ -501,5 +501,38 @@ describe CouchbaseOrm::Relation do
|
|
|
501
501
|
end
|
|
502
502
|
end
|
|
503
503
|
end
|
|
504
|
+
|
|
505
|
+
it "should use adhoc: true by default (no prepared statement plan caching)" do
|
|
506
|
+
expect(Couchbase::Options::Query).to receive(:new).with(hash_including(adhoc: true)).and_call_original
|
|
507
|
+
RelationModel.where(active: true).ids
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
describe "adhoc option via with" do
|
|
511
|
+
it "should return a relation when calling with(adhoc:)" do
|
|
512
|
+
expect(RelationModel.all.with(adhoc: false)).to be_a(CouchbaseOrm::Relation::CouchbaseOrm_Relation)
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
it "should pass adhoc: false to query options when set on the relation" do
|
|
516
|
+
expect(Couchbase::Options::Query).to receive(:new).with(hash_including(adhoc: false)).and_call_original
|
|
517
|
+
RelationModel.where(active: true).with(adhoc: false).ids
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
it "should override N1ql.config adhoc when set on the relation" do
|
|
521
|
+
default_config = CouchbaseOrm::N1ql.config
|
|
522
|
+
CouchbaseOrm::N1ql.config(adhoc: false)
|
|
523
|
+
expect(Couchbase::Options::Query).to receive(:new).with(hash_including(adhoc: true)).and_call_original
|
|
524
|
+
RelationModel.where(active: true).with(adhoc: true).ids
|
|
525
|
+
ensure
|
|
526
|
+
CouchbaseOrm::N1ql.config(default_config)
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
it "should be chainable with other relation methods" do
|
|
530
|
+
m1 = RelationModel.create!(active: true, age: 10)
|
|
531
|
+
_m2 = RelationModel.create!(active: false, age: 20)
|
|
532
|
+
expect(Couchbase::Options::Query).to receive(:new).with(hash_including(adhoc: false)).and_call_original
|
|
533
|
+
result = RelationModel.where(active: true).order(:age).with(adhoc: false).to_a
|
|
534
|
+
expect(result).to match_array([m1])
|
|
535
|
+
end
|
|
536
|
+
end
|
|
504
537
|
end
|
|
505
538
|
|
metadata
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: couchbase-orm
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stephen von Takach
|
|
8
8
|
- Gauthier Monserand
|
|
9
9
|
- Pierre Merlin
|
|
10
10
|
- Julien Burnet-Fauche
|
|
11
|
-
autorequire:
|
|
12
11
|
bindir: bin
|
|
13
12
|
cert_chain: []
|
|
14
|
-
date:
|
|
13
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
15
14
|
dependencies:
|
|
16
15
|
- !ruby/object:Gem::Dependency
|
|
17
16
|
name: activemodel
|
|
@@ -210,7 +209,6 @@ dependencies:
|
|
|
210
209
|
- !ruby/object:Gem::Version
|
|
211
210
|
version: '0'
|
|
212
211
|
description: A Couchbase ORM for Rails
|
|
213
|
-
email:
|
|
214
212
|
executables: []
|
|
215
213
|
extensions: []
|
|
216
214
|
extra_rdoc_files: []
|
|
@@ -354,7 +352,6 @@ metadata:
|
|
|
354
352
|
bug_tracker_uri: https://github.com/Couchbase-Ecosystem/couchbase-ruby-orm/issues
|
|
355
353
|
documentation_uri: https://www.couchbase-ruby-orm.com/
|
|
356
354
|
homepage_uri: https://github.com/Couchbase-Ecosystem/couchbase-ruby-orm
|
|
357
|
-
post_install_message:
|
|
358
355
|
rdoc_options: []
|
|
359
356
|
require_paths:
|
|
360
357
|
- lib
|
|
@@ -362,15 +359,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
362
359
|
requirements:
|
|
363
360
|
- - ">="
|
|
364
361
|
- !ruby/object:Gem::Version
|
|
365
|
-
version: 3.
|
|
362
|
+
version: 3.3.0
|
|
366
363
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
367
364
|
requirements:
|
|
368
365
|
- - ">="
|
|
369
366
|
- !ruby/object:Gem::Version
|
|
370
367
|
version: '0'
|
|
371
368
|
requirements: []
|
|
372
|
-
rubygems_version:
|
|
373
|
-
signing_key:
|
|
369
|
+
rubygems_version: 4.0.10
|
|
374
370
|
specification_version: 4
|
|
375
371
|
summary: Couchbase ORM for Rails
|
|
376
372
|
test_files:
|