veritas-sql-generator 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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::Unary, '#visit_veritas_algebra_rename' 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(:rename) { operand.rename(:id => :user_id) }
16
16
  let(:object) { described_class.new }
17
17
 
@@ -20,8 +20,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_rename' do
20
20
 
21
21
  it_should_behave_like 'a generated SQL SELECT query'
22
22
 
23
- its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users"') }
24
- its(:to_subquery) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users"') }
23
+ its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users"') }
24
+ its(:to_subquery) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM "users")') }
25
25
  end
26
26
 
27
27
  context 'when the operand is a projection' do
@@ -29,8 +29,17 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_rename' do
29
29
 
30
30
  it_should_behave_like 'a generated SQL SELECT query'
31
31
 
32
- its(:to_s) { should eql('SELECT DISTINCT "id" AS "user_id", "name" FROM "users"') }
33
- its(:to_subquery) { should eql('SELECT DISTINCT "id" AS "user_id", "name" FROM "users"') }
32
+ its(:to_s) { should eql('SELECT DISTINCT "id" AS "user_id", "name" FROM "users"') }
33
+ its(:to_subquery) { should eql('(SELECT DISTINCT "id" AS "user_id", "name" FROM "users")') }
34
+ end
35
+
36
+ context 'when the operand is an extension' do
37
+ let(:operand) { base_relation.extend { |r| r.add(:one, 1) } }
38
+
39
+ it_should_behave_like 'a generated SQL SELECT query'
40
+
41
+ its(:to_s) { pending { should eql('SELECT "id" AS "user_id", "name", "age", 1 AS "one" FROM "users"') } }
42
+ its(:to_subquery) { pending { should eql('SELECT "id" AS "user_id", "name", "age", 1 AS "one" FROM "users"') } }
34
43
  end
35
44
 
36
45
  context 'when the operand is a rename' do
@@ -39,8 +48,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_rename' do
39
48
  context 'when the relation is not optimized' do
40
49
  it_should_behave_like 'a generated SQL SELECT query'
41
50
 
42
- its(:to_s) { should eql('SELECT "id" AS "user_id", "other_name", "age" FROM (SELECT "id", "name" AS "other_name", "age" FROM "users") AS "users"') }
43
- its(:to_subquery) { should eql('SELECT "id" AS "user_id", "other_name", "age" FROM (SELECT "id", "name" AS "other_name", "age" FROM "users") AS "users"') }
51
+ its(:to_s) { should eql('SELECT "id" AS "user_id", "other_name", "age" FROM (SELECT "id", "name" AS "other_name", "age" FROM "users") AS "users"') }
52
+ its(:to_subquery) { should eql('(SELECT "id" AS "user_id", "other_name", "age" FROM (SELECT "id", "name" AS "other_name", "age" FROM "users") AS "users")') }
44
53
  end
45
54
 
46
55
  context 'when the operand is empty' do
@@ -48,8 +57,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_rename' do
48
57
 
49
58
  it_should_behave_like 'a generated SQL SELECT query'
50
59
 
51
- its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM (SELECT "id", "name", "age" FROM "users") AS "users"') }
52
- its(:to_subquery) { should eql('SELECT "id" AS "user_id", "name", "age" FROM (SELECT "id", "name", "age" FROM "users") AS "users"') }
60
+ its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM (SELECT "id", "name", "age" FROM "users") AS "users"') }
61
+ its(:to_subquery) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM (SELECT "id", "name", "age" FROM "users") AS "users")') }
53
62
  end
54
63
  end
55
64
 
@@ -58,8 +67,41 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_rename' do
58
67
 
59
68
  it_should_behave_like 'a generated SQL SELECT query'
60
69
 
61
- its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users" WHERE "id" = 1') }
62
- its(:to_subquery) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users" WHERE "id" = 1') }
70
+ its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users" WHERE "id" = 1') }
71
+ its(:to_subquery) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM "users" WHERE "id" = 1)') }
72
+ end
73
+
74
+ context 'when the operand is a summarization' do
75
+ context 'summarize per table dee' do
76
+ let(:summarize_per) { TABLE_DEE }
77
+ let(:operand) { base_relation.summarize(summarize_per) { |r| r.add(:count, r[:id].count) } }
78
+ let(:rename) { operand.rename(:count => :other_count) }
79
+
80
+ it_should_behave_like 'a generated SQL SELECT query'
81
+
82
+ its(:to_s) { should eql('SELECT "count" AS "other_count" FROM (SELECT COUNT ("id") AS "count" FROM "users") AS "users"') }
83
+ its(:to_subquery) { should eql('(SELECT "count" AS "other_count" FROM (SELECT COUNT ("id") AS "count" FROM "users") AS "users")') }
84
+ end
85
+
86
+ context 'summarize per table dum' do
87
+ let(:summarize_per) { TABLE_DUM }
88
+ let(:operand) { base_relation.summarize(summarize_per) { |r| r.add(:count, r[:id].count) } }
89
+ let(:rename) { operand.rename(:count => :other_count) }
90
+
91
+ it_should_behave_like 'a generated SQL SELECT query'
92
+
93
+ its(:to_s) { should eql('SELECT "count" AS "other_count" FROM (SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE) AS "users"') }
94
+ its(:to_subquery) { should eql('(SELECT "count" AS "other_count" FROM (SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE) AS "users")') }
95
+ end
96
+
97
+ context 'summarize by a subset of the operand header' do
98
+ let(:operand) { base_relation.summarize([ :id, :name ]) { |r| r.add(:count, r[:age].count) } }
99
+
100
+ it_should_behave_like 'a generated SQL SELECT query'
101
+
102
+ its(:to_s) { pending { should eql('SELECT "id" AS "user_id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name"') } }
103
+ its(:to_subquery) { pending { should eql('SELECT "id" AS "user_id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name"') } }
104
+ end
63
105
  end
64
106
 
65
107
  context 'when the operand is ordered' do
@@ -67,8 +109,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_rename' do
67
109
 
68
110
  it_should_behave_like 'a generated SQL SELECT query'
69
111
 
70
- its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users" ORDER BY "id", "name", "age"') }
71
- its(:to_subquery) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users" ORDER BY "id", "name", "age"') }
112
+ its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users" ORDER BY "id", "name", "age"') }
113
+ its(:to_subquery) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM "users" ORDER BY "id", "name", "age")') }
72
114
  end
73
115
 
