From fca0acd1e2f10daee9319a3f17f3fb792f9ebb1a Mon Sep 17 00:00:00 2001 From: Jon Snelling Date: Mon, 26 Dec 2016 05:49:51 -0800 Subject: [PATCH] Preserve RECURSIVE flag of CTE relations when they are merged. Queries like the following: Tag.all.merge(Tag.with.recursive(recursive: Tag.where(tag: 'tag'))) Tag.with.recursive(recursive: Tag.where(tag: 'tag')).merge(Tag.all) would both be expected to produce a query like: WITH RECURSIVE "recursive" AS ( SELECT "tags".* FROM "tags" WHERE "tags"."tag" = 'tag') SELECT "tags".* FROM "tags" but currently only the second one would. The first would lose the recursive flag during merge and result in: WITH "recursive" AS ( SELECT "tags".* FROM "tags" WHERE "tags"."tag" = 'tag') SELECT "tags".* FROM "tags" Adding :recursive to ActiveRecord::Relation::Merger#normal_values and a #recursive! method to ActiveRecord::QueryMethods the expected behavior regardless of the direction of the merge. --- lib/postgres_ext/active_record/relation/merger.rb | 2 +- lib/postgres_ext/active_record/relation/query_methods.rb | 5 +++++ test/queries/common_table_expression_test.rb | 8 ++++++++ test/test_helper.rb | 2 ++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/postgres_ext/active_record/relation/merger.rb b/lib/postgres_ext/active_record/relation/merger.rb index dca6b4e..da8163f 100644 --- a/lib/postgres_ext/active_record/relation/merger.rb +++ b/lib/postgres_ext/active_record/relation/merger.rb @@ -2,7 +2,7 @@ module ActiveRecord class Relation class Merger # :nodoc: def normal_values - NORMAL_VALUES + [:with] + NORMAL_VALUES + [:with, :recursive] end end end diff --git a/lib/postgres_ext/active_record/relation/query_methods.rb b/lib/postgres_ext/active_record/relation/query_methods.rb index fee3765..9ad16c4 100644 --- a/lib/postgres_ext/active_record/relation/query_methods.rb +++ b/lib/postgres_ext/active_record/relation/query_methods.rb @@ -201,6 +201,11 @@ def ranked!(value) self end + def recursive!(value) + self.recursive_value = value + self + end + def build_arel_with_extensions arel = build_arel_without_extensions diff --git a/test/queries/common_table_expression_test.rb b/test/queries/common_table_expression_test.rb index 885c61d..c77a10a 100644 --- a/test/queries/common_table_expression_test.rb +++ b/test/queries/common_table_expression_test.rb @@ -22,6 +22,14 @@ query.to_sql.must_match(/WITH RECURSIVE "lucky_number_seven" AS \(SELECT "people".* FROM "people"(\s+)WHERE "people"."lucky_number" = 7\) SELECT "people".* FROM "people" JOIN lucky_number_seven ON lucky_number_seven.id = people.id/) end + it 'preserves recursive expression during merges' do + merge_recursive_in = Tag.all.merge(Tag.recursive) + merge_recursive_in.to_sql.must_match(/WITH RECURSIVE "recursive" AS \(SELECT "tags".* FROM "tags"(\s+)WHERE "tags"."tag" = 'tag'\) SELECT "tags".* FROM "tags"/) + + merge_into_recursive = Tag.recursive.merge(Tag.all) + merge_into_recursive.to_sql.must_match(/WITH RECURSIVE "recursive" AS \(SELECT "tags".* FROM "tags"(\s+)WHERE "tags"."tag" = 'tag'\) SELECT "tags".* FROM "tags"/) + end + it 'accepts Arel::SelectMangers' do arel_table = Arel::Table.new 'test' arel_manager = arel_table.project arel_table[:foo] diff --git a/test/test_helper.rb b/test/test_helper.rb index 6c0105a..1ccc7e6 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -25,6 +25,8 @@ def self.wicked_people class Tag < ActiveRecord::Base belongs_to :person + + scope :recursive, -> { with.recursive(recursive: Tag.where(tag: 'tag')) } end class ParentTag < Tag