veritas-sql-generator 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. data/.gemtest +0 -0
  2. data/.rvmrc +1 -0
  3. data/.travis.yml +8 -0
  4. data/Gemfile +20 -10
  5. data/Guardfile +22 -0
  6. data/README.rdoc +2 -0
  7. data/Rakefile +4 -2
  8. data/TODO +16 -2
  9. data/config/flay.yml +2 -2
  10. data/config/flog.yml +1 -1
  11. data/config/roodi.yml +5 -5
  12. data/config/site.reek +21 -19
  13. data/lib/veritas/sql/generator.rb +25 -2
  14. data/lib/veritas/sql/generator/core_ext/date.rb +20 -0
  15. data/lib/veritas/sql/generator/core_ext/date_time.rb +45 -0
  16. data/lib/veritas/sql/generator/direction.rb +3 -1
  17. data/lib/veritas/sql/generator/function.rb +54 -0
  18. data/lib/veritas/sql/generator/function/aggregate.rb +134 -0
  19. data/lib/veritas/sql/generator/function/connective.rb +53 -0
  20. data/lib/veritas/sql/generator/function/numeric.rb +135 -0
  21. data/lib/veritas/sql/generator/function/predicate.rb +266 -0
  22. data/lib/veritas/sql/generator/function/proposition.rb +38 -0
  23. data/lib/veritas/sql/generator/function/string.rb +29 -0
  24. data/lib/veritas/sql/generator/identifier.rb +2 -1
  25. data/lib/veritas/sql/generator/literal.rb +15 -18
  26. data/lib/veritas/sql/generator/relation.rb +144 -17
  27. data/lib/veritas/sql/generator/relation/binary.rb +16 -64
  28. data/lib/veritas/sql/generator/relation/set.rb +30 -22
  29. data/lib/veritas/sql/generator/relation/unary.rb +131 -78
  30. data/lib/veritas/sql/generator/version.rb +1 -1
  31. data/spec/unit/date/iso8601_spec.rb +23 -0
  32. data/spec/unit/date_time/iso_8601_spec.rb +115 -0
  33. data/spec/unit/veritas/sql/generator/class_methods/parenthesize_spec.rb +18 -0
  34. data/spec/unit/veritas/sql/generator/function/aggregate/visit_veritas_aggregate_count_spec.rb +16 -0
  35. data/spec/unit/veritas/sql/generator/function/aggregate/visit_veritas_aggregate_maximum_spec.rb +16 -0
  36. data/spec/unit/veritas/sql/generator/function/aggregate/visit_veritas_aggregate_mean_spec.rb +16 -0
  37. data/spec/unit/veritas/sql/generator/function/aggregate/visit_veritas_aggregate_minimum_spec.rb +16 -0
  38. data/spec/unit/veritas/sql/generator/function/aggregate/visit_veritas_aggregate_standard_deviation_spec.rb +16 -0
  39. data/spec/unit/veritas/sql/generator/function/aggregate/visit_veritas_aggregate_sum_spec.rb +16 -0
  40. data/spec/unit/veritas/sql/generator/function/aggregate/visit_veritas_aggregate_variance_spec.rb +16 -0
  41. data/spec/unit/veritas/sql/generator/function/connective/visit_veritas_function_connective_conjunction_spec.rb +20 -0
  42. data/spec/unit/veritas/sql/generator/function/connective/visit_veritas_function_connective_disjunction_spec.rb +20 -0
  43. data/spec/unit/veritas/sql/generator/function/connective/visit_veritas_function_connective_negation_spec.rb +20 -0
  44. data/spec/unit/veritas/sql/generator/function/numeric/visit_veritas_function_numeric_absolute_spec.rb +15 -0
  45. data/spec/unit/veritas/sql/generator/function/numeric/visit_veritas_function_numeric_addition_spec.rb +15 -0
  46. data/spec/unit/veritas/sql/generator/function/numeric/visit_veritas_function_numeric_division_spec.rb +15 -0
  47. data/spec/unit/veritas/sql/generator/function/numeric/visit_veritas_function_numeric_exponentiation_spec.rb +15 -0
  48. data/spec/unit/veritas/sql/generator/function/numeric/visit_veritas_function_numeric_modulo_spec.rb +15 -0
  49. data/spec/unit/veritas/sql/generator/function/numeric/visit_veritas_function_numeric_multiplication_spec.rb +15 -0
  50. data/spec/unit/veritas/sql/generator/function/numeric/visit_veritas_function_numeric_square_root_spec.rb +15 -0
  51. data/spec/unit/veritas/sql/generator/function/numeric/visit_veritas_function_numeric_subtraction_spec.rb +15 -0
  52. data/spec/unit/veritas/sql/generator/function/numeric/visit_veritas_function_numeric_unary_minus_spec.rb +15 -0
  53. data/spec/unit/veritas/sql/generator/function/numeric/visit_veritas_function_numeric_unary_plus_spec.rb +15 -0
  54. data/spec/unit/veritas/sql/generator/{logic/visit_veritas_logic_predicate_equality_spec.rb → function/predicate/visit_veritas_function_predicate_equality_spec.rb} +5 -5
  55. data/spec/unit/veritas/sql/generator/{logic/visit_veritas_logic_predicate_exclusion_spec.rb → function/predicate/visit_veritas_function_predicate_exclusion_spec.rb} +10 -6
  56. data/spec/unit/veritas/sql/generator/function/predicate/visit_veritas_function_predicate_greater_than_or_equal_to_spec.rb +15 -0
  57. data/spec/unit/veritas/sql/generator/{logic/visit_veritas_logic_predicate_greater_than_spec.rb → function/predicate/visit_veritas_function_predicate_greater_than_spec.rb} +5 -5
  58. data/spec/unit/veritas/sql/generator/{logic/visit_veritas_logic_predicate_inclusion_spec.rb → function/predicate/visit_veritas_function_predicate_inclusion_spec.rb} +10 -6
  59. data/spec/unit/veritas/sql/generator/{logic/visit_veritas_logic_predicate_inequality_spec.rb → function/predicate/visit_veritas_function_predicate_inequality_spec.rb} +8 -8
  60. data/spec/unit/veritas/sql/generator/function/predicate/visit_veritas_function_predicate_less_than_or_equal_to_spec.rb +15 -0
  61. data/spec/unit/veritas/sql/generator/{logic/visit_veritas_logic_predicate_less_than_spec.rb → function/predicate/visit_veritas_function_predicate_less_than_spec.rb} +5 -5
  62. data/spec/unit/veritas/sql/generator/function/proposition/visit_veritas_function_proposition_contradiction_spec.rb +15 -0
  63. data/spec/unit/veritas/sql/generator/function/proposition/visit_veritas_function_proposition_tautology_spec.rb +15 -0
  64. data/spec/unit/veritas/sql/generator/function/string/visit_veritas_function_string_length_spec.rb +15 -0
  65. data/spec/unit/veritas/sql/generator/literal/class_methods/dup_frozen_spec.rb +2 -2
  66. data/spec/unit/veritas/sql/generator/relation/binary/base/to_subquery_spec.rb +1 -1
  67. data/spec/unit/veritas/sql/generator/relation/binary/base/{visit_veritas_base_relation_spec.rb → visit_veritas_relation_base_spec.rb} +3 -3
  68. data/spec/unit/veritas/sql/generator/relation/binary/to_s_spec.rb +2 -2
  69. data/spec/unit/veritas/sql/generator/relation/binary/to_subquery_spec.rb +2 -2
  70. data/spec/unit/veritas/sql/generator/relation/binary/visit_veritas_algebra_join_spec.rb +74 -33
  71. data/spec/unit/veritas/sql/generator/relation/binary/visit_veritas_algebra_product_spec.rb +63 -19
  72. data/spec/unit/veritas/sql/generator/relation/class_methods/visit_spec.rb +1 -1
  73. data/spec/unit/veritas/sql/generator/relation/set/class_methods/normalize_operand_headers_spec.rb +35 -0
  74. data/spec/unit/veritas/sql/generator/relation/set/to_s_spec.rb +1 -1
  75. data/spec/unit/veritas/sql/generator/relation/set/to_subquery_spec.rb +4 -4
  76. data/spec/unit/veritas/sql/generator/relation/set/visit_veritas_algebra_difference_spec.rb +83 -30
  77. data/spec/unit/veritas/sql/generator/relation/set/visit_veritas_algebra_intersection_spec.rb +80 -30
  78. data/spec/unit/veritas/sql/generator/relation/set/visit_veritas_algebra_union_spec.rb +80 -30
  79. data/spec/unit/veritas/sql/generator/relation/to_s_spec.rb +50 -0
  80. data/spec/unit/veritas/sql/generator/relation/to_subquery_spec.rb +49 -0
  81. data/spec/unit/veritas/sql/generator/relation/unary/to_s_spec.rb +1 -1
  82. data/spec/unit/veritas/sql/generator/relation/unary/to_subquery_spec.rb +6 -6
  83. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_algebra_extension_spec.rb +165 -0
  84. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_algebra_projection_spec.rb +84 -29
  85. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_algebra_rename_spec.rb +69 -27
  86. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_algebra_restriction_spec.rb +64 -22
  87. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_algebra_summarization_spec.rb +652 -0
  88. data/spec/unit/veritas/sql/generator/relation/unary/{visit_veritas_base_relation_spec.rb → visit_veritas_relation_base_spec.rb} +4 -4
  89. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_relation_operation_limit_spec.rb +60 -20
  90. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_relation_operation_offset_spec.rb +60 -20
  91. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_relation_operation_order_spec.rb +63 -23
  92. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_relation_operation_reverse_spec.rb +60 -20
  93. data/spec/unit/veritas/sql/generator/relation/visited_spec.rb +1 -1
  94. data/tasks/metrics/ci.rake +7 -0
  95. data/tasks/{quality → metrics}/flay.rake +0 -0
  96. data/tasks/{quality → metrics}/flog.rake +0 -0
  97. data/tasks/{quality → metrics}/heckle.rake +1 -0
  98. data/tasks/{quality → metrics}/metric_fu.rake +3 -0
  99. data/tasks/{quality → metrics}/reek.rake +0 -0
  100. data/tasks/{quality → metrics}/roodi.rake +0 -0
  101. data/tasks/{quality → metrics}/yardstick.rake +0 -0
  102. data/tasks/spec.rake +1 -0
  103. data/veritas-sql-generator.gemspec +82 -114
  104. metadata +137 -125
  105. data/lib/veritas/base_relation.rb +0 -36
  106. data/lib/veritas/sql/generator/logic.rb +0 -349
  107. data/spec/unit/veritas/base_relation/name_spec.rb +0 -45
  108. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_connective_conjunction_spec.rb +0 -16
  109. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_connective_disjunction_spec.rb +0 -16
  110. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_connective_negation_spec.rb +0 -16
  111. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_predicate_greater_than_or_equal_to_spec.rb +0 -15
  112. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_predicate_less_than_or_equal_to_spec.rb +0 -15
  113. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_proposition_contradiction_spec.rb +0 -15
  114. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_proposition_tautology_spec.rb +0 -15
  115. data/spec/unit/veritas/sql/generator/relation/binary/class_methods/subquery_spec.rb +0 -42
  116. data/spec/unit/veritas/sql/generator/relation/class_methods/subquery_spec.rb +0 -33
  117. data/tasks/quality/ci.rake +0 -2