74
116
  context 'when the operand is reversed' do
@@ -76,8 +118,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_rename' do
76
118
 
77
119
  it_should_behave_like 'a generated SQL SELECT query'
78
120
 
79
- its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC') }
80
- its(:to_subquery) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC') }
121
+ its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC') }
122
+ its(:to_subquery) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC)') }
81
123
  end
82
124
 
83
125
  context 'when the operand is limited' do
@@ -85,8 +127,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_rename' do
85
127
 
86
128
  it_should_behave_like 'a generated SQL SELECT query'
87
129
 
88
- its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users" ORDER BY "id", "name", "age" LIMIT 1') }
89
- its(:to_subquery) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users" ORDER BY "id", "name", "age" LIMIT 1') }
130
+ its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users" ORDER BY "id", "name", "age" LIMIT 1') }
131
+ its(:to_subquery) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM "users" ORDER BY "id", "name", "age" LIMIT 1)') }
90
132
  end
91
133
 
92
134
  context 'when the operand is an offset' do
@@ -94,8 +136,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_rename' do
94
136
 
95
137
  it_should_behave_like 'a generated SQL SELECT query'
96
138
 
97
- its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users" ORDER BY "id", "name", "age" OFFSET 1') }
98
- its(:to_subquery) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users" ORDER BY "id", "name", "age" OFFSET 1') }
139
+ its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users" ORDER BY "id", "name", "age" OFFSET 1') }
140
+ its(:to_subquery) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM "users" ORDER BY "id", "name", "age" OFFSET 1)') }
99
141
  end
100
142
 
101
143
  context 'when the operand is a difference' do
@@ -103,8 +145,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_rename' do
103
145
 
104
146
  it_should_behave_like 'a generated SQL SELECT query'
105
147
 
106
- its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM ((SELECT * FROM "users") EXCEPT (SELECT * FROM "users")) AS "users"') }
107
- its(:to_subquery) { should eql('SELECT "id" AS "user_id", "name", "age" FROM ((SELECT * FROM "users") EXCEPT (SELECT * FROM "users")) AS "users"') }
148
+ its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "users"') }
149
+ its(:to_subquery) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "users")') }
108
150
  end
109
151
 
110
152
  context 'when the operand is an intersection' do
@@ -112,8 +154,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_rename' do
112
154
 
113
155
  it_should_behave_like 'a generated SQL SELECT query'
114
156
 
115
- its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM ((SELECT * FROM "users") INTERSECT (SELECT * FROM "users")) AS "users"') }
116
- its(:to_subquery) { should eql('SELECT "id" AS "user_id", "name", "age" FROM ((SELECT * FROM "users") INTERSECT (SELECT * FROM "users")) AS "users"') }
157
+ its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "users"') }
158
+ its(:to_subquery) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "users")') }
117
159
  end
118
160
 
119
161
  context 'when the operand is a union' do
@@ -121,8 +163,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_rename' do
121
163
 
122
164
  it_should_behave_like 'a generated SQL SELECT query'
123
165
 
124
- its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM ((SELECT * FROM "users") UNION (SELECT * FROM "users")) AS "users"') }
125
- its(:to_subquery) { should eql('SELECT "id" AS "user_id", "name", "age" FROM ((SELECT * FROM "users") UNION (SELECT * FROM "users")) AS "users"') }
166
+ its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "users"') }
167
+ its(:to_subquery) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "users")') }
126
168
  end
127
169
 
128
170
  context 'when the operand is a join' do
@@ -130,7 +172,7 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_rename' do
130
172
 
131
173
  it_should_behave_like 'a generated SQL SELECT query'
132
174
 
133
- its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM (SELECT * FROM "users" NATURAL JOIN "users") AS "users"') }
134
- its(:to_subquery) { should eql('SELECT "id" AS "user_id", "name", "age" FROM (SELECT * FROM "users" NATURAL JOIN "users") AS "users"') }
175
+ its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "users"') }
176
+ its(:to_subquery) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "users")') }
135
177
  end
136
178
  end
@@ -11,7 +11,7 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_restriction' d
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(:restriction) { operand.restrict { |r| r[:id].eq(1) } }
16
16
  let(:object) { described_class.new }
17
17
 
@@ -21,7 +21,7 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_restriction' d
21
21
  it_should_behave_like 'a generated SQL SELECT query'
22
22
 
23
23
  its(:to_s) { should eql('SELECT "id", "name", "age" FROM "users" WHERE "id" = 1') }
24
- its(:to_subquery) { should eql('SELECT * FROM "users" WHERE "id" = 1') }
24
+ its(:to_subquery) { should eql('(SELECT * FROM "users" WHERE "id" = 1)') }
25
25
  end
26
26
 
27
27
  context 'when the operand is a projection' do
@@ -29,8 +29,17 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_restriction' d
29
29
 
30
30
  it_should_behave_like 'a generated SQL SELECT query'
31
31
 
32
- its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM "users" WHERE "id" = 1') }
33
- its(:to_subquery) { should eql('SELECT DISTINCT "id", "name" FROM "users" WHERE "id" = 1') }
32
+ its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM "users" WHERE "id" = 1') }
33
+ its(:to_subquery) { should eql('(SELECT DISTINCT "id", "name" FROM "users" WHERE "id" = 1)') }
34
+ end
35
+
36
+ context 'when the operand is an extension' do
37
+ let(:operand) { base_relation.extend { |r| r.add(:one, 1) } }
38
+
39
+ it_should_behave_like 'a generated SQL SELECT query'
40
+
41
+ its(:to_s) { should eql('SELECT "id", "name", "age", "one" FROM (SELECT *, 1 AS "one" FROM "users") AS "users" WHERE "id" = 1') }
42
+ its(:to_subquery) { should eql('(SELECT * FROM (SELECT *, 1 AS "one" FROM "users") AS "users" WHERE "id" = 1)') }
34
43
  end
35
44
 
36
45
  context 'when the operand is a projection then a restriction' do
@@ -39,17 +48,17 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_restriction' d
39
48
  it_should_behave_like 'a generated SQL SELECT query'
40
49
 
41
50
  its(:to_s) { should eql('SELECT "id", "name" FROM (SELECT DISTINCT "id", "name" FROM "users" WHERE "id" <> 2) AS "users" WHERE "id" = 1') }
