diff --git a/.gitignore b/.gitignore index a1d21bd..a852b7a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.idea .rvmrc .bundle coverage/* diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a5b643..69124b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,14 @@ +## [next] + +Fixes: + + - `XapianDb.database.delete_docs_of_class(klass)` now deletes docs of all descendants of `klass`, too (if tracked) + ##1.3.6 (August 14th, 2015) Changes: + - The required Ruby version is now 2.0.0 since we started using keyword parameters in method definitions - Ability do define and handle dependencies between blueprints (see README) - explicit order option for searches diff --git a/README.rdoc b/README.rdoc index 43b4bfd..51520c4 100644 --- a/README.rdoc +++ b/README.rdoc @@ -32,9 +32,9 @@ I tried hard but I couldn't find such a thing so I decided to write it, based on == Requirements -* ruby 1.9.2 or newer +* ruby 2.0.0 or newer * rails 3.0 or newer (if you want to use it with rails) -* xapian-core and xapian-ruby binaries installed +* xapian-core and xapian-ruby binaries 1.2.x installed == Installing xapian binaries diff --git a/examples/basic.rb b/examples/basic.rb index 87f19ca..7b03cd4 100644 --- a/examples/basic.rb +++ b/examples/basic.rb @@ -19,6 +19,9 @@ # 2: Define a class which should get indexed; we define a class that # could be an ActiveRecord or Datamapper Domain class class Person + # If you are using inheritance hierarchies among indexed classes outside of ActiveRecord, + # using DescendantsTracker helps with rebuilding the Xapian index for a given class and all its subclasses. + extend DescendantsTracker attr_accessor :id, :name, :first_name, :date_of_birth diff --git a/lib/xapian_db/database.rb b/lib/xapian_db/database.rb index bf36155..3ca2c06 100644 --- a/lib/xapian_db/database.rb +++ b/lib/xapian_db/database.rb @@ -35,10 +35,19 @@ def delete_doc_with_unique_term(term) true end - # Delete all docs of a specific class + # Delete all docs of a specific class. + # + # If `klass` tracks its descendants, then docs of any subclasses will be deleted, too. + # (ActiveRecord does this by default; the gem 'descendants_tracker' offers an alternative.) + # # @param [Class] klass A class that has a {XapianDb::DocumentBlueprint} configuration def delete_docs_of_class(klass) writer.delete_document("C#{klass}") + if klass.respond_to? :descendants + klass.descendants.each do |subclass| + writer.delete_document("C#{subclass}") + end + end true end diff --git a/spec/basic_mocks.rb b/spec/basic_mocks.rb index 61cc92f..f8a93e6 100644 --- a/spec/basic_mocks.rb +++ b/spec/basic_mocks.rb @@ -9,7 +9,7 @@ def tableize self # not really important what we return end - def parameterize + def parameterize self # not really important what we return end @@ -24,6 +24,23 @@ def initialize(id) end end +class IndexedObjectSubclass < IndexedObject +end + +require 'descendants_tracker' +class IndexedObjectDT + extend DescendantsTracker + + attr_reader :id + + def initialize(id) + @id = id + end +end + +class IndexedObjectTrackedSubclass < IndexedObjectDT +end + class OtherIndexedObject attr_reader :id diff --git a/spec/xapian_db/database_spec.rb b/spec/xapian_db/database_spec.rb index 4d8e4d3..65dfc4f 100644 --- a/spec/xapian_db/database_spec.rb +++ b/spec/xapian_db/database_spec.rb @@ -73,11 +73,15 @@ config.adapter :generic config.database :memory end - XapianDb::DocumentBlueprint.setup(:IndexedObject) do |blueprint| - blueprint.attribute :id + %i[ IndexedObject IndexedObjectSubclass IndexedObjectDT IndexedObjectTrackedSubclass ].each do |klass| + XapianDb::DocumentBlueprint.setup(klass) do |blueprint| + blueprint.attribute :id + end end - @blueprint = XapianDb::DocumentBlueprint.blueprint_for(:IndexedObject) - @indexer = XapianDb::Indexer.new(XapianDb.database, @blueprint) + @blueprint = XapianDb::DocumentBlueprint.blueprint_for(:IndexedObject) + @blueprint_dt = XapianDb::DocumentBlueprint.blueprint_for(:IndexedObjectDT) + @indexer = XapianDb::Indexer.new(XapianDb.database, @blueprint) + @indexer_dt = XapianDb::Indexer.new(XapianDb.database, @blueprint_dt) end it "should delete all docs of the given class" do @@ -99,6 +103,40 @@ end + it "should delete all docs of descendant classes, too, if they are tracked" do + + # Create a doc for a tracked subclass + obj = IndexedObjectTrackedSubclass.new(1) + doc = @indexer_dt.build_document_for(obj) + expect(XapianDb.database.store_doc(doc)).to be_truthy + + XapianDb.database.commit + expect(XapianDb.database.size).to eq(1) + + # Now delete all docs of the object's superclass + XapianDb.database.delete_docs_of_class(IndexedObjectDT) + XapianDb.database.commit + expect(XapianDb.database.size).to eq(0) + + end + + it "ignore descendant classes where no descendants tracking mechanism is employed" do + + # Create a doc for a non-tracked subclass + obj = IndexedObjectSubclass.new(1) + doc = @indexer.build_document_for(obj) + expect(XapianDb.database.store_doc(doc)).to be_truthy + + XapianDb.database.commit + expect(XapianDb.database.size).to eq(1) + + # Now delete all docs of the object's superclass + XapianDb.database.delete_docs_of_class(IndexedObject) + XapianDb.database.commit + expect(XapianDb.database.size).to eq(1) + + end + it "must not delete docs of a different class that have a term like the name of " do class LeaveMeAlone diff --git a/spec/xapian_db/document_blueprint_spec.rb b/spec/xapian_db/document_blueprint_spec.rb index ab49c82..d000b2c 100644 --- a/spec/xapian_db/document_blueprint_spec.rb +++ b/spec/xapian_db/document_blueprint_spec.rb @@ -226,9 +226,12 @@ class InheritedIndexedObject < IndexedObject; end it "does replace the blueprint for a class if the class is reloaded" do XapianDb::DocumentBlueprint.setup(:IndexedObject) expect(XapianDb::DocumentBlueprint.configured_classes.size).to eq(1) + # reload IndexedObject Object.send(:remove_const, :IndexedObject) + Object.send(:remove_const, :IndexedObjectSubclass) load File.expand_path('../../basic_mocks.rb', __FILE__) + XapianDb::DocumentBlueprint.setup(:IndexedObject) expect(XapianDb::DocumentBlueprint.configured_classes.size).to eq(1) end diff --git a/xapian_db.gemspec b/xapian_db.gemspec index 37a187f..1e15671 100644 --- a/xapian_db.gemspec +++ b/xapian_db.gemspec @@ -14,7 +14,8 @@ Gem::Specification.new do |s| s.homepage = %q{https://github.com/garaio/xapian_db} s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Xapian-DB", "--main", "README.rdoc"] - s.required_rubygems_version = ">=1.3.6" + s.required_ruby_version = ">= 2.0.0" + s.required_rubygems_version = ">= 1.3.6" s.add_dependency "daemons", ">= 1.0.10" @@ -26,8 +27,9 @@ Gem::Specification.new do |s| s.add_development_dependency "ruby-progressbar" s.add_development_dependency "resque", ">= 1.19.0" s.add_development_dependency "sidekiq", ">= 2.13.0" - s.add_development_dependency "xapian-ruby", "= 1.2.21" + s.add_development_dependency "xapian-ruby", "= 1.2.22" s.add_development_dependency "pry-rails" + s.add_development_dependency "descendants_tracker" s.files = Dir.glob("lib/**/*") + Dir.glob("tasks/*") + Dir.glob("xapian_source/*") + %w(LICENSE README.rdoc CHANGELOG.md Rakefile) s.require_path = "lib"