From 3315c3290ef193f469a418f61f1415399318ac05 Mon Sep 17 00:00:00 2001 From: Tiago Cardoso Date: Mon, 27 May 2013 11:06:11 +0200 Subject: [PATCH 1/9] added collection adapter for active record, so that certain query/object instantiation methods are made available from it as well --- lib/orm_adapter/adapters/active_record.rb | 39 ++++++++++++++ lib/orm_adapter/base.rb | 15 ++++++ lib/orm_adapter/to_adapter.rb | 6 +++ .../adapters/active_record_spec.rb | 2 +- spec/orm_adapter/example_app_shared.rb | 53 +++++++++++++++++++ 5 files changed, 114 insertions(+), 1 deletion(-) diff --git a/lib/orm_adapter/adapters/active_record.rb b/lib/orm_adapter/adapters/active_record.rb index 9626f04..ce67df2 100644 --- a/lib/orm_adapter/adapters/active_record.rb +++ b/lib/orm_adapter/adapters/active_record.rb @@ -65,10 +65,49 @@ def conditions_to_fields(conditions) def order_clause(order) order.map {|pair| "#{pair[0]} #{pair[1]}"}.join(",") end + + class Collection + + attr_reader :collection + + def initialize(collection) + @collection = collection + end + + def klass + collection.klass + end + + def klass_adapter + @klass_adapter ||= klass.to_adapter + end + + def find_first(options = {}) + conditions, order = klass_adapter.send(:extract_conditions!, options) + collection.scoped.where(klass_adapter.send(:conditions_to_fields, conditions)).order(*klass_adapter.send(:order_clause, order)).first + end + + def find(options = {}) + conditions, order, limit, offset = klass_adapter.send(:extract_conditions!, options) + collection.scoped.where(klass_adapter.send(:conditions_to_fields, conditions)).order(*klass_adapter.send(:order_clause, order)).limit(limit).offset(offset) + end + + def build(attributes = {}) + collection.build(attributes) + end + + def create!(attributes = {}) + collection.create!(attributes) + end + + end end end ActiveSupport.on_load(:active_record) do extend ::OrmAdapter::ToAdapter self::OrmAdapter = ::OrmAdapter::ActiveRecord + ActiveRecord::Associations::CollectionAssociation.send :include, ::OrmAdapter::ToCollectionAdapter + ActiveRecord::Associations::CollectionAssociation::OrmAdapter = ::OrmAdapter::ActiveRecord::Collection + ActiveRecord::Associations::CollectionProxy.delegate :to_adapter, :to => :@association end diff --git a/lib/orm_adapter/base.rb b/lib/orm_adapter/base.rb index 1bb6133..3fa8832 100644 --- a/lib/orm_adapter/base.rb +++ b/lib/orm_adapter/base.rb @@ -119,6 +119,21 @@ def normalize_order(order) end end + + module Collection + class Base + attr_reader :collection + + def initialize(collection) + @collection = collection + end + + def klass + raise NotSupportedError + end + end + end + class NotSupportedError < NotImplementedError def to_s "method not supported by this orm adapter" diff --git a/lib/orm_adapter/to_adapter.rb b/lib/orm_adapter/to_adapter.rb index 7bf6419..6ec56d1 100644 --- a/lib/orm_adapter/to_adapter.rb +++ b/lib/orm_adapter/to_adapter.rb @@ -5,4 +5,10 @@ def to_adapter @_to_adapter ||= self::OrmAdapter.new(self) end end + + module ToCollectionAdapter + def to_adapter + @_to_adapter ||= self.class::OrmAdapter.new(self) + end + end end \ No newline at end of file diff --git a/spec/orm_adapter/adapters/active_record_spec.rb b/spec/orm_adapter/adapters/active_record_spec.rb index 126beb0..ea44edb 100644 --- a/spec/orm_adapter/adapters/active_record_spec.rb +++ b/spec/orm_adapter/adapters/active_record_spec.rb @@ -9,7 +9,7 @@ ActiveRecord::Migration.suppress_messages do ActiveRecord::Schema.define(:version => 0) do create_table(:users, :force => true) {|t| t.string :name; t.integer :rating; } - create_table(:notes, :force => true) {|t| t.belongs_to :owner, :polymorphic => true } + create_table(:notes, :force => true) {|t| t.belongs_to :owner, :polymorphic => true ; t.string :description } end end diff --git a/spec/orm_adapter/example_app_shared.rb b/spec/orm_adapter/example_app_shared.rb index a80dc31..b1ca818 100644 --- a/spec/orm_adapter/example_app_shared.rb +++ b/spec/orm_adapter/example_app_shared.rb @@ -237,4 +237,57 @@ def reload_model(model) end end end + + describe "an ORM collection" do + def notes_adapter + user.notes.to_adapter + end + let(:user) { create_model(user_class) } + describe "#klass" do + it "should return the class of the elements belonging to the collection" do + user.notes.to_adapter.klass.should == note_class + end + end + describe "#find_first" do + describe "(conditions)" do + describe "if note belongs to the user" do + it "should return first model matching conditions, if it exists" do + create_model(note_class, :description => "stuff") + note = create_model(note_class, :owner => user, :description => "stuff") + notes_adapter.find_first(:description => "stuff").should == note + end + end + + describe "if note does not belongs to the user" do + it "should not return first model matching conditions, if it exists" do + create_model(note_class, :description => "stuff") + notes_adapter.find_first(:description => "stuff").should == nil + end + end + end + end + + describe "#find" do + it "should only return notes belonging to the given user" do + note1 = create_model(note_class, :owner => user) + note2 = create_model(note_class, :owner => user) + note3 = create_model(note_class) + note4 = create_model(note_class) + notes_adapter.find.should == [note1, note2] + end + end + + describe "#create!" do + it "should create the object with the association to the collection owner established" do + note = notes_adapter.create! + note.owner.should == user + end + end + describe "#build" do + it "should build the object and establish the association to the collection owner" do + note = notes_adapter.build + note.owner = user + end + end + end end From b10dc1fd1ba14177b05937f3abd80e177b988f6d Mon Sep 17 00:00:00 2001 From: Tiago Cardoso Date: Tue, 28 May 2013 09:14:39 +0200 Subject: [PATCH 2/9] disabling previously added collection abstractions (for now commented, to be removed in a later stage) --- lib/orm_adapter/adapters/active_record.rb | 72 ++++++------ .../adapters/active_record_spec.rb | 2 +- spec/orm_adapter/example_app_shared.rb | 103 +++++++++--------- 3 files changed, 89 insertions(+), 88 deletions(-) diff --git a/lib/orm_adapter/adapters/active_record.rb b/lib/orm_adapter/adapters/active_record.rb index ce67df2..287dad2 100644 --- a/lib/orm_adapter/adapters/active_record.rb +++ b/lib/orm_adapter/adapters/active_record.rb @@ -66,41 +66,41 @@ def order_clause(order) order.map {|pair| "#{pair[0]} #{pair[1]}"}.join(",") end - class Collection - - attr_reader :collection - - def initialize(collection) - @collection = collection - end - - def klass - collection.klass - end - - def klass_adapter - @klass_adapter ||= klass.to_adapter - end - - def find_first(options = {}) - conditions, order = klass_adapter.send(:extract_conditions!, options) - collection.scoped.where(klass_adapter.send(:conditions_to_fields, conditions)).order(*klass_adapter.send(:order_clause, order)).first - end - - def find(options = {}) - conditions, order, limit, offset = klass_adapter.send(:extract_conditions!, options) - collection.scoped.where(klass_adapter.send(:conditions_to_fields, conditions)).order(*klass_adapter.send(:order_clause, order)).limit(limit).offset(offset) - end - - def build(attributes = {}) - collection.build(attributes) - end - - def create!(attributes = {}) - collection.create!(attributes) - end - - end + #class Collection + # + # attr_reader :collection + # + # def initialize(collection) + # @collection = collection + # end + # + # def klass + # collection.klass + # end + # + # def klass_adapter + # @klass_adapter ||= klass.to_adapter + # end + # + # def find_first(options = {}) + # conditions, order = klass_adapter.send(:extract_conditions!, options) + # collection.scoped.where(klass_adapter.send(:conditions_to_fields, conditions)).order(*klass_adapter.send(:order_clause, order)).first + # end + # + # def find(options = {}) + # conditions, order, limit, offset = klass_adapter.send(:extract_conditions!, options) + # collection.scoped.where(klass_adapter.send(:conditions_to_fields, conditions)).order(*klass_adapter.send(:order_clause, order)).limit(limit).offset(offset) + # end + # + # def build(attributes = {}) + # collection.build(attributes) + # end + # + # def create!(attributes = {}) + # collection.create!(attributes) + # end + # + #end end end @@ -108,6 +108,4 @@ def create!(attributes = {}) extend ::OrmAdapter::ToAdapter self::OrmAdapter = ::OrmAdapter::ActiveRecord ActiveRecord::Associations::CollectionAssociation.send :include, ::OrmAdapter::ToCollectionAdapter - ActiveRecord::Associations::CollectionAssociation::OrmAdapter = ::OrmAdapter::ActiveRecord::Collection - ActiveRecord::Associations::CollectionProxy.delegate :to_adapter, :to => :@association end diff --git a/spec/orm_adapter/adapters/active_record_spec.rb b/spec/orm_adapter/adapters/active_record_spec.rb index ea44edb..126beb0 100644 --- a/spec/orm_adapter/adapters/active_record_spec.rb +++ b/spec/orm_adapter/adapters/active_record_spec.rb @@ -9,7 +9,7 @@ ActiveRecord::Migration.suppress_messages do ActiveRecord::Schema.define(:version => 0) do create_table(:users, :force => true) {|t| t.string :name; t.integer :rating; } - create_table(:notes, :force => true) {|t| t.belongs_to :owner, :polymorphic => true ; t.string :description } + create_table(:notes, :force => true) {|t| t.belongs_to :owner, :polymorphic => true } end end diff --git a/spec/orm_adapter/example_app_shared.rb b/spec/orm_adapter/example_app_shared.rb index b1ca818..a3d5c7b 100644 --- a/spec/orm_adapter/example_app_shared.rb +++ b/spec/orm_adapter/example_app_shared.rb @@ -238,56 +238,59 @@ def reload_model(model) end end - describe "an ORM collection" do - def notes_adapter - user.notes.to_adapter - end - let(:user) { create_model(user_class) } - describe "#klass" do - it "should return the class of the elements belonging to the collection" do - user.notes.to_adapter.klass.should == note_class - end - end - describe "#find_first" do - describe "(conditions)" do - describe "if note belongs to the user" do - it "should return first model matching conditions, if it exists" do - create_model(note_class, :description => "stuff") - note = create_model(note_class, :owner => user, :description => "stuff") - notes_adapter.find_first(:description => "stuff").should == note - end - end - - describe "if note does not belongs to the user" do - it "should not return first model matching conditions, if it exists" do - create_model(note_class, :description => "stuff") - notes_adapter.find_first(:description => "stuff").should == nil - end - end - end - end - - describe "#find" do - it "should only return notes belonging to the given user" do - note1 = create_model(note_class, :owner => user) - note2 = create_model(note_class, :owner => user) - note3 = create_model(note_class) - note4 = create_model(note_class) - notes_adapter.find.should == [note1, note2] - end - end - - describe "#create!" do - it "should create the object with the association to the collection owner established" do - note = notes_adapter.create! - note.owner.should == user - end - end - describe "#build" do - it "should build the object and establish the association to the collection owner" do - note = notes_adapter.build - note.owner = user - end end end + + #describe "an ORM collection" do + # def notes_adapter + # user.notes.to_adapter + # end + # let(:user) { create_model(user_class) } + # describe "#klass" do + # it "should return the class of the elements belonging to the collection" do + # user.notes.to_adapter.klass.should == note_class + # end + # end + # describe "#find_first" do + # describe "(conditions)" do + # describe "if note belongs to the user" do + # it "should return first model matching conditions, if it exists" do + # create_model(note_class, :description => "stuff") + # note = create_model(note_class, :owner => user, :description => "stuff") + # notes_adapter.find_first(:description => "stuff").should == note + # end + # end + # + # describe "if note does not belongs to the user" do + # it "should not return first model matching conditions, if it exists" do + # create_model(note_class, :description => "stuff") + # notes_adapter.find_first(:description => "stuff").should == nil + # end + # end + # end + # end + # + # describe "#find" do + # it "should only return notes belonging to the given user" do + # note1 = create_model(note_class, :owner => user) + # note2 = create_model(note_class, :owner => user) + # note3 = create_model(note_class) + # note4 = create_model(note_class) + # notes_adapter.find.should == [note1, note2] + # end + # end + # + # describe "#create!" do + # it "should create the object with the association to the collection owner established" do + # note = notes_adapter.create! + # note.owner.should == user + # end + # end + # describe "#build" do + # it "should build the object and establish the association to the collection owner" do + # note = notes_adapter.build + # note.owner = user + # end + # end + #end end From 73b0f4d4b94128a8e72f5b26810697e22fb77571 Mon Sep 17 00:00:00 2001 From: Tiago Cardoso Date: Tue, 28 May 2013 09:15:57 +0200 Subject: [PATCH 3/9] added scoped adapters specification --- spec/orm_adapter/example_app_shared.rb | 86 +++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 2 deletions(-) diff --git a/spec/orm_adapter/example_app_shared.rb b/spec/orm_adapter/example_app_shared.rb index a3d5c7b..345627f 100644 --- a/spec/orm_adapter/example_app_shared.rb +++ b/spec/orm_adapter/example_app_shared.rb @@ -62,6 +62,18 @@ def reload_model(model) it "should raise an error if there is no instance with that id" do lambda { user_adapter.get!("nonexistent id") }.should raise_error end + + describe "scoped" do + let(:user_adapter) { user_class.to_adapter(:name => "balls") } + it "should return the instance if it belongs to the scope" do + user = create_model(user_class, :name => "balls") + user_adapter.get!(user.id).should == user + end + it "should not return the instance if it does not belong to the scope" do + user = create_model(user_class) + user_adapter.get!(user.id).should raise_error + end + end end describe "#get(id)" do @@ -78,6 +90,18 @@ def reload_model(model) it "should return nil if there is no instance with that id" do user_adapter.get("nonexistent id").should be_nil end + + describe "scoped" do + let(:user_adapter) { user_class.to_adapter(:name => "balls") } + it "should return the instance if it belongs to the scope" do + user = create_model(user_class, :name => "balls") + user_adapter.get!(user.id).should == user + end + it "should not return the instance if it does not belong to the scope" do + user = create_model(user_class) + user_adapter.get!(user.id).should == nil + end + end end describe "#find_first" do @@ -126,6 +150,15 @@ def reload_model(model) user_adapter.find_first(:conditions => {:name => "Fred"}, :order => [:rating, :desc]).should == user2 end end + + describe "scoped" do + let(:user_adapter) { user_class.to_adapter(:name => "balls") } + it "should return first model matching conditions belonging to the scope" do + user1 = create_model(user_class, :name => "something else") + user2 = create_model(user_class, :name => "balls") + user_adapter.find_first.should == user2 + end + end end describe "#find_all" do @@ -194,6 +227,49 @@ def reload_model(model) user_adapter.find_all(:limit => 1, :offset => 1).should == [user2] end end + + describe "scoped" do + let(:user_adapter) { user_class.to_adapter(:name => "balls") } + it "should return all models matching conditions belonging to the scope" do + user1 = create_model(user_class, :name => "something else") + user2 = create_model(user_class, :name => "something other") + user3 = create_model(user_class, :name => "balls") + user4 = create_model(user_class, :name => "balls") + user_adapter.find_all.should == [user3, user4] + end + end + end + + describe "#build(attributes)" do + it "should build a non-persistent model" do + user = user_adapter.build + user.should_not be_persisted + end + + it "should build a model with the passed attributes" do + user = user_adapter.build(:name => "Fred") + user.name.should == "Fred" + end + + it "when attributes contain an associated object, should build a model with the attributes" do + user = create_model(user_class) + note = note_adapter.build(:owner => user) + note.owner.should == user + end + + it "when attributes contain an has_many assoc, should build a model with the attributes" do + notes = [create_model(note_class), create_model(note_class)] + user = user_adapter.build(:notes => notes) + user.notes.should == notes + end + + describe "scoped" do + let(:user_adapter) { user_class.to_adapter(:name => "balls") } + it "should pass the adapter conditions as attributes to the built model" do + user = user_adapter.build + user.name.should == "balls" + end + end end describe "#create!(attributes)" do @@ -217,6 +293,14 @@ def reload_model(model) user = user_adapter.create!(:notes => notes) reload_model(user).notes.should == notes end + + describe "scoped" do + let(:user_adapter) { user_class.to_adapter(:name => "balls") } + it "should pass the adapter conditions as attributes to the created model" do + user = user_adapter.create! + reload_model(user).name.should == "balls" + end + end end describe "#destroy(instance)" do @@ -235,8 +319,6 @@ def reload_model(model) note_adapter.destroy(user).should be_nil user_adapter.get(user.id).should == user end - end - end end end From 5c9ebe45546c67f4367793eeca2cbc98ea7e15a8 Mon Sep 17 00:00:00 2001 From: Tiago Cardoso Date: Tue, 28 May 2013 09:16:42 +0200 Subject: [PATCH 4/9] missing removal of collection abstraction --- lib/orm_adapter/adapters/active_record.rb | 1 - lib/orm_adapter/to_adapter.rb | 5 ----- 2 files changed, 6 deletions(-) diff --git a/lib/orm_adapter/adapters/active_record.rb b/lib/orm_adapter/adapters/active_record.rb index 287dad2..ec9ec06 100644 --- a/lib/orm_adapter/adapters/active_record.rb +++ b/lib/orm_adapter/adapters/active_record.rb @@ -107,5 +107,4 @@ def order_clause(order) ActiveSupport.on_load(:active_record) do extend ::OrmAdapter::ToAdapter self::OrmAdapter = ::OrmAdapter::ActiveRecord - ActiveRecord::Associations::CollectionAssociation.send :include, ::OrmAdapter::ToCollectionAdapter end diff --git a/lib/orm_adapter/to_adapter.rb b/lib/orm_adapter/to_adapter.rb index 6ec56d1..872b583 100644 --- a/lib/orm_adapter/to_adapter.rb +++ b/lib/orm_adapter/to_adapter.rb @@ -6,9 +6,4 @@ def to_adapter end end - module ToCollectionAdapter - def to_adapter - @_to_adapter ||= self.class::OrmAdapter.new(self) - end - end end \ No newline at end of file From 0880667edb36c359a0341fe52c2733f60767da82 Mon Sep 17 00:00:00 2001 From: Tiago Cardoso Date: Tue, 28 May 2013 11:01:18 +0200 Subject: [PATCH 5/9] added build abstract method and completed the adapter constructor. Due to the changes (no fix parameters list) I opted for removing the memoization of the adapter on a class variable due to the thread-safety implications --- lib/orm_adapter/base.rb | 24 +++++++----------------- lib/orm_adapter/to_adapter.rb | 4 ++-- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/lib/orm_adapter/base.rb b/lib/orm_adapter/base.rb index 3fa8832..62deb9d 100644 --- a/lib/orm_adapter/base.rb +++ b/lib/orm_adapter/base.rb @@ -1,6 +1,6 @@ module OrmAdapter class Base - attr_reader :klass + attr_reader :klass, :scope # Your ORM adapter needs to inherit from this Base class and its adapter # will be registered. To create an adapter you should create an inner @@ -14,8 +14,9 @@ def self.inherited(adapter) super end - def initialize(klass) + def initialize(klass, scope={}) @klass = klass + @scope = scope end # Get a list of column/property/field names @@ -68,6 +69,10 @@ def find_all(options = {}) raise NotSupportedError end + def build(attributes = {}) + raise NotSupportedError + end + # Create a model using attributes def create!(attributes = {}) raise NotSupportedError @@ -119,21 +124,6 @@ def normalize_order(order) end end - - module Collection - class Base - attr_reader :collection - - def initialize(collection) - @collection = collection - end - - def klass - raise NotSupportedError - end - end - end - class NotSupportedError < NotImplementedError def to_s "method not supported by this orm adapter" diff --git a/lib/orm_adapter/to_adapter.rb b/lib/orm_adapter/to_adapter.rb index 872b583..9eb8428 100644 --- a/lib/orm_adapter/to_adapter.rb +++ b/lib/orm_adapter/to_adapter.rb @@ -1,8 +1,8 @@ module OrmAdapter # Extend into a class that has an OrmAdapter module ToAdapter - def to_adapter - @_to_adapter ||= self::OrmAdapter.new(self) + def to_adapter(scope = {}) + self::OrmAdapter.new(self, scope) end end From 9d5ffc8a323ac710c7607c94ee47229423e2ef56 Mon Sep 17 00:00:00 2001 From: Tiago Cardoso Date: Tue, 28 May 2013 11:01:50 +0200 Subject: [PATCH 6/9] rearranged the specs (scoped blocks are not separated anymore) --- spec/orm_adapter/example_app_shared.rb | 49 +++++++++++--------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/spec/orm_adapter/example_app_shared.rb b/spec/orm_adapter/example_app_shared.rb index 345627f..607fd3a 100644 --- a/spec/orm_adapter/example_app_shared.rb +++ b/spec/orm_adapter/example_app_shared.rb @@ -39,7 +39,7 @@ def reload_model(model) subject.to_adapter.klass.should == subject end - it "#to_adapter should be cached" do + pending "#to_adapter should be cached" do subject.to_adapter.object_id.should == subject.to_adapter.object_id end end @@ -47,6 +47,7 @@ def reload_model(model) describe "adapter instance" do let(:note_adapter) { note_class.to_adapter } let(:user_adapter) { user_class.to_adapter } + let(:scoped_user_adapter) { user_class.to_adapter(:name => "balls") } describe "#get!(id)" do it "should return the instance with id if it exists" do @@ -63,16 +64,13 @@ def reload_model(model) lambda { user_adapter.get!("nonexistent id") }.should raise_error end - describe "scoped" do - let(:user_adapter) { user_class.to_adapter(:name => "balls") } - it "should return the instance if it belongs to the scope" do - user = create_model(user_class, :name => "balls") - user_adapter.get!(user.id).should == user - end - it "should not return the instance if it does not belong to the scope" do - user = create_model(user_class) - user_adapter.get!(user.id).should raise_error - end + it "should return the instance if it belongs to the scope" do + user = create_model(user_class, :name => "balls") + scoped_user_adapter.get!(user.id).should == user + end + it "should not return the instance if it does not belong to the scope" do + user = create_model(user_class) + lambda { scoped_user_adapter.get!(user.id) }.should raise_error end end @@ -91,16 +89,13 @@ def reload_model(model) user_adapter.get("nonexistent id").should be_nil end - describe "scoped" do - let(:user_adapter) { user_class.to_adapter(:name => "balls") } - it "should return the instance if it belongs to the scope" do - user = create_model(user_class, :name => "balls") - user_adapter.get!(user.id).should == user - end - it "should not return the instance if it does not belong to the scope" do - user = create_model(user_class) - user_adapter.get!(user.id).should == nil - end + it "should return the instance if it belongs to the scope" do + user = create_model(user_class, :name => "balls") + scoped_user_adapter.get(user.id).should == user + end + it "should not return the instance if it does not belong to the scope" do + user = create_model(user_class) + scoped_user_adapter.get(user.id).should == nil end end @@ -152,11 +147,10 @@ def reload_model(model) end describe "scoped" do - let(:user_adapter) { user_class.to_adapter(:name => "balls") } it "should return first model matching conditions belonging to the scope" do user1 = create_model(user_class, :name => "something else") user2 = create_model(user_class, :name => "balls") - user_adapter.find_first.should == user2 + scoped_user_adapter.find_first.should == user2 end end end @@ -229,13 +223,12 @@ def reload_model(model) end describe "scoped" do - let(:user_adapter) { user_class.to_adapter(:name => "balls") } it "should return all models matching conditions belonging to the scope" do user1 = create_model(user_class, :name => "something else") user2 = create_model(user_class, :name => "something other") user3 = create_model(user_class, :name => "balls") user4 = create_model(user_class, :name => "balls") - user_adapter.find_all.should == [user3, user4] + scoped_user_adapter.find_all.should == [user3, user4] end end end @@ -264,9 +257,8 @@ def reload_model(model) end describe "scoped" do - let(:user_adapter) { user_class.to_adapter(:name => "balls") } it "should pass the adapter conditions as attributes to the built model" do - user = user_adapter.build + user = scoped_user_adapter.build user.name.should == "balls" end end @@ -295,9 +287,8 @@ def reload_model(model) end describe "scoped" do - let(:user_adapter) { user_class.to_adapter(:name => "balls") } it "should pass the adapter conditions as attributes to the created model" do - user = user_adapter.create! + user = scoped_user_adapter.create! reload_model(user).name.should == "balls" end end From 023b2f93b7c175d0ff3cad7be4c7d81b205f0a4d Mon Sep 17 00:00:00 2001 From: Tiago Cardoso Date: Tue, 28 May 2013 11:02:38 +0200 Subject: [PATCH 7/9] started implementing solutions for activerecord and datamapper (the get solution for datamapper could be less complicated, though) --- lib/orm_adapter/adapters/active_record.rb | 18 +++++++++++---- lib/orm_adapter/adapters/data_mapper.rb | 28 +++++++++++++++++------ 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/lib/orm_adapter/adapters/active_record.rb b/lib/orm_adapter/adapters/active_record.rb index ec9ec06..9ba1705 100644 --- a/lib/orm_adapter/adapters/active_record.rb +++ b/lib/orm_adapter/adapters/active_record.rb @@ -9,29 +9,33 @@ def column_names # @see OrmAdapter::Base#get! def get!(id) - klass.find(wrap_key(id)) + scoped.find(wrap_key(id)) end # @see OrmAdapter::Base#get def get(id) - klass.where(klass.primary_key => wrap_key(id)).first + scoped.where(klass.primary_key => wrap_key(id)).first end # @see OrmAdapter::Base#find_first def find_first(options = {}) conditions, order = extract_conditions!(options) - klass.where(conditions_to_fields(conditions)).order(*order_clause(order)).first + scoped.where(conditions_to_fields(conditions)).order(*order_clause(order)).first end # @see OrmAdapter::Base#find_all def find_all(options = {}) conditions, order, limit, offset = extract_conditions!(options) - klass.where(conditions_to_fields(conditions)).order(*order_clause(order)).limit(limit).offset(offset).all + scoped.where(conditions_to_fields(conditions)).order(*order_clause(order)).limit(limit).offset(offset).all + end + + def build(attributes = {}) + scoped.build(attributes) end # @see OrmAdapter::Base#create! def create!(attributes = {}) - klass.create!(attributes) + scoped.create!(attributes) end # @see OrmAdapter::Base#destroy @@ -41,6 +45,10 @@ def destroy(object) protected + def scoped + klass.where(conditions_to_fields(@scope)) + end + # Introspects the klass to convert and objects in conditions into foreign key and type fields def conditions_to_fields(conditions) fields = {} diff --git a/lib/orm_adapter/adapters/data_mapper.rb b/lib/orm_adapter/adapters/data_mapper.rb index 8fb1530..0dce69d 100644 --- a/lib/orm_adapter/adapters/data_mapper.rb +++ b/lib/orm_adapter/adapters/data_mapper.rb @@ -13,19 +13,24 @@ def column_names end # @see OrmAdapter::Base#get! - def get!(id) - klass.get!(id) + def get!(*id) + get(*id) || raise(DataMapper::ObjectNotFoundError) end # @see OrmAdapter::Base#get - def get(id) - klass.get(id) + def get(*id) + if @scope.empty? + klass.get(*id) + else + primary_key_conditions = klass.key_conditions(klass.repository, klass.key(klass.repository.name).typecast(id)).update(:order => nil) + klass.first(@scope.merge(primary_key_conditions)) + end end # @see OrmAdapter::Base#find_first def find_first(options = {}) conditions, order = extract_conditions!(options) - klass.first :conditions => conditions, :order => order_clause(order) + klass.first(scoped_query.update(:conditions => conditions, :order => order_clause(order))) end # @see OrmAdapter::Base#find_all @@ -34,12 +39,17 @@ def find_all(options = {}) opts = { :conditions => conditions, :order => order_clause(order) } opts = opts.merge({ :limit => limit }) unless limit.nil? opts = opts.merge({ :offset => offset }) unless offset.nil? - klass.all opts + klass.all(scoped_query.update(opts)) + end + + # @see OrmAdapter::Base#build + def build(attributes = {}) + klass.new(@scope.merge(attributes)) end # @see OrmAdapter::Base#create! def create!(attributes = {}) - klass.create(attributes) + klass.create(@scope.merge(attributes)) end # @see OrmAdapter::Base#destroy @@ -49,6 +59,10 @@ def destroy(object) protected + def scoped_query + klass.all(@scope).query + end + def order_clause(order) order.map {|pair| pair.first.send(pair.last)} end From 0f5df824204be06ec7284c812071cd5c899a5647 Mon Sep 17 00:00:00 2001 From: Tiago Cardoso Date: Tue, 28 May 2013 11:56:21 +0200 Subject: [PATCH 8/9] updated the value for destroy (in the mongo cases, it returns something other than true, but still true-y) --- spec/orm_adapter/example_app_shared.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/orm_adapter/example_app_shared.rb b/spec/orm_adapter/example_app_shared.rb index 607fd3a..451d12a 100644 --- a/spec/orm_adapter/example_app_shared.rb +++ b/spec/orm_adapter/example_app_shared.rb @@ -297,7 +297,7 @@ def reload_model(model) describe "#destroy(instance)" do it "should destroy the instance if it exists" do user = create_model(user_class) - user_adapter.destroy(user).should == true + user_adapter.destroy(user).should be_true user_adapter.get(user.id).should be_nil end From 0fd87c4e04356dd9a90302c3a7402d4497c9b3d1 Mon Sep 17 00:00:00 2001 From: Tiago Cardoso Date: Tue, 28 May 2013 11:57:20 +0200 Subject: [PATCH 9/9] added scoping to the mongos. Also updated the mongoid spec, which seemed to be compatible with an older version --- lib/orm_adapter/adapters/mongo_mapper.rb | 19 ++++++++++++++----- lib/orm_adapter/adapters/mongoid.rb | 19 ++++++++++++++----- .../orm_adapter/adapters/mongo_mapper_spec.rb | 4 +--- spec/orm_adapter/adapters/mongoid_spec.rb | 6 +++--- 4 files changed, 32 insertions(+), 16 deletions(-) diff --git a/lib/orm_adapter/adapters/mongo_mapper.rb b/lib/orm_adapter/adapters/mongo_mapper.rb index 2937d3c..0f27d71 100644 --- a/lib/orm_adapter/adapters/mongo_mapper.rb +++ b/lib/orm_adapter/adapters/mongo_mapper.rb @@ -14,19 +14,19 @@ def column_names # @see OrmAdapter::Base#get! def get!(id) - klass.find!(wrap_key(id)) + scoped.find!(wrap_key(id)) end # @see OrmAdapter::Base#get def get(id) - klass.first({ :id => wrap_key(id) }) + scoped.first({ :id => wrap_key(id) }) end # @see OrmAdapter::Base#find_first def find_first(conditions = {}) conditions, order = extract_conditions!(conditions) conditions = conditions.merge(:sort => order) unless order.nil? - klass.first(conditions_to_fields(conditions)) + scoped.first(conditions_to_fields(conditions)) end # @see OrmAdapter::Base#find_all @@ -35,12 +35,17 @@ def find_all(conditions = {}) conditions = conditions.merge(:sort => order) unless order.nil? conditions = conditions.merge(:limit => limit) unless limit.nil? conditions = conditions.merge(:offset => offset) unless limit.nil? || offset.nil? - klass.all(conditions_to_fields(conditions)) + scoped.all(conditions_to_fields(conditions)) + end + + # @see OrmAdapter::Base#build + def build(attributes = {}) + klass.new(@scope.merge(attributes)) end # @see OrmAdapter::Base#create! def create!(attributes = {}) - klass.create!(attributes) + klass.create!(@scope.merge(attributes)) end # @see OrmAdapter::Base#destroy @@ -50,6 +55,10 @@ def destroy(object) protected + def scoped + klass.where(conditions_to_fields(@scope)) + end + # converts and documents to ids def conditions_to_fields(conditions) conditions.inject({}) do |fields, (key, value)| diff --git a/lib/orm_adapter/adapters/mongoid.rb b/lib/orm_adapter/adapters/mongoid.rb index aaca494..6df888a 100644 --- a/lib/orm_adapter/adapters/mongoid.rb +++ b/lib/orm_adapter/adapters/mongoid.rb @@ -14,29 +14,34 @@ def column_names # @see OrmAdapter::Base#get! def get!(id) - klass.find(wrap_key(id)) + scoped.find(wrap_key(id)) end # @see OrmAdapter::Base#get def get(id) - klass.where(:_id => wrap_key(id)).first + scoped.where(:_id => wrap_key(id)).first end # @see OrmAdapter::Base#find_first def find_first(options = {}) conditions, order = extract_conditions!(options) - klass.limit(1).where(conditions_to_fields(conditions)).order_by(order).first + scoped.limit(1).where(conditions_to_fields(conditions)).order_by(order).first end # @see OrmAdapter::Base#find_all def find_all(options = {}) conditions, order, limit, offset = extract_conditions!(options) - klass.where(conditions_to_fields(conditions)).order_by(order).limit(limit).offset(offset) + scoped.where(conditions_to_fields(conditions)).order_by(order).limit(limit).offset(offset) + end + + # @see OrmAdapter::Base#build + def build(attributes = {}) + scoped.new(attributes) end # @see OrmAdapter::Base#create! def create!(attributes = {}) - klass.create!(attributes) + scoped.create!(attributes) end # @see OrmAdapter::Base#destroy @@ -46,6 +51,10 @@ def destroy(object) protected + def scoped + klass.where(conditions_to_fields(@scope)) + end + # converts and documents to ids def conditions_to_fields(conditions) conditions.inject({}) do |fields, (key, value)| diff --git a/spec/orm_adapter/adapters/mongo_mapper_spec.rb b/spec/orm_adapter/adapters/mongo_mapper_spec.rb index c75f480..4d44c0e 100644 --- a/spec/orm_adapter/adapters/mongo_mapper_spec.rb +++ b/spec/orm_adapter/adapters/mongo_mapper_spec.rb @@ -27,9 +27,7 @@ class Note describe MongoMapper::Document::OrmAdapter do before do - MongoMapper.database.collections.each do | coll | - coll.remove - end + MongoMapper.database.collections.each(&:remove) end it_should_behave_like "example app with orm_adapter" do diff --git a/spec/orm_adapter/adapters/mongoid_spec.rb b/spec/orm_adapter/adapters/mongoid_spec.rb index d2ad526..2f50e38 100644 --- a/spec/orm_adapter/adapters/mongoid_spec.rb +++ b/spec/orm_adapter/adapters/mongoid_spec.rb @@ -6,7 +6,7 @@ else Mongoid.configure do |config| - config.master = Mongo::Connection.new.db('orm_adapter_spec') + config.connect_to( 'orm_adapter_spec' ) end module MongoidOrmSpec @@ -14,13 +14,13 @@ class User include Mongoid::Document field :name field :rating - has_many_related :notes, :foreign_key => :owner_id, :class_name => 'MongoidOrmSpec::Note' + has_many :notes, :foreign_key => :owner_id, :class_name => 'MongoidOrmSpec::Note' end class Note include Mongoid::Document field :body, :default => "made by orm" - belongs_to_related :owner, :class_name => 'MongoidOrmSpec::User' + belongs_to :owner, :class_name => 'MongoidOrmSpec::User' end # here be the specs!