42
- its(:to_subquery) { should eql('SELECT * FROM (SELECT DISTINCT "id", "name" FROM "users" WHERE "id" <> 2) AS "users" WHERE "id" = 1') }
51
+ its(:to_subquery) { should eql('(SELECT * FROM (SELECT DISTINCT "id", "name" FROM "users" WHERE "id" <> 2) AS "users" WHERE "id" = 1)') }
43
52
  end
44
53
 
45
54
  context 'when the operand is a projection then a restriction, followed by another restriction' do
46
- let(:tautology) { Logic::Proposition::Tautology.instance }
47
- let(:operand) { base_relation.project([ :id, :name ]).restrict(tautology).restrict(tautology) }
55
+ let(:tautology) { Function::Proposition::Tautology.instance }
56
+ let(:operand) { base_relation.project([ :id, :name ]).restrict { tautology }.restrict { tautology } }
48
57
 
49
58
  it_should_behave_like 'a generated SQL SELECT query'
50
59
 
51
- its(:to_s) { should eql('SELECT "id", "name" FROM (SELECT * FROM (SELECT DISTINCT "id", "name" FROM "users" WHERE 1 = 1) AS "users" WHERE 1 = 1) AS "users" WHERE "id" = 1') }
52
- its(:to_subquery) { should eql('SELECT * FROM (SELECT * FROM (SELECT DISTINCT "id", "name" FROM "users" WHERE 1 = 1) AS "users" WHERE 1 = 1) AS "users" WHERE "id" = 1') }
60
+ its(:to_s) { should eql('SELECT "id", "name" FROM (SELECT * FROM (SELECT DISTINCT "id", "name" FROM "users" WHERE TRUE) AS "users" WHERE TRUE) AS "users" WHERE "id" = 1') }
61
+ its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM (SELECT DISTINCT "id", "name" FROM "users" WHERE TRUE) AS "users" WHERE TRUE) AS "users" WHERE "id" = 1)') }
53
62
  end
54
63
 
55
64
  context 'when the operand is a rename' do
@@ -80,7 +89,40 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_restriction' d
80
89
  it_should_behave_like 'a generated SQL SELECT query'
81
90
 
82
91
  its(:to_s) { should eql('SELECT "id", "name", "age" FROM (SELECT * FROM "users" WHERE "id" = 1) AS "users" WHERE "id" = 1') }
83
- its(:to_subquery) { should eql('SELECT * FROM (SELECT * FROM "users" WHERE "id" = 1) AS "users" WHERE "id" = 1') }
92
+ its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" WHERE "id" = 1) AS "users" WHERE "id" = 1)') }
93
+ end
94
+
95
+ context 'when the operand is a summarization' do
96
+ context 'summarize per table dee' do
97
+ let(:summarize_per) { TABLE_DEE }
98
+ let(:operand) { base_relation.summarize(summarize_per) { |r| r.add(:count, r[:id].count) } }
99
+ let(:restriction) { operand.restrict { |r| r[:count].eq(1) } }
100
+
101
+ it_should_behave_like 'a generated SQL SELECT query'
102
+
103
+ its(:to_s) { should eql('SELECT "count" FROM (SELECT COUNT ("id") AS "count" FROM "users") AS "users" WHERE "count" = 1') }
104
+ its(:to_subquery) { should eql('(SELECT * FROM (SELECT COUNT ("id") AS "count" FROM "users") AS "users" WHERE "count" = 1)') }
105
+ end
106
+
107
+ context 'summarize per table dum' do
108
+ let(:summarize_per) { TABLE_DUM }
109
+ let(:operand) { base_relation.summarize(summarize_per) { |r| r.add(:count, r[:id].count) } }
110
+ let(:restriction) { operand.restrict { |r| r[:count].eq(1) } }
111
+
112
+ it_should_behave_like 'a generated SQL SELECT query'
113
+
114
+ its(:to_s) { should eql('SELECT "count" FROM (SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE) AS "users" WHERE "count" = 1') }
115
+ its(:to_subquery) { should eql('(SELECT * FROM (SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE) AS "users" WHERE "count" = 1)') }
116
+ end
117
+
118
+ context 'summarize by a subset of the operand header' do
119
+ let(:operand) { base_relation.summarize([ :id, :name ]) { |r| r.add(:count, r[:age].count) } }
120
+
121
+ it_should_behave_like 'a generated SQL SELECT query'
122
+
123
+ its(:to_s) { should eql('SELECT "id", "name", "count" FROM (SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0) AS "users" WHERE "id" = 1') }
124
+ its(:to_subquery) { should eql('(SELECT * FROM (SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0) AS "users" WHERE "id" = 1)') }
125
+ end
84
126
  end
85
127
 
86
128
  context 'when the operand is ordered' do
@@ -89,7 +131,7 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_restriction' d
89
131
  it_should_behave_like 'a generated SQL SELECT query'
90
132
 
91
133
  its(:to_s) { should eql('SELECT "id", "name", "age" FROM "users" WHERE "id" = 1 ORDER BY "id", "name", "age"') }
92
- its(:to_subquery) { should eql('SELECT * FROM "users" WHERE "id" = 1 ORDER BY "id", "name", "age"') }
134
+ its(:to_subquery) { should eql('(SELECT * FROM "users" WHERE "id" = 1 ORDER BY "id", "name", "age")') }
93
135
  end
94
136
 
95
137
  context 'when the operand is reversed' do
@@ -98,7 +140,7 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_restriction' d
98
140
  it_should_behave_like 'a generated SQL SELECT query'
99
141
 
100
142
  its(:to_s) { should eql('SELECT "id", "name", "age" FROM "users" WHERE "id" = 1 ORDER BY "id" DESC, "name" DESC, "age" DESC') }
101
- its(:to_subquery) { should eql('SELECT * FROM "users" WHERE "id" = 1 ORDER BY "id" DESC, "name" DESC, "age" DESC') }
143
+ its(:to_subquery) { should eql('(SELECT * FROM "users" WHERE "id" = 1 ORDER BY "id" DESC, "name" DESC, "age" DESC)') }
102
144
  end
103
145
 
104
146
  context 'when the operand is limited' do
@@ -107,7 +149,7 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_restriction' d
107
149
  it_should_behave_like 'a generated SQL SELECT query'
108
150
 
109
151
  its(:to_s) { should eql('SELECT "id", "name", "age" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "users" WHERE "id" = 1') }
110
- its(:to_subquery) { should eql('SELECT * FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "users" WHERE "id" = 1') }
152
+ its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "users" WHERE "id" = 1)') }
111
153
  end
