From e1519eb0f608c72706c8da67aa0f0b401d5ad4b5 Mon Sep 17 00:00:00 2001 From: Gauthier Monserand Date: Thu, 3 Nov 2022 15:00:17 +0100 Subject: [PATCH 1/4] chain scopes --- lib/couchbase-orm/relation.rb | 32 +++++++++++++++++++++++++------ spec/relation_spec.rb | 36 ++++++++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/lib/couchbase-orm/relation.rb b/lib/couchbase-orm/relation.rb index 4b414700..8ea615d8 100644 --- a/lib/couchbase-orm/relation.rb +++ b/lib/couchbase-orm/relation.rb @@ -171,28 +171,48 @@ def build_update(**cond) end.join(", ") end + def scoping + scopes = (Thread.current[@model.name] ||= []) + scopes.push(self) + result = yield + scopes.pop + result + end + + def method_missing(method, *args, &block) + if @model.respond_to?(method) + scoping { + @model.public_send(method, *args, &block) + } + else + super + end + end end module ClassMethods + def relation + Thread.current[self.name]&.last || CouchbaseOrm_Relation.new(model: self) + end + def where(**conds) - CouchbaseOrm_Relation.new(model: self, where: conds) + relation.where(**conds) end def not(**conds) - CouchbaseOrm_Relation.new(model: self, where: conds, _not: true) + relation.not(**conds) end def order(*ordersl, **ordersh) - order = ordersh.reverse_merge(ordersl.map{ |o| [o, :asc] }.to_h) - CouchbaseOrm_Relation.new(model: self, order: order) + relation.order(*ordersl, **ordersh) end def limit(limit) - CouchbaseOrm_Relation.new(model: self, limit: limit) + relation.limit(limit) end def all - CouchbaseOrm_Relation.new(model: self) + relation.all end delegate :ids, :delete_all, :count, :empty?, :filter, :reduce, :find_by, to: :all diff --git a/spec/relation_spec.rb b/spec/relation_spec.rb index 55a6b5c9..9d68e172 100644 --- a/spec/relation_spec.rb +++ b/spec/relation_spec.rb @@ -8,6 +8,18 @@ class RelationModel < CouchbaseOrm::Base attribute :last_name, :string attribute :active, :boolean attribute :age, :integer + + def self.adult + where(age: {_gte: 18}) + end + + def self.active + where(active: true) + end + + def self.test(&block) + yield + end end describe CouchbaseOrm::Relation do @@ -215,7 +227,6 @@ class RelationModel < CouchbaseOrm::Base expect(RelationModel.order(:age).pluck(:age, :active)).to match_array([[10, true], [20, true], [30, false]]) end - it "should query true boolean" do m1 = RelationModel.create!(active: true) _m2 = RelationModel.create!(active: false) @@ -300,5 +311,28 @@ class RelationModel < CouchbaseOrm::Base expect(m3.reload.age).to eq(50) expect(m4.reload.age).to eq(40) end + describe "scopes" do + it "should chain scopes" do + _m1 = RelationModel.create!(age: 10, active: true) + _m2 = RelationModel.create!(age: 20, active: false) + m3 = RelationModel.create!(age: 30, active: true) + m4 = RelationModel.create!(age: 40, active: true) + + + expect(RelationModel.all.adult.all.active.all).to match_array([m3, m4]) + expect(RelationModel.where(active: true).adult).to match_array([m3, m4]) + end + + it "should be thread safe" do + m1 = RelationModel.create!(age: 10, active: true) + m2 = RelationModel.create!(age: 20, active: false) + RelationModel.active.test do + expect(RelationModel.all).to match_array([m1]) + Thread.start do + expect(RelationModel.all).to match_array([m1, m2]) + end + end + end + end end From d41a696a34213c77cb2b9e31621292228ded9d2c Mon Sep 17 00:00:00 2001 From: Gauthier Monserand Date: Thu, 3 Nov 2022 16:31:00 +0100 Subject: [PATCH 2/4] cleanup and fix race condition --- lib/couchbase-orm/relation.rb | 38 +++++++++-------------------------- spec/relation_spec.rb | 6 +++--- 2 files changed, 13 insertions(+), 31 deletions(-) diff --git a/lib/couchbase-orm/relation.rb b/lib/couchbase-orm/relation.rb index 8ea615d8..140040ff 100644 --- a/lib/couchbase-orm/relation.rb +++ b/lib/couchbase-orm/relation.rb @@ -128,6 +128,14 @@ def all CouchbaseOrm_Relation.new(**initializer_arguments) end + def scoping + scopes = (Thread.current[@model.name] ||= []) + scopes.push(self) + result = yield + scopes.pop + result + end + private def build_limit @@ -171,14 +179,6 @@ def build_update(**cond) end.join(", ") end - def scoping - scopes = (Thread.current[@model.name] ||= []) - scopes.push(self) - result = yield - scopes.pop - result - end - def method_missing(method, *args, &block) if @model.respond_to?(method) scoping { @@ -195,27 +195,9 @@ def relation Thread.current[self.name]&.last || CouchbaseOrm_Relation.new(model: self) end - def where(**conds) - relation.where(**conds) - end - - def not(**conds) - relation.not(**conds) - end - - def order(*ordersl, **ordersh) - relation.order(*ordersl, **ordersh) - end - - def limit(limit) - relation.limit(limit) - end - - def all - relation.all - end - delegate :ids, :delete_all, :count, :empty?, :filter, :reduce, :find_by, to: :all + + delegate :where, :not, :order, :limit, :all, to: :relation end end end diff --git a/spec/relation_spec.rb b/spec/relation_spec.rb index 9d68e172..c6e0a9b1 100644 --- a/spec/relation_spec.rb +++ b/spec/relation_spec.rb @@ -311,6 +311,7 @@ def self.test(&block) expect(m3.reload.age).to eq(50) expect(m4.reload.age).to eq(40) end + describe "scopes" do it "should chain scopes" do _m1 = RelationModel.create!(age: 10, active: true) @@ -318,7 +319,6 @@ def self.test(&block) m3 = RelationModel.create!(age: 30, active: true) m4 = RelationModel.create!(age: 40, active: true) - expect(RelationModel.all.adult.all.active.all).to match_array([m3, m4]) expect(RelationModel.where(active: true).adult).to match_array([m3, m4]) end @@ -326,11 +326,11 @@ def self.test(&block) it "should be thread safe" do m1 = RelationModel.create!(age: 10, active: true) m2 = RelationModel.create!(age: 20, active: false) - RelationModel.active.test do + RelationModel.active.scoping do expect(RelationModel.all).to match_array([m1]) Thread.start do expect(RelationModel.all).to match_array([m1, m2]) - end + end.join end end end From 7f7bddbc66f32cc27b74c9843cad51cc4c9be2aa Mon Sep 17 00:00:00 2001 From: Gauthier Monserand Date: Thu, 3 Nov 2022 16:31:55 +0100 Subject: [PATCH 3/4] cleanup --- spec/relation_spec.rb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/spec/relation_spec.rb b/spec/relation_spec.rb index c6e0a9b1..325f6ff7 100644 --- a/spec/relation_spec.rb +++ b/spec/relation_spec.rb @@ -16,10 +16,6 @@ def self.adult def self.active where(active: true) end - - def self.test(&block) - yield - end end describe CouchbaseOrm::Relation do @@ -324,8 +320,8 @@ def self.test(&block) end it "should be thread safe" do - m1 = RelationModel.create!(age: 10, active: true) - m2 = RelationModel.create!(age: 20, active: false) + m1 = RelationModel.create!(active: true) + m2 = RelationModel.create!(active: false) RelationModel.active.scoping do expect(RelationModel.all).to match_array([m1]) Thread.start do From 097851edf1b95130ccb5e7647a6f6460c9b74fb6 Mon Sep 17 00:00:00 2001 From: Gauthier Monserand Date: Thu, 3 Nov 2022 16:32:47 +0100 Subject: [PATCH 4/4] cleanup --- spec/relation_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/relation_spec.rb b/spec/relation_spec.rb index 325f6ff7..cb41bf53 100644 --- a/spec/relation_spec.rb +++ b/spec/relation_spec.rb @@ -319,7 +319,7 @@ def self.active expect(RelationModel.where(active: true).adult).to match_array([m3, m4]) end - it "should be thread safe" do + it "should be scoped only in current thread" do m1 = RelationModel.create!(active: true) m2 = RelationModel.create!(active: false) RelationModel.active.scoping do