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,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe SQL::Generator::Relation::Binary, '#to_s' do
|
6
|
+
subject { object.to_s }
|
7
|
+
|
8
|
+
let(:id) { Attribute::Integer.new(:id) }
|
9
|
+
let(:name) { Attribute::String.new(:name) }
|
10
|
+
let(:age) { Attribute::Integer.new(:age, :required => false) }
|
11
|
+
let(:header) { [ id, name, age ] }
|
12
|
+
let(:body) { [ [ 1, 'Dan Kubb', 35 ] ].each }
|
13
|
+
let(:base_relation) { Relation::Base.new('users', header, body) }
|
14
|
+
let(:object) { described_class.new }
|
15
|
+
|
16
|
+
context 'when no object visited' do
|
17
|
+
it_should_behave_like 'an idempotent method'
|
18
|
+
|
19
|
+
it { should respond_to(:to_s) }
|
20
|
+
|
21
|
+
it { should be_frozen }
|
22
|
+
|
23
|
+
its(:to_s) { should == '' }
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'when a join is visited' do
|
27
|
+
before do
|
28
|
+
object.visit(base_relation.join(base_relation))
|
29
|
+
end
|
30
|
+
|
31
|
+
it_should_behave_like 'a generated SQL expression'
|
32
|
+
|
33
|
+
its(:to_s) { should eql('SELECT "id", "name", "age" FROM "users" AS "left" NATURAL JOIN "users" AS "right"') }
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe SQL::Generator::Relation::Binary, '#to_subquery' do
|
6
|
+
subject { object.to_subquery }
|
7
|
+
|
8
|
+
let(:id) { Attribute::Integer.new(:id) }
|
9
|
+
let(:name) { Attribute::String.new(:name) }
|
10
|
+
let(:age) { Attribute::Integer.new(:age, :required => false) }
|
11
|
+
let(:header) { [ id, name, age ] }
|
12
|
+
let(:body) { [ [ 1, 'Dan Kubb', 35 ] ].each }
|
13
|
+
let(:base_relation) { Relation::Base.new('users', header, body) }
|
14
|
+
let(:object) { described_class.new }
|
15
|
+
|
16
|
+
context 'when no object visited' do
|
17
|
+
it_should_behave_like 'an idempotent method'
|
18
|
+
|
19
|
+
it { should respond_to(:to_s) }
|
20
|
+
|
21
|
+
it { should be_frozen }
|
22
|
+
|
23
|
+
its(:to_s) { should == '' }
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'when a join is visited' do
|
27
|
+
before do
|
28
|
+
object.visit(base_relation.join(base_relation))
|
29
|
+
end
|
30
|
+
|
31
|
+
it_should_behave_like 'a generated SQL expression'
|
32
|
+
|
33
|
+
its(:to_s) { should eql('(SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right")') }
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe SQL::Generator::Relation::Binary, '#visit_axiom_algebra_join' do
|
6
|
+
subject { object.visit_axiom_algebra_join(join) }
|
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', header, body) }
|
16
|
+
let(:left) { operand }
|
17
|
+
let(:right) { operand }
|
18
|
+
let(:join) { left.join(right) }
|
19
|
+
let(:object) { described_class.new }
|
20
|
+
|
21
|
+
context 'when the operands are base relations' do
|
22
|
+
let(:operand) { base_relation }
|
23
|
+
|
24
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
25
|
+
|
26
|
+
its(:to_s) { should eql('SELECT "id", "name", "age" FROM "users" AS "left" NATURAL JOIN "users" AS "right"') }
|
27
|
+
its(:to_subquery) { should eql('(SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right")') }
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when the operands are projections' do
|
31
|
+
let(:operand) { base_relation.project([ :id, :name ]) }
|
32
|
+
|
33
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
34
|
+
|
35
|
+
its(:to_s) { should eql('SELECT "id", "name" FROM (SELECT DISTINCT "id", "name" FROM "users") AS "left" NATURAL JOIN (SELECT DISTINCT "id", "name" FROM "users") AS "right"') }
|
36
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT DISTINCT "id", "name" FROM "users") AS "left" NATURAL JOIN (SELECT DISTINCT "id", "name" FROM "users") AS "right")') }
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when the operand is an extension' do
|
40
|
+
let(:operand) { base_relation.extend { |r| r.add(:one, 1) } }
|
41
|
+
|
42
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
43
|
+
|
44
|
+
its(:to_s) { should eql('SELECT "id", "name", "age", "one" FROM (SELECT *, 1 AS "one" FROM "users") AS "left" NATURAL JOIN (SELECT *, 1 AS "one" FROM "users") AS "right"') }
|
45
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT *, 1 AS "one" FROM "users") AS "left" NATURAL JOIN (SELECT *, 1 AS "one" FROM "users") AS "right")') }
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'when the operands are rename' do
|
49
|
+
let(:operand) { base_relation.rename(:id => :user_id) }
|
50
|
+
|
51
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
52
|
+
|
53
|
+
its(:to_s) { should eql('SELECT "user_id", "name", "age" FROM (SELECT "id" AS "user_id", "name", "age" FROM "users") AS "left" NATURAL JOIN (SELECT "id" AS "user_id", "name", "age" FROM "users") AS "right"') }
|
54
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT "id" AS "user_id", "name", "age" FROM "users") AS "left" NATURAL JOIN (SELECT "id" AS "user_id", "name", "age" FROM "users") AS "right")') }
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when the operands are restrictions' do
|
58
|
+
let(:operand) { base_relation.restrict { |r| r.id.eq(1) } }
|
59
|
+
|
60
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
61
|
+
|
62
|
+
its(:to_s) { should eql('SELECT "id", "name", "age" FROM (SELECT * FROM "users" WHERE "id" = 1) AS "left" NATURAL JOIN (SELECT * FROM "users" WHERE "id" = 1) AS "right"') }
|
63
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" WHERE "id" = 1) AS "left" NATURAL JOIN (SELECT * FROM "users" WHERE "id" = 1) AS "right")') }
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when the operand is a summarization' do
|
67
|
+
context 'summarize per table dee' do
|
68
|
+
let(:summarize_per) { TABLE_DEE }
|
69
|
+
let(:operand) { base_relation.summarize(summarize_per) { |r| r.add(:count, r.id.count) } }
|
70
|
+
|
71
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
72
|
+
|
73
|
+
its(:to_s) { should eql('SELECT "count" FROM (SELECT COUNT ("id") AS "count" FROM "users") AS "left" NATURAL JOIN (SELECT COUNT ("id") AS "count" FROM "users") AS "right"') }
|
74
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT COUNT ("id") AS "count" FROM "users") AS "left" NATURAL JOIN (SELECT COUNT ("id") AS "count" FROM "users") AS "right")') }
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'summarize per table dum' do
|
78
|
+
let(:summarize_per) { TABLE_DUM }
|
79
|
+
let(:operand) { base_relation.summarize(summarize_per) { |r| r.add(:count, r.id.count) } }
|
80
|
+
|
81
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
82
|
+
|
83
|
+
its(:to_s) { should eql('SELECT "count" FROM (SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE) AS "left" NATURAL JOIN (SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE) AS "right"') }
|
84
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE) AS "left" NATURAL JOIN (SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE) AS "right")') }
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'summarize by a subset of the operand header' do
|
88
|
+
let(:operand) { base_relation.summarize([ :id, :name ]) { |r| r.add(:count, r.age.count) } }
|
89
|
+
|
90
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
91
|
+
|
92
|
+
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 "left" NATURAL JOIN (SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0) AS "right"') }
|
93
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0) AS "left" NATURAL JOIN (SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0) AS "right")') }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'when the operands are ordered' do
|
98
|
+
let(:operand) { base_relation.sort_by { |r| [ r.id, r.name, r.age ] } }
|
99
|
+
|
100
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
101
|
+
|
102
|
+
its(:to_s) { should eql('SELECT "id", "name", "age" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "left" NATURAL JOIN (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "right"') }
|
103
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "left" NATURAL JOIN (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "right")') }
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'when the operands are reversed' do
|
107
|
+
let(:operand) { base_relation.sort_by { |r| [ r.id, r.name, r.age ] }.reverse }
|
108
|
+
|
109
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
110
|
+
|
111
|
+
its(:to_s) { should eql('SELECT "id", "name", "age" FROM (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) AS "left" NATURAL JOIN (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) AS "right"') }
|
112
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) AS "left" NATURAL JOIN (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) AS "right")') }
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'when the operands are limited' do
|
116
|
+
let(:operand) { base_relation.sort_by { |r| [ r.id, r.name, r.age ] }.take(1) }
|
117
|
+
|
118
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
119
|
+
|
120
|
+
its(:to_s) { should eql('SELECT "id", "name", "age" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "left" NATURAL JOIN (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "right"') }
|
121
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "left" NATURAL JOIN (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "right")') }
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'when the operands are offsets' do
|
125
|
+
let(:operand) { base_relation.sort_by { |r| [ r.id, r.name, r.age ] }.drop(1) }
|
126
|
+
|
127
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
128
|
+
|
129
|
+
its(:to_s) { should eql('SELECT "id", "name", "age" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "left" NATURAL JOIN (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "right"') }
|
130
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "left" NATURAL JOIN (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "right")') }
|
131
|
+
end
|
132
|
+
|
133
|
+
context 'when the operands are differences' do
|
134
|
+
let(:operand) { base_relation.difference(base_relation) }
|
135
|
+
|
136
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
137
|
+
|
138
|
+
its(:to_s) { should eql('SELECT "id", "name", "age" FROM ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "left" NATURAL JOIN ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "right"') }
|
139
|
+
its(:to_subquery) { should eql('(SELECT * FROM ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "left" NATURAL JOIN ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "right")') }
|
140
|
+
end
|
141
|
+
|
142
|
+
context 'when the operands are intersections' do
|
143
|
+
let(:operand) { base_relation.intersect(base_relation) }
|
144
|
+
|
145
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
146
|
+
|
147
|
+
its(:to_s) { should eql('SELECT "id", "name", "age" FROM ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "left" NATURAL JOIN ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "right"') }
|
148
|
+
its(:to_subquery) { should eql('(SELECT * FROM ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "left" NATURAL JOIN ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "right")') }
|
149
|
+
end
|
150
|
+
|
151
|
+
context 'when the operands are unions' do
|
152
|
+
let(:operand) { base_relation.union(base_relation) }
|
153
|
+
|
154
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
155
|
+
|
156
|
+
its(:to_s) { should eql('SELECT "id", "name", "age" FROM ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "left" NATURAL JOIN ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "right"') }
|
157
|
+
its(:to_subquery) { should eql('(SELECT * FROM ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "left" NATURAL JOIN ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "right")') }
|
158
|
+
end
|
159
|
+
|
160
|
+
context 'when the operands are joins' do
|
161
|
+
let(:operand) { base_relation.join(base_relation) }
|
162
|
+
|
163
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
164
|
+
|
165
|
+
its(:to_s) { should eql('SELECT "id", "name", "age" FROM (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "left" NATURAL JOIN (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "right"') }
|
166
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "left" NATURAL JOIN (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "right")') }
|
167
|
+
end
|
168
|
+
|
169
|
+
context 'when the operands have different base relations' do
|
170
|
+
let(:relation_name) { 'users_others' }
|
171
|
+
let(:left) { Relation::Base.new('users', header, body) }
|
172
|
+
let(:right) { Relation::Base.new('others', header, body) }
|
173
|
+
|
174
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
175
|
+
|
176
|
+
its(:to_s) { should eql('SELECT "id", "name", "age" FROM "users" AS "left" NATURAL JOIN "others" AS "right"') }
|
177
|
+
its(:to_subquery) { should eql('(SELECT * FROM "users" AS "left" NATURAL JOIN "others" AS "right")') }
|
178
|
+
end
|
179
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe SQL::Generator::Relation::Binary, '#visit_axiom_algebra_product' do
|
6
|
+
subject { object.visit_axiom_algebra_product(product) }
|
7
|
+
|
8
|
+
let(:relation_name) { 'users_other' }
|
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(:other_header) { [ id.rename(:other_id), name.rename(:other_name), age.rename(:other_age) ] }
|
14
|
+
let(:body) { [ [ 1, 'Dan Kubb', 35 ] ].each }
|
15
|
+
let(:users) { Relation::Base.new('users', header, body) }
|
16
|
+
let(:other) { Relation::Base.new('other', other_header, body) }
|
17
|
+
let(:product) { left.product(right) }
|
18
|
+
let(:object) { described_class.new }
|
19
|
+
|
20
|
+
context 'when the operands are base relations' do
|
21
|
+
let(:left) { users }
|
22
|
+
let(:right) { other }
|
23
|
+
|
24
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
25
|
+
|
26
|
+
its(:to_s) { should eql('SELECT "id", "name", "age", "other_id", "other_name", "other_age" FROM "users" AS "left" CROSS JOIN "other" AS "right"') }
|
27
|
+
its(:to_subquery) { should eql('(SELECT * FROM "users" AS "left" CROSS JOIN "other" AS "right")') }
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when the operands are a projection' do
|
31
|
+
let(:left) { users.project([ :id, :name ]) }
|
32
|
+
let(:right) { other.project([ :other_id, :other_name ]) }
|
33
|
+
|
34
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
35
|
+
|
36
|
+
its(:to_s) { should eql('SELECT "id", "name", "other_id", "other_name" FROM (SELECT DISTINCT "id", "name" FROM "users") AS "left" CROSS JOIN (SELECT DISTINCT "other_id", "other_name" FROM "other") AS "right"') }
|
37
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT DISTINCT "id", "name" FROM "users") AS "left" CROSS JOIN (SELECT DISTINCT "other_id", "other_name" FROM "other") AS "right")') }
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when the operand is an extension' do
|
41
|
+
let(:left) { users.extend { |r| r.add(:one, 1) } }
|
42
|
+
let(:right) { other.extend { |r| r.add(:two, 2) } }
|
43
|
+
|
44
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
45
|
+
|
46
|
+
its(:to_s) { should eql('SELECT "id", "name", "age", "one", "other_id", "other_name", "other_age", "two" FROM (SELECT *, 1 AS "one" FROM "users") AS "left" CROSS JOIN (SELECT *, 2 AS "two" FROM "other") AS "right"') }
|
47
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT *, 1 AS "one" FROM "users") AS "left" CROSS JOIN (SELECT *, 2 AS "two" FROM "other") AS "right")') }
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'when the operand is a rename' do
|
51
|
+
let(:left) { users.rename(:id => :user_id) }
|
52
|
+
let(:right) { other.rename(:other_id => :other_user_id) }
|
53
|
+
|
54
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
55
|
+
|
56
|
+
its(:to_s) { should eql('SELECT "user_id", "name", "age", "other_user_id", "other_name", "other_age" FROM (SELECT "id" AS "user_id", "name", "age" FROM "users") AS "left" CROSS JOIN (SELECT "other_id" AS "other_user_id", "other_name", "other_age" FROM "other") AS "right"') }
|
57
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT "id" AS "user_id", "name", "age" FROM "users") AS "left" CROSS JOIN (SELECT "other_id" AS "other_user_id", "other_name", "other_age" FROM "other") AS "right")') }
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'when the operand is a restriction' do
|
61
|
+
let(:left) { users.restrict { |r| r.id.eq(1) } }
|
62
|
+
let(:right) { other.restrict { |r| r.other_id.eq(1) } }
|
63
|
+
|
64
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
65
|
+
|
66
|
+
its(:to_s) { should eql('SELECT "id", "name", "age", "other_id", "other_name", "other_age" FROM (SELECT * FROM "users" WHERE "id" = 1) AS "left" CROSS JOIN (SELECT * FROM "other" WHERE "other_id" = 1) AS "right"') }
|
67
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" WHERE "id" = 1) AS "left" CROSS JOIN (SELECT * FROM "other" WHERE "other_id" = 1) AS "right")') }
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'when the operand is a summarization' do
|
71
|
+
context 'summarize per table dee' do
|
72
|
+
let(:summarize_per) { TABLE_DEE }
|
73
|
+
let(:left) { users.summarize(summarize_per) { |r| r.add(:count, r.id.count) } }
|
74
|
+
let(:right) { other.summarize(summarize_per) { |r| r.add(:other_count, r.other_id.count) } }
|
75
|
+
|
76
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
77
|
+
|
78
|
+
its(:to_s) { should eql('SELECT "count", "other_count" FROM (SELECT COUNT ("id") AS "count" FROM "users") AS "left" CROSS JOIN (SELECT COUNT ("other_id") AS "other_count" FROM "other") AS "right"') }
|
79
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT COUNT ("id") AS "count" FROM "users") AS "left" CROSS JOIN (SELECT COUNT ("other_id") AS "other_count" FROM "other") AS "right")') }
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'summarize per table dum' do
|
83
|
+
let(:summarize_per) { TABLE_DUM }
|
84
|
+
let(:left) { users.summarize(summarize_per) { |r| r.add(:count, r.id.count) } }
|
85
|
+
let(:right) { other.summarize(summarize_per) { |r| r.add(:other_count, r.other_id.count) } }
|
86
|
+
|
87
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
88
|
+
|
89
|
+
its(:to_s) { should eql('SELECT "count", "other_count" FROM (SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE) AS "left" CROSS JOIN (SELECT COUNT ("other_id") AS "other_count" FROM "other" HAVING FALSE) AS "right"') }
|
90
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE) AS "left" CROSS JOIN (SELECT COUNT ("other_id") AS "other_count" FROM "other" HAVING FALSE) AS "right")') }
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'summarize by a subset of the operand header' do
|
94
|
+
let(:left) { users.summarize([ :id, :name ]) { |r| r.add(:count, r.age.count) } }
|
95
|
+
let(:right) { other.summarize([ :other_id, :other_name ]) { |r| r.add(:other_count, r.other_age.count) } }
|
96
|
+
|
97
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
98
|
+
|
99
|
+
its(:to_s) { should eql('SELECT "id", "name", "count", "other_id", "other_name", "other_count" FROM (SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0) AS "left" CROSS JOIN (SELECT "other_id", "other_name", COUNT ("other_age") AS "other_count" FROM "other" GROUP BY "other_id", "other_name" HAVING COUNT (*) > 0) AS "right"') }
|
100
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0) AS "left" CROSS JOIN (SELECT "other_id", "other_name", COUNT ("other_age") AS "other_count" FROM "other" GROUP BY "other_id", "other_name" HAVING COUNT (*) > 0) AS "right")') }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'when the operand is ordered' do
|
105
|
+
let(:left) { users.sort_by { |r| [ r.id, r.name, r.age ] } }
|
106
|
+
let(:right) { other.sort_by { |r| [ r.other_id, r.other_name, r.other_age ] } }
|
107
|
+
|
108
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
109
|
+
|
110
|
+
its(:to_s) { should eql('SELECT "id", "name", "age", "other_id", "other_name", "other_age" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "left" CROSS JOIN (SELECT * FROM "other" ORDER BY "other_id", "other_name", "other_age") AS "right"') }
|
111
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "left" CROSS JOIN (SELECT * FROM "other" ORDER BY "other_id", "other_name", "other_age") AS "right")') }
|
112
|
+
end
|
113
|
+
|
114
|
+
context 'when the operand is reversed' do
|
115
|
+
let(:left) { users.sort_by { |r| [ r.id, r.name, r.age ] }.reverse }
|
116
|
+
let(:right) { other.sort_by { |r| [ r.other_id, r.other_name, r.other_age ] }.reverse }
|
117
|
+
|
118
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
119
|
+
|
120
|
+
its(:to_s) { should eql('SELECT "id", "name", "age", "other_id", "other_name", "other_age" FROM (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) AS "left" CROSS JOIN (SELECT * FROM "other" ORDER BY "other_id" DESC, "other_name" DESC, "other_age" DESC) AS "right"') }
|
121
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) AS "left" CROSS JOIN (SELECT * FROM "other" ORDER BY "other_id" DESC, "other_name" DESC, "other_age" DESC) AS "right")') }
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'when the operand is limited' do
|
125
|
+
let(:left) { users.sort_by { |r| [ r.id, r.name, r.age ] }.take(1) }
|
126
|
+
let(:right) { other.sort_by { |r| [ r.other_id, r.other_name, r.other_age ] }.take(1) }
|
127
|
+
|
128
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
129
|
+
|
130
|
+
its(:to_s) { should eql('SELECT "id", "name", "age", "other_id", "other_name", "other_age" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "left" CROSS JOIN (SELECT * FROM "other" ORDER BY "other_id", "other_name", "other_age" LIMIT 1) AS "right"') }
|
131
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "left" CROSS JOIN (SELECT * FROM "other" ORDER BY "other_id", "other_name", "other_age" LIMIT 1) AS "right")') }
|
132
|
+
end
|
133
|
+
|
134
|
+
context 'when the operand is an offset' do
|
135
|
+
let(:left) { users.sort_by { |r| [ r.id, r.name, r.age ] }.drop(1) }
|
136
|
+
let(:right) { other.sort_by { |r| [ r.other_id, r.other_name, r.other_age ] }.drop(1) }
|
137
|
+
|
138
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
139
|
+
|
140
|
+
its(:to_s) { should eql('SELECT "id", "name", "age", "other_id", "other_name", "other_age" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "left" CROSS JOIN (SELECT * FROM "other" ORDER BY "other_id", "other_name", "other_age" OFFSET 1) AS "right"') }
|
141
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "left" CROSS JOIN (SELECT * FROM "other" ORDER BY "other_id", "other_name", "other_age" OFFSET 1) AS "right")') }
|
142
|
+
end
|
143
|
+
|
144
|
+
context 'when the operand is a difference' do
|
145
|
+
let(:left) { users.difference(users) }
|
146
|
+
let(:right) { other.difference(other) }
|
147
|
+
|
148
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
149
|
+
|
150
|
+
its(:to_s) { should eql('SELECT "id", "name", "age", "other_id", "other_name", "other_age" FROM ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "left" CROSS JOIN ((SELECT "other_id", "other_name", "other_age" FROM "other") EXCEPT (SELECT "other_id", "other_name", "other_age" FROM "other")) AS "right"') }
|
151
|
+
its(:to_subquery) { should eql('(SELECT * FROM ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "left" CROSS JOIN ((SELECT "other_id", "other_name", "other_age" FROM "other") EXCEPT (SELECT "other_id", "other_name", "other_age" FROM "other")) AS "right")') }
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'when the operand is a intersection' do
|
155
|
+
let(:left) { users.intersect(users) }
|
156
|
+
let(:right) { other.intersect(other) }
|
157
|
+
|
158
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
159
|
+
|
160
|
+
its(:to_s) { should eql('SELECT "id", "name", "age", "other_id", "other_name", "other_age" FROM ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "left" CROSS JOIN ((SELECT "other_id", "other_name", "other_age" FROM "other") INTERSECT (SELECT "other_id", "other_name", "other_age" FROM "other")) AS "right"') }
|
161
|
+
its(:to_subquery) { should eql('(SELECT * FROM ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "left" CROSS JOIN ((SELECT "other_id", "other_name", "other_age" FROM "other") INTERSECT (SELECT "other_id", "other_name", "other_age" FROM "other")) AS "right")') }
|
162
|
+
end
|
163
|
+
|
164
|
+
context 'when the operand is a union' do
|
165
|
+
let(:left) { users.union(users) }
|
166
|
+
let(:right) { other.union(other) }
|
167
|
+
|
168
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
169
|
+
|
170
|
+
its(:to_s) { should eql('SELECT "id", "name", "age", "other_id", "other_name", "other_age" FROM ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "left" CROSS JOIN ((SELECT "other_id", "other_name", "other_age" FROM "other") UNION (SELECT "other_id", "other_name", "other_age" FROM "other")) AS "right"') }
|
171
|
+
its(:to_subquery) { should eql('(SELECT * FROM ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "left" CROSS JOIN ((SELECT "other_id", "other_name", "other_age" FROM "other") UNION (SELECT "other_id", "other_name", "other_age" FROM "other")) AS "right")') }
|
172
|
+
end
|
173
|
+
|
174
|
+
context 'when the operand is a join' do
|
175
|
+
let(:left) { users.join(users) }
|
176
|
+
let(:right) { other.join(other) }
|
177
|
+
|
178
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
179
|
+
|
180
|
+
its(:to_s) { should eql('SELECT "id", "name", "age", "other_id", "other_name", "other_age" FROM (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "left" CROSS JOIN (SELECT * FROM "other" AS "left" NATURAL JOIN "other" AS "right") AS "right"') }
|
181
|
+
its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "left" CROSS JOIN (SELECT * FROM "other" AS "left" NATURAL JOIN "other" AS "right") AS "right")') }
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe SQL::Generator::Relation, '.visit' do
|
6
|
+
subject { object.visit(relation) }
|
7
|
+
|
8
|
+
let(:id) { Attribute::Integer.new(:id) }
|
9
|
+
let(:name) { Attribute::String.new(:name) }
|
10
|
+
let(:age) { Attribute::Integer.new(:age, :required => false) }
|
11
|
+
let(:header) { [ id, name, age ] }
|
12
|
+
let(:body) { [ [ 1, 'Dan Kubb', 35 ] ].each }
|
13
|
+
let(:base_relation) { Relation::Base.new('users', header, body) }
|
14
|
+
let(:object) { described_class }
|
15
|
+
|
16
|
+
context 'when the relation is an insertion operation' do
|
17
|
+
let(:relation) { base_relation.insert(base_relation) }
|
18
|
+
|
19
|
+
it { should be_kind_of(SQL::Generator::Relation::Insertion) }
|
20
|
+
|
21
|
+
its(:name) { should == 'users' }
|
22
|
+
|
23
|
+
it { should be_frozen }
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'when the relation is a set operation' do
|
27
|
+
let(:relation) { base_relation.union(base_relation) }
|
28
|
+
|
29
|
+
it { should be_kind_of(SQL::Generator::Relation::Set) }
|
30
|
+
|
31
|
+
its(:name) { should == 'users' }
|
32
|
+
|
33
|
+
it { should be_frozen }
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when the relation is a binary operation' do
|
37
|
+
let(:relation) { base_relation.join(base_relation.project([ :id ])) }
|
38
|
+
|
39
|
+
it { should be_kind_of(SQL::Generator::Relation::Binary) }
|
40
|
+
|
41
|
+
its(:name) { should == 'users' }
|
42
|
+
|
43
|
+
it { should be_frozen }
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'when the relation is a unary operation' do
|
47
|
+
let(:relation) { base_relation.project([ :id ]) }
|
48
|
+
|
49
|
+
it { should be_kind_of(SQL::Generator::Relation::Unary) }
|
50
|
+
|
51
|
+
its(:name) { should == 'users' }
|
52
|
+
|
53
|
+
it { should be_frozen }
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'when the relation is a base relation' do
|
57
|
+
let(:relation) { base_relation }
|
58
|
+
|
59
|
+
it { should be_kind_of(SQL::Generator::Relation::Base) }
|
60
|
+
|
61
|
+
its(:name) { should == 'users' }
|
62
|
+
|
63
|
+
it { should be_frozen }
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when the relation is invalid' do
|
67
|
+
let(:relation) { mock('Invalid Relation') }
|
68
|
+
|
69
|
+
specify { expect { subject }.to raise_error(SQL::Generator::InvalidRelationError, "#{relation.class} is not a visitable relation") }
|
70
|
+
end
|
71
|
+
end
|