112
154
 
113
155
  context 'when the operand is an offset' do
@@ -116,7 +158,7 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_restriction' d
116
158
  it_should_behave_like 'a generated SQL SELECT query'
117
159
 
118
160
  its(:to_s) { should eql('SELECT "id", "name", "age" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "users" WHERE "id" = 1') }
119
- its(:to_subquery) { should eql('SELECT * FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "users" WHERE "id" = 1') }
161
+ its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "users" WHERE "id" = 1)') }
120
162
  end
121
163
 
122
164
  context 'when the operand is a difference' do
@@ -124,8 +166,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_restriction' d
124
166
 
125
167
  it_should_behave_like 'a generated SQL SELECT query'
126
168
 
127
- its(:to_s) { should eql('SELECT "id", "name", "age" FROM ((SELECT * FROM "users") EXCEPT (SELECT * FROM "users")) AS "users" WHERE "id" = 1') }
128
- its(:to_subquery) { should eql('SELECT * FROM ((SELECT * FROM "users") EXCEPT (SELECT * FROM "users")) AS "users" WHERE "id" = 1') }
169
+ its(:to_s) { should eql('SELECT "id", "name", "age" FROM ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "users" WHERE "id" = 1') }
170
+ its(:to_subquery) { should eql('(SELECT * FROM ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "users" WHERE "id" = 1)') }
129
171
  end
130
172
 
131
173
  context 'when the operand is an intersection' do
@@ -133,8 +175,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_restriction' d
133
175
 
134
176
  it_should_behave_like 'a generated SQL SELECT query'
135
177
 
136
- its(:to_s) { should eql('SELECT "id", "name", "age" FROM ((SELECT * FROM "users") INTERSECT (SELECT * FROM "users")) AS "users" WHERE "id" = 1') }
137
- its(:to_subquery) { should eql('SELECT * FROM ((SELECT * FROM "users") INTERSECT (SELECT * FROM "users")) AS "users" WHERE "id" = 1') }
178
+ its(:to_s) { should eql('SELECT "id", "name", "age" FROM ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "users" WHERE "id" = 1') }
179
+ its(:to_subquery) { should eql('(SELECT * FROM ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "users" WHERE "id" = 1)') }
138
180
  end
139
181
 
140
182
  context 'when the operand is a union' do
@@ -142,8 +184,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_restriction' d
142
184
 
143
185
  it_should_behave_like 'a generated SQL SELECT query'
144
186
 
145
- its(:to_s) { should eql('SELECT "id", "name", "age" FROM ((SELECT * FROM "users") UNION (SELECT * FROM "users")) AS "users" WHERE "id" = 1') }
146
- its(:to_subquery) { should eql('SELECT * FROM ((SELECT * FROM "users") UNION (SELECT * FROM "users")) AS "users" WHERE "id" = 1') }
187
+ its(:to_s) { should eql('SELECT "id", "name", "age" FROM ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "users" WHERE "id" = 1') }
188
+ its(:to_subquery) { should eql('(SELECT * FROM ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "users" WHERE "id" = 1)') }
147
189
  end
148
190
 
149
191
  context 'when the operand is a join' do
@@ -151,7 +193,7 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_restriction' d
151
193
 
152
194
  it_should_behave_like 'a generated SQL SELECT query'
153
195
 
154
- its(:to_s) { should eql('SELECT "id", "name", "age" FROM (SELECT * FROM "users" NATURAL JOIN "users") AS "users" WHERE "id" = 1') }
155
- its(:to_subquery) { should eql('SELECT * FROM (SELECT * FROM "users" NATURAL JOIN "users") AS "users" WHERE "id" = 1') }
196
+ its(:to_s) { should eql('SELECT "id", "name", "age" FROM (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "users" WHERE "id" = 1') }
197
+ its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "users" WHERE "id" = 1)') }
156
198
  end
157
199
  end