@@ -11,7 +11,7 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_intersection' do
11
11
  let(:age) { Attribute::Integer.new(:age, :required => false) }
12
12
  let(:header) { [ id, name, age ] }
13
13
  let(:body) { [ [ 1, 'Dan Kubb', 35 ] ].each }
14
- let(:base_relation) { BaseRelation.new(relation_name, header, body) }
14
+ let(:base_relation) { Relation::Base.new(relation_name, header, body) }
15
15
  let(:left) { operand }
16
16
  let(:right) { operand }
17
17
  let(:intersection) { left.intersect(right) }
@@ -22,8 +22,8 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_intersection' do
22
22
 
23
23
  it_should_behave_like 'a generated SQL SELECT query'
24
24
 
25
- its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")') }
26
- its(:to_subquery) { should eql('(SELECT * FROM "users") INTERSECT (SELECT * FROM "users")') }
25
+ its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")') }
26
+ its(:to_subquery) { should eql('((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users"))') }
27
27
  end
28
28
 
29
29
  context 'when the operands are projections' do
@@ -31,8 +31,17 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_intersection' do
31
31
 
32
32
  it_should_behave_like 'a generated SQL SELECT query'
33
33
 
34
- its(:to_s) { should eql('(SELECT DISTINCT "id", "name" FROM "users") INTERSECT (SELECT DISTINCT "id", "name" FROM "users")') }
35
- its(:to_subquery) { should eql('(SELECT DISTINCT "id", "name" FROM "users") INTERSECT (SELECT DISTINCT "id", "name" FROM "users")') }
34
+ its(:to_s) { should eql('(SELECT DISTINCT "id", "name" FROM "users") INTERSECT (SELECT DISTINCT "id", "name" FROM "users")') }
35
+ its(:to_subquery) { should eql('((SELECT DISTINCT "id", "name" FROM "users") INTERSECT (SELECT DISTINCT "id", "name" FROM "users"))') }
36
+ end
37
+
38
+ context 'when the operand is an extension' do
39
+ let(:operand) { base_relation.extend { |r| r.add(:one, 1) } }
40
+
41
+ it_should_behave_like 'a generated SQL SELECT query'
42
+
43
+ its(:to_s) { should eql('(SELECT "id", "name", "age", 1 AS "one" FROM "users") INTERSECT (SELECT "id", "name", "age", 1 AS "one" FROM "users")') }
44
+ its(:to_subquery) { should eql('((SELECT "id", "name", "age", 1 AS "one" FROM "users") INTERSECT (SELECT "id", "name", "age", 1 AS "one" FROM "users"))') }
36
45
  end
