From 59ecbf6b32d62f65c9369a183bf5f523b90bdbdf Mon Sep 17 00:00:00 2001 From: CedricCouton Date: Tue, 28 Feb 2023 17:03:48 +0100 Subject: [PATCH 01/29] can override scan consistency --- lib/couchbase-orm/n1ql.rb | 10 +++++++++- lib/couchbase-orm/relation.rb | 6 +++--- lib/couchbase-orm/views.rb | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index 352ed30d..cba04901 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -19,6 +19,14 @@ def self.sanitize(value) end end + @@couchbase_orm_config_n1ql = nil + def self.config(new_config = nil) + @@couchbase_orm_config_n1ql = new_config if new_config + @@couchbase_orm_config_n1ql || { + :scan_consistency => :request_plus + } + end + module ClassMethods # Defines a query N1QL for the model # @@ -49,7 +57,7 @@ def n1ql(name, query_fn: nil, emit_key: [], custom_order: nil, **options) @indexes[name] = method_opts singleton_class.__send__(:define_method, name) do |key: NO_VALUE, **opts, &result_modifier| - opts = options.merge(opts).reverse_merge(scan_consistency: :request_plus) + opts = options.merge(opts).reverse_merge(scan_consistency: CouchbaseOrm::N1ql.config[:scan_consistency]) values = key == NO_VALUE ? NO_VALUE : convert_values(method_opts[:emit_key], key) current_query = run_query(method_opts[:emit_key], values, query_fn, custom_order: custom_order, **opts.except(:include_docs, :key)) if result_modifier diff --git a/lib/couchbase-orm/relation.rb b/lib/couchbase-orm/relation.rb index 8a92ece7..5beb4b2d 100644 --- a/lib/couchbase-orm/relation.rb +++ b/lib/couchbase-orm/relation.rb @@ -27,7 +27,7 @@ def to_n1ql end def execute(n1ql_query) - result = @model.cluster.query(n1ql_query, Couchbase::Options::Query.new(scan_consistency: :request_plus)) + result = @model.cluster.query(n1ql_query, Couchbase::Options::Query.new(scan_consistency: CouchbaseOrm::N1ql.config[:scan_consistency])) CouchbaseOrm.logger.debug { "Relation query: #{n1ql_query} return #{result.rows.to_a.length} rows" } N1qlProxy.new(result) end @@ -52,13 +52,13 @@ def ids end def first - result = @model.cluster.query(self.limit(1).to_n1ql, Couchbase::Options::Query.new(scan_consistency: :request_plus)) + result = @model.cluster.query(self.limit(1).to_n1ql, Couchbase::Options::Query.new(scan_consistency: CouchbaseOrm::N1ql.config[:scan_consistency])) first_id = result.rows.to_a.first @model.find(first_id) if first_id end def last - result = @model.cluster.query(to_n1ql, Couchbase::Options::Query.new(scan_consistency: :request_plus)) + result = @model.cluster.query(to_n1ql, Couchbase::Options::Query.new(scan_consistency: CouchbaseOrm::N1ql.config[:scan_consistency])) last_id = result.rows.to_a.last @model.find(last_id) if last_id end diff --git a/lib/couchbase-orm/views.rb b/lib/couchbase-orm/views.rb index b2e55493..20135086 100644 --- a/lib/couchbase-orm/views.rb +++ b/lib/couchbase-orm/views.rb @@ -66,7 +66,7 @@ def view(name, map: nil, emit_key: nil, reduce: nil, **options) @views[name] = method_opts singleton_class.__send__(:define_method, name) do |**opts, &result_modifier| - opts = options.merge(opts).reverse_merge(scan_consistency: :request_plus) + opts = options.merge(opts).reverse_merge(scan_consistency: CouchbaseOrm::N1ql.config[:scan_consistency]) CouchbaseOrm.logger.debug("View [#{@design_document}, #{name.inspect}] options: #{opts.inspect}") if result_modifier include_docs(bucket.view_query(@design_document, name.to_s, Couchbase::Options::View.new(**opts.except(:include_docs)))).map(&result_modifier) From 6d4260ede33fd2fe34e68577aff9ace25d41c935 Mon Sep 17 00:00:00 2001 From: CedricCouton Date: Wed, 1 Mar 2023 10:25:52 +0100 Subject: [PATCH 02/29] log scan consistency --- lib/couchbase-orm/n1ql.rb | 2 +- lib/couchbase-orm/relation.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index cba04901..74a82d87 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -124,7 +124,7 @@ 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}" result = cluster.query(n1ql_query, Couchbase::Options::Query.new(**options)) - CouchbaseOrm.logger.debug { "N1QL query: #{n1ql_query} return #{result.rows.to_a.length} rows" } + CouchbaseOrm.logger.debug { "N1QL query: #{n1ql_query} return #{result.rows.to_a.length} rows with scan_consistency : #{options[:scan_consistency]}" } N1qlProxy.new(result) end end diff --git a/lib/couchbase-orm/relation.rb b/lib/couchbase-orm/relation.rb index 5beb4b2d..99d76a2e 100644 --- a/lib/couchbase-orm/relation.rb +++ b/lib/couchbase-orm/relation.rb @@ -28,7 +28,7 @@ def to_n1ql def execute(n1ql_query) result = @model.cluster.query(n1ql_query, Couchbase::Options::Query.new(scan_consistency: CouchbaseOrm::N1ql.config[:scan_consistency])) - CouchbaseOrm.logger.debug { "Relation query: #{n1ql_query} return #{result.rows.to_a.length} rows" } + CouchbaseOrm.logger.debug { "Relation query: #{n1ql_query} return #{result.rows.to_a.length} rows with scan_consistency : #{CouchbaseOrm::N1ql.config[:scan_consistency]}" } N1qlProxy.new(result) end From c5167ce30a470f7984c345964b5532ce6c71337d Mon Sep 17 00:00:00 2001 From: CedricCouton Date: Thu, 2 Mar 2023 10:23:59 +0100 Subject: [PATCH 03/29] add tests --- lib/couchbase-orm/n1ql.rb | 2 +- spec/n1ql_spec.rb | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index 74a82d87..e15519a6 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -124,7 +124,7 @@ 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}" result = cluster.query(n1ql_query, Couchbase::Options::Query.new(**options)) - CouchbaseOrm.logger.debug { "N1QL query: #{n1ql_query} return #{result.rows.to_a.length} rows with scan_consistency : #{options[:scan_consistency]}" } + CouchbaseOrm.logger.debug "N1QL query: #{n1ql_query} return #{result.rows.to_a.length} rows with scan_consistency : #{options[:scan_consistency]}" N1qlProxy.new(result) end end diff --git a/spec/n1ql_spec.rb b/spec/n1ql_spec.rb index 1418be31..1cb8a841 100644 --- a/spec/n1ql_spec.rb +++ b/spec/n1ql_spec.rb @@ -170,6 +170,24 @@ class N1QLTest < CouchbaseOrm::Base expect(Set.new(docs)).to eq(Set.new(%w[bob jane mel])) end + it "should log the default scan_consistency when n1ql query is executed" do + allow(CouchbaseOrm.logger).to receive(:debug) + N1QLTest.by_rating_reverse() + expect(CouchbaseOrm.logger).to have_received(:debug).at_least(:once).with('N1QL query: select raw meta().id from `billeo-cb-bucket` where type="n1_ql_test" order by name DESC return 0 rows with scan_consistency : request_plus') + 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 }) + N1QLTest.by_rating_reverse() + expect(CouchbaseOrm.logger).to have_received(:debug).at_least(:once).with('N1QL query: select raw meta().id from `billeo-cb-bucket` where type="n1_ql_test" order by name DESC return 0 rows with scan_consistency : not_bounded') + + CouchbaseOrm::N1ql.config(default_n1ql_config) + N1QLTest.by_rating_reverse() + expect(CouchbaseOrm.logger).to have_received(:debug).at_least(:once).with('N1QL query: select raw meta().id from `billeo-cb-bucket` where type="n1_ql_test" order by name DESC return 0 rows with scan_consistency : request_plus') + end + after(:all) do N1QLTest.delete_all end From 335ae29ad3f99fbee0d7b1f718e913e08f40f95c Mon Sep 17 00:00:00 2001 From: CedricCouton Date: Thu, 2 Mar 2023 10:34:28 +0100 Subject: [PATCH 04/29] fix usage with a thread local var for // execution --- lib/couchbase-orm/n1ql.rb | 5 ++--- spec/n1ql_spec.rb | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index e15519a6..6f632f15 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -19,10 +19,9 @@ def self.sanitize(value) end end - @@couchbase_orm_config_n1ql = nil def self.config(new_config = nil) - @@couchbase_orm_config_n1ql = new_config if new_config - @@couchbase_orm_config_n1ql || { + Thread.current['__couchbaseorm_n1ql_config_n1ql__'] = new_config if new_config + Thread.current['__couchbaseorm_n1ql_config_n1ql__'] || { :scan_consistency => :request_plus } end diff --git a/spec/n1ql_spec.rb b/spec/n1ql_spec.rb index 1cb8a841..40a10203 100644 --- a/spec/n1ql_spec.rb +++ b/spec/n1ql_spec.rb @@ -181,11 +181,11 @@ class N1QLTest < CouchbaseOrm::Base default_n1ql_config = CouchbaseOrm::N1ql.config CouchbaseOrm::N1ql.config({ scan_consistency: :not_bounded }) N1QLTest.by_rating_reverse() - expect(CouchbaseOrm.logger).to have_received(:debug).at_least(:once).with('N1QL query: select raw meta().id from `billeo-cb-bucket` where type="n1_ql_test" order by name DESC return 0 rows with scan_consistency : not_bounded') + expect(CouchbaseOrm.logger).to have_received(:debug).at_least(:once).with("N1QL query: select raw meta().id from `#{CouchbaseOrm::Connection.bucket.name}` where type=\"n1_ql_test\" order by name DESC return 0 rows with scan_consistency : not_bounded") CouchbaseOrm::N1ql.config(default_n1ql_config) N1QLTest.by_rating_reverse() - expect(CouchbaseOrm.logger).to have_received(:debug).at_least(:once).with('N1QL query: select raw meta().id from `billeo-cb-bucket` where type="n1_ql_test" order by name DESC return 0 rows with scan_consistency : request_plus') + expect(CouchbaseOrm.logger).to have_received(:debug).at_least(:once).with("N1QL query: select raw meta().id from `#{CouchbaseOrm::Connection.bucket.name}` where type=\"n1_ql_test\" order by name DESC return 0 rows with scan_consistency : request_plus") end after(:all) do From c03727078d9c0bb2cd9663a90cd4777c113b562e Mon Sep 17 00:00:00 2001 From: CedricCouton Date: Thu, 2 Mar 2023 10:35:30 +0100 Subject: [PATCH 05/29] fix usage with a thread local var for // execution --- lib/couchbase-orm/n1ql.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index 6f632f15..768f4ac1 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -20,8 +20,8 @@ def self.sanitize(value) end def self.config(new_config = nil) - Thread.current['__couchbaseorm_n1ql_config_n1ql__'] = new_config if new_config - Thread.current['__couchbaseorm_n1ql_config_n1ql__'] || { + Thread.current['__couchbaseorm_n1ql_config__'] = new_config if new_config + Thread.current['__couchbaseorm_n1ql_config__'] || { :scan_consistency => :request_plus } end From 9a57ab3ef4b492e183225aac8e79822c0266b017 Mon Sep 17 00:00:00 2001 From: CedricCouton Date: Thu, 2 Mar 2023 10:45:36 +0100 Subject: [PATCH 06/29] fix test --- spec/n1ql_spec.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/n1ql_spec.rb b/spec/n1ql_spec.rb index 40a10203..eccd0d3b 100644 --- a/spec/n1ql_spec.rb +++ b/spec/n1ql_spec.rb @@ -173,13 +173,15 @@ class N1QLTest < CouchbaseOrm::Base it "should log the default scan_consistency when n1ql query is executed" do allow(CouchbaseOrm.logger).to receive(:debug) N1QLTest.by_rating_reverse() - expect(CouchbaseOrm.logger).to have_received(:debug).at_least(:once).with('N1QL query: select raw meta().id from `billeo-cb-bucket` where type="n1_ql_test" order by name DESC return 0 rows with scan_consistency : request_plus') + expect(CouchbaseOrm.logger).to have_received(:debug).at_least(:once).with("N1QL query: select raw meta().id from `#{CouchbaseOrm::Connection.bucket.name}` where type=\"n1_ql_test\" order by name DESC return 0 rows with scan_consistency : request_plus") 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 }) + puts "CouchbaseOrm::N1ql.config" + puts CouchbaseOrm::N1ql.config N1QLTest.by_rating_reverse() expect(CouchbaseOrm.logger).to have_received(:debug).at_least(:once).with("N1QL query: select raw meta().id from `#{CouchbaseOrm::Connection.bucket.name}` where type=\"n1_ql_test\" order by name DESC return 0 rows with scan_consistency : not_bounded") From 8ac6625a0fb7863da4c11ad30a2ff32126a37790 Mon Sep 17 00:00:00 2001 From: Pierre Merlin Date: Thu, 2 Mar 2023 11:02:48 +0100 Subject: [PATCH 07/29] use a DEFAULT_SCAN_CONSISTENCY const --- lib/couchbase-orm/n1ql.rb | 5 +++-- spec/n1ql_spec.rb | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index 768f4ac1..d356c864 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -8,6 +8,7 @@ module CouchbaseOrm module N1ql extend ActiveSupport::Concern NO_VALUE = :no_value_specified + DEFAULT_SCAN_CONSISTENCY = :request_plus # sanitize for injection query def self.sanitize(value) if value.is_a?(String) @@ -22,7 +23,7 @@ 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 => :request_plus + scan_consistency: DEFAULT_SCAN_CONSISTENCY } end @@ -56,7 +57,7 @@ def n1ql(name, query_fn: nil, emit_key: [], custom_order: nil, **options) @indexes[name] = method_opts singleton_class.__send__(:define_method, name) do |key: NO_VALUE, **opts, &result_modifier| - opts = options.merge(opts).reverse_merge(scan_consistency: CouchbaseOrm::N1ql.config[:scan_consistency]) + opts = options.merge(opts).reverse_merge(scan_consistency: CouchbaseOrm::N1ql.config[:scan_consistency] || DEFAULT_SCAN_CONSISTENCY) values = key == NO_VALUE ? NO_VALUE : convert_values(method_opts[:emit_key], key) current_query = run_query(method_opts[:emit_key], values, query_fn, custom_order: custom_order, **opts.except(:include_docs, :key)) if result_modifier diff --git a/spec/n1ql_spec.rb b/spec/n1ql_spec.rb index eccd0d3b..c4266559 100644 --- a/spec/n1ql_spec.rb +++ b/spec/n1ql_spec.rb @@ -173,7 +173,7 @@ class N1QLTest < CouchbaseOrm::Base it "should log the default scan_consistency when n1ql query is executed" do allow(CouchbaseOrm.logger).to receive(:debug) N1QLTest.by_rating_reverse() - expect(CouchbaseOrm.logger).to have_received(:debug).at_least(:once).with("N1QL query: select raw meta().id from `#{CouchbaseOrm::Connection.bucket.name}` where type=\"n1_ql_test\" order by name DESC return 0 rows with scan_consistency : request_plus") + expect(CouchbaseOrm.logger).to have_received(:debug).at_least(:once).with("N1QL query: select raw meta().id from `#{CouchbaseOrm::Connection.bucket.name}` where type=\"n1_ql_test\" order by name DESC return 0 rows with scan_consistency : #{described_class::DEFAULT_SCAN_CONSISTENCY}") end it "should log the set scan_consistency when n1ql query is executed with a specific scan_consistency" do @@ -187,7 +187,7 @@ class N1QLTest < CouchbaseOrm::Base CouchbaseOrm::N1ql.config(default_n1ql_config) N1QLTest.by_rating_reverse() - expect(CouchbaseOrm.logger).to have_received(:debug).at_least(:once).with("N1QL query: select raw meta().id from `#{CouchbaseOrm::Connection.bucket.name}` where type=\"n1_ql_test\" order by name DESC return 0 rows with scan_consistency : request_plus") + expect(CouchbaseOrm.logger).to have_received(:debug).at_least(:once).with("N1QL query: select raw meta().id from `#{CouchbaseOrm::Connection.bucket.name}` where type=\"n1_ql_test\" order by name DESC return 0 rows with scan_consistency : #{described_class::DEFAULT_SCAN_CONSISTENCY}") end after(:all) do From c620ef7c167775fcfb03526522a433ffba87cceb Mon Sep 17 00:00:00 2001 From: Pierre Merlin Date: Thu, 2 Mar 2023 11:07:36 +0100 Subject: [PATCH 08/29] allow to have nil value for scan_consistency --- lib/couchbase-orm/n1ql.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index d356c864..4dd5fe2d 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -57,7 +57,7 @@ def n1ql(name, query_fn: nil, emit_key: [], custom_order: nil, **options) @indexes[name] = method_opts singleton_class.__send__(:define_method, name) do |key: NO_VALUE, **opts, &result_modifier| - opts = options.merge(opts).reverse_merge(scan_consistency: CouchbaseOrm::N1ql.config[:scan_consistency] || DEFAULT_SCAN_CONSISTENCY) + opts = options.merge(opts).reverse_merge(scan_consistency: CouchbaseOrm::N1ql.config[:scan_consistency]) values = key == NO_VALUE ? NO_VALUE : convert_values(method_opts[:emit_key], key) current_query = run_query(method_opts[:emit_key], values, query_fn, custom_order: custom_order, **opts.except(:include_docs, :key)) if result_modifier From 7ef991fec9eb3a9fe477e9e2461f0473927343ca Mon Sep 17 00:00:00 2001 From: Pierre Merlin Date: Wed, 15 Mar 2023 12:57:46 +0100 Subject: [PATCH 09/29] Prevent to expose dead callbacks for nested --- lib/couchbase-orm/base.rb | 3 ++- spec/base_spec.rb | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/couchbase-orm/base.rb b/lib/couchbase-orm/base.rb index 0f4d98cd..89cff1c3 100644 --- a/lib/couchbase-orm/base.rb +++ b/lib/couchbase-orm/base.rb @@ -123,7 +123,6 @@ class Document extend Enum define_model_callbacks :initialize, :only => :after - define_model_callbacks :create, :destroy, :save, :update Metadata = Struct.new(:cas) @@ -212,6 +211,8 @@ class Base < Document extend Index extend IgnoredProperties + define_model_callbacks :create, :destroy, :save, :update + class << self def connect(**options) @bucket = BucketProxy.new(::MTLibcouchbase::Bucket.new(**options)) diff --git a/spec/base_spec.rb b/spec/base_spec.rb index f2e33d2c..d9d7a0a1 100644 --- a/spec/base_spec.rb +++ b/spec/base_spec.rb @@ -220,6 +220,15 @@ class BaseTestWithIgnoredProperties < CouchbaseOrm::Base it_behaves_like "ActiveModel" end + it 'does not expose callbacks for nested that wont never be called' do + expect{ + class InvalidNested < CouchbaseOrm::NestedDocument + before_save {p "this should raise on loading class"} + end + + }.to raise_error NoMethodError + end + describe '.ignored_properties' do From d059dd221e529357e816a9800a3fda35455cf690 Mon Sep 17 00:00:00 2001 From: Pierre Merlin Date: Mon, 27 Mar 2023 15:36:13 +0200 Subject: [PATCH 10/29] Upgrade Couchbase ruby client version --- couchbase-orm.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchbase-orm.gemspec b/couchbase-orm.gemspec index aad5fefc..91136378 100644 --- a/couchbase-orm.gemspec +++ b/couchbase-orm.gemspec @@ -16,7 +16,7 @@ Gem::Specification.new do |gem| gem.add_runtime_dependency 'activemodel', ENV["ACTIVE_MODEL_VERSION"] || '>= 5.2' gem.add_runtime_dependency 'activerecord', ENV["ACTIVE_MODEL_VERSION"] || '>= 5.2' - gem.add_runtime_dependency 'couchbase', '~> 3.3.0' + gem.add_runtime_dependency 'couchbase', '~> 3.4.1' gem.add_runtime_dependency 'radix', '~> 2.2' # converting numbers to and from any base gem.add_development_dependency 'rake', '~> 12.2' From 013ec7bab52ab320d36998e0847eb480b59fff79 Mon Sep 17 00:00:00 2001 From: Pierre Merlin Date: Thu, 6 Apr 2023 12:00:27 +0200 Subject: [PATCH 11/29] Update ignored_properties api To be similar to (usual) ActiveRecord ignored column --- lib/couchbase-orm/utilities/ignored_properties.rb | 10 ++++++++-- spec/base_spec.rb | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/couchbase-orm/utilities/ignored_properties.rb b/lib/couchbase-orm/utilities/ignored_properties.rb index 7ef5cfd9..86ac8386 100644 --- a/lib/couchbase-orm/utilities/ignored_properties.rb +++ b/lib/couchbase-orm/utilities/ignored_properties.rb @@ -1,9 +1,15 @@ module CouchbaseOrm module IgnoredProperties + def ignored_properties=(properties) + @@ignored_properties = properties.map(&:to_s) + end + def ignored_properties(*args) + if args.any? + CouchbaseOrm.logger.warn('Passing aruments to `.ignored_properties` is deprecated. PLease use `.ignored_properties=` intead.') + return send :ignored_properties=, args + end @@ignored_properties ||= [] - return @@ignored_properties if args.empty? - @@ignored_properties += args.map(&:to_s) end end end diff --git a/spec/base_spec.rb b/spec/base_spec.rb index d9d7a0a1..a35e513f 100644 --- a/spec/base_spec.rb +++ b/spec/base_spec.rb @@ -17,7 +17,7 @@ class TimestampTest < CouchbaseOrm::Base end class BaseTestWithIgnoredProperties < CouchbaseOrm::Base - ignored_properties :deprecated_property + self.ignored_properties += [:deprecated_property] attribute :name, :string attribute :job, :string end From 772e154f3728674e288f80c8f2f89430d43da8b8 Mon Sep 17 00:00:00 2001 From: CedricCouton Date: Wed, 12 Apr 2023 11:22:59 +0200 Subject: [PATCH 12/29] test and solve cases of find with multiple ids --- lib/couchbase-orm/base.rb | 2 +- lib/couchbase-orm/proxies/collection_proxy.rb | 3 +-- spec/base_spec.rb | 21 +++++++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/couchbase-orm/base.rb b/lib/couchbase-orm/base.rb index 89cff1c3..2df13da6 100644 --- a/lib/couchbase-orm/base.rb +++ b/lib/couchbase-orm/base.rb @@ -254,7 +254,7 @@ def find(*ids, quiet: false) records = quiet ? collection.get_multi(ids, transcoder: transcoder) : collection.get_multi!(ids, transcoder: transcoder) CouchbaseOrm.logger.debug { "Base.find found(#{records})" } records = records.zip(ids).map { |record, id| - self.new(record, id: id) if record + self.new(record, id: id) if record && record.error.nil? } records.compact! ids.length > 1 ? records : records[0] diff --git a/lib/couchbase-orm/proxies/collection_proxy.rb b/lib/couchbase-orm/proxies/collection_proxy.rb index 9ddf54c6..5492994c 100644 --- a/lib/couchbase-orm/proxies/collection_proxy.rb +++ b/lib/couchbase-orm/proxies/collection_proxy.rb @@ -21,8 +21,7 @@ def get_multi!(*ids, **options) end def get_multi(*ids, **options) - result = @proxyfied.get_multi(*ids, Couchbase::Options::GetMulti.new(**options)) - result.reject(&:error) + @proxyfied.get_multi(*ids, Couchbase::Options::GetMulti.new(**options)) end def remove!(id, **options) diff --git a/spec/base_spec.rb b/spec/base_spec.rb index a35e513f..319d1afa 100644 --- a/spec/base_spec.rb +++ b/spec/base_spec.rb @@ -212,6 +212,27 @@ class BaseTestWithIgnoredProperties < CouchbaseOrm::Base expect(base.created_at).to be_a(Time) end + it "should find multiple ids at same time" do + base1 = BaseTest.create!(name: 'joe1') + base2 = BaseTest.create!(name: 'joe2') + base3 = BaseTest.create!(name: 'joe3') + expect(BaseTest.find([base1.id, base2.id, base3.id])).to eq([base1, base2, base3]) + end + + it "should find multiple ids at same time with a not found id with exception" do + base1 = BaseTest.create!(name: 'joe1') + base2 = BaseTest.create!(name: 'joe2') + base3 = BaseTest.create!(name: 'joe3') + expect { BaseTest.find([base1.id, 't', base3.id]) }.to raise_error(Couchbase::Error::DocumentNotFound) + end + + it "should find multiple ids at same time with a not found id without exception" do + base1 = BaseTest.create!(name: 'joe1') + base2 = BaseTest.create!(name: 'joe2') + base3 = BaseTest.create!(name: 'joe3') + expect(BaseTest.find([base1.id, 't', 't', base2.id, base3.id], quiet: true)).to eq([base1, base2, base3]) + end + describe BaseTest do it_behaves_like "ActiveModel" end From 856b5df5fc4453a6f67b3519801073353b6d267e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Couton?= <57408786+CedricCouton@users.noreply.github.com> Date: Wed, 12 Apr 2023 11:43:32 +0200 Subject: [PATCH 13/29] Update lib/couchbase-orm/base.rb Co-authored-by: Pierre Merlin --- lib/couchbase-orm/base.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/couchbase-orm/base.rb b/lib/couchbase-orm/base.rb index 2df13da6..bfbecbe7 100644 --- a/lib/couchbase-orm/base.rb +++ b/lib/couchbase-orm/base.rb @@ -254,7 +254,8 @@ def find(*ids, quiet: false) records = quiet ? collection.get_multi(ids, transcoder: transcoder) : collection.get_multi!(ids, transcoder: transcoder) CouchbaseOrm.logger.debug { "Base.find found(#{records})" } records = records.zip(ids).map { |record, id| - self.new(record, id: id) if record && record.error.nil? + next unless record&.error&.nil? + self.new(record, id: id) } records.compact! ids.length > 1 ? records : records[0] From 53b5f69c9529e4f99ada886b845efdab9beb63da Mon Sep 17 00:00:00 2001 From: CedricCouton Date: Wed, 12 Apr 2023 11:49:23 +0200 Subject: [PATCH 14/29] better lisibility --- lib/couchbase-orm/base.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/couchbase-orm/base.rb b/lib/couchbase-orm/base.rb index bfbecbe7..df8a5317 100644 --- a/lib/couchbase-orm/base.rb +++ b/lib/couchbase-orm/base.rb @@ -254,7 +254,8 @@ def find(*ids, quiet: false) records = quiet ? collection.get_multi(ids, transcoder: transcoder) : collection.get_multi!(ids, transcoder: transcoder) CouchbaseOrm.logger.debug { "Base.find found(#{records})" } records = records.zip(ids).map { |record, id| - next unless record&.error&.nil? + next unless record + next if record.error self.new(record, id: id) } records.compact! From 50f9af8c59b516707d450ec057f2934dd4a89696 Mon Sep 17 00:00:00 2001 From: CedricCouton Date: Wed, 12 Apr 2023 11:49:58 +0200 Subject: [PATCH 15/29] better lisibility --- lib/couchbase-orm/base.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/couchbase-orm/base.rb b/lib/couchbase-orm/base.rb index df8a5317..d0a5625b 100644 --- a/lib/couchbase-orm/base.rb +++ b/lib/couchbase-orm/base.rb @@ -257,8 +257,7 @@ def find(*ids, quiet: false) next unless record next if record.error self.new(record, id: id) - } - records.compact! + }.compact ids.length > 1 ? records : records[0] end From 02e5e08102a63967f68bbf1e60c01c426f2b6d77 Mon Sep 17 00:00:00 2001 From: Pierre Merlin Date: Thu, 13 Apr 2023 14:47:38 +0200 Subject: [PATCH 16/29] Bump Couchbase ruby client to 3.4.2 NB : 3.4.1 and 3.4.0 are not compatible with CouchbaseOrm --- couchbase-orm.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchbase-orm.gemspec b/couchbase-orm.gemspec index 91136378..2d5dd7c1 100644 --- a/couchbase-orm.gemspec +++ b/couchbase-orm.gemspec @@ -16,7 +16,7 @@ Gem::Specification.new do |gem| gem.add_runtime_dependency 'activemodel', ENV["ACTIVE_MODEL_VERSION"] || '>= 5.2' gem.add_runtime_dependency 'activerecord', ENV["ACTIVE_MODEL_VERSION"] || '>= 5.2' - gem.add_runtime_dependency 'couchbase', '~> 3.4.1' + gem.add_runtime_dependency 'couchbase', '~> 3.4.2' gem.add_runtime_dependency 'radix', '~> 2.2' # converting numbers to and from any base gem.add_development_dependency 'rake', '~> 12.2' From 33a7d04dd2a3ceaba547756c183e76ccf4b14957 Mon Sep 17 00:00:00 2001 From: Pierre Merlin Date: Tue, 9 May 2023 16:46:56 +0200 Subject: [PATCH 17/29] Add red test on strict_loading for instance --- spec/associations_spec.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spec/associations_spec.rb b/spec/associations_spec.rb index ff45ed1d..fd5db6a4 100644 --- a/spec/associations_spec.rb +++ b/spec/associations_spec.rb @@ -209,4 +209,13 @@ class Part < CouchbaseOrm::Base it_behaves_like "ActiveModel" end end + + describe 'strict_loading' do + it 'raises StrictLoadingViolationError on lazy loading child relation' do + parent = Parent.create!(name: 'joe') + child = Child.create!(name: 'bob', parent_id: parent.id) + child.strict_loading! + expect {child.parent.id}.to raise_error(ActiveRecord::StrictLoadingViolationError) + end + end end From 51b50f4d77e81de93ebd26dda2628ae58d238a6e Mon Sep 17 00:00:00 2001 From: Pierre Merlin Date: Tue, 9 May 2023 17:34:35 +0200 Subject: [PATCH 18/29] WIP first implem --- lib/couchbase-orm/associations.rb | 2 ++ lib/couchbase-orm/base.rb | 9 +++++++++ lib/couchbase-orm/relation.rb | 10 ++++++++-- spec/associations_spec.rb | 22 +++++++++++++++++----- 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/lib/couchbase-orm/associations.rb b/lib/couchbase-orm/associations.rb index 71514d5b..687784d6 100644 --- a/lib/couchbase-orm/associations.rb +++ b/lib/couchbase-orm/associations.rb @@ -32,6 +32,8 @@ def belongs_to(name, **options) val = if options[:polymorphic] ::CouchbaseOrm.try_load(self.send(ref)) else + raise ActiveRecord::StrictLoadingViolationError, "#{self.class} is marked as strict_loading and #{assoc} cannot be lazily loaded." if strict_loading? + assoc.constantize.find(self.send(ref), quiet: true) end instance_variable_set(instance_var, val) diff --git a/lib/couchbase-orm/base.rb b/lib/couchbase-orm/base.rb index d0a5625b..80f74299 100644 --- a/lib/couchbase-orm/base.rb +++ b/lib/couchbase-orm/base.rb @@ -241,6 +241,15 @@ def uuid_generator def uuid_generator=(generator) @uuid_generator = generator end + + def strict_loading + @strict_loading = true + self + end + + def strict_loading? + !!@strict_loading + end def find(*ids, quiet: false) CouchbaseOrm.logger.debug { "Base.find(l##{ids.length}) #{ids}" } diff --git a/lib/couchbase-orm/relation.rb b/lib/couchbase-orm/relation.rb index 99d76a2e..b76fb83b 100644 --- a/lib/couchbase-orm/relation.rb +++ b/lib/couchbase-orm/relation.rb @@ -51,10 +51,16 @@ def ids query.to_a end + def strict_loading + @strict_loading = true + self + end + def first result = @model.cluster.query(self.limit(1).to_n1ql, Couchbase::Options::Query.new(scan_consistency: CouchbaseOrm::N1ql.config[:scan_consistency])) - first_id = result.rows.to_a.first - @model.find(first_id) if first_id + return unless (first_id = result.rows.to_a.first) + + @model.find(first_id).tap { |instance| instance.strict_loading! if @strict_loading || @model.strict_loading? } end def last diff --git a/spec/associations_spec.rb b/spec/associations_spec.rb index fd5db6a4..82972796 100644 --- a/spec/associations_spec.rb +++ b/spec/associations_spec.rb @@ -211,11 +211,23 @@ class Part < CouchbaseOrm::Base end describe 'strict_loading' do - it 'raises StrictLoadingViolationError on lazy loading child relation' do - parent = Parent.create!(name: 'joe') - child = Child.create!(name: 'bob', parent_id: parent.id) - child.strict_loading! - expect {child.parent.id}.to raise_error(ActiveRecord::StrictLoadingViolationError) + let(:parent) {Parent.create!(name: 'joe')} + let(:child) {Child.create!(name: 'bob', parent_id: parent.id)} + context 'instance strict loading' do + it 'raises StrictLoadingViolationError on lazy loading child relation' do + + expect {child.parent.id}.not_to raise_error(ActiveRecord::StrictLoadingViolationError) + expect {Child.find(child.id).tap{|child| child.strict_loading! }.parent.id}.to raise_error(ActiveRecord::StrictLoadingViolationError) + end + end + context 'scope strict loading' do + it 'raises StrictLoadingViolationError on lazy loading child relation' do + expect {Child.where(id: child.id).strict_loading.first.parent}.to raise_error(ActiveRecord::StrictLoadingViolationError) + expect {Child.strict_loading.where(id: child.id).first.parent}.to raise_error(ActiveRecord::StrictLoadingViolationError) + expect {Child.strict_loading.where(id: child.id).last.parent}.to raise_error(ActiveRecord::StrictLoadingViolationError) + expect {Child.strict_loading.where(id: child.id).to_a.first.parent}.to raise_error(ActiveRecord::StrictLoadingViolationError) + # ... cover all access methods (test should be refactored and split elsewhere) + end end end end From 1280468c3b144ae2f559e3a9463e1dae5cafbfdb Mon Sep 17 00:00:00 2001 From: Pierre Merlin Date: Tue, 16 May 2023 16:55:41 +0200 Subject: [PATCH 19/29] Handle first, last and find --- lib/couchbase-orm/base.rb | 6 ++++-- lib/couchbase-orm/relation.rb | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/couchbase-orm/base.rb b/lib/couchbase-orm/base.rb index 80f74299..60b2ba5e 100644 --- a/lib/couchbase-orm/base.rb +++ b/lib/couchbase-orm/base.rb @@ -251,7 +251,7 @@ def strict_loading? !!@strict_loading end - def find(*ids, quiet: false) + def find(*ids, quiet: false, with_strict_loading: false) CouchbaseOrm.logger.debug { "Base.find(l##{ids.length}) #{ids}" } ids = ids.flatten.select { |id| id.present? } @@ -265,7 +265,9 @@ def find(*ids, quiet: false) records = records.zip(ids).map { |record, id| next unless record next if record.error - self.new(record, id: id) + new(record, id:).tap do |instance| + instance.strict_loading! if with_strict_loading || strict_loading? + end }.compact ids.length > 1 ? records : records[0] end diff --git a/lib/couchbase-orm/relation.rb b/lib/couchbase-orm/relation.rb index b76fb83b..4618b187 100644 --- a/lib/couchbase-orm/relation.rb +++ b/lib/couchbase-orm/relation.rb @@ -60,13 +60,13 @@ def first result = @model.cluster.query(self.limit(1).to_n1ql, Couchbase::Options::Query.new(scan_consistency: CouchbaseOrm::N1ql.config[:scan_consistency])) return unless (first_id = result.rows.to_a.first) - @model.find(first_id).tap { |instance| instance.strict_loading! if @strict_loading || @model.strict_loading? } + @model.find(first_id, with_strict_loading: @strict_loading) end def last result = @model.cluster.query(to_n1ql, Couchbase::Options::Query.new(scan_consistency: CouchbaseOrm::N1ql.config[:scan_consistency])) last_id = result.rows.to_a.last - @model.find(last_id) if last_id + @model.find(last_id, with_strict_loading: @strict_loading) if last_id end def count From ab1f12552983605f1ce562a1ed37686ce6dea3b9 Mon Sep 17 00:00:00 2001 From: Pierre Merlin Date: Tue, 16 May 2023 17:03:32 +0200 Subject: [PATCH 20/29] refacto test --- spec/associations_spec.rb | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/spec/associations_spec.rb b/spec/associations_spec.rb index 82972796..bbd02d45 100644 --- a/spec/associations_spec.rb +++ b/spec/associations_spec.rb @@ -217,17 +217,21 @@ class Part < CouchbaseOrm::Base it 'raises StrictLoadingViolationError on lazy loading child relation' do expect {child.parent.id}.not_to raise_error(ActiveRecord::StrictLoadingViolationError) - expect {Child.find(child.id).tap{|child| child.strict_loading! }.parent.id}.to raise_error(ActiveRecord::StrictLoadingViolationError) + expect_strict_loading_error_on_calling_parent(Child.find(child.id).tap{|child| child.strict_loading!}) end end context 'scope strict loading' do it 'raises StrictLoadingViolationError on lazy loading child relation' do - expect {Child.where(id: child.id).strict_loading.first.parent}.to raise_error(ActiveRecord::StrictLoadingViolationError) - expect {Child.strict_loading.where(id: child.id).first.parent}.to raise_error(ActiveRecord::StrictLoadingViolationError) - expect {Child.strict_loading.where(id: child.id).last.parent}.to raise_error(ActiveRecord::StrictLoadingViolationError) - expect {Child.strict_loading.where(id: child.id).to_a.first.parent}.to raise_error(ActiveRecord::StrictLoadingViolationError) - # ... cover all access methods (test should be refactored and split elsewhere) + expect_strict_loading_error_on_calling_parent(Child.where(id: child.id).strict_loading.first) + expect_strict_loading_error_on_calling_parent(Child.strict_loading.where(id: child.id).first) + expect_strict_loading_error_on_calling_parent(Child.strict_loading.where(id: child.id).last) + expect_strict_loading_error_on_calling_parent(Child.strict_loading.where(id: child.id).to_a.first) + expect_strict_loading_error_on_calling_parent(Child.strict_loading.all.to_a.first) end end end + + def expect_strict_loading_error_on_calling_parent(child_instance) + expect {child_instance.parent}.to raise_error(ActiveRecord::StrictLoadingViolationError) + end end From c022b298cf959f3b26ff8092d8ad20a0a0394bdb Mon Sep 17 00:00:00 2001 From: Pierre Merlin Date: Tue, 16 May 2023 17:56:52 +0200 Subject: [PATCH 21/29] consistant (and strange) implem --- lib/couchbase-orm/relation.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/couchbase-orm/relation.rb b/lib/couchbase-orm/relation.rb index 4618b187..7ad543b6 100644 --- a/lib/couchbase-orm/relation.rb +++ b/lib/couchbase-orm/relation.rb @@ -3,14 +3,15 @@ module Relation extend ActiveSupport::Concern class CouchbaseOrm_Relation - def initialize(model:, where: where = nil, order: order = nil, limit: limit = nil, _not: _not = false) - CouchbaseOrm::logger.debug "CouchbaseOrm_Relation init: #{model} where:#{where.inspect} not:#{_not.inspect} order:#{order.inspect} limit: #{limit}" + def initialize(model:, where: where = nil, order: order = nil, limit: limit = nil, _not: _not = false, strict_loading: strict_loading = false) + CouchbaseOrm::logger.debug "CouchbaseOrm_Relation init: #{model} where:#{where.inspect} not:#{_not.inspect} order:#{order.inspect} limit: #{limit} strict_loading: #{strict_loading}" @model = model @limit = limit @where = [] @order = {} @order = merge_order(**order) if order @where = merge_where(where, _not) if where + @strict_loading = strict_loading CouchbaseOrm::logger.debug "- #{to_s}" end @@ -52,8 +53,7 @@ def ids end def strict_loading - @strict_loading = true - self + CouchbaseOrm_Relation.new(**initializer_arguments.merge(strict_loading: true)) end def first @@ -239,7 +239,7 @@ def relation delegate :ids, :update_all, :delete_all, :count, :empty?, :filter, :reduce, :find_by, to: :all - delegate :where, :not, :order, :limit, :all, to: :relation + delegate :where, :not, :order, :limit, :all, :strict_loading, to: :relation end end end From 89ecb85a95d351d73b1441119198e6bfc851de7a Mon Sep 17 00:00:00 2001 From: Pierre Merlin Date: Tue, 16 May 2023 18:00:37 +0200 Subject: [PATCH 22/29] fix --- lib/couchbase-orm/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/couchbase-orm/base.rb b/lib/couchbase-orm/base.rb index 60b2ba5e..7c6603a5 100644 --- a/lib/couchbase-orm/base.rb +++ b/lib/couchbase-orm/base.rb @@ -265,7 +265,7 @@ def find(*ids, quiet: false, with_strict_loading: false) records = records.zip(ids).map { |record, id| next unless record next if record.error - new(record, id:).tap do |instance| + new(record, id: id).tap do |instance| instance.strict_loading! if with_strict_loading || strict_loading? end }.compact From 9379e9acef31552267eb2d97648487ebd5400b04 Mon Sep 17 00:00:00 2001 From: Pierre Merlin Date: Tue, 30 May 2023 16:26:11 +0200 Subject: [PATCH 23/29] red again... implem is leaky --- spec/associations_spec.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/associations_spec.rb b/spec/associations_spec.rb index bbd02d45..b13022e1 100644 --- a/spec/associations_spec.rb +++ b/spec/associations_spec.rb @@ -228,6 +228,11 @@ class Part < CouchbaseOrm::Base expect_strict_loading_error_on_calling_parent(Child.strict_loading.where(id: child.id).to_a.first) expect_strict_loading_error_on_calling_parent(Child.strict_loading.all.to_a.first) end + + it 'does not raise StrictLoadingViolationError on lazy loading child relation without declaring it' do + expect_strict_loading_error_on_calling_parent(Child.strict_loading.where(id: child.id).first) + expect { Child.where(id: child.id).last.parent}.not_to raise_error + end end end From 79b54b94e17d3bfa04b8e986ad1356c28fca9c2f Mon Sep 17 00:00:00 2001 From: Pierre Merlin Date: Tue, 30 May 2023 16:55:57 +0200 Subject: [PATCH 24/29] Fix leaky implem --- lib/couchbase-orm/base.rb | 18 +++++++++--------- lib/couchbase-orm/relation.rb | 12 ++++++++---- spec/associations_spec.rb | 1 - 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/lib/couchbase-orm/base.rb b/lib/couchbase-orm/base.rb index 7c6603a5..c0cd470f 100644 --- a/lib/couchbase-orm/base.rb +++ b/lib/couchbase-orm/base.rb @@ -213,6 +213,15 @@ class Base < Document define_model_callbacks :create, :destroy, :save, :update + def strict_loading + @strict_loading = true + self + end + + def strict_loading? + !!@strict_loading + end + class << self def connect(**options) @bucket = BucketProxy.new(::MTLibcouchbase::Bucket.new(**options)) @@ -241,15 +250,6 @@ def uuid_generator def uuid_generator=(generator) @uuid_generator = generator end - - def strict_loading - @strict_loading = true - self - end - - def strict_loading? - !!@strict_loading - end def find(*ids, quiet: false, with_strict_loading: false) CouchbaseOrm.logger.debug { "Base.find(l##{ids.length}) #{ids}" } diff --git a/lib/couchbase-orm/relation.rb b/lib/couchbase-orm/relation.rb index 7ad543b6..006b8314 100644 --- a/lib/couchbase-orm/relation.rb +++ b/lib/couchbase-orm/relation.rb @@ -16,7 +16,7 @@ def initialize(model:, where: where = nil, order: order = nil, limit: limit = ni end def to_s - "CouchbaseOrm_Relation: #{@model} where:#{@where.inspect} order:#{@order.inspect} limit: #{@limit}" + "CouchbaseOrm_Relation: #{@model} where:#{@where.inspect} order:#{@order.inspect} limit: #{@limit} strict_loading: #{@strict_loading}" end def to_n1ql @@ -56,6 +56,10 @@ def strict_loading CouchbaseOrm_Relation.new(**initializer_arguments.merge(strict_loading: true)) end + def strict_loading? + !!@strict_loading + end + def first result = @model.cluster.query(self.limit(1).to_n1ql, Couchbase::Options::Query.new(scan_consistency: CouchbaseOrm::N1ql.config[:scan_consistency])) return unless (first_id = result.rows.to_a.first) @@ -95,7 +99,7 @@ def pluck(*fields) def to_ary ids = query.results return [] if ids.empty? - Array(ids && @model.find(ids)) + Array(ids && @model.find(ids, with_strict_loading: @strict_loading)) end alias :to_a :to_ary @@ -152,7 +156,7 @@ def build_limit end def initializer_arguments - { model: @model, order: @order, where: @where, limit: @limit } + { model: @model, order: @order, where: @where, limit: @limit, strict_loading: @strict_loading } end def merge_order(*lorder, **horder) @@ -239,7 +243,7 @@ def relation delegate :ids, :update_all, :delete_all, :count, :empty?, :filter, :reduce, :find_by, to: :all - delegate :where, :not, :order, :limit, :all, :strict_loading, to: :relation + delegate :where, :not, :order, :limit, :all, :strict_loading, :strict_loading?, to: :relation end end end diff --git a/spec/associations_spec.rb b/spec/associations_spec.rb index b13022e1..d1f46927 100644 --- a/spec/associations_spec.rb +++ b/spec/associations_spec.rb @@ -215,7 +215,6 @@ class Part < CouchbaseOrm::Base let(:child) {Child.create!(name: 'bob', parent_id: parent.id)} context 'instance strict loading' do it 'raises StrictLoadingViolationError on lazy loading child relation' do - expect {child.parent.id}.not_to raise_error(ActiveRecord::StrictLoadingViolationError) expect_strict_loading_error_on_calling_parent(Child.find(child.id).tap{|child| child.strict_loading!}) end From 571c92dbc7d5a687a63e5f3f22d9e1abb6ddf8fc Mon Sep 17 00:00:00 2001 From: Pierre Merlin Date: Tue, 30 May 2023 17:09:58 +0200 Subject: [PATCH 25/29] handle habtm relations --- lib/couchbase-orm/associations.rb | 2 ++ spec/associations_spec.rb | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/lib/couchbase-orm/associations.rb b/lib/couchbase-orm/associations.rb index 687784d6..ce08b74d 100644 --- a/lib/couchbase-orm/associations.rb +++ b/lib/couchbase-orm/associations.rb @@ -83,6 +83,8 @@ def has_and_belongs_to_many(name, **options) val = if options[:polymorphic] ::CouchbaseOrm.try_load(ref_value) if ref_value else + raise ActiveRecord::StrictLoadingViolationError, "#{self.class} is marked as strict_loading and #{assoc} cannot be lazily loaded." if strict_loading? + assoc.constantize.find(ref_value) if ref_value end val = Array.wrap(val || []) diff --git a/spec/associations_spec.rb b/spec/associations_spec.rb index d1f46927..f9ae5142 100644 --- a/spec/associations_spec.rb +++ b/spec/associations_spec.rb @@ -5,6 +5,7 @@ class Parent < CouchbaseOrm::Base attribute :name + has_and_belongs_to_many :children end class RandomOtherType < CouchbaseOrm::Base @@ -232,6 +233,10 @@ class Part < CouchbaseOrm::Base expect_strict_loading_error_on_calling_parent(Child.strict_loading.where(id: child.id).first) expect { Child.where(id: child.id).last.parent}.not_to raise_error end + + it 'raises StrictLoadingViolationError on lazy loading habtm relation' do + expect {Parent.strict_loading.where(id: parent.id).first.children}.to raise_error(ActiveRecord::StrictLoadingViolationError) + end end end From 52784edafca19f95e3683e01e556721f2088fc58 Mon Sep 17 00:00:00 2001 From: Pierre Merlin Date: Tue, 30 May 2023 17:45:37 +0200 Subject: [PATCH 26/29] remove useless code --- lib/couchbase-orm/base.rb | 13 +++---------- spec/associations_spec.rb | 4 +++- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/lib/couchbase-orm/base.rb b/lib/couchbase-orm/base.rb index c0cd470f..ddb2e943 100644 --- a/lib/couchbase-orm/base.rb +++ b/lib/couchbase-orm/base.rb @@ -213,15 +213,6 @@ class Base < Document define_model_callbacks :create, :destroy, :save, :update - def strict_loading - @strict_loading = true - self - end - - def strict_loading? - !!@strict_loading - end - class << self def connect(**options) @bucket = BucketProxy.new(::MTLibcouchbase::Bucket.new(**options)) @@ -266,7 +257,9 @@ def find(*ids, quiet: false, with_strict_loading: false) next unless record next if record.error new(record, id: id).tap do |instance| - instance.strict_loading! if with_strict_loading || strict_loading? + if with_strict_loading + instance.strict_loading! + end end }.compact ids.length > 1 ? records : records[0] diff --git a/spec/associations_spec.rb b/spec/associations_spec.rb index f9ae5142..6e1ae991 100644 --- a/spec/associations_spec.rb +++ b/spec/associations_spec.rb @@ -235,7 +235,9 @@ class Part < CouchbaseOrm::Base end it 'raises StrictLoadingViolationError on lazy loading habtm relation' do - expect {Parent.strict_loading.where(id: parent.id).first.children}.to raise_error(ActiveRecord::StrictLoadingViolationError) + expect {Parent.strict_loading.where(id: parent.id).first.children}.to raise_error(ActiveRecord::StrictLoadingViolationError) + # NB any action called on model class breaks find return type (find return an enumerator instead of a record) + expect {Parent.strict_loading.find(parent.id).first.children}.to raise_error(ActiveRecord::StrictLoadingViolationError) end end end From 9f886c53280f20c1d8ee2e58688923126a006636 Mon Sep 17 00:00:00 2001 From: Pierre Merlin Date: Tue, 30 May 2023 18:05:10 +0200 Subject: [PATCH 27/29] Cover AR default strict loading usage --- spec/associations_spec.rb | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/spec/associations_spec.rb b/spec/associations_spec.rb index 6e1ae991..9cebe410 100644 --- a/spec/associations_spec.rb +++ b/spec/associations_spec.rb @@ -8,6 +8,12 @@ class Parent < CouchbaseOrm::Base has_and_belongs_to_many :children end +class StrictLoadingParent < CouchbaseOrm::Base + attribute :name + has_and_belongs_to_many :children + self.strict_loading_by_default = true +end + class RandomOtherType < CouchbaseOrm::Base attribute :name end @@ -216,7 +222,7 @@ class Part < CouchbaseOrm::Base let(:child) {Child.create!(name: 'bob', parent_id: parent.id)} context 'instance strict loading' do it 'raises StrictLoadingViolationError on lazy loading child relation' do - expect {child.parent.id}.not_to raise_error(ActiveRecord::StrictLoadingViolationError) + expect {child.parent.id}.not_to raise_error expect_strict_loading_error_on_calling_parent(Child.find(child.id).tap{|child| child.strict_loading!}) end end @@ -239,6 +245,14 @@ class Part < CouchbaseOrm::Base # NB any action called on model class breaks find return type (find return an enumerator instead of a record) expect {Parent.strict_loading.find(parent.id).first.children}.to raise_error(ActiveRecord::StrictLoadingViolationError) end + + it 'raises StrictLoadingViolationError on lazy loading relation when model is by default strict_loading' do + strict_loading_parent = StrictLoadingParent.create!(name: 'joe') + expect {StrictLoadingParent.where(id: strict_loading_parent.id).first.children}.to raise_error(ActiveRecord::StrictLoadingViolationError) + expect {Parent.find(parent.id).children}.not_to raise_error + # NB any action called on model class breaks find return type (find return an enumerator instead of a record) + expect {Parent.strict_loading.find(strict_loading_parent.id).first.children}.to raise_error(ActiveRecord::StrictLoadingViolationError) + end end end From dcbfb580190af926acbcf89981045ab80f1970e8 Mon Sep 17 00:00:00 2001 From: Pierre Merlin Date: Thu, 29 Jun 2023 18:10:43 +0200 Subject: [PATCH 28/29] Fix Mapotempo/couchbase-orm/issues/71 --- lib/couchbase-orm/persistence.rb | 2 +- spec/base_spec.rb | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/couchbase-orm/persistence.rb b/lib/couchbase-orm/persistence.rb index efa6f8ec..a3704cc0 100644 --- a/lib/couchbase-orm/persistence.rb +++ b/lib/couchbase-orm/persistence.rb @@ -209,7 +209,7 @@ def reload CouchbaseOrm.logger.debug "Data - Get #{id}" resp = self.class.collection.get!(id) - assign_attributes(decode_encrypted_attributes(resp.content.except("id"))) # API return a nil id + assign_attributes(decode_encrypted_attributes(resp.content.except("id", *self.class.ignored_properties ))) # API return a nil id @__metadata__.cas = resp.cas reset_associations diff --git a/spec/base_spec.rb b/spec/base_spec.rb index 319d1afa..2391c441 100644 --- a/spec/base_spec.rb +++ b/spec/base_spec.rb @@ -284,6 +284,10 @@ class InvalidNested < CouchbaseOrm::NestedDocument from(%w[deprecated_property job name type]). to(%w[job name type]) end + + it 'does not raise for reload' do + expect{ loaded_model.reload }.not_to raise_error + end end end end From fcf9e4fe97090bbcbd546f6d433f6fe6831460d7 Mon Sep 17 00:00:00 2001 From: Pierre Merlin Date: Wed, 12 Jul 2023 19:13:18 +0200 Subject: [PATCH 29/29] =?UTF-8?q?=E2=9C=85=20Desrialize=20an=20unexpected?= =?UTF-8?q?=20prop=20set=20to=20null=20raise?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spec/base_spec.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/spec/base_spec.rb b/spec/base_spec.rb index 2391c441..dc288cd9 100644 --- a/spec/base_spec.rb +++ b/spec/base_spec.rb @@ -82,6 +82,20 @@ class BaseTestWithIgnoredProperties < CouchbaseOrm::Base BaseTest.bucket.default_collection.remove 'doc_1' end + it "raises ActiveModel::UnknownAttributeError on loading objects with unexpected properties even valued to null" do + too_much_properties_valued_to_null_doc = { + type: BaseTest.design_document, + name: 'Pierre', + job: 'dev', + age: nil + } + BaseTest.bucket.default_collection.upsert 'doc_1', too_much_properties_valued_to_null_doc + + expect { BaseTest.find_by_id('doc_1') }.to raise_error(ActiveModel::UnknownAttributeError) + + BaseTest.bucket.default_collection.remove 'doc_1' + end + it "loads objects even if there is a missing property in doc" do missing_properties_doc = { type: BaseTest.design_document,