@@ -0,0 +1,652 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_summarization' do
6
+ subject { object.visit_veritas_algebra_summarization(summarization) }
7
+
8
+ let(:relation_name) { 'users' }
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(relation_name, header, body) }
15
+ let(:other_relation) { Relation::Base.new('other', [ id ], [ [ 1 ] ]) }
16
+ let(:object) { described_class.new }
17
+
18
+ context 'summarize per table dee' do
19
+ let(:summarize_per) { TABLE_DEE }
20
+ let(:summarization) { operand.summarize(summarize_per) { |r| r.add(:count, r[:age].count) } }
21
+
22
+ context 'when the operand is a base relation' do
23
+ let(:operand) { base_relation }
24
+
25
+ it_should_behave_like 'a generated SQL SELECT query'
26
+
27
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM "users"') }
28
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM "users")') }
29
+ end
30
+
31
+ context 'when the operand is an extension' do
32
+ let(:operand) { base_relation.extend { |r| r.add(:one, 1) } }
33
+
34
+ it_should_behave_like 'a generated SQL SELECT query'
35
+
36
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM (SELECT *, 1 AS "one" FROM "users") AS "users"') }
37
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM (SELECT *, 1 AS "one" FROM "users") AS "users")') }
38
+ end
39
+
40
+ context 'when the operand is a projection' do
41
+ let(:operand) { base_relation.project([ :id, :name ]) }
42
+ let(:summarization) { operand.summarize(summarize_per) { |r| r.add(:count, r[:id].count) } }
43
+
44
+ it_should_behave_like 'a generated SQL SELECT query'
45
+
46
+ its(:to_s) { should eql('SELECT COUNT ("id") AS "count" FROM (SELECT DISTINCT "id", "name" FROM "users") AS "users"') }
47
+ its(:to_subquery) { should eql('(SELECT COUNT ("id") AS "count" FROM (SELECT DISTINCT "id", "name" FROM "users") AS "users")') }
48
+ end
49
+
50
+ context 'when the operand is a rename' do
51
+ let(:operand) { base_relation.rename(:name => :other_name) }
52
+
53
+ it_should_behave_like 'a generated SQL SELECT query'
54
+
55
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM (SELECT "id", "name" AS "other_name", "age" FROM "users") AS "users"') }
56
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM (SELECT "id", "name" AS "other_name", "age" FROM "users") AS "users")') }
57
+ end
58
+
59
+ context 'when the operand is a restriction' do
60
+ let(:operand) { base_relation.restrict { |r| r[:id].eq(1) } }
61
+
62
+ it_should_behave_like 'a generated SQL SELECT query'
63
+
64
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" WHERE "id" = 1) AS "users"') }
65
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" WHERE "id" = 1) AS "users")') }
66
+ end
67
+
68
+ context 'when the operand is a summarization' do
69
+ let(:operand) { base_relation.summarize([ :id ]) { |r| r.add(:count, r[:age].count) } }
70
+ let(:summarization) { operand.summarize(summarize_per) { |r| r.add(:count, r[:count].count) } }
71
+
72
+ it_should_behave_like 'a generated SQL SELECT query'
73
+
74
+ its(:to_s) { should eql('SELECT COUNT ("count") AS "count" FROM (SELECT "id", COUNT ("age") AS "count" FROM "users" GROUP BY "id" HAVING COUNT (*) > 0) AS "users"') }
75
+ its(:to_subquery) { should eql('(SELECT COUNT ("count") AS "count" FROM (SELECT "id", COUNT ("age") AS "count" FROM "users" GROUP BY "id" HAVING COUNT (*) > 0) AS "users")') }
76
+ end
77
+
78
+ context 'when the operand is ordered' do
79
+ let(:operand) { base_relation.order }
80
+
81
+ it_should_behave_like 'a generated SQL SELECT query'
82
+
83
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "users"') }
84
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "users")') }
85
+ end
86
+
87
+ context 'when the operand is reversed' do
88
+ let(:operand) { base_relation.order.reverse }
89
+
90
+ it_should_behave_like 'a generated SQL SELECT query'
91
+
92
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) AS "users"') }
93
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) AS "users")') }
94
+ end
95
+
96
+ context 'when the operand is limited' do
97
+ let(:operand) { base_relation.order.take(1) }
98
+
99
+ it_should_behave_like 'a generated SQL SELECT query'
100
+
101
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "users"') }
102
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "users")') }
103
+ end
104
+
105
+ context 'when the operand is an offset' do
106
+ let(:operand) { base_relation.order.drop(1) }
107
+
108
+ it_should_behave_like 'a generated SQL SELECT query'
109
+
110
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "users"') }
111
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "users")') }
112
+ end
113
+
114
+ context 'when the operand is a difference' do
115
+ let(:operand) { base_relation.difference(base_relation) }
116
+
117
+ it_should_behave_like 'a generated SQL SELECT query'
118
+
119
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "users"') }
120
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "users")') }
121
+ end
122
+
123
+ context 'when the operand is an intersection' do
124
+ let(:operand) { base_relation.intersect(base_relation) }
125
+
126
+ it_should_behave_like 'a generated SQL SELECT query'
127
+
128
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "users"') }
129
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "users")') }
130
+ end
131
+
132
+ context 'when the operand is a union' do
133
+ let(:operand) { base_relation.union(base_relation) }
134
+
135
+ it_should_behave_like 'a generated SQL SELECT query'
136
+
137
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "users"') }
138
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "users")') }
139
+ end
140
+
141
+ context 'when the operand is a join' do
142
+ let(:operand) { base_relation.join(base_relation) }
143
+
144
+ it_should_behave_like 'a generated SQL SELECT query'
145
+
146
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "users"') }
147
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "users")') }
148
+ end
149
+ end
150
+
151
+ context 'summarize per table dum' do
152
+ let(:summarize_per) { TABLE_DUM }
153
+ let(:summarization) { operand.summarize(summarize_per) { |r| r.add(:count, r[:age].count) } }
154
+
155
+ context 'when the operand is a base relation' do
156
+ let(:operand) { base_relation }
157
+
158
+ it_should_behave_like 'a generated SQL SELECT query'
159
+
160
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM "users" HAVING FALSE') }
161
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM "users" HAVING FALSE)') }
162
+ end
163
+
164
+ context 'when the operand is an extension' do
165
+ let(:operand) { base_relation.extend { |r| r.add(:one, 1) } }
166
+
167
+ it_should_behave_like 'a generated SQL SELECT query'
168
+
169
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM (SELECT *, 1 AS "one" FROM "users") AS "users" HAVING FALSE') }
170
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM (SELECT *, 1 AS "one" FROM "users") AS "users" HAVING FALSE)') }
171
+ end
172
+
173
+ context 'when the operand is a projection' do
174
+ let(:operand) { base_relation.project([ :id, :name ]) }
175
+ let(:summarization) { operand.summarize(summarize_per) { |r| r.add(:count, r[:id].count) } }
176
+
177
+ it_should_behave_like 'a generated SQL SELECT query'
178
+
179
+ its(:to_s) { should eql('SELECT COUNT ("id") AS "count" FROM (SELECT DISTINCT "id", "name" FROM "users") AS "users" HAVING FALSE') }
180
+ its(:to_subquery) { should eql('(SELECT COUNT ("id") AS "count" FROM (SELECT DISTINCT "id", "name" FROM "users") AS "users" HAVING FALSE)') }
181
+ end
182
+
183
+ context 'when the operand is a rename' do
184
+ let(:operand) { base_relation.rename(:name => :other_name) }
185
+
186
+ it_should_behave_like 'a generated SQL SELECT query'
187
+
188
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM (SELECT "id", "name" AS "other_name", "age" FROM "users") AS "users" HAVING FALSE') }
189
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM (SELECT "id", "name" AS "other_name", "age" FROM "users") AS "users" HAVING FALSE)') }
190
+ end
191
+
192
+ context 'when the operand is a restriction' do
193
+ let(:operand) { base_relation.restrict { |r| r[:id].eq(1) } }
194
+
195
+ it_should_behave_like 'a generated SQL SELECT query'
196
+
197
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" WHERE "id" = 1) AS "users" HAVING FALSE') }
198
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" WHERE "id" = 1) AS "users" HAVING FALSE)') }
199
+ end
200
+
201
+ context 'when the operand is a summarization' do
202
+ let(:operand) { base_relation.summarize([ :id ]) { |r| r.add(:count, r[:age].count) } }
203
+ let(:summarization) { operand.summarize(summarize_per) { |r| r.add(:count, r[:count].count) } }
204
+
205
+ it_should_behave_like 'a generated SQL SELECT query'
206
+
207
+ its(:to_s) { should eql('SELECT COUNT ("count") AS "count" FROM (SELECT "id", COUNT ("age") AS "count" FROM "users" GROUP BY "id" HAVING COUNT (*) > 0) AS "users" HAVING FALSE') }
208
+ its(:to_subquery) { should eql('(SELECT COUNT ("count") AS "count" FROM (SELECT "id", COUNT ("age") AS "count" FROM "users" GROUP BY "id" HAVING COUNT (*) > 0) AS "users" HAVING FALSE)') }
209
+ end
210
+
211
+ context 'when the operand is ordered' do
212
+ let(:operand) { base_relation.order }
213
+
214
+ it_should_behave_like 'a generated SQL SELECT query'
215
+
216
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "users" HAVING FALSE') }
217
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "users" HAVING FALSE)') }
218
+ end
219
+
220
+ context 'when the operand is reversed' do
221
+ let(:operand) { base_relation.order.reverse }
222
+
223
+ it_should_behave_like 'a generated SQL SELECT query'
224
+
225
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) AS "users" HAVING FALSE') }
226
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) AS "users" HAVING FALSE)') }
227
+ end
228
+
229
+ context 'when the operand is limited' do
230
+ let(:operand) { base_relation.order.take(1) }
231
+
232
+ it_should_behave_like 'a generated SQL SELECT query'
233
+
234
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "users" HAVING FALSE') }
235
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "users" HAVING FALSE)') }
236
+ end
237
+
238
+ context 'when the operand is an offset' do
239
+ let(:operand) { base_relation.order.drop(1) }
240
+
241
+ it_should_behave_like 'a generated SQL SELECT query'
242
+
243
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "users" HAVING FALSE') }
244
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "users" HAVING FALSE)') }
245
+ end
246
+
247
+ context 'when the operand is a difference' do
248
+ let(:operand) { base_relation.difference(base_relation) }
249
+
250
+ it_should_behave_like 'a generated SQL SELECT query'
251
+
252
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "users" HAVING FALSE') }
253
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "users" HAVING FALSE)') }
254
+ end
255
+
256
+ context 'when the operand is an intersection' do
257
+ let(:operand) { base_relation.intersect(base_relation) }
258
+
259
+ it_should_behave_like 'a generated SQL SELECT query'
260
+
261
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "users" HAVING FALSE') }
262
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "users" HAVING FALSE)') }
263
+ end
264
+
265
+ context 'when the operand is a union' do
266
+ let(:operand) { base_relation.union(base_relation) }
267
+
268
+ it_should_behave_like 'a generated SQL SELECT query'
269
+
270
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "users" HAVING FALSE') }
271
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "users" HAVING FALSE)') }
272
+ end
273
+
274
+ context 'when the operand is a join' do
275
+ let(:operand) { base_relation.join(base_relation) }
276
+
277
+ it_should_behave_like 'a generated SQL SELECT query'
278
+
279
+ its(:to_s) { should eql('SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "users" HAVING FALSE') }
280
+ its(:to_subquery) { should eql('(SELECT COUNT ("age") AS "count" FROM (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "users" HAVING FALSE)') }
281
+ end
282
+ end
283
+
284
+ context 'summarize by a subset of the operand header' do
285
+ let(:summarize_by) { [ :id ] }
286
+ let(:summarization) { operand.summarize(summarize_by) { |r| r.add(:count, r[:age].count) } }
287
+
288
+ context 'when the operand is a base relation' do
289
+ let(:operand) { base_relation }
290
+
291
+ it_should_behave_like 'a generated SQL SELECT query'
292
+
293
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM "users" GROUP BY "id" HAVING COUNT (*) > 0') }
294
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM "users" GROUP BY "id" HAVING COUNT (*) > 0)') }
295
+ end
296
+
297
+ context 'when the operand is a projection' do
298
+ let(:operand) { base_relation.project([ :id, :name ]) }
299
+ let(:summarization) { operand.summarize(summarize_by) { |r| r.add(:count, r[:name].count) } }
300
+
301
+ it_should_behave_like 'a generated SQL SELECT query'
302
+
303
+ its(:to_s) { should eql('SELECT "id", COUNT ("name") AS "count" FROM (SELECT DISTINCT "id", "name" FROM "users") AS "users" GROUP BY "id" HAVING COUNT (*) > 0') }
304
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("name") AS "count" FROM (SELECT DISTINCT "id", "name" FROM "users") AS "users" GROUP BY "id" HAVING COUNT (*) > 0)') }
305
+ end
306
+
307
+ context 'when the operand is an extension' do
308
+ let(:operand) { base_relation.extend { |r| r.add(:one, 1) } }
309
+
310
+ it_should_behave_like 'a generated SQL SELECT query'
311
+
312
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM (SELECT *, 1 AS "one" FROM "users") AS "users" GROUP BY "id" HAVING COUNT (*) > 0') }
313
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM (SELECT *, 1 AS "one" FROM "users") AS "users" GROUP BY "id" HAVING COUNT (*) > 0)') }
314
+ end
315
+
316
+ context 'when the operand is a rename' do
317
+ let(:operand) { base_relation.rename(:name => :other_name) }
318
+
319
+ it_should_behave_like 'a generated SQL SELECT query'
320
+
321
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM (SELECT "id", "name" AS "other_name", "age" FROM "users") AS "users" GROUP BY "id" HAVING COUNT (*) > 0') }
322
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM (SELECT "id", "name" AS "other_name", "age" FROM "users") AS "users" GROUP BY "id" HAVING COUNT (*) > 0)') }
323
+ end
324
+
325
+ context 'when the operand is a restriction' do
326
+ let(:operand) { base_relation.restrict { |r| r[:id].eq(1) } }
327
+
328
+ it_should_behave_like 'a generated SQL SELECT query'
329
+
330
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM (SELECT * FROM "users" WHERE "id" = 1) AS "users" GROUP BY "id" HAVING COUNT (*) > 0') }
331
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM (SELECT * FROM "users" WHERE "id" = 1) AS "users" GROUP BY "id" HAVING COUNT (*) > 0)') }
332
+ end
333
+
334
+ context 'when the operand is ordered' do
335
+ let(:operand) { base_relation.order }
336
+
337
+ it_should_behave_like 'a generated SQL SELECT query'
338
+
339
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "users" GROUP BY "id" HAVING COUNT (*) > 0') }
340
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "users" GROUP BY "id" HAVING COUNT (*) > 0)') }
341
+ end
342
+
343
+ context 'when the operand is reversed' do
344
+ let(:operand) { base_relation.order.reverse }
345
+
346
+ it_should_behave_like 'a generated SQL SELECT query'
347
+
348
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) AS "users" GROUP BY "id" HAVING COUNT (*) > 0') }
349
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) AS "users" GROUP BY "id" HAVING COUNT (*) > 0)') }
350
+ end
351
+
352
+ context 'when the operand is limited' do
353
+ let(:operand) { base_relation.order.take(1) }
354
+
355
+ it_should_behave_like 'a generated SQL SELECT query'
356
+
357
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "users" GROUP BY "id" HAVING COUNT (*) > 0') }
358
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "users" GROUP BY "id" HAVING COUNT (*) > 0)') }
359
+ end
360
+
361
+ context 'when the operand is an offset' do
362
+ let(:operand) { base_relation.order.drop(1) }
363
+
364
+ it_should_behave_like 'a generated SQL SELECT query'
365
+
366
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "users" GROUP BY "id" HAVING COUNT (*) > 0') }
367
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "users" GROUP BY "id" HAVING COUNT (*) > 0)') }
368
+ end
369
+
370
+ context 'when the operand is a difference' do
371
+ let(:operand) { base_relation.difference(base_relation) }
372
+
373
+ it_should_behave_like 'a generated SQL SELECT query'
374
+
375
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "users" GROUP BY "id" HAVING COUNT (*) > 0') }
376
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "users" GROUP BY "id" HAVING COUNT (*) > 0)') }
377
+ end
378
+
379
+ context 'when the operand is an intersection' do
380
+ let(:operand) { base_relation.intersect(base_relation) }
381
+
382
+ it_should_behave_like 'a generated SQL SELECT query'
383
+
384
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "users" GROUP BY "id" HAVING COUNT (*) > 0') }
385
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "users" GROUP BY "id" HAVING COUNT (*) > 0)') }
386
+ end
387
+
388
+ context 'when the operand is a union' do
389
+ let(:operand) { base_relation.union(base_relation) }
390
+
391
+ it_should_behave_like 'a generated SQL SELECT query'
392
+
393
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "users" GROUP BY "id" HAVING COUNT (*) > 0') }
394
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "users" GROUP BY "id" HAVING COUNT (*) > 0)') }
395
+ end
396
+
397
+ context 'when the operand is a join' do
398
+ let(:operand) { base_relation.join(base_relation) }
399
+
400
+ it_should_behave_like 'a generated SQL SELECT query'
401
+
402
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "users" GROUP BY "id" HAVING COUNT (*) > 0') }
403
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "users" GROUP BY "id" HAVING COUNT (*) > 0)') }
404
+ end
405
+ end
406
+
407
+ context 'summarize per another base relation' do
408
+ let(:summarize_per) { other_relation }
409
+ let(:summarization) { operand.summarize(summarize_per) { |r| r.add(:count, r[:age].count) } }
410
+
411
+ context 'when the operand is a base relation' do
412
+ let(:operand) { base_relation }
413
+
414
+ it_should_behave_like 'a generated SQL SELECT query'
415
+
416
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN "users" GROUP BY "id"') }
417
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN "users" GROUP BY "id")') }
418
+ end
419
+
420
+ context 'when the operand is a projection' do
421
+ let(:operand) { base_relation.project([ :id, :name ]) }
422
+ let(:summarization) { operand.summarize(summarize_per) { |r| r.add(:count, r[:name].count) } }
423
+
424
+ it_should_behave_like 'a generated SQL SELECT query'
425
+
426
+ its(:to_s) { should eql('SELECT "id", COUNT ("name") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN (SELECT DISTINCT "id", "name" FROM "users") AS "users" GROUP BY "id"') }
427
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("name") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN (SELECT DISTINCT "id", "name" FROM "users") AS "users" GROUP BY "id")') }
428
+ end
429
+
430
+ context 'when the operand is an extension' do
431
+ let(:operand) { base_relation.extend { |r| r.add(:one, 1) } }
432
+
433
+ it_should_behave_like 'a generated SQL SELECT query'
434
+
435
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN (SELECT *, 1 AS "one" FROM "users") AS "users" GROUP BY "id"') }
436
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN (SELECT *, 1 AS "one" FROM "users") AS "users" GROUP BY "id")') }
437
+ end
438
+
439
+ context 'when the operand is a rename' do
440
+ let(:operand) { base_relation.rename(:name => :other_name) }
441
+
442
+ it_should_behave_like 'a generated SQL SELECT query'
443
+
444
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN (SELECT "id", "name" AS "other_name", "age" FROM "users") AS "users" GROUP BY "id"') }
445
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN (SELECT "id", "name" AS "other_name", "age" FROM "users") AS "users" GROUP BY "id")') }
446
+ end
447
+
448
+ context 'when the operand is a restriction' do
449
+ let(:operand) { base_relation.restrict { |r| r[:id].eq(1) } }
450
+
451
+ it_should_behave_like 'a generated SQL SELECT query'
452
+
453
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" WHERE "id" = 1) AS "users" GROUP BY "id"') }
454
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" WHERE "id" = 1) AS "users" GROUP BY "id")') }
455
+ end
456
+
457
+ context 'when the operand is ordered' do
458
+ let(:operand) { base_relation.order }
459
+
460
+ it_should_behave_like 'a generated SQL SELECT query'
461
+
462
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "users" GROUP BY "id"') }
463
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "users" GROUP BY "id")') }
464
+ end
465
+
466
+ context 'when the operand is reversed' do
467
+ let(:operand) { base_relation.order.reverse }
468
+
469
+ it_should_behave_like 'a generated SQL SELECT query'
470
+
471
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) AS "users" GROUP BY "id"') }
472
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) AS "users" GROUP BY "id")') }
473
+ end
474
+
475
+ context 'when the operand is limited' do
476
+ let(:operand) { base_relation.order.take(1) }
477
+
478
+ it_should_behave_like 'a generated SQL SELECT query'
479
+
480
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "users" GROUP BY "id"') }
481
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "users" GROUP BY "id")') }
482
+ end
483
+
484
+ context 'when the operand is an offset' do
485
+ let(:operand) { base_relation.order.drop(1) }
486
+
487
+ it_should_behave_like 'a generated SQL SELECT query'
488
+
489
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "users" GROUP BY "id"') }
490
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "users" GROUP BY "id")') }
491
+ end
492
+
493
+ context 'when the operand is a difference' do
494
+ let(:operand) { base_relation.difference(base_relation) }
495
+
496
+ it_should_behave_like 'a generated SQL SELECT query'
497
+
498
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "users" GROUP BY "id"') }
499
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "users" GROUP BY "id")') }
500
+ end
501
+
502
+ context 'when the operand is an intersection' do
503
+ let(:operand) { base_relation.intersect(base_relation) }
504
+
505
+ it_should_behave_like 'a generated SQL SELECT query'
506
+
507
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "users" GROUP BY "id"') }
508
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "users" GROUP BY "id")') }
509
+ end
510
+
511
+ context 'when the operand is a union' do
512
+ let(:operand) { base_relation.union(base_relation) }
513
+
514
+ it_should_behave_like 'a generated SQL SELECT query'
515
+
516
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "users" GROUP BY "id"') }
517
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "users" GROUP BY "id")') }
518
+ end
519
+
520
+ context 'when the operand is a join' do
521
+ let(:operand) { base_relation.join(base_relation) }
522
+
523
+ it_should_behave_like 'a generated SQL SELECT query'
524
+
525
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "users" GROUP BY "id"') }
526
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM "other" AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "users" GROUP BY "id")') }
527
+ end
528
+ end
529
+
530
+ context 'summarize per another projected relation' do
531
+ let(:summarize_per) { other_relation.project([ :id ]) }
532
+ let(:summarization) { operand.summarize(summarize_per) { |r| r.add(:count, r[:age].count) } }
533
+
534
+ context 'when the operand is a base relation' do
535
+ let(:operand) { base_relation }
536
+
537
+ it_should_behave_like 'a generated SQL SELECT query'
538
+
539
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN "users" GROUP BY "id"') }
540
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN "users" GROUP BY "id")') }
541
+ end
542
+
543
+ context 'when the operand is a projection' do
544
+ let(:operand) { base_relation.project([ :id, :name ]) }
545
+ let(:summarization) { operand.summarize(summarize_per) { |r| r.add(:count, r[:name].count) } }
546
+
547
+ it_should_behave_like 'a generated SQL SELECT query'
548
+
549
+ its(:to_s) { should eql('SELECT "id", COUNT ("name") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN (SELECT DISTINCT "id", "name" FROM "users") AS "users" GROUP BY "id"') }
550
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("name") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN (SELECT DISTINCT "id", "name" FROM "users") AS "users" GROUP BY "id")') }
551
+ end
552
+
553
+ context 'when the operand is an extension' do
554
+ let(:operand) { base_relation.extend { |r| r.add(:one, 1) } }
555
+
556
+ it_should_behave_like 'a generated SQL SELECT query'
557
+
558
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN (SELECT *, 1 AS "one" FROM "users") AS "users" GROUP BY "id"') }
559
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN (SELECT *, 1 AS "one" FROM "users") AS "users" GROUP BY "id")') }
560
+ end
561
+
562
+ context 'when the operand is a rename' do
563
+ let(:operand) { base_relation.rename(:name => :other_name) }
564
+
565
+ it_should_behave_like 'a generated SQL SELECT query'
566
+
567
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN (SELECT "id", "name" AS "other_name", "age" FROM "users") AS "users" GROUP BY "id"') }
568
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN (SELECT "id", "name" AS "other_name", "age" FROM "users") AS "users" GROUP BY "id")') }
569
+ end
570
+
571
+ context 'when the operand is a restriction' do
572
+ let(:operand) { base_relation.restrict { |r| r[:id].eq(1) } }
573
+
574
+ it_should_behave_like 'a generated SQL SELECT query'
575
+
576
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" WHERE "id" = 1) AS "users" GROUP BY "id"') }
577
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" WHERE "id" = 1) AS "users" GROUP BY "id")') }
578
+ end
579
+
580
+ context 'when the operand is ordered' do
581
+ let(:operand) { base_relation.order }
582
+
583
+ it_should_behave_like 'a generated SQL SELECT query'
584
+
585
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "users" GROUP BY "id"') }
586
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "users" GROUP BY "id")') }
587
+ end
588
+
589
+ context 'when the operand is reversed' do
590
+ let(:operand) { base_relation.order.reverse }
591
+
592
+ it_should_behave_like 'a generated SQL SELECT query'
593
+
594
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) AS "users" GROUP BY "id"') }
595
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) AS "users" GROUP BY "id")') }
596
+ end
597
+
598
+ context 'when the operand is limited' do
599
+ let(:operand) { base_relation.order.take(1) }
600
+
601
+ it_should_behave_like 'a generated SQL SELECT query'
602
+
603
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "users" GROUP BY "id"') }
604
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "users" GROUP BY "id")') }
605
+ end
606
+
607
+ context 'when the operand is an offset' do
608
+ let(:operand) { base_relation.order.drop(1) }
609
+
610
+ it_should_behave_like 'a generated SQL SELECT query'
611
+
612
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "users" GROUP BY "id"') }
613
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "users" GROUP BY "id")') }
614
+ end
615
+
616
+ context 'when the operand is a difference' do
617
+ let(:operand) { base_relation.difference(base_relation) }
618
+
619
+ it_should_behave_like 'a generated SQL SELECT query'
620
+
621
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "users" GROUP BY "id"') }
622
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "users" GROUP BY "id")') }
623
+ end
624
+
625
+ context 'when the operand is an intersection' do
626
+ let(:operand) { base_relation.intersect(base_relation) }
627
+
628
+ it_should_behave_like 'a generated SQL SELECT query'
629
+
630
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "users" GROUP BY "id"') }
631
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "users" GROUP BY "id")') }
632
+ end
633
+
634
+ context 'when the operand is a union' do
635
+ let(:operand) { base_relation.union(base_relation) }
636
+
637
+ it_should_behave_like 'a generated SQL SELECT query'
638
+
639
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "users" GROUP BY "id"') }
640
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "users" GROUP BY "id")') }
641
+ end
642
+
643
+ context 'when the operand is a join' do
644
+ let(:operand) { base_relation.join(base_relation) }
645
+
646
+ it_should_behave_like 'a generated SQL SELECT query'
647
+
648
+ its(:to_s) { should eql('SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "users" GROUP BY "id"') }
649
+ its(:to_subquery) { should eql('(SELECT "id", COUNT ("age") AS "count" FROM (SELECT DISTINCT "id" FROM "other") AS "other" NATURAL LEFT JOIN (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "users" GROUP BY "id")') }
650
+ end
651
+ end
652
+ end