37
46
 
38
47
  context 'when the operands are renames' do
@@ -40,8 +49,8 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_intersection' do
40
49
 
41
50
  it_should_behave_like 'a generated SQL SELECT query'
42
51
 
43
- its(:to_s) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM "users") INTERSECT (SELECT "id" AS "user_id", "name", "age" FROM "users")') }
44
- its(:to_subquery) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM "users") INTERSECT (SELECT "id" AS "user_id", "name", "age" FROM "users")') }
52
+ its(:to_s) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM "users") INTERSECT (SELECT "id" AS "user_id", "name", "age" FROM "users")') }
53
+ its(:to_subquery) { should eql('((SELECT "id" AS "user_id", "name", "age" FROM "users") INTERSECT (SELECT "id" AS "user_id", "name", "age" FROM "users"))') }
45
54
  end
46
55
 
47
56
  context 'when the operands are restrictions' do
@@ -49,8 +58,39 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_intersection' do
49
58
 
50
59
  it_should_behave_like 'a generated SQL SELECT query'
51
60
 
52
- its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" WHERE "id" = 1) INTERSECT (SELECT "id", "name", "age" FROM "users" WHERE "id" = 1)') }
53
- its(:to_subquery) { should eql('(SELECT * FROM "users" WHERE "id" = 1) INTERSECT (SELECT * FROM "users" WHERE "id" = 1)') }
61
+ its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" WHERE "id" = 1) INTERSECT (SELECT "id", "name", "age" FROM "users" WHERE "id" = 1)') }
62
+ its(:to_subquery) { should eql('((SELECT "id", "name", "age" FROM "users" WHERE "id" = 1) INTERSECT (SELECT "id", "name", "age" FROM "users" WHERE "id" = 1))') }
63
+ end
64
+
65
+ context 'when the operand is a summarization' do
66
+ context 'summarize per table dee' do
67
+ let(:summarize_per) { TABLE_DEE }
68
+ let(:operand) { base_relation.summarize(summarize_per) { |r| r.add(:count, r[:id].count) } }
69
+
70
+ it_should_behave_like 'a generated SQL SELECT query'
71
+
72
+ its(:to_s) { should eql('(SELECT COUNT ("id") AS "count" FROM "users") INTERSECT (SELECT COUNT ("id") AS "count" FROM "users")') }
73
+ its(:to_subquery) { should eql('((SELECT COUNT ("id") AS "count" FROM "users") INTERSECT (SELECT COUNT ("id") AS "count" FROM "users"))') }
74
+ end
75
+
76
+ context 'summarize per table dum' do
77
+ let(:summarize_per) { TABLE_DUM }
78
+ let(:operand) { base_relation.summarize(summarize_per) { |r| r.add(:count, r[:id].count) } }
79
+
80
+ it_should_behave_like 'a generated SQL SELECT query'
81
+
82
+ its(:to_s) { should eql('(SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE) INTERSECT (SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE)') }
83
+ its(:to_subquery) { should eql('((SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE) INTERSECT (SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE))') }
84
+ end
85
+
86
+ context 'summarize by a subset of the operand header' do
87
+ let(:operand) { base_relation.summarize([ :id, :name ]) { |r| r.add(:count, r[:age].count) } }
88
+
89
+ it_should_behave_like 'a generated SQL SELECT query'
90
+
91
+ its(:to_s) { should eql('(SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0) INTERSECT (SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0)') }
92
+ its(:to_subquery) { should eql('((SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0) INTERSECT (SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0))') }
93
+ end
54
94
  end
