From 40045221040298b11219c679f07b87a0f10c7792 Mon Sep 17 00:00:00 2001 From: dajvido Date: Tue, 21 Jul 2015 22:44:11 +0200 Subject: [PATCH] Add method to get Array of given nodes and their ancestors except these in options --- lib/acts_as_sane_tree/singleton_methods.rb | 34 ++++++++++++++++++++++ spec/acts_as_sane_tree_spec.rb | 14 +++++++++ 2 files changed, 48 insertions(+) diff --git a/lib/acts_as_sane_tree/singleton_methods.rb b/lib/acts_as_sane_tree/singleton_methods.rb index ebd3216..7fec221 100644 --- a/lib/acts_as_sane_tree/singleton_methods.rb +++ b/lib/acts_as_sane_tree/singleton_methods.rb @@ -33,6 +33,40 @@ def root end end + # nodes:: Array of node ids + # options:: Hash with except key and value of node id/ids + # Return Array of given nodes and their ancestors except these in options + def ancestors_with_nodes(nodes, options={}) + table_name = configuration[:class].table_name + query_select_string = "DISTINCT #{table_name}.*" + query_string = <<-SQL + (WITH RECURSIVE crumbs AS ( + SELECT #{table_name}.* + FROM #{table_name} + WHERE id IN (?) + UNION ALL + SELECT alias1.* + FROM crumbs + JOIN #{table_name} alias1 ON alias1.id = crumbs.parent_id + ) SELECT * FROM crumbs) as #{table_name} + SQL + sanitize_query_string = ActiveRecord::Base.send(:sanitize_sql_array, [query_string, Array(nodes)]) + + if options[:except] + aditional_query_string = <<-SQL + WHERE #{table_name}.id NOT IN (?) + SQL + sanitize_aditional_query_string = ActiveRecord::Base.send(:sanitize_sql_array, [aditional_query_string, Array(options[:except])]) + sanitize_query_string += sanitize_aditional_query_string + end + + if(rails_arel?) + configuration[:class].select(query_select_string).from(sanitize_query_string) + else + configuration[:class].scoped(select: query_select_string, from: sanitize_query_string) + end + end + # src:: Array of nodes # chk:: Array of nodes # Return true if any nodes within chk are found within src diff --git a/spec/acts_as_sane_tree_spec.rb b/spec/acts_as_sane_tree_spec.rb index 807b71f..eef0f21 100644 --- a/spec/acts_as_sane_tree_spec.rb +++ b/spec/acts_as_sane_tree_spec.rb @@ -196,6 +196,12 @@ end describe "when using an acts_as_sane_tree class" do + before do + @root_0 = Node.find_by(name: :root_0) + @root_1 = Node.find_by(name: :root_1) + @node_0_10 = Node.find_by(name: :node_0_10) + @node_1_5 = Node.find_by(name: :node_1_5) + end it "should provide all roots" do if(AREL) assert_equal Node.where(:parent_id => nil).count, Node.roots.count @@ -207,6 +213,14 @@ assert_kind_of Node, Node.root assert Node.root.parent_id.nil?, 'Expecting root node to have no parent' end + it "should provide nodes with all ancestors" do + assert_equal Node.find(4).ancestors.count + 1, Node.ancestors_with_nodes(4).length + assert_equal @node_0_10.ancestors.count + @node_1_5.ancestors.count + 2, Node.ancestors_with_nodes([@node_0_10.id, @node_1_5.id]).length + end + it "should provide nodes with all ancestors except given in options" do + assert_equal Node.find(4).ancestors.count, Node.ancestors_with_nodes(4, {except: 4}).length + assert_equal @node_0_10.ancestors.count + @node_1_5.ancestors.count, Node.ancestors_with_nodes([@node_0_10.id, @node_1_5.id], {except: [@root_0.id, @root_1.id]}).length + end describe "when checking for nodes within other node descendants" do before do @root = Node.root