axiom-sql-generator 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gemtest +0 -0
- data/.gitignore +37 -0
- data/.rspec +4 -0
- data/.rvmrc +1 -0
- data/.travis.yml +35 -0
- data/CONTRIBUTING.md +11 -0
- data/Gemfile +8 -0
- data/Gemfile.devtools +57 -0
- data/Guardfile +23 -0
- data/LICENSE +20 -0
- data/README.md +70 -0
- data/Rakefile +5 -0
- data/TODO +34 -0
- data/axiom-sql-generator.gemspec +25 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/mutant.yml +3 -0
- data/config/reek.yml +165 -0
- data/config/yardstick.yml +2 -0
- data/lib/axiom-sql-generator.rb +3 -0
- data/lib/axiom/sql/generator.rb +61 -0
- data/lib/axiom/sql/generator/attribute.rb +25 -0
- data/lib/axiom/sql/generator/core_ext/date.rb +20 -0
- data/lib/axiom/sql/generator/core_ext/date_time.rb +46 -0
- data/lib/axiom/sql/generator/direction.rb +38 -0
- data/lib/axiom/sql/generator/function.rb +55 -0
- data/lib/axiom/sql/generator/function/aggregate.rb +134 -0
- data/lib/axiom/sql/generator/function/connective.rb +53 -0
- data/lib/axiom/sql/generator/function/numeric.rb +135 -0
- data/lib/axiom/sql/generator/function/predicate.rb +266 -0
- data/lib/axiom/sql/generator/function/proposition.rb +38 -0
- data/lib/axiom/sql/generator/function/string.rb +29 -0
- data/lib/axiom/sql/generator/identifier.rb +28 -0
- data/lib/axiom/sql/generator/literal.rb +157 -0
- data/lib/axiom/sql/generator/relation.rb +240 -0
- data/lib/axiom/sql/generator/relation/base.rb +14 -0
- data/lib/axiom/sql/generator/relation/binary.rb +136 -0
- data/lib/axiom/sql/generator/relation/insertion.rb +62 -0
- data/lib/axiom/sql/generator/relation/materialized.rb +60 -0
- data/lib/axiom/sql/generator/relation/set.rb +107 -0
- data/lib/axiom/sql/generator/relation/unary.rb +379 -0
- data/lib/axiom/sql/generator/version.rb +12 -0
- data/lib/axiom/sql/generator/visitor.rb +121 -0
- data/spec/rcov.opts +7 -0
- data/spec/shared/generated_sql_behavior.rb +15 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/support/config_alias.rb +3 -0
- data/spec/unit/axiom/sql/generator/attribute/visit_axiom_attribute_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/class_methods/parenthesize_spec.rb +18 -0
- data/spec/unit/axiom/sql/generator/direction/visit_axiom_relation_operation_order_ascending_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/direction/visit_axiom_relation_operation_order_descending_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_count_spec.rb +16 -0
- data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_maximum_spec.rb +16 -0
- data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_mean_spec.rb +16 -0
- data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_minimum_spec.rb +16 -0
- data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_standard_deviation_spec.rb +16 -0
- data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_sum_spec.rb +16 -0
- data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_variance_spec.rb +16 -0
- data/spec/unit/axiom/sql/generator/function/connective/visit_axiom_function_connective_conjunction_spec.rb +20 -0
- data/spec/unit/axiom/sql/generator/function/connective/visit_axiom_function_connective_disjunction_spec.rb +20 -0
- data/spec/unit/axiom/sql/generator/function/connective/visit_axiom_function_connective_negation_spec.rb +20 -0
- data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_absolute_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_addition_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_division_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_exponentiation_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_modulo_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_multiplication_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_square_root_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_subtraction_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_unary_minus_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_unary_plus_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_equality_spec.rb +27 -0
- data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_exclusion_spec.rb +47 -0
- data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_greater_than_or_equal_to_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_greater_than_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_inclusion_spec.rb +47 -0
- data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_inequality_spec.rb +55 -0
- data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_less_than_or_equal_to_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_less_than_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/proposition/visit_axiom_function_proposition_contradiction_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/proposition/visit_axiom_function_proposition_tautology_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/string/visit_axiom_function_string_length_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/identifier/visit_identifier_spec.rb +26 -0
- data/spec/unit/axiom/sql/generator/literal/class_methods/dup_frozen_spec.rb +23 -0
- data/spec/unit/axiom/sql/generator/literal/visit_class_spec.rb +31 -0
- data/spec/unit/axiom/sql/generator/literal/visit_date_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/literal/visit_date_time_spec.rb +55 -0
- data/spec/unit/axiom/sql/generator/literal/visit_enumerable_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/literal/visit_false_class_spec.rb +14 -0
- data/spec/unit/axiom/sql/generator/literal/visit_nil_class_spec.rb +14 -0
- data/spec/unit/axiom/sql/generator/literal/visit_numeric_spec.rb +34 -0
- data/spec/unit/axiom/sql/generator/literal/visit_string_spec.rb +26 -0
- data/spec/unit/axiom/sql/generator/literal/visit_time_spec.rb +97 -0
- data/spec/unit/axiom/sql/generator/literal/visit_true_class_spec.rb +14 -0
- data/spec/unit/axiom/sql/generator/relation/binary/base/to_subquery_spec.rb +35 -0
- data/spec/unit/axiom/sql/generator/relation/binary/base/visit_axiom_relation_base_spec.rb +22 -0
- data/spec/unit/axiom/sql/generator/relation/binary/to_s_spec.rb +35 -0
- data/spec/unit/axiom/sql/generator/relation/binary/to_subquery_spec.rb +35 -0
- data/spec/unit/axiom/sql/generator/relation/binary/visit_axiom_algebra_join_spec.rb +179 -0
- data/spec/unit/axiom/sql/generator/relation/binary/visit_axiom_algebra_product_spec.rb +183 -0
- data/spec/unit/axiom/sql/generator/relation/class_methods/visit_spec.rb +71 -0
- data/spec/unit/axiom/sql/generator/relation/insertion/to_subquery_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/relation/insertion/visit_axiom_relation_operation_insertion_spec.rb +187 -0
- data/spec/unit/axiom/sql/generator/relation/materialized/visit_axiom_relation_materialized_spec.rb +28 -0
- data/spec/unit/axiom/sql/generator/relation/materialized/visited_spec.rb +26 -0
- data/spec/unit/axiom/sql/generator/relation/name_spec.rb +30 -0
- data/spec/unit/axiom/sql/generator/relation/set/class_methods/normalize_operand_headers_spec.rb +35 -0
- data/spec/unit/axiom/sql/generator/relation/set/to_s_spec.rb +55 -0
- data/spec/unit/axiom/sql/generator/relation/set/to_subquery_spec.rb +55 -0
- data/spec/unit/axiom/sql/generator/relation/set/visit_axiom_algebra_difference_spec.rb +191 -0
- data/spec/unit/axiom/sql/generator/relation/set/visit_axiom_algebra_intersection_spec.rb +188 -0
- data/spec/unit/axiom/sql/generator/relation/set/visit_axiom_algebra_union_spec.rb +188 -0
- data/spec/unit/axiom/sql/generator/relation/to_s_spec.rb +50 -0
- data/spec/unit/axiom/sql/generator/relation/to_sql_spec.rb +52 -0
- data/spec/unit/axiom/sql/generator/relation/to_subquery_spec.rb +49 -0
- data/spec/unit/axiom/sql/generator/relation/unary/to_s_spec.rb +55 -0
- data/spec/unit/axiom/sql/generator/relation/unary/to_subquery_spec.rb +75 -0
- data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_algebra_extension_spec.rb +165 -0
- data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_algebra_projection_spec.rb +193 -0
- data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_algebra_rename_spec.rb +178 -0
- data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_algebra_restriction_spec.rb +199 -0
- data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_algebra_summarization_spec.rb +652 -0
- data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_relation_base_spec.rb +21 -0
- data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_relation_operation_limit_spec.rb +165 -0
- data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_relation_operation_offset_spec.rb +165 -0
- data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_relation_operation_order_spec.rb +183 -0
- data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_relation_operation_reverse_spec.rb +165 -0
- data/spec/unit/axiom/sql/generator/relation/visit_spec.rb +54 -0
- data/spec/unit/axiom/sql/generator/relation/visited_spec.rb +35 -0
- data/spec/unit/axiom/sql/generator/visitor/class_methods/handler_for_spec.rb +71 -0
- data/spec/unit/axiom/sql/generator/visitor/visit_spec.rb +12 -0
- data/spec/unit/axiom/sql/generator/visitor/visited_spec.rb +11 -0
- data/spec/unit/date/iso8601_spec.rb +23 -0
- data/spec/unit/date_time/iso8601_spec.rb +112 -0
- metadata +325 -0
@@ -0,0 +1,178 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe SQL::Generator::Relation::Unary, '#visit_axiom_algebra_rename' do
|
6
|
+
subject { object.visit_axiom_algebra_rename(rename) }
|
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(:rename) { operand.rename(:id => :user_id) }
|
16
|
+
let(:object) { described_class.new }
|
17
|
+
|
18
|
+
context 'when the operand is a base relation' do
|
19
|
+
let(:operand) { base_relation }
|
20
|
+
|
21
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
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")') }
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'when the operand is a projection' do
|
28
|
+
let(:operand) { base_relation.project([ :id, :name ]) }
|
29
|
+
|
30
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
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")') }
|
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"') } }
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when the operand is a rename' do
|
46
|
+
let(:operand) { base_relation.rename(:name => :other_name) }
|
47
|
+
|
48
|
+
context 'when the relation is not optimized' do
|
49
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
50
|
+
|
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")') }
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when the operand is empty' do
|
56
|
+
let(:operand) { base_relation.rename({}) }
|
57
|
+
|
58
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
59
|
+
|
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")') }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'when the operand is a restriction' do
|
66
|
+
let(:operand) { base_relation.restrict { |r| r.id.eq(1) } }
|
67
|
+
|
68
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
69
|
+
|
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
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'when the operand is ordered' do
|
108
|
+
let(:operand) { base_relation.sort_by { |r| [ r.id, r.name, r.age ] } }
|
109
|
+
|
110
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
111
|
+
|
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")') }
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'when the operand is reversed' do
|
117
|
+
let(:operand) { base_relation.sort_by { |r| [ r.id, r.name, r.age ] }.reverse }
|
118
|
+
|
119
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
120
|
+
|
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)') }
|
123
|
+
end
|
124
|
+
|
125
|
+
context 'when the operand is limited' do
|
126
|
+
let(:operand) { base_relation.sort_by { |r| [ r.id, r.name, r.age ] }.take(1) }
|
127
|
+
|
128
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
129
|
+
|
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)') }
|
132
|
+
end
|
133
|
+
|
134
|
+
context 'when the operand is an offset' do
|
135
|
+
let(:operand) { base_relation.sort_by { |r| [ r.id, r.name, r.age ] }.drop(1) }
|
136
|
+
|
137
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
138
|
+
|
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)') }
|
141
|
+
end
|
142
|
+
|
143
|
+
context 'when the operand is a difference' do
|
144
|
+
let(:operand) { base_relation.difference(base_relation) }
|
145
|
+
|
146
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
147
|
+
|
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")') }
|
150
|
+
end
|
151
|
+
|
152
|
+
context 'when the operand is an intersection' do
|
153
|
+
let(:operand) { base_relation.intersect(base_relation) }
|
154
|
+
|
155
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
156
|
+
|
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")') }
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'when the operand is a union' do
|
162
|
+
let(:operand) { base_relation.union(base_relation) }
|
163
|
+
|
164
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
165
|
+
|
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")') }
|
168
|
+
end
|
169
|
+
|
170
|
+
context 'when the operand is a join' do
|
171
|
+
let(:operand) { base_relation.join(base_relation) }
|
172
|
+
|
173
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
174
|
+
|
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")') }
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe SQL::Generator::Relation::Unary, '#visit_axiom_algebra_restriction' do
|
6
|
+
subject { object.visit_axiom_algebra_restriction(restriction) }
|
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(:restriction) { operand.restrict { |r| r.id.eq(1) } }
|
16
|
+
let(:object) { described_class.new }
|
17
|
+
|
18
|
+
context 'when the operand is a base relation' do
|
19
|
+
let(:operand) { base_relation }
|
20
|
+
|
21
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
22
|
+
|
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)') }
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'when the operand is a projection' do
|
28
|
+
let(:operand) { base_relation.project([ :id, :name ]) }
|
29
|
+
|
30
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
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)') }
|
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)') }
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when the operand is a projection then a restriction' do
|
46
|
+
let(:operand) { base_relation.project([ :id, :name ]).restrict { |r| r.id.ne(2) } }
|
47
|
+
|
48
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
49
|
+
|
50
|
+
its(:to_s) { should eql('SELECT "id", "name" 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)') }
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when the operand is a projection then a restriction, followed by another restriction' do
|
55
|
+
let(:tautology) { Function::Proposition::Tautology.instance }
|
56
|
+
let(:operand) { base_relation.project([ :id, :name ]).restrict { tautology }.restrict { tautology } }
|
57
|
+
|
58
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
59
|
+
|
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)') }
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'when the operand is a rename' do
|
65
|
+
context 'when the restriction includes the renamed column' do
|
66
|
+
let(:operand) { base_relation.rename(:id => :user_id) }
|
67
|
+
let(:restriction) { operand.restrict { |r| r.user_id.eq(1) } }
|
68
|
+
|
69
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
70
|
+
|
71
|
+
its(:to_s) { pending { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users" WHERE "id" = 1') } }
|
72
|
+
its(:to_subquery) { pending { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users" WHERE "id" = 1') } }
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'when the restriction does not include the renamed column' do
|
76
|
+
let(:operand) { base_relation.rename(:name => :other_name) }
|
77
|
+
let(:restriction) { operand.restrict { |r| r.id.eq(1) } }
|
78
|
+
|
79
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
80
|
+
|
81
|
+
its(:to_s) { pending { should eql('SELECT "id", "name" AS "other_name", "age" FROM "users" WHERE "id" = 1') } }
|
82
|
+
its(:to_subquery) { pending { should eql('SELECT "id", "name" AS "other_name", "age" FROM "users" WHERE "id" = 1') } }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'when the operand is a restriction' do
|
87
|
+
let(:operand) { base_relation.restrict { |r| r.id.eq(1) } }
|
88
|
+
|
89
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
90
|
+
|
91
|
+
its(:to_s) { should eql('SELECT "id", "name", "age" 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
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'when the operand is ordered' do
|
129
|
+
let(:operand) { base_relation.sort_by { |r| [ r.id, r.name, r.age ] } }
|
130
|
+
|
131
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
132
|
+
|
133
|
+
its(:to_s) { should eql('SELECT "id", "name", "age" 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")') }
|
135
|
+
end
|
136
|
+
|
137
|
+
context 'when the operand is reversed' do
|
138
|
+
let(:operand) { base_relation.sort_by { |r| [ r.id, r.name, r.age ] }.reverse }
|
139
|
+
|
140
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
141
|
+
|
142
|
+
its(:to_s) { should eql('SELECT "id", "name", "age" 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)') }
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'when the operand is limited' do
|
147
|
+
let(:operand) { base_relation.sort_by { |r| [ r.id, r.name, r.age ] }.take(1) }
|
148
|
+
|
149
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
150
|
+
|
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') }
|
152
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "users" WHERE "id" = 1)') }
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'when the operand is an offset' do
|
156
|
+
let(:operand) { base_relation.sort_by { |r| [ r.id, r.name, r.age ] }.drop(1) }
|
157
|
+
|
158
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
159
|
+
|
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') }
|
161
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "users" WHERE "id" = 1)') }
|
162
|
+
end
|
163
|
+
|
164
|
+
context 'when the operand is a difference' do
|
165
|
+
let(:operand) { base_relation.difference(base_relation) }
|
166
|
+
|
167
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
168
|
+
|
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)') }
|
171
|
+
end
|
172
|
+
|
173
|
+
context 'when the operand is an intersection' do
|
174
|
+
let(:operand) { base_relation.intersect(base_relation) }
|
175
|
+
|
176
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
177
|
+
|
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)') }
|
180
|
+
end
|
181
|
+
|
182
|
+
context 'when the operand is a union' do
|
183
|
+
let(:operand) { base_relation.union(base_relation) }
|
184
|
+
|
185
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
186
|
+
|
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)') }
|
189
|
+
end
|
190
|
+
|
191
|
+
context 'when the operand is a join' do
|
192
|
+
let(:operand) { base_relation.join(base_relation) }
|
193
|
+
|
194
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
195
|
+
|
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)') }
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,652 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe SQL::Generator::Relation::Unary, '#visit_axiom_algebra_summarization' do
|
6
|
+
subject { object.visit_axiom_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.sort_by { |r| [ r.id, r.name, r.age ] } }
|
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.sort_by { |r| [ r.id, r.name, r.age ] }.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.sort_by { |r| [ r.id, r.name, r.age ] }.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.sort_by { |r| [ r.id, r.name, r.age ] }.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.sort_by { |r| [ r.id, r.name, r.age ] } }
|
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.sort_by { |r| [ r.id, r.name, r.age ] }.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.sort_by { |r| [ r.id, r.name, r.age ] }.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.sort_by { |r| [ r.id, r.name, r.age ] }.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.sort_by { |r| [ r.id, r.name, r.age ] } }
|
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.sort_by { |r| [ r.id, r.name, r.age ] }.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.sort_by { |r| [ r.id, r.name, r.age ] }.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.sort_by { |r| [ r.id, r.name, r.age ] }.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.sort_by { |r| [ r.id, r.name, r.age ] } }
|
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.sort_by { |r| [ r.id, r.name, r.age ] }.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.sort_by { |r| [ r.id, r.name, r.age ] }.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.sort_by { |r| [ r.id, r.name, r.age ] }.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.sort_by { |r| [ r.id, r.name, r.age ] } }
|
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.sort_by { |r| [ r.id, r.name, r.age ] }.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.sort_by { |r| [ r.id, r.name, r.age ] }.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.sort_by { |r| [ r.id, r.name, r.age ] }.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
|