55
95
 
56
96
  context 'when the operand is ordered' do
@@ -58,8 +98,8 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_intersection' do
58
98
 
59
99
  it_should_behave_like 'a generated SQL SELECT query'
60
100
 
61
- its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age") INTERSECT (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age")') }
62
- its(:to_subquery) { should eql('(SELECT * FROM "users" ORDER BY "id", "name", "age") INTERSECT (SELECT * FROM "users" ORDER BY "id", "name", "age")') }
101
+ its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age") INTERSECT (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age")') }
102
+ its(:to_subquery) { should eql('((SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age") INTERSECT (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age"))') }
63
103
  end
64
104
 
65
105
  context 'when the operand is reversed' do
@@ -67,8 +107,8 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_intersection' do
67
107
 
68
108
  it_should_behave_like 'a generated SQL SELECT query'
69
109
 
70
- its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) INTERSECT (SELECT "id", "name", "age" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC)') }
71
- its(:to_subquery) { should eql('(SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) INTERSECT (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC)') }
110
+ its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) INTERSECT (SELECT "id", "name", "age" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC)') }
111
+ its(:to_subquery) { should eql('((SELECT "id", "name", "age" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) INTERSECT (SELECT "id", "name", "age" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC))') }
72
112
  end
73
113
 
74
114
  context 'when the operand is limited' do
@@ -76,8 +116,8 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_intersection' do
76
116
 
77
117
  it_should_behave_like 'a generated SQL SELECT query'
78
118
 
79
- its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" LIMIT 1) INTERSECT (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" LIMIT 1)') }
80
- its(:to_subquery) { should eql('(SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) INTERSECT (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1)') }
119
+ its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" LIMIT 1) INTERSECT (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" LIMIT 1)') }
120
+ its(:to_subquery) { should eql('((SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" LIMIT 1) INTERSECT (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" LIMIT 1))') }
81
121
  end
