-before_install: gem install bundler --pre
+language: ruby
notifications:
email:
- parndt@gmail.com
+script: bundle exec rspec spec
env:
- DB=sqlite3
- DB=sqlite3mem
+ - DB=postgresql
+ - DB=mysql
rvm:
- - 1.8.7
- - 1.9.2
+ - 2.0.0
- 1.9.3
- - rbx
- - jruby
+ - 1.8.7
+ - rbx-19mode
+ - jruby-19mode
+ - rbx-18mode
+ - jruby-18mode
gemfile:
- gemfiles/Gemfile.rails-3.0.rb
- gemfiles/Gemfile.rails-3.1.rb
- - gemfiles/Gemfile.rails-3.2.rb
\ No newline at end of file
+ - gemfiles/Gemfile.rails-3.2.rb
+2.1.6
+* Fixed rebuild! when there is a default_scope with order [Adrian Serafin]
+* Testing with stable bundler, ruby 2.0, MySQL and PostgreSQL [Philip Arndt]
+* Optimized move_to for large trees [ericsmith66]
+
2.1.5
* Worked around issues where AR#association wasn't present on Rails 3.0.x. [Philip Arndt]
* Adds option 'order_column' which defaults to 'left_column_name'. [gudata]
require 'bundler/setup'
require 'awesome_nested_set/version'
-require "rspec/core/rake_task"
-RSpec::Core::RakeTask.new(:spec)
-
task :default => :spec
+task :spec do
+ %w(3.0 3.1 3.2).each do |rails_version|
+ puts "\n" + (cmd = "BUNDLE_GEMFILE='gemfiles/Gemfile.rails-#{rails_version}.rb' bundle exec rspec spec")
+ system cmd
+ end
+end
+
task :build do
system "gem build awesome_nested_set.gemspec"
end
# -*- encoding: utf-8 -*-
-lib = File.expand_path('../lib/', __FILE__)
-$:.unshift lib unless $:.include?(lib)
-require 'awesome_nested_set/version'
+require File.expand_path('../lib/awesome_nested_set/version', __FILE__)
Gem::Specification.new do |s|
s.name = %q{awesome_nested_set}
s.authors = ["Brandon Keepers", "Daniel Morrison", "Philip Arndt"]
s.description = %q{An awesome nested set implementation for Active Record}
s.email = %q{info@collectiveidea.com}
- s.extra_rdoc_files = [
- "README.rdoc"
- ]
+ s.extra_rdoc_files = %w[README.rdoc]
s.files = Dir.glob("lib/**/*") + %w(MIT-LICENSE README.rdoc CHANGELOG)
s.homepage = %q{http://github.com/collectiveidea/awesome_nested_set}
s.rdoc_options = ["--main", "README.rdoc", "--inline-source", "--line-numbers"]
s.require_paths = ["lib"]
s.rubygems_version = %q{1.3.6}
s.summary = %q{An awesome nested set implementation for Active Record}
+ s.license = %q{MIT}
+
s.add_runtime_dependency 'activerecord', '>= 3.0.0'
- s.add_development_dependency 'rspec-rails', '~> 2.8'
+
+ s.add_development_dependency 'rspec-rails', '~> 2.12'
+ s.add_development_dependency 'rake', '~> 10'
+ s.add_development_dependency 'combustion', '>= 0.3.3'
end
+++ /dev/null
-require File.dirname(__FILE__) + '/lib/awesome_nested_set'
# Rebuilds the left & rights if unset or invalid.
# Also very useful for converting from acts_as_tree.
def rebuild!(validate_nodes = true)
- # Don't rebuild a valid tree.
- return true if valid?
-
- scope = lambda{|node|}
- if acts_as_nested_set_options[:scope]
- scope = lambda{|node|
- scope_column_names.inject(""){|str, column_name|
- str << "AND #{connection.quote_column_name(column_name)} = #{connection.quote(node.send(column_name.to_sym))} "
+ # default_scope with order may break database queries so we do all operation without scope
+ unscoped do
+ # Don't rebuild a valid tree.
+ return true if valid?
+
+ scope = lambda{|node|}
+ if acts_as_nested_set_options[:scope]
+ scope = lambda{|node|
+ scope_column_names.inject(""){|str, column_name|
+ str << "AND #{connection.quote_column_name(column_name)} = #{connection.quote(node.send(column_name.to_sym))} "
+ }
}
- }
- end
- indices = {}
-
- set_left_and_rights = lambda do |node|
- # set left
- node[left_column_name] = indices[scope.call(node)] += 1
- # find
- where(["#{quoted_parent_column_full_name} = ? #{scope.call(node)}", node]).order("#{quoted_left_column_full_name}, #{quoted_right_column_full_name}, id").each{|n| set_left_and_rights.call(n) }
- # set right
- node[right_column_name] = indices[scope.call(node)] += 1
- node.save!(:validate => validate_nodes)
- end
+ end
+ indices = {}
+
+ set_left_and_rights = lambda do |node|
+ # set left
+ node[left_column_name] = indices[scope.call(node)] += 1
+ # find
+ where(["#{quoted_parent_column_full_name} = ? #{scope.call(node)}", node]).order("#{quoted_left_column_full_name}, #{quoted_right_column_full_name}, id").each{|n| set_left_and_rights.call(n) }
+ # set right
+ node[right_column_name] = indices[scope.call(node)] += 1
+ node.save!(:validate => validate_nodes)
+ end
- # Find root node(s)
- root_nodes = where("#{quoted_parent_column_full_name} IS NULL").order("#{quoted_left_column_full_name}, #{quoted_right_column_full_name}, id").each do |root_node|
- # setup index for this scope
- indices[scope.call(root_node)] ||= 0
- set_left_and_rights.call(root_node)
+ # Find root node(s)
+ root_nodes = where("#{quoted_parent_column_full_name} IS NULL").order("#{quoted_left_column_full_name}, #{quoted_right_column_full_name}, id").each do |root_node|
+ # setup index for this scope
+ indices[scope.call(root_node)] ||= 0
+ set_left_and_rights.call(root_node)
+ end
end
end
["#{quoted_right_column_name} = (#{quoted_right_column_name} - ?)", diff]
)
- # Reload is needed because children may have updated their parent (self) during deletion.
- reload
# Don't allow multiple calls to destroy to corrupt the set
self.skip_before_destroy = true
end
else target[parent_column_name]
end
- self.nested_set_scope.update_all([
+ where_statement = ["not (#{quoted_left_column_name} = CASE " +
+ "WHEN #{quoted_left_column_name} BETWEEN :a AND :b " +
+ "THEN #{quoted_left_column_name} + :d - :b " +
+ "WHEN #{quoted_left_column_name} BETWEEN :c AND :d " +
+ "THEN #{quoted_left_column_name} + :a - :c " +
+ "ELSE #{quoted_left_column_name} END AND " +
+ "#{quoted_right_column_name} = CASE " +
+ "WHEN #{quoted_right_column_name} BETWEEN :a AND :b " +
+ "THEN #{quoted_right_column_name} + :d - :b " +
+ "WHEN #{quoted_right_column_name} BETWEEN :c AND :d " +
+ "THEN #{quoted_right_column_name} + :a - :c " +
+ "ELSE #{quoted_right_column_name} END AND " +
+ "#{quoted_parent_column_name} = CASE " +
+ "WHEN #{self.class.base_class.primary_key} = :id THEN :new_parent " +
+ "ELSE #{quoted_parent_column_name} END)" ,
+ {:a => a, :b => b, :c => c, :d => d, :id => self.id, :new_parent => new_parent} ]
+
+
+
+
+ self.nested_set_scope.where(*where_statement).update_all([
"#{quoted_left_column_name} = CASE " +
"WHEN #{quoted_left_column_name} BETWEEN :a AND :b " +
"THEN #{quoted_left_column_name} + :d - :b " +
module AwesomeNestedSet
- VERSION = '2.1.5' unless defined?(::AwesomeNestedSet::VERSION)
+ VERSION = '2.1.6' unless defined?(::AwesomeNestedSet::VERSION)
end
require 'spec_helper'
+require 'awesome_nested_set/helper'
describe "Helper" do
include CollectiveIdea::Acts::NestedSet::Helper
end
end
+ describe 'rebuilding tree with a default scope ordering' do
+ it "doesn't throw exception" do
+ expect { Position.rebuild! }.not_to raise_error
+ end
+ end
+
describe 'creating roots with a default scope ordering' do
it "assigns rgt and lft correctly" do
alpha = Order.create(:name => 'Alpha')
database: ":memory:"
postgresql:
adapter: postgresql
+ encoding: unicode
+ database: awesome_nested_set_plugin_test
+ pool: 5
username: postgres
password: postgres
- database: awesome_nested_set_plugin_test
- min_messages: ERROR
+ min_messages: warning
mysql:
adapter: mysql2
host: localhost
username: root
- password:
+ password:
database: awesome_nested_set_plugin_test
## Add DB Configuration to run Oracle tests
oracle:
adapter: oracle_enhanced
host: localhost
username: awesome_nested_set_dev
- password:
+ password:
database: xe
t.column :depth, :integer
end
+ create_table :positions, :force => true do |t|
+ t.column :name, :string
+ t.column :parent_id, :integer
+ t.column :lft, :integer
+ t.column :rgt, :integer
+ t.column :depth, :integer
+ t.column :position, :integer
+ end
+
create_table :no_depths, :force => true do |t|
t.column :name, :string
t.column :parent_id, :integer
-$:.unshift(File.dirname(__FILE__) + '/../lib')
plugin_test_dir = File.dirname(__FILE__)
require 'rubygems'
require 'bundler/setup'
-require 'rspec'
require 'logger'
-
-require 'active_support'
-require 'active_model'
require 'active_record'
-require 'action_controller'
-
-require 'awesome_nested_set'
-
ActiveRecord::Base.logger = Logger.new(plugin_test_dir + "/debug.log")
require 'yaml'
require 'erb'
ActiveRecord::Base.configurations = YAML::load(ERB.new(IO.read(plugin_test_dir + "/db/database.yml")).result)
-ActiveRecord::Base.establish_connection(ENV["DB"] || "sqlite3mem")
+ActiveRecord::Base.establish_connection(ENV["DB"] ||= "sqlite3mem")
ActiveRecord::Migration.verbose = false
+
+require 'combustion/database'
+Combustion::Database.create_database(ActiveRecord::Base.configurations[ENV["DB"]])
load(File.join(plugin_test_dir, "db", "schema.rb"))
+require 'awesome_nested_set'
require 'support/models'
+require 'action_controller'
require 'rspec/rails'
RSpec.configure do |config|
config.fixture_path = "#{plugin_test_dir}/fixtures"
config.use_transactional_fixtures = true
+ config.after(:suite) do
+ unless /sqlite/ === ENV['DB']
+ Combustion::Database.drop_database(ActiveRecord::Base.configurations[ENV['DB']])
+ end
+ end
end
default_scope order(:name)
end
+class Position < ActiveRecord::Base
+ acts_as_nested_set
+
+ default_scope order(:position)
+end
+
class NoDepth < ActiveRecord::Base
acts_as_nested_set
end