From 757faed13b5a37cfb4e1b243c39bd0b0d1922cb7 Mon Sep 17 00:00:00 2001 From: Caio Torres Date: Mon, 19 Nov 2012 10:05:08 -0200 Subject: [PATCH] Added mongoid support --- Rakefile | 3 +- lib/active_repository/base.rb | 93 +++++++++++++++---- lib/active_repository/write_support.rb | 11 ++- spec/active_repository/base_spec.rb | 70 +++++++++++++- .../sql_query_executor_spec.rb | 1 - spec/support/shared_examples.rb | 39 +++++--- support/mongoid.yml | 6 ++ 7 files changed, 187 insertions(+), 36 deletions(-) create mode 100644 support/mongoid.yml diff --git a/Rakefile b/Rakefile index 7867b15..66575ca 100644 --- a/Rakefile +++ b/Rakefile @@ -5,7 +5,8 @@ desc 'Default: run rspec tests.' task :default => [:travis] task :travis do - puts "Starting to run `rspec spec`..." + cmd = "rspec spec" + puts "Starting to run `#{cmd}`..." system("export DISPLAY=:99.0 && bundle exec rspec spec -c") raise "#{cmd} failed!" unless $?.exitstatus == 0 end \ No newline at end of file diff --git a/lib/active_repository/base.rb b/lib/active_repository/base.rb index b547785..8827d19 100644 --- a/lib/active_repository/base.rb +++ b/lib/active_repository/base.rb @@ -11,8 +11,6 @@ class Base < ActiveHash::Base include ActiveModel::Validations::Callbacks include ActiveRepository::Associations - # TODO: implement first, last, - class_attribute :model_class, :save_in_memory before_validation :set_timestamps @@ -40,7 +38,11 @@ def self.define_custom_find_by_field(field_name) if self == get_model_class object = self.where(field_name.to_sym => args.first).first else - object = get_model_class.send(method_name, args) + if mongoid? + object = get_model_class.where(field_name.to_sym => args.first).first + else + object = get_model_class.send(method_name, args) + end end object.nil? ? nil : serialize!(object.attributes) @@ -57,7 +59,12 @@ def self.define_custom_find_all_by_field(field_name) if self == get_model_class objects = self.where(field_name.to_sym => args.first) else - objects = get_model_class.send(method_name, args) + objects = [] + if mongoid? + objects = get_model_class.where(field_name.to_sym => args.first) + else + objects = get_model_class.send(method_name, args) + end end objects.empty? ? [] : objects.map{ |object| serialize!(object.attributes) } @@ -70,7 +77,13 @@ def self.find(id) if self == get_model_class super(id) else - object = get_model_class.find(id) + object = nil + + if id == :all + object = all + else + object = get_model_class.find(id) + end if object.is_a?(Array) object.map { |o| serialize!(o.attributes) } @@ -99,7 +112,11 @@ def self.exists?(id) if self == get_model_class !find_by_id(id).nil? else - get_model_class.exists?(id) + if mongoid? + find_by_id(id).present? + else + get_model_class.exists?(id) + end end end @@ -107,7 +124,11 @@ def self.find_by_id(id) if self == get_model_class super(id) else - get_model_class.find_by_id(id) + if mongoid? + get_model_class.where(:id => id).entries.first + else + get_model_class.find_by_id(id) + end end end @@ -122,23 +143,49 @@ def self.find_or_create(attributes) def self.create(attributes={}) object = get_model_class.new(attributes) - object.id = nil if get_model_class.exists?(object.id) + object.id = nil if exists?(object.id) - object.save + if get_model_class == self + object.save + else + repository = serialize!(object.attributes) + repository.valid? ? (object = get_model_class.create(attributes)) : false + end serialize!(object.attributes) unless object.class.name == self end def update_attributes(attributes) - object = self.class.get_model_class.find(self.id) + object = nil + if mongoid? + object = self.class.get_model_class.find(self.id) + else + object = self.class.get_model_class.find(self.id) + end attributes.each do |k,v| - object.send("#{k.to_s}=", v) unless k == :id + object.update_attribute("#{k.to_s}", v) unless k == :id end - object.save + self.reload + end + + def update_attribute(key, value) + if self.class == self.class.get_model_class + super(key,value) + else + object = self.class.get_model_class.find(self.id) + + if mongoid? + super(key,value) + key = key.to_s == 'id' ? '_id' : key.to_s + end + + object.update_attribute(key, value) + object.save + end - self.attributes = object.attributes + self.reload end def self.all @@ -203,7 +250,13 @@ def self.get(position) end def convert(attribute="id") - object = self.class.get_model_class.send("find_by_#{attribute}", self.send(attribute)) + object = nil + + if mongoid? + object = self.class.where(attribute.to_sym => self.send(attribute)).first + else + object = self.class.get_model_class.send("find_by_#{attribute}", self.send(attribute)) + end object = self.class.get_model_class.new if object.nil? @@ -220,14 +273,14 @@ def convert(attribute="id") def attributes=(new_attributes) new_attributes.each do |k,v| - self.send("#{k.to_s}=", v) + self.send("#{k.to_s == '_id' ? 'id' : k.to_s}=", v) end end def serialize!(attributes) unless attributes.nil? attributes.each do |k,v| - self.send("#{k.to_s}=", v) + self.send("#{k.to_s == '_id' ? 'id' : k.to_s}=", v) end end @@ -262,5 +315,13 @@ def set_timestamps self.created_at = DateTime.now.utc if self.new_record? self.updated_at = DateTime.now.utc end + + def self.mongoid? + get_model_class.included_modules.include?(Mongoid::Document) + end + + def mongoid? + self.class.mongoid? + end end end diff --git a/lib/active_repository/write_support.rb b/lib/active_repository/write_support.rb index aed76a0..eee4695 100644 --- a/lib/active_repository/write_support.rb +++ b/lib/active_repository/write_support.rb @@ -51,6 +51,11 @@ def self.validate_unique_id(record) raise IdError.new("Duplicate Id found for record #{record.attributes}") if record_index.has_key?(record.id.to_s) end + def update_attribute(key, value) + self.send("#{key}=", value) + self.save(:validate => false) + end + def readonly? false end @@ -62,9 +67,13 @@ def save(*args) true end + def to_param + id.present? ? id.to_s : nil + end + def persisted? other = self.class.find_by_id(id) - other.present? && other.created_at + other.present? end def eql?(other) diff --git a/spec/active_repository/base_spec.rb b/spec/active_repository/base_spec.rb index b3dc43c..7083a7d 100644 --- a/spec/active_repository/base_spec.rb +++ b/spec/active_repository/base_spec.rb @@ -2,8 +2,8 @@ require 'support/shared_examples' require 'active_repository' -require "active_record" -require "mongoid" +require 'active_record' +require 'mongoid' describe ActiveRepository, "Base" do @@ -120,4 +120,70 @@ class CountryModel < ActiveRecord::Base it_behaves_like '.transaction' it_behaves_like '.delete_all' end + + context "mongoid" do + before do + Country.fields :name, :monarch, :language + + Mongoid.load!("support/mongoid.yml", :development) + + class CountryModel + include Mongoid::Document + + store_in collection: "countries" + + field :name + field :monarch + field :language + field :_id, type: Integer, default: -> { CountryModel.last ? CountryModel.last.id + 1 : 1 } + field :updated_at + field :created_at + end + + Country.set_model_class(CountryModel) + Country.set_save_in_memory(false) + + Country.delete_all + + Country.create(:id => 1, :name => "US", :language => 'English') + Country.create(:id => 2, :name => "Canada", :language => 'English', :monarch => "The Crown of England") + Country.create(:id => 3, :name => "Mexico", :language => 'Spanish') + Country.create(:id => 4, :name => "UK", :language => 'English', :monarch => "The Crown of England") + Country.create(:id => 5, :name => "Brazil") + end + + after do + Object.send :remove_const, :CountryModel + end + + it_behaves_like '.update_attributes' + it_behaves_like '.all' + it_behaves_like '.where' + it_behaves_like '.exists?' + it_behaves_like '.count' + it_behaves_like '.first' + it_behaves_like '.last' + it_behaves_like '.find' + it_behaves_like '.find_by_id' + it_behaves_like 'custom finders' + it_behaves_like '#method_missing' + it_behaves_like '#attributes' + it_behaves_like 'reader_methods' + it_behaves_like 'interrogator methods' + it_behaves_like '#id' + it_behaves_like '#quoted_id' + it_behaves_like '#to_param' + it_behaves_like '#persisted?' + it_behaves_like '#eql?' + it_behaves_like '#==' + it_behaves_like '#hash' + it_behaves_like '#readonly?' + it_behaves_like '#cache_key' + it_behaves_like '#save' + it_behaves_like '.create' + it_behaves_like '#valid?' + it_behaves_like '#new_record?' + it_behaves_like '.transaction' + it_behaves_like '.delete_all' + end end diff --git a/spec/active_repository/sql_query_executor_spec.rb b/spec/active_repository/sql_query_executor_spec.rb index a8553e0..00be797 100644 --- a/spec/active_repository/sql_query_executor_spec.rb +++ b/spec/active_repository/sql_query_executor_spec.rb @@ -3,7 +3,6 @@ require 'active_repository' require "active_record" -require "mongoid" describe ActiveRepository, "Base" do diff --git a/spec/support/shared_examples.rb b/spec/support/shared_examples.rb index a92f9cb..161cdfa 100644 --- a/spec/support/shared_examples.rb +++ b/spec/support/shared_examples.rb @@ -30,10 +30,9 @@ it "populates the data correctly" do records = Country.all - records.first.id.should == 1 - records.first.name.should == "US" - records.last.id.should == 5 - records.last.name.should == "Brazil" + records.should include(Country.first) + records.should include(Country.last) + records.size.should == 5 end end @@ -72,12 +71,13 @@ shared_examples ".exists?" do it "checks if a record exists" do - id = Country.last.id + 1 + id = Country.last.id Country.delete_all Country.exists?(id).should be_false - country = Country.create(:id => id, :name => "France") + country = Country.create(:name => "France") + id = country.id Country.exists?(id).should be_true end @@ -120,7 +120,11 @@ context "with :all" do it "returns all records" do - Country.find(:all).should == [Country.find(1), Country.find(2), Country.find(3), Country.find(4), Country.find(5)] + records = Country.find(:all) + + records.should include(Country.first) + records.should include(Country.last) + records.size.should == 5 end end @@ -446,9 +450,13 @@ class Region < ActiveRepository::Base end it 'should use the record\'s updated_at if present' do - country = Country.create(:id => 6, :name => "foo") + country = Country.create(:name => "foo") - Country.first.cache_key.should == "countries/6-#{country.updated_at.to_s(:number)}" + id = Country.last.id + + date_string = country.updated_at.nil? ? "" : "-#{country.updated_at.to_s(:number)}" + + Country.first.cache_key.should == "countries/#{id}#{date_string}" end it 'should use "new" instead of the id for a new record' do @@ -479,14 +487,15 @@ class Region < ActiveRepository::Base it "works with no args" do Country.all.should be_empty - country = Country.create :id => 6 - country.id.should == 6 + country = Country.create + + country.id.should == Country.last.id end it "adds the new object to the data collection" do Country.all.should be_empty - country = Country.create :id => 6, :name => "foo" - country.id.should == 6 + country = Country.create :name => "foo" + country.id.should == Country.last.id country.name.should == "foo" Country.all.should == [country] end @@ -509,8 +518,8 @@ class Region < ActiveRepository::Base it "adds the new object to the data collection" do Country.all.should be_empty - country = Country.create :id => 6, :name => "foo" - country.id.should == 6 + country = Country.create :name => "foo" + country.id.should == Country.last.id country.name.should == "foo" Country.all.should == [country] diff --git a/support/mongoid.yml b/support/mongoid.yml new file mode 100644 index 0000000..bf4ad54 --- /dev/null +++ b/support/mongoid.yml @@ -0,0 +1,6 @@ +development: + sessions: + default: + database: active_repository + hosts: + - localhost:27017 \ No newline at end of file