82
122
 
83
123
  context 'when the operands are offsets' do
@@ -85,8 +125,8 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_intersection' do
85
125
 
86
126
  it_should_behave_like 'a generated SQL SELECT query'
87
127
 
88
- its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" OFFSET 1) INTERSECT (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" OFFSET 1)') }
89
- its(:to_subquery) { should eql('(SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) INTERSECT (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1)') }
128
+ its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" OFFSET 1) INTERSECT (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" OFFSET 1)') }
129
+ its(:to_subquery) { should eql('((SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" OFFSET 1) INTERSECT (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" OFFSET 1))') }
90
130
  end
91
131
 
92
132
  context 'when the operands are differences' do
@@ -94,8 +134,8 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_intersection' do
94
134
 
95
135
  it_should_behave_like 'a generated SQL SELECT query'
96
136
 
97
- its(:to_s) { should eql('((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) INTERSECT ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users"))') }
98
- its(:to_subquery) { should eql('((SELECT * FROM "users") EXCEPT (SELECT * FROM "users")) INTERSECT ((SELECT * FROM "users") EXCEPT (SELECT * FROM "users"))') }
137
+ its(:to_s) { should eql('((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) INTERSECT ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users"))') }
138
+ its(:to_subquery) { should eql('(((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) INTERSECT ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")))') }
99
139
  end
100
140
 
101
141
  context 'when the operands are intersections' do
@@ -103,8 +143,8 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_intersection' do
103
143
 
104
144
  it_should_behave_like 'a generated SQL SELECT query'
105
145
 
106
- its(:to_s) { should eql('((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) INTERSECT ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users"))') }
107
- its(:to_subquery) { should eql('((SELECT * FROM "users") INTERSECT (SELECT * FROM "users")) INTERSECT ((SELECT * FROM "users") INTERSECT (SELECT * FROM "users"))') }
146
+ its(:to_s) { should eql('((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) INTERSECT ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users"))') }
147
+ its(:to_subquery) { should eql('(((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) INTERSECT ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")))') }
108
148
  end
109
149
 
110
150
  context 'when the operands are unions' do
@@ -112,8 +152,8 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_intersection' do
112
152
 
113
153
  it_should_behave_like 'a generated SQL SELECT query'
114
154
 
115
- its(:to_s) { should eql('((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) INTERSECT ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users"))') }
116
- its(:to_subquery) { should eql('((SELECT * FROM "users") UNION (SELECT * FROM "users")) INTERSECT ((SELECT * FROM "users") UNION (SELECT * FROM "users"))') }
155
+ its(:to_s) { should eql('((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) INTERSECT ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users"))') }
156
+ its(:to_subquery) { should eql('(((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) INTERSECT ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")))') }
117
157
  end
118
158
 
119
159
  context 'when the operands are joins' do
@@ -121,18 +161,28 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_intersection' do
121
161
 
122
162
  it_should_behave_like 'a generated SQL SELECT query'
123
163
 
124
- its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" NATURAL JOIN "users") INTERSECT (SELECT "id", "name", "age" FROM "users" NATURAL JOIN "users")') }
125
- its(:to_subquery) { should eql('(SELECT * FROM "users" NATURAL JOIN "users") INTERSECT (SELECT * FROM "users" NATURAL JOIN "users")') }
164
+ its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" AS "left" NATURAL JOIN "users" AS "right") INTERSECT (SELECT "id", "name", "age" FROM "users" AS "left" NATURAL JOIN "users" AS "right")') }
165
+ its(:to_subquery) { should eql('((SELECT "id", "name", "age" FROM "users" AS "left" NATURAL JOIN "users" AS "right") INTERSECT (SELECT "id", "name", "age" FROM "users" AS "left" NATURAL JOIN "users" AS "right"))') }
126
166
  end
127
167
 
128
168
  context 'when the operands have different base relations' do
129
- let(:relation_name) { 'users_others' }
130
- let(:left) { BaseRelation.new('users', header, body) }
131
- let(:right) { BaseRelation.new('others', header, body) }
169
+ let(:relation_name) { 'users_others' }
170
+ let(:left) { Relation::Base.new('users', header, body) }
171
+ let(:right) { Relation::Base.new('others', header, body) }
172
+
173
+ it_should_behave_like 'a generated SQL SELECT query'
174
+
175
+ its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "others")') }
176
+ its(:to_subquery) { should eql('((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "others"))') }
177
+ end
178
+
179
+ context 'when the operands have headers sorted in different orders' do
180
+ let(:left) { Relation::Base.new(relation_name, header, body) }
181
+ let(:right) { Relation::Base.new(relation_name, header.reverse, body) }
132
182
 
133
183
  it_should_behave_like 'a generated SQL SELECT query'
134
184
 
