From c35c35157a5404a58c2d539f8851da0063e62102 Mon Sep 17 00:00:00 2001 From: Matt Aimonetti Date: Wed, 27 May 2009 18:16:50 -0700 Subject: [PATCH 1/3] added an automated way to mark design docs as dirty after the db was reset --- lib/couchrest/core/database.rb | 15 +++++++++++++ lib/couchrest/more/extended_document.rb | 11 ++++++++++ spec/couchrest/more/extended_doc_view_spec.rb | 21 ++++++------------- spec/fixtures/more/article.rb | 2 +- spec/fixtures/more/card.rb | 2 +- spec/fixtures/more/cat.rb | 2 +- spec/fixtures/more/event.rb | 2 +- spec/fixtures/more/invoice.rb | 2 +- spec/fixtures/more/service.rb | 2 +- spec/spec_helper.rb | 7 +++---- 10 files changed, 41 insertions(+), 25 deletions(-) diff --git a/lib/couchrest/core/database.rb b/lib/couchrest/core/database.rb index ed97127..475afc3 100644 --- a/lib/couchrest/core/database.rb +++ b/lib/couchrest/core/database.rb @@ -236,6 +236,16 @@ module CouchRest copy_doc(doc, dest) end + def extended_document_classes + @extended_document_classes ||= [] + end + + # store extended document classes so we can clear + # their freshness when we reset the DB + def register_extended_document_class(klass) + extended_document_classes << klass + end + # Compact the database, removing old document revisions and optimizing space use. def compact! CouchRest.post "#{@uri}/_compact" @@ -271,11 +281,16 @@ module CouchRest # DELETE the database itself. This is not undoable and could be rather # catastrophic. Use with care! def delete! + clear_extended_doc_fresh_cache CouchRest.delete @uri end private + def clear_extended_doc_fresh_cache + extended_document_classes.each{|klass| klass.design_doc_fresh = false if klass.respond_to?(:design_doc_fresh=) } + end + def uri_for_attachment(doc, name) if doc.is_a?(String) puts "CouchRest::Database#fetch_attachment will eventually require a doc as the first argument, not a doc.id" diff --git a/lib/couchrest/more/extended_document.rb b/lib/couchrest/more/extended_document.rb index 4fe8182..3ea7031 100644 --- a/lib/couchrest/more/extended_document.rb +++ b/lib/couchrest/more/extended_document.rb @@ -20,6 +20,15 @@ module CouchRest subklass.properties = self.properties.dup end EOS + + # re opening the use_database method so we can register our class + subklass.class_eval <<-EOS, __FILE__, __LINE__ + def self.use_database(db) + super + db.register_extended_document_class(self) if db.respond_to?(:register_extended_document_class) && !db.extended_document_classes.include?(self) + end + EOS + end # Accessors @@ -45,6 +54,8 @@ module CouchRest end end + + # Automatically set updated_at and created_at fields # on the document whenever saving occurs. CouchRest uses a pretty diff --git a/spec/couchrest/more/extended_doc_view_spec.rb b/spec/couchrest/more/extended_doc_view_spec.rb index 5b60aeb..1a5df71 100644 --- a/spec/couchrest/more/extended_doc_view_spec.rb +++ b/spec/couchrest/more/extended_doc_view_spec.rb @@ -61,12 +61,12 @@ describe "ExtendedDocument views" do describe "another model with a simple view" do before(:all) do reset_test_db! + Course.design_doc_fresh = false %w{aaa bbb ddd eee}.each do |title| Course.new(:title => title).save end end it "should make the design doc upon first query" do - Course.design_doc_fresh = false Course.by_title doc = Course.design_doc doc['views']['all']['map'].should include('Course') @@ -74,13 +74,11 @@ describe "ExtendedDocument views" do it "should can query via view" do # register methods with method-missing, for local dispatch. method # missing lookup table, no heuristics. - Course.design_doc_fresh = false view = Course.view :by_title designed = Course.by_title view.should == designed end it "should get them" do - Course.design_doc_fresh = false rs = Course.by_title rs.length.should == 4 end @@ -104,7 +102,7 @@ describe "ExtendedDocument views" do describe "a ducktype view" do before(:all) do reset_test_db! - @id = TEST_SERVER.default_database.save_doc({:dept => true})['id'] + @id = DB.save_doc({:dept => true})['id'] end it "should setup" do duck = Course.get(@id) # from a different db @@ -126,7 +124,7 @@ describe "ExtendedDocument views" do describe "a model class not tied to a database" do before(:all) do reset_test_db! - @db = TEST_SERVER.default_database + @db = DB %w{aaa bbb ddd eee}.each do |title| u = Unattached.new(:title => title) u.database = @db @@ -191,7 +189,7 @@ describe "ExtendedDocument views" do end it "should be able to cleanup the db/bump the revision number" do # if the previous specs were not run, the model_design_doc will be blank - Unattached.use_database TEST_SERVER.default_database + Unattached.use_database DB Unattached.view_by :questions Unattached.by_questions(:database => @db) original_revision = Unattached.model_design_doc(@db)['_rev'] @@ -204,8 +202,8 @@ describe "ExtendedDocument views" do before(:all) do reset_test_db! # setup the class default doc to save the design doc - Unattached.use_database TEST_SERVER.default_database - @us = Unattached.on(TEST_SERVER.default_database) + Unattached.use_database DB + @us = Unattached.on(DB) %w{aaa bbb ddd eee}.each do |title| u = @us.new(:title => title) u.save @@ -213,12 +211,10 @@ describe "ExtendedDocument views" do end end it "should query all" do - Unattached.design_doc_fresh = false rs = @us.all rs.length.should == 4 end it "should make the design doc upon first query" do - Unattached.design_doc_fresh = false @us.by_title doc = @us.design_doc doc['views']['all']['map'].should include('Unattached') @@ -265,7 +261,6 @@ describe "ExtendedDocument views" do describe "a model with a compound key view" do before(:all) do - Article.design_doc_fresh = false Article.by_user_id_and_date.each{|a| a.destroy(true)} Article.database.bulk_delete written_at = Time.now - 24 * 3600 * 7 @@ -309,19 +304,16 @@ describe "ExtendedDocument views" do end end it "should be available raw" do - Article.design_doc_fresh = false view = Article.by_tags :raw => true view['rows'].length.should == 5 end it "should be default to :reduce => false" do - Article.design_doc_fresh = false ars = Article.by_tags ars.first.tags.first.should == 'cool' end it "should be raw when reduce is true" do - Article.design_doc_fresh = false view = Article.by_tags :reduce => true, :group => true view['rows'].find{|r|r['key'] == 'cool'}['value'].should == 3 end @@ -331,7 +323,6 @@ describe "ExtendedDocument views" do describe "adding a view" do before(:each) do reset_test_db! - Article.design_doc_fresh = false Article.by_date @original_doc_rev = Article.model_design_doc['_rev'] @design_docs = Article.database.documents :startkey => "_design/", :endkey => "_design/\u9999" diff --git a/spec/fixtures/more/article.rb b/spec/fixtures/more/article.rb index 02b7944..e0a6393 100644 --- a/spec/fixtures/more/article.rb +++ b/spec/fixtures/more/article.rb @@ -1,5 +1,5 @@ class Article < CouchRest::ExtendedDocument - use_database TEST_SERVER.default_database + use_database DB unique_id :slug view_by :date, :descending => true diff --git a/spec/fixtures/more/card.rb b/spec/fixtures/more/card.rb index 46307ad..2562c9d 100644 --- a/spec/fixtures/more/card.rb +++ b/spec/fixtures/more/card.rb @@ -5,7 +5,7 @@ class Card < CouchRest::ExtendedDocument auto_validate! # Set the default database to use - use_database TEST_SERVER.default_database + use_database DB # Official Schema property :first_name diff --git a/spec/fixtures/more/cat.rb b/spec/fixtures/more/cat.rb index f53a2a2..54abad5 100644 --- a/spec/fixtures/more/cat.rb +++ b/spec/fixtures/more/cat.rb @@ -2,7 +2,7 @@ class Cat < CouchRest::ExtendedDocument include ::CouchRest::Validation # Set the default database to use - use_database TEST_SERVER.default_database + use_database DB property :name property :toys, :cast_as => ['CatToy'], :default => [] diff --git a/spec/fixtures/more/event.rb b/spec/fixtures/more/event.rb index c36527a..221865e 100644 --- a/spec/fixtures/more/event.rb +++ b/spec/fixtures/more/event.rb @@ -1,5 +1,5 @@ class Event < CouchRest::ExtendedDocument - use_database TEST_SERVER.default_database + use_database DB property :subject property :occurs_at, :cast_as => 'Time', :send => 'parse' diff --git a/spec/fixtures/more/invoice.rb b/spec/fixtures/more/invoice.rb index f308f7c..273e6f2 100644 --- a/spec/fixtures/more/invoice.rb +++ b/spec/fixtures/more/invoice.rb @@ -3,7 +3,7 @@ class Invoice < CouchRest::ExtendedDocument include CouchRest::Validation # Set the default database to use - use_database TEST_SERVER.default_database + use_database DB # Official Schema property :client_name diff --git a/spec/fixtures/more/service.rb b/spec/fixtures/more/service.rb index ea54a7a..6ecf276 100644 --- a/spec/fixtures/more/service.rb +++ b/spec/fixtures/more/service.rb @@ -3,7 +3,7 @@ class Service < CouchRest::ExtendedDocument include CouchRest::Validation auto_validate! # Set the default database to use - use_database TEST_SERVER.default_database + use_database DB # Official Schema property :name, :length => 4...20 diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 7e6800a..cafdcc5 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -12,6 +12,7 @@ unless defined?(FIXTURE_PATH) TESTDB = 'couchrest-test' TEST_SERVER = CouchRest.new TEST_SERVER.default_database = TESTDB + DB = TEST_SERVER.database(TESTDB) end class Basic < CouchRest::ExtendedDocument @@ -19,10 +20,8 @@ class Basic < CouchRest::ExtendedDocument end def reset_test_db! - cr = TEST_SERVER - db = cr.database(TESTDB) - db.recreate! rescue nil - db + DB.recreate! rescue nil + DB end Spec::Runner.configure do |config| From 295c0f05117f33daddd4a4b662c7967fb96309ff Mon Sep 17 00:00:00 2001 From: Matt Aimonetti Date: Wed, 27 May 2009 23:59:43 -0700 Subject: [PATCH 2/3] fixed the design doc cache issue --- couchrest.gemspec | 2 +- lib/couchrest.rb | 2 +- lib/couchrest/core/database.rb | 12 +----------- lib/couchrest/more/extended_document.rb | 14 +++++--------- spec/couchrest/more/extended_doc_view_spec.rb | 3 --- 5 files changed, 8 insertions(+), 25 deletions(-) diff --git a/couchrest.gemspec b/couchrest.gemspec index db09d15..043f1a6 100644 --- a/couchrest.gemspec +++ b/couchrest.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{couchrest} - s.version = "0.27" + s.version = "0.28" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["J. Chris Anderson", "Matt Aimonetti"] diff --git a/lib/couchrest.rb b/lib/couchrest.rb index af0b83c..a05b1ae 100644 --- a/lib/couchrest.rb +++ b/lib/couchrest.rb @@ -28,7 +28,7 @@ require 'couchrest/monkeypatches' # = CouchDB, close to the metal module CouchRest - VERSION = '0.27' unless self.const_defined?("VERSION") + VERSION = '0.28' unless self.const_defined?("VERSION") autoload :Server, 'couchrest/core/server' autoload :Database, 'couchrest/core/database' diff --git a/lib/couchrest/core/database.rb b/lib/couchrest/core/database.rb index 475afc3..8c43917 100644 --- a/lib/couchrest/core/database.rb +++ b/lib/couchrest/core/database.rb @@ -236,16 +236,6 @@ module CouchRest copy_doc(doc, dest) end - def extended_document_classes - @extended_document_classes ||= [] - end - - # store extended document classes so we can clear - # their freshness when we reset the DB - def register_extended_document_class(klass) - extended_document_classes << klass - end - # Compact the database, removing old document revisions and optimizing space use. def compact! CouchRest.post "#{@uri}/_compact" @@ -288,7 +278,7 @@ module CouchRest private def clear_extended_doc_fresh_cache - extended_document_classes.each{|klass| klass.design_doc_fresh = false if klass.respond_to?(:design_doc_fresh=) } + ::CouchRest::ExtendedDocument.subclasses.each{|klass| klass.design_doc_fresh = false if klass.respond_to?(:design_doc_fresh=) } end def uri_for_attachment(doc, name) diff --git a/lib/couchrest/more/extended_document.rb b/lib/couchrest/more/extended_document.rb index 3ea7031..bcc2afd 100644 --- a/lib/couchrest/more/extended_document.rb +++ b/lib/couchrest/more/extended_document.rb @@ -1,6 +1,7 @@ require 'mime/types' require File.join(File.dirname(__FILE__), "property") require File.join(File.dirname(__FILE__), '..', 'mixins', 'extended_document_mixins') +require "enumerator" module CouchRest @@ -12,6 +13,10 @@ module CouchRest include CouchRest::Mixins::DesignDoc include CouchRest::Mixins::ExtendedAttachments include CouchRest::Mixins::ClassProxy + + def self.subclasses + ObjectSpace.enum_for(:each_object, class << self; self; end).to_a.delete_if{|k| k == self} + end def self.inherited(subklass) subklass.send(:include, CouchRest::Mixins::Properties) @@ -20,15 +25,6 @@ module CouchRest subklass.properties = self.properties.dup end EOS - - # re opening the use_database method so we can register our class - subklass.class_eval <<-EOS, __FILE__, __LINE__ - def self.use_database(db) - super - db.register_extended_document_class(self) if db.respond_to?(:register_extended_document_class) && !db.extended_document_classes.include?(self) - end - EOS - end # Accessors diff --git a/spec/couchrest/more/extended_doc_view_spec.rb b/spec/couchrest/more/extended_doc_view_spec.rb index 1a5df71..4d797e5 100644 --- a/spec/couchrest/more/extended_doc_view_spec.rb +++ b/spec/couchrest/more/extended_doc_view_spec.rb @@ -61,7 +61,6 @@ describe "ExtendedDocument views" do describe "another model with a simple view" do before(:all) do reset_test_db! - Course.design_doc_fresh = false %w{aaa bbb ddd eee}.each do |title| Course.new(:title => title).save end @@ -109,13 +108,11 @@ describe "ExtendedDocument views" do duck["dept"].should == true end it "should make the design doc" do - Course.design_doc_fresh = false @as = Course.by_dept @doc = Course.design_doc @doc["views"]["by_dept"]["map"].should_not include("couchrest") end it "should not look for class" do - Course.design_doc_fresh = false @as = Course.by_dept @as[0]['_id'].should == @id end From 5e0632c1d00024666a5b7561e2a5f09822873abb Mon Sep 17 00:00:00 2001 From: Matt Aimonetti Date: Thu, 28 May 2009 10:36:25 -0700 Subject: [PATCH 3/3] removed ObjectSpace usage --- lib/couchrest/more/extended_document.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/couchrest/more/extended_document.rb b/lib/couchrest/more/extended_document.rb index bcc2afd..f4497b9 100644 --- a/lib/couchrest/more/extended_document.rb +++ b/lib/couchrest/more/extended_document.rb @@ -15,7 +15,8 @@ module CouchRest include CouchRest::Mixins::ClassProxy def self.subclasses - ObjectSpace.enum_for(:each_object, class << self; self; end).to_a.delete_if{|k| k == self} + @subclasses ||= [] + # ObjectSpace.enum_for(:each_object, class << self; self; end).to_a.delete_if{|k| k == self} end def self.inherited(subklass) @@ -25,6 +26,7 @@ module CouchRest subklass.properties = self.properties.dup end EOS + subclasses << subklass end # Accessors