veritas-sql-generator 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +33 -0
- data/LICENSE +20 -0
- data/README.rdoc +27 -0
- data/Rakefile +25 -0
- data/TODO +17 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/roodi.yml +16 -0
- data/config/site.reek +124 -0
- data/config/yardstick.yml +2 -0
- data/lib/veritas-sql-generator.rb +3 -0
- data/lib/veritas/base_relation.rb +36 -0
- data/lib/veritas/sql/generator.rb +35 -0
- data/lib/veritas/sql/generator/attribute.rb +25 -0
- data/lib/veritas/sql/generator/direction.rb +36 -0
- data/lib/veritas/sql/generator/identifier.rb +27 -0
- data/lib/veritas/sql/generator/literal.rb +160 -0
- data/lib/veritas/sql/generator/logic.rb +349 -0
- data/lib/veritas/sql/generator/relation.rb +111 -0
- data/lib/veritas/sql/generator/relation/base.rb +14 -0
- data/lib/veritas/sql/generator/relation/binary.rb +184 -0
- data/lib/veritas/sql/generator/relation/set.rb +99 -0
- data/lib/veritas/sql/generator/relation/unary.rb +326 -0
- data/lib/veritas/sql/generator/version.rb +9 -0
- data/lib/veritas/sql/generator/visitor.rb +121 -0
- data/spec/rcov.opts +6 -0
- data/spec/shared/command_method_behavior.rb +7 -0
- data/spec/shared/generated_sql_behavior.rb +15 -0
- data/spec/shared/idempotent_method_behavior.rb +7 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/unit/veritas/base_relation/name_spec.rb +45 -0
- data/spec/unit/veritas/sql/generator/attribute/visit_veritas_attribute_spec.rb +15 -0
- data/spec/unit/veritas/sql/generator/direction/visit_veritas_relation_operation_order_ascending_spec.rb +15 -0
- data/spec/unit/veritas/sql/generator/direction/visit_veritas_relation_operation_order_descending_spec.rb +15 -0
- data/spec/unit/veritas/sql/generator/identifier/visit_identifier_spec.rb +26 -0
- data/spec/unit/veritas/sql/generator/literal/class_methods/dup_frozen_spec.rb +23 -0
- data/spec/unit/veritas/sql/generator/literal/visit_class_spec.rb +31 -0
- data/spec/unit/veritas/sql/generator/literal/visit_date_spec.rb +15 -0
- data/spec/unit/veritas/sql/generator/literal/visit_date_time_spec.rb +61 -0
- data/spec/unit/veritas/sql/generator/literal/visit_enumerable_spec.rb +15 -0
- data/spec/unit/veritas/sql/generator/literal/visit_false_class_spec.rb +14 -0
- data/spec/unit/veritas/sql/generator/literal/visit_nil_class_spec.rb +14 -0
- data/spec/unit/veritas/sql/generator/literal/visit_numeric_spec.rb +34 -0
- data/spec/unit/veritas/sql/generator/literal/visit_string_spec.rb +26 -0
- data/spec/unit/veritas/sql/generator/literal/visit_time_spec.rb +97 -0
- data/spec/unit/veritas/sql/generator/literal/visit_true_class_spec.rb +14 -0
- data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_connective_conjunction_spec.rb +16 -0
- data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_connective_disjunction_spec.rb +16 -0
- data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_connective_negation_spec.rb +16 -0
- data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_predicate_equality_spec.rb +27 -0
- data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_predicate_exclusion_spec.rb +43 -0
- data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_predicate_greater_than_or_equal_to_spec.rb +15 -0
- data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_predicate_greater_than_spec.rb +15 -0
- data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_predicate_inclusion_spec.rb +43 -0
- data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_predicate_inequality_spec.rb +55 -0
- data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_predicate_less_than_or_equal_to_spec.rb +15 -0
- data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_predicate_less_than_spec.rb +15 -0
- data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_proposition_contradiction_spec.rb +15 -0
- data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_proposition_tautology_spec.rb +15 -0
- data/spec/unit/veritas/sql/generator/relation/binary/base/to_subquery_spec.rb +35 -0
- data/spec/unit/veritas/sql/generator/relation/binary/base/visit_veritas_base_relation_spec.rb +22 -0
- data/spec/unit/veritas/sql/generator/relation/binary/class_methods/subquery_spec.rb +42 -0
- data/spec/unit/veritas/sql/generator/relation/binary/to_s_spec.rb +35 -0
- data/spec/unit/veritas/sql/generator/relation/binary/to_subquery_spec.rb +35 -0
- data/spec/unit/veritas/sql/generator/relation/binary/visit_veritas_algebra_join_spec.rb +138 -0
- data/spec/unit/veritas/sql/generator/relation/binary/visit_veritas_algebra_product_spec.rb +139 -0
- data/spec/unit/veritas/sql/generator/relation/class_methods/subquery_spec.rb +33 -0
- data/spec/unit/veritas/sql/generator/relation/class_methods/visit_spec.rb +61 -0
- data/spec/unit/veritas/sql/generator/relation/name_spec.rb +30 -0
- data/spec/unit/veritas/sql/generator/relation/set/to_s_spec.rb +55 -0
- data/spec/unit/veritas/sql/generator/relation/set/to_subquery_spec.rb +55 -0
- data/spec/unit/veritas/sql/generator/relation/set/visit_veritas_algebra_difference_spec.rb +138 -0
- data/spec/unit/veritas/sql/generator/relation/set/visit_veritas_algebra_intersection_spec.rb +138 -0
- data/spec/unit/veritas/sql/generator/relation/set/visit_veritas_algebra_union_spec.rb +138 -0
- data/spec/unit/veritas/sql/generator/relation/to_sql_spec.rb +52 -0
- data/spec/unit/veritas/sql/generator/relation/unary/to_s_spec.rb +55 -0
- data/spec/unit/veritas/sql/generator/relation/unary/to_subquery_spec.rb +75 -0
- data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_algebra_projection_spec.rb +138 -0
- data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_algebra_rename_spec.rb +136 -0
- data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_algebra_restriction_spec.rb +157 -0
- data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_base_relation_spec.rb +21 -0
- data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_relation_operation_limit_spec.rb +125 -0
- data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_relation_operation_offset_spec.rb +125 -0
- data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_relation_operation_order_spec.rb +136 -0
- data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_relation_operation_reverse_spec.rb +125 -0
- data/spec/unit/veritas/sql/generator/relation/visit_spec.rb +54 -0
- data/spec/unit/veritas/sql/generator/relation/visited_spec.rb +35 -0
- data/spec/unit/veritas/sql/generator/visitor/class_methods/handler_for_spec.rb +71 -0
- data/spec/unit/veritas/sql/generator/visitor/visit_spec.rb +12 -0
- data/spec/unit/veritas/sql/generator/visitor/visited_spec.rb +11 -0
- data/tasks/quality/ci.rake +2 -0
- data/tasks/quality/flay.rake +41 -0
- data/tasks/quality/flog.rake +45 -0
- data/tasks/quality/heckle.rake +203 -0
- data/tasks/quality/metric_fu.rake +26 -0
- data/tasks/quality/reek.rake +9 -0
- data/tasks/quality/roodi.rake +15 -0
- data/tasks/quality/yardstick.rake +23 -0
- data/tasks/spec.rake +38 -0
- data/tasks/yard.rake +9 -0
- data/veritas-sql-generator.gemspec +222 -0
- metadata +285 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe SQL::Generator::Relation::Set, '#visit_veritas_algebra_union' do
|
|
6
|
+
subject { object.visit_veritas_algebra_union(union) }
|
|
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) { BaseRelation.new(relation_name, header, body) }
|
|
15
|
+
let(:left) { operand }
|
|
16
|
+
let(:right) { operand }
|
|
17
|
+
let(:union) { left.union(right) }
|
|
18
|
+
let(:object) { described_class.new }
|
|
19
|
+
|
|
20
|
+
context 'when the operands are base relations' do
|
|
21
|
+
let(:operand) { base_relation }
|
|
22
|
+
|
|
23
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
24
|
+
|
|
25
|
+
its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")') }
|
|
26
|
+
its(:to_subquery) { should eql('(SELECT * FROM "users") UNION (SELECT * FROM "users")') }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context 'when the operands are projections' do
|
|
30
|
+
let(:operand) { base_relation.project([ :id, :name ]) }
|
|
31
|
+
|
|
32
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
33
|
+
|
|
34
|
+
its(:to_s) { should eql('(SELECT DISTINCT "id", "name" FROM "users") UNION (SELECT DISTINCT "id", "name" FROM "users")') }
|
|
35
|
+
its(:to_subquery) { should eql('(SELECT DISTINCT "id", "name" FROM "users") UNION (SELECT DISTINCT "id", "name" FROM "users")') }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context 'when the operands are renames' do
|
|
39
|
+
let(:operand) { base_relation.rename(:id => :user_id) }
|
|
40
|
+
|
|
41
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
42
|
+
|
|
43
|
+
its(:to_s) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM "users") UNION (SELECT "id" AS "user_id", "name", "age" FROM "users")') }
|
|
44
|
+
its(:to_subquery) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM "users") UNION (SELECT "id" AS "user_id", "name", "age" FROM "users")') }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
context 'when the operands are restrictions' do
|
|
48
|
+
let(:operand) { base_relation.restrict { |r| r[:id].eq(1) } }
|
|
49
|
+
|
|
50
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
51
|
+
|
|
52
|
+
its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" WHERE "id" = 1) UNION (SELECT "id", "name", "age" FROM "users" WHERE "id" = 1)') }
|
|
53
|
+
its(:to_subquery) { should eql('(SELECT * FROM "users" WHERE "id" = 1) UNION (SELECT * FROM "users" WHERE "id" = 1)') }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
context 'when the operand is ordered' do
|
|
57
|
+
let(:operand) { base_relation.order }
|
|
58
|
+
|
|
59
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
60
|
+
|
|
61
|
+
its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age") UNION (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age")') }
|
|
62
|
+
its(:to_subquery) { should eql('(SELECT * FROM "users" ORDER BY "id", "name", "age") UNION (SELECT * FROM "users" ORDER BY "id", "name", "age")') }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
context 'when the operand is reversed' do
|
|
66
|
+
let(:operand) { base_relation.order.reverse }
|
|
67
|
+
|
|
68
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
69
|
+
|
|
70
|
+
its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) UNION (SELECT "id", "name", "age" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC)') }
|
|
71
|
+
its(:to_subquery) { should eql('(SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) UNION (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC)') }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
context 'when the operand is limited' do
|
|
75
|
+
let(:operand) { base_relation.order.take(1) }
|
|
76
|
+
|
|
77
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
78
|
+
|
|
79
|
+
its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" LIMIT 1) UNION (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" LIMIT 1)') }
|
|
80
|
+
its(:to_subquery) { should eql('(SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) UNION (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1)') }
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
context 'when the operands are offsets' do
|
|
84
|
+
let(:operand) { base_relation.order.drop(1) }
|
|
85
|
+
|
|
86
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
87
|
+
|
|
88
|
+
its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" OFFSET 1) UNION (SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" OFFSET 1)') }
|
|
89
|
+
its(:to_subquery) { should eql('(SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) UNION (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1)') }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
context 'when the operands are differences' do
|
|
93
|
+
let(:operand) { base_relation.difference(base_relation) }
|
|
94
|
+
|
|
95
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
96
|
+
|
|
97
|
+
its(:to_s) { should eql('((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) UNION ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users"))') }
|
|
98
|
+
its(:to_subquery) { should eql('((SELECT * FROM "users") EXCEPT (SELECT * FROM "users")) UNION ((SELECT * FROM "users") EXCEPT (SELECT * FROM "users"))') }
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
context 'when the operands are intersections' do
|
|
102
|
+
let(:operand) { base_relation.intersect(base_relation) }
|
|
103
|
+
|
|
104
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
105
|
+
|
|
106
|
+
its(:to_s) { should eql('((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) UNION ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users"))') }
|
|
107
|
+
its(:to_subquery) { should eql('((SELECT * FROM "users") INTERSECT (SELECT * FROM "users")) UNION ((SELECT * FROM "users") INTERSECT (SELECT * FROM "users"))') }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
context 'when the operands are unions' do
|
|
111
|
+
let(:operand) { base_relation.union(base_relation) }
|
|
112
|
+
|
|
113
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
114
|
+
|
|
115
|
+
its(:to_s) { should eql('((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) UNION ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users"))') }
|
|
116
|
+
its(:to_subquery) { should eql('((SELECT * FROM "users") UNION (SELECT * FROM "users")) UNION ((SELECT * FROM "users") UNION (SELECT * FROM "users"))') }
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
context 'when the operands are joins' do
|
|
120
|
+
let(:operand) { base_relation.join(base_relation) }
|
|
121
|
+
|
|
122
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
123
|
+
|
|
124
|
+
its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users" NATURAL JOIN "users") UNION (SELECT "id", "name", "age" FROM "users" NATURAL JOIN "users")') }
|
|
125
|
+
its(:to_subquery) { should eql('(SELECT * FROM "users" NATURAL JOIN "users") UNION (SELECT * FROM "users" NATURAL JOIN "users")') }
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
context 'when the operands have different base relations' do
|
|
129
|
+
let(:relation_name) { 'users_others' }
|
|
130
|
+
let(:left) { BaseRelation.new('users', header, body) }
|
|
131
|
+
let(:right) { BaseRelation.new('others', header, body) }
|
|
132
|
+
|
|
133
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
134
|
+
|
|
135
|
+
its(:to_s) { should eql('(SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "others")') }
|
|
136
|
+
its(:to_subquery) { should eql('(SELECT * FROM "users") UNION (SELECT * FROM "others")') }
|
|
137
|
+
end
|
|
138
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe SQL::Generator::Relation, '#to_sql' do
|
|
6
|
+
subject { object.to_sql }
|
|
7
|
+
|
|
8
|
+
let(:described_class) { Class.new(SQL::Generator::Relation) }
|
|
9
|
+
let(:id) { Attribute::Integer.new(:id) }
|
|
10
|
+
let(:name) { Attribute::String.new(:name) }
|
|
11
|
+
let(:age) { Attribute::Integer.new(:age, :required => false) }
|
|
12
|
+
let(:header) { [ id, name, age ] }
|
|
13
|
+
let(:body) { [ [ 1, 'Dan Kubb', 35 ] ].each }
|
|
14
|
+
let(:object) { described_class.new }
|
|
15
|
+
|
|
16
|
+
context 'when no object visited' do
|
|
17
|
+
it_should_behave_like 'an idempotent method'
|
|
18
|
+
|
|
19
|
+
it { should be_kind_of(String) }
|
|
20
|
+
|
|
21
|
+
it { should be_frozen }
|
|
22
|
+
|
|
23
|
+
it { should == '' }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
context 'when an object is visited' do
|
|
27
|
+
let(:visitable) { mock('Visitable') }
|
|
28
|
+
|
|
29
|
+
before do
|
|
30
|
+
described_class.class_eval do
|
|
31
|
+
def visit_spec_mocks_mock(mock)
|
|
32
|
+
mock
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
before do
|
|
38
|
+
@original = object.to_sql
|
|
39
|
+
object.visit(visitable)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it_should_behave_like 'an idempotent method'
|
|
43
|
+
|
|
44
|
+
it { should be_kind_of(String) }
|
|
45
|
+
|
|
46
|
+
it { should be_frozen }
|
|
47
|
+
|
|
48
|
+
it { should_not equal(@original) }
|
|
49
|
+
|
|
50
|
+
it { should eql(visitable.to_s) }
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe SQL::Generator::Relation::Unary, '#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) { BaseRelation.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 restriction is visited' do
|
|
27
|
+
before do
|
|
28
|
+
object.visit(base_relation.restrict { |r| r[:id].eq(1) })
|
|
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" WHERE "id" = 1') }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context 'when a limit is visited' do
|
|
37
|
+
before do
|
|
38
|
+
object.visit(base_relation.order.take(1))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it_should_behave_like 'a generated SQL expression'
|
|
42
|
+
|
|
43
|
+
its(:to_s) { should eql('SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" LIMIT 1') }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
context 'when an offset is visited' do
|
|
47
|
+
before do
|
|
48
|
+
object.visit(base_relation.order.drop(1))
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it_should_behave_like 'a generated SQL expression'
|
|
52
|
+
|
|
53
|
+
its(:to_s) { should eql('SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age" OFFSET 1') }
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe SQL::Generator::Relation::Unary, '#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) { BaseRelation.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 projection is visited' do
|
|
27
|
+
before do
|
|
28
|
+
object.visit(base_relation.project([ :id, :name ]))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it_should_behave_like 'a generated SQL expression'
|
|
32
|
+
|
|
33
|
+
its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM "users"') }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context 'when a rename is visited' do
|
|
37
|
+
before do
|
|
38
|
+
object.visit(base_relation.rename(:id => :user_id))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it_should_behave_like 'a generated SQL expression'
|
|
42
|
+
|
|
43
|
+
its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users"') }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
context 'when a restriction is visited' do
|
|
47
|
+
before do
|
|
48
|
+
object.visit(base_relation.restrict { |r| r[:id].eq(1) })
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it_should_behave_like 'a generated SQL expression'
|
|
52
|
+
|
|
53
|
+
its(:to_s) { should eql('SELECT * FROM "users" WHERE "id" = 1') }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
context 'when a limit is visited' do
|
|
57
|
+
before do
|
|
58
|
+
object.visit(base_relation.order.take(1))
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it_should_behave_like 'a generated SQL expression'
|
|
62
|
+
|
|
63
|
+
its(:to_s) { should eql('SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1') }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
context 'when an offset is visited' do
|
|
67
|
+
before do
|
|
68
|
+
object.visit(base_relation.order.drop(1))
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it_should_behave_like 'a generated SQL expression'
|
|
72
|
+
|
|
73
|
+
its(:to_s) { should eql('SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1') }
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_projection' do
|
|
6
|
+
subject { object.visit_veritas_algebra_projection(projection) }
|
|
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) { BaseRelation.new(relation_name, header, body) }
|
|
15
|
+
let(:projection) { operand.project([ :id, :name ]) }
|
|
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 DISTINCT "id", "name" FROM "users"') }
|
|
24
|
+
its(:to_subquery) { should eql('SELECT DISTINCT "id", "name" 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", "name" FROM "users"') }
|
|
33
|
+
its(:to_subquery) { should eql('SELECT DISTINCT "id", "name" FROM "users"') }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context 'when the operand is a rename' do
|
|
37
|
+
context 'when the projection includes the renamed column' do
|
|
38
|
+
let(:operand) { base_relation.rename(:id => :user_id) }
|
|
39
|
+
let(:projection) { operand.project([ :user_id, :name ]) }
|
|
40
|
+
|
|
41
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
42
|
+
|
|
43
|
+
its(:to_s) { pending { should eql('SELECT DISTINCT "id" AS "user_id", "name" FROM "users"') } }
|
|
44
|
+
its(:to_subquery) { pending { should eql('SELECT DISTINCT "id" AS "user_id", "name" FROM "users"') } }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
context 'when the projection does not include the renamed column' do
|
|
48
|
+
let(:operand) { base_relation.rename(:id => :user_id) }
|
|
49
|
+
let(:projection) { operand.project([ :name, :age ]) }
|
|
50
|
+
|
|
51
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
52
|
+
|
|
53
|
+
its(:to_s) { should eql('SELECT DISTINCT "name", "age" FROM (SELECT "id" AS "user_id", "name", "age" FROM "users") AS "users"') }
|
|
54
|
+
its(:to_subquery) { should eql('SELECT DISTINCT "name", "age" FROM (SELECT "id" AS "user_id", "name", "age" FROM "users") AS "users"') }
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
context 'when the operand is a restriction' do
|
|
59
|
+
let(:operand) { base_relation.restrict { |r| r[:id].eq(1) } }
|
|
60
|
+
|
|
61
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
62
|
+
|
|
63
|
+
its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM "users" WHERE "id" = 1') }
|
|
64
|
+
its(:to_subquery) { should eql('SELECT DISTINCT "id", "name" FROM "users" WHERE "id" = 1') }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
context 'when the operand is ordered' do
|
|
68
|
+
let(:operand) { base_relation.order }
|
|
69
|
+
|
|
70
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
71
|
+
|
|
72
|
+
its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "users"') }
|
|
73
|
+
its(:to_subquery) { should eql('SELECT DISTINCT "id", "name" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "users"') }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
context 'when the operand is reversed' do
|
|
77
|
+
let(:operand) { base_relation.order.reverse }
|
|
78
|
+
|
|
79
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
80
|
+
|
|
81
|
+
its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) AS "users"') }
|
|
82
|
+
its(:to_subquery) { should eql('SELECT DISTINCT "id", "name" FROM (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) AS "users"') }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
context 'when the operand is limited' do
|
|
86
|
+
let(:operand) { base_relation.order.take(1) }
|
|
87
|
+
|
|
88
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
89
|
+
|
|
90
|
+
its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "users"') }
|
|
91
|
+
its(:to_subquery) { should eql('SELECT DISTINCT "id", "name" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "users"') }
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
context 'when the operand is an offset' do
|
|
95
|
+
let(:operand) { base_relation.order.drop(1) }
|
|
96
|
+
|
|
97
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
98
|
+
|
|
99
|
+
its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "users"') }
|
|
100
|
+
its(:to_subquery) { should eql('SELECT DISTINCT "id", "name" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "users"') }
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
context 'when the operand is a difference' do
|
|
104
|
+
let(:operand) { base_relation.difference(base_relation) }
|
|
105
|
+
|
|
106
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
107
|
+
|
|
108
|
+
its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM ((SELECT * FROM "users") EXCEPT (SELECT * FROM "users")) AS "users"') }
|
|
109
|
+
its(:to_subquery) { should eql('SELECT DISTINCT "id", "name" FROM ((SELECT * FROM "users") EXCEPT (SELECT * FROM "users")) AS "users"') }
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
context 'when the operand is an intersection' do
|
|
113
|
+
let(:operand) { base_relation.intersect(base_relation) }
|
|
114
|
+
|
|
115
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
116
|
+
|
|
117
|
+
its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM ((SELECT * FROM "users") INTERSECT (SELECT * FROM "users")) AS "users"') }
|
|
118
|
+
its(:to_subquery) { should eql('SELECT DISTINCT "id", "name" FROM ((SELECT * FROM "users") INTERSECT (SELECT * FROM "users")) AS "users"') }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
context 'when the operand is a union' do
|
|
122
|
+
let(:operand) { base_relation.union(base_relation) }
|
|
123
|
+
|
|
124
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
125
|
+
|
|
126
|
+
its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM ((SELECT * FROM "users") UNION (SELECT * FROM "users")) AS "users"') }
|
|
127
|
+
its(:to_subquery) { should eql('SELECT DISTINCT "id", "name" FROM ((SELECT * FROM "users") UNION (SELECT * FROM "users")) AS "users"') }
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
context 'when the operand is a join' do
|
|
131
|
+
let(:operand) { base_relation.join(base_relation) }
|
|
132
|
+
|
|
133
|
+
it_should_behave_like 'a generated SQL SELECT query'
|
|
134
|
+
|
|
135
|
+
its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM (SELECT * FROM "users" NATURAL JOIN "users") AS "users"') }
|
|
136
|
+
its(:to_subquery) { should eql('SELECT DISTINCT "id", "name" FROM (SELECT * FROM "users" NATURAL JOIN "users") AS "users"') }
|
|
137
|
+
end
|
|
138
|
+
end
|