135
- its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "others")') }
136
- its(:to_subquery) { should eql('(SELECT * FROM "users") INTERSECT (SELECT * FROM "others")') }
185
+ its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT DISTINCT "id", "name", "age" FROM "users")') }
186
+ its(:to_subquery) { should eql('((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT DISTINCT "id", "name", "age" FROM "users"))') }
137
187
  end
138
188
  end
@@ -11,7 +11,7 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_union' do
11
11
  let(:age) { Attribute::Integer.new(:age, :required => false) }
12
12
  let(:header) { [ id, name, age ] }
13
13
  let(:body) { [ [ 1, 'Dan Kubb', 35 ] ].each }
14
- let(:base_relation) { BaseRelation.new(relation_name, header, body) }
14
+ let(:base_relation) { Relation::Base.new(relation_name, header, body) }
15
15
  let(:left) { operand }
16
16
  let(:right) { operand }
17
17
  let(:union) { left.union(right) }
@@ -22,8 +22,8 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_union' do
22
22
 
23
23
  it_should_behave_like 'a generated SQL SELECT query'
24
24
 
25
- its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")') }
26
- its(:to_subquery) { should eql('(SELECT * FROM "users") UNION (SELECT * FROM "users")') }
25
+ its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")') }
26
+ its(:to_subquery) { should eql('((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users"))') }
27
27
  end
28
28
 
29
29
  context 'when the operands are projections' do
@@ -31,8 +31,17 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_union' do
31
31
 
32
32
  it_should_behave_like 'a generated SQL SELECT query'
33
33
 
34
- its(:to_s) { should eql('(SELECT DISTINCT "id", "name" FROM "users") UNION (SELECT DISTINCT "id", "name" FROM "users")') }
35
- its(:to_subquery) { should eql('(SELECT DISTINCT "id", "name" FROM "users") UNION (SELECT DISTINCT "id", "name" FROM "users")') }
34
+ its(:to_s) { should eql('(SELECT DISTINCT "id", "name" FROM "users") UNION (SELECT DISTINCT "id", "name" FROM "users")') }
35
+ its(:to_subquery) { should eql('((SELECT DISTINCT "id", "name" FROM "users") UNION (SELECT DISTINCT "id", "name" FROM "users"))') }
36
+ end
37
+
38
+ context 'when the operand is an extension' do
39
+ let(:operand) { base_relation.extend { |r| r.add(:one, 1) } }
40
+
41
+ it_should_behave_like 'a generated SQL SELECT query'
42
+
43
+ its(:to_s) { should eql('(SELECT "id", "name", "age", 1 AS "one" FROM "users") UNION (SELECT "id", "name", "age", 1 AS "one" FROM "users")') }
44
+ its(:to_subquery) { should eql('((SELECT "id", "name", "age", 1 AS "one" FROM "users") UNION (SELECT "id", "name", "age", 1 AS "one" FROM "users"))') }
36
45
  end
37
46
 
38
47
  context 'when the operands are renames' do
@@ -40,8 +49,8 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_union' do
40
49
 
41
50
  it_should_behave_like 'a generated SQL SELECT query'
42
51
 
43
- its(:to_s) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM "users") UNION (SELECT "id" AS "user_id", "name", "age" FROM "users")') }
44
- its(:to_subquery) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM "users") UNION (SELECT "id" AS "user_id", "name", "age" FROM "users")') }
52
+ its(:to_s) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM "users") UNION (SELECT "id" AS "user_id", "name", "age" FROM "users")') }
53
+ its(:to_subquery) { should eql('((SELECT "id" AS "user_id", "name", "age" FROM "users") UNION (SELECT "id" AS "user_id", "name", "age" FROM "users"))') }
45
54
  end
46
55
 
47
56
  context 'when the operands are restrictions' do
@@ -49,8 +58,39 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_union' do
49
58
 
50
59
  it_should_behave_like 'a generated SQL SELECT query'
51
60
 
52
- its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" WHERE "id" = 1) UNION (SELECT "id", "name", "age" FROM "users" WHERE "id" = 1)') }
53
- its(:to_subquery) { should eql('(SELECT * FROM "users" WHERE "id" = 1) UNION (SELECT * FROM "users" WHERE "id" = 1)') }
61
+ its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" WHERE "id" = 1) UNION (SELECT "id", "name", "age" FROM "users" WHERE "id" = 1)') }
62
+ its(:to_subquery) { should eql('((SELECT "id", "name", "age" FROM "users" WHERE "id" = 1) UNION (SELECT "id", "name", "age" FROM "users" WHERE "id" = 1))') }
63
+ end
64
+
65
+ context 'when the operand is a summarization' do
66
+ context 'summarize per table dee' do
67
+ let(:summarize_per) { TABLE_DEE }
68
+ let(:operand) { base_relation.summarize(summarize_per) { |r| r.add(:count, r[:id].count) } }
69
+
70
+ it_should_behave_like 'a generated SQL SELECT query'
71
+
72
+ its(:to_s) { should eql('(SELECT COUNT ("id") AS "count" FROM "users") UNION (SELECT COUNT ("id") AS "count" FROM "users")') }
73
+ its(:to_subquery) { should eql('((SELECT COUNT ("id") AS "count" FROM "users") UNION (SELECT COUNT ("id") AS "count" FROM "users"))') }
74
+ end
75
+
76
+ context 'summarize per table dum' do
77
+ let(:summarize_per) { TABLE_DUM }
78
+ let(:operand) { base_relation.summarize(summarize_per) { |r| r.add(:count, r[:id].count) } }
79
+
80
+ it_should_behave_like 'a generated SQL SELECT query'
81
+
82
+ its(:to_s) { should eql('(SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE) UNION (SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE)') }
83
+ its(:to_subquery) { should eql('((SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE) UNION (SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE))') }
84
+ end
85
+
86
+ context 'summarize by a subset of the operand header' do
87
+ let(:operand) { base_relation.summarize([ :id, :name ]) { |r| r.add(:count, r[:age].count) } }
88
+
89
+ it_should_behave_like 'a generated SQL SELECT query'
90
+
91
+ its(:to_s) { should eql('(SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0) UNION (SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0)') }
92
+ its(:to_subquery) { should eql('((SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0) UNION (SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0))') }
93
+ end
54
94
  end
55
95
 
56
96
  context 'when the operand is ordered' do
@@ -58,8 +98,8 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_union' do
58
98
 
59
99
  it_should_behave_like 'a generated SQL SELECT query'
60
100
 
61
- its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age") UNION (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age")') }
62
- its(:to_subquery) { should eql('(SELECT * FROM "users" ORDER BY "id", "name", "age") UNION (SELECT * FROM "users" ORDER BY "id", "name", "age")') }
101
+ its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age") UNION (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age")') }
102
+ its(:to_subquery) { should eql('((SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age") UNION (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age"))') }
63
103
  end
64
104
 
65
105
  context 'when the operand is reversed' do
@@ -67,8 +107,8 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_union' do
67
107
 
68
108
  it_should_behave_like 'a generated SQL SELECT query'
69
109
 
70
- its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) UNION (SELECT "id", "name", "age" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC)') }
71
- its(:to_subquery) { should eql('(SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) UNION (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC)') }
110
+ its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) UNION (SELECT "id", "name", "age" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC)') }
111
+ its(:to_subquery) { should eql('((SELECT "id", "name", "age" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) UNION (SELECT "id", "name", "age" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC))') }
72
112
  end
73
113
 
74
114
  context 'when the operand is limited' do
@@ -76,8 +116,8 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_union' do
76
116
 
77
117
  it_should_behave_like 'a generated SQL SELECT query'
78
118
 
79
- its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" LIMIT 1) UNION (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" LIMIT 1)') }
80
- its(:to_subquery) { should eql('(SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) UNION (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1)') }
119
+ its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" LIMIT 1) UNION (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" LIMIT 1)') }
120
+ its(:to_subquery) { should eql('((SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" LIMIT 1) UNION (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" LIMIT 1))') }
81
121
  end
82
122
 
83
123
  context 'when the operands are offsets' do
@@ -85,8 +125,8 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_union' do
85
125
 
86
126
  it_should_behave_like 'a generated SQL SELECT query'
87
127
 
88
- its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" OFFSET 1) UNION (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" OFFSET 1)') }
89
- its(:to_subquery) { should eql('(SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) UNION (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1)') }
128
+ its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" OFFSET 1) UNION (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" OFFSET 1)') }
129
+ its(:to_subquery) { should eql('((SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" OFFSET 1) UNION (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" OFFSET 1))') }
90
130
  end
91
131
 
92
132
  context 'when the operands are differences' do
@@ -94,8 +134,8 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_union' do
94
134
 
95
135
  it_should_behave_like 'a generated SQL SELECT query'
96
136
 
97
- its(:to_s) { should eql('((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) UNION ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users"))') }
98
- its(:to_subquery) { should eql('((SELECT * FROM "users") EXCEPT (SELECT * FROM "users")) UNION ((SELECT * FROM "users") EXCEPT (SELECT * FROM "users"))') }
137
+ its(:to_s) { should eql('((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) UNION ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users"))') }
138
+ its(:to_subquery) { should eql('(((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) UNION ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")))') }
99
139
  end
100
140
 
101
141
  context 'when the operands are intersections' do
@@ -103,8 +143,8 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_union' do
103
143
 
104
144
  it_should_behave_like 'a generated SQL SELECT query'
105
145
 
106
- its(:to_s) { should eql('((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) UNION ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users"))') }
107
- its(:to_subquery) { should eql('((SELECT * FROM "users") INTERSECT (SELECT * FROM "users")) UNION ((SELECT * FROM "users") INTERSECT (SELECT * FROM "users"))') }
146
+ its(:to_s) { should eql('((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) UNION ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users"))') }
147
+ its(:to_subquery) { should eql('(((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) UNION ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")))') }
108
148
  end
109
149
 
110
150
  context 'when the operands are unions' do
@@ -112,8 +152,8 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_union' do
112
152
 
113
153
  it_should_behave_like 'a generated SQL SELECT query'
114
154
 
115
- its(:to_s) { should eql('((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) UNION ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users"))') }
116
- its(:to_subquery) { should eql('((SELECT * FROM "users") UNION (SELECT * FROM "users")) UNION ((SELECT * FROM "users") UNION (SELECT * FROM "users"))') }
155
+ its(:to_s) { should eql('((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) UNION ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users"))') }
156
+ its(:to_subquery) { should eql('(((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) UNION ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")))') }
117
157
  end
118
158
 
119
159
  context 'when the operands are joins' do
@@ -121,18 +161,28 @@ describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_union' do
121
161
 
122
162
  it_should_behave_like 'a generated SQL SELECT query'
123
163
 
124
- its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" NATURAL JOIN "users") UNION (SELECT "id", "name", "age" FROM "users" NATURAL JOIN "users")') }
125
- its(:to_subquery) { should eql('(SELECT * FROM "users" NATURAL JOIN "users") UNION (SELECT * FROM "users" NATURAL JOIN "users")') }
164
+ its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" AS "left" NATURAL JOIN "users" AS "right") UNION (SELECT "id", "name", "age" FROM "users" AS "left" NATURAL JOIN "users" AS "right")') }
165
+ its(:to_subquery) { should eql('((SELECT "id", "name", "age" FROM "users" AS "left" NATURAL JOIN "users" AS "right") UNION (SELECT "id", "name", "age" FROM "users" AS "left" NATURAL JOIN "users" AS "right"))') }
126
166
  end
127
167
 
128
168
  context 'when the operands have different base relations' do
129
- let(:relation_name) { 'users_others' }
130
- let(:left) { BaseRelation.new('users', header, body) }
131
- let(:right) { BaseRelation.new('others', header, body) }
169
+ let(:relation_name) { 'users_others' }
170
+ let(:left) { Relation::Base.new('users', header, body) }
171
+ let(:right) { Relation::Base.new('others', header, body) }
172
+
173
+ it_should_behave_like 'a generated SQL SELECT query'
174
+
175
+ its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "others")') }
176
+ its(:to_subquery) { should eql('((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "others"))') }
177
+ end
178
+
179
+ context 'when the operands have headers sorted in different orders' do
180
+ let(:left) { Relation::Base.new(relation_name, header, body) }
181
+ let(:right) { Relation::Base.new(relation_name, header.reverse, body) }
132
182
 
133
183
  it_should_behave_like 'a generated SQL SELECT query'
134
184
 
135
- its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "others")') }
136
- its(:to_subquery) { should eql('(SELECT * FROM "users") UNION (SELECT * FROM "others")') }
185
+ its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users") UNION (SELECT DISTINCT "id", "name", "age" FROM "users")') }
186
+ its(:to_subquery) { should eql('((SELECT "id", "name", "age" FROM "users") UNION (SELECT DISTINCT "id", "name", "age" FROM "users"))') }
137
187
  end
138
188
  end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe SQL::Generator::Relation, '#to_s' do
6
+ subject { object.to_s }
7
+
8
+ let(:described_class) { Class.new(SQL::Generator::Relation) }
9
+ let(:id) { Attribute::Integer.new(:id) }
10
+ let(:name) { Attribute::String.new(:name) }
11
+ let(:age) { Attribute::Integer.new(:age, :required => false) }
12
+ let(:header) { [ id, name, age ] }
13
+ let(:body) { [ [ 1, 'Dan Kubb', 35 ] ].each }
14
+ let(:base_relation) { Relation::Base.new('users', header, body) }
15
+ let(:object) { described_class.new }
16
+
17
+ context 'when no object visited' do
18
+ it_should_behave_like 'an idempotent method'
19
+
20
+ it { should respond_to(:to_s) }
21
+
22
+ it { should be_frozen }
23
+
24
+ its(:to_s) { should == '' }
25
+ end
26
+
27
+ context 'when an object is visited' do
28
+ let(:visitable) { mock('Visitable') }
29
+
30
+ before do
31
+ described_class.class_eval do
32
+ def visit_spec_mocks_mock(mock)
33
+ @name = mock.instance_variable_get(:@name)
34
+ @distinct = 'DISTINCT'
35
+ @scope = Set.new
36
+ end
37
+
38
+ def generate_sql(columns)
39
+ "SELECT #{columns} FROM #{@name}"
40
+ end
41
+ end
42
+
43
+ object.visit(visitable)
44
+ end
45
+
46
+ it_should_behave_like 'a generated SQL expression'
47
+
48
+ its(:to_s) { should eql('SELECT DISTINCT FROM Visitable') }
49
+ end
50
+ end