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.
Files changed (103) hide show
  1. data/Gemfile +33 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +27 -0
  4. data/Rakefile +25 -0
  5. data/TODO +17 -0
  6. data/config/flay.yml +3 -0
  7. data/config/flog.yml +2 -0
  8. data/config/roodi.yml +16 -0
  9. data/config/site.reek +124 -0
  10. data/config/yardstick.yml +2 -0
  11. data/lib/veritas-sql-generator.rb +3 -0
  12. data/lib/veritas/base_relation.rb +36 -0
  13. data/lib/veritas/sql/generator.rb +35 -0
  14. data/lib/veritas/sql/generator/attribute.rb +25 -0
  15. data/lib/veritas/sql/generator/direction.rb +36 -0
  16. data/lib/veritas/sql/generator/identifier.rb +27 -0
  17. data/lib/veritas/sql/generator/literal.rb +160 -0
  18. data/lib/veritas/sql/generator/logic.rb +349 -0
  19. data/lib/veritas/sql/generator/relation.rb +111 -0
  20. data/lib/veritas/sql/generator/relation/base.rb +14 -0
  21. data/lib/veritas/sql/generator/relation/binary.rb +184 -0
  22. data/lib/veritas/sql/generator/relation/set.rb +99 -0
  23. data/lib/veritas/sql/generator/relation/unary.rb +326 -0
  24. data/lib/veritas/sql/generator/version.rb +9 -0
  25. data/lib/veritas/sql/generator/visitor.rb +121 -0
  26. data/spec/rcov.opts +6 -0
  27. data/spec/shared/command_method_behavior.rb +7 -0
  28. data/spec/shared/generated_sql_behavior.rb +15 -0
  29. data/spec/shared/idempotent_method_behavior.rb +7 -0
  30. data/spec/spec.opts +3 -0
  31. data/spec/spec_helper.rb +15 -0
  32. data/spec/unit/veritas/base_relation/name_spec.rb +45 -0
  33. data/spec/unit/veritas/sql/generator/attribute/visit_veritas_attribute_spec.rb +15 -0
  34. data/spec/unit/veritas/sql/generator/direction/visit_veritas_relation_operation_order_ascending_spec.rb +15 -0
  35. data/spec/unit/veritas/sql/generator/direction/visit_veritas_relation_operation_order_descending_spec.rb +15 -0
  36. data/spec/unit/veritas/sql/generator/identifier/visit_identifier_spec.rb +26 -0
  37. data/spec/unit/veritas/sql/generator/literal/class_methods/dup_frozen_spec.rb +23 -0
  38. data/spec/unit/veritas/sql/generator/literal/visit_class_spec.rb +31 -0
  39. data/spec/unit/veritas/sql/generator/literal/visit_date_spec.rb +15 -0
  40. data/spec/unit/veritas/sql/generator/literal/visit_date_time_spec.rb +61 -0
  41. data/spec/unit/veritas/sql/generator/literal/visit_enumerable_spec.rb +15 -0
  42. data/spec/unit/veritas/sql/generator/literal/visit_false_class_spec.rb +14 -0
  43. data/spec/unit/veritas/sql/generator/literal/visit_nil_class_spec.rb +14 -0
  44. data/spec/unit/veritas/sql/generator/literal/visit_numeric_spec.rb +34 -0
  45. data/spec/unit/veritas/sql/generator/literal/visit_string_spec.rb +26 -0
  46. data/spec/unit/veritas/sql/generator/literal/visit_time_spec.rb +97 -0
  47. data/spec/unit/veritas/sql/generator/literal/visit_true_class_spec.rb +14 -0
  48. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_connective_conjunction_spec.rb +16 -0
  49. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_connective_disjunction_spec.rb +16 -0
  50. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_connective_negation_spec.rb +16 -0
  51. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_predicate_equality_spec.rb +27 -0
  52. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_predicate_exclusion_spec.rb +43 -0
  53. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_predicate_greater_than_or_equal_to_spec.rb +15 -0
  54. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_predicate_greater_than_spec.rb +15 -0
  55. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_predicate_inclusion_spec.rb +43 -0
  56. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_predicate_inequality_spec.rb +55 -0
  57. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_predicate_less_than_or_equal_to_spec.rb +15 -0
  58. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_predicate_less_than_spec.rb +15 -0
  59. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_proposition_contradiction_spec.rb +15 -0
  60. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_proposition_tautology_spec.rb +15 -0
  61. data/spec/unit/veritas/sql/generator/relation/binary/base/to_subquery_spec.rb +35 -0
  62. data/spec/unit/veritas/sql/generator/relation/binary/base/visit_veritas_base_relation_spec.rb +22 -0
  63. data/spec/unit/veritas/sql/generator/relation/binary/class_methods/subquery_spec.rb +42 -0
  64. data/spec/unit/veritas/sql/generator/relation/binary/to_s_spec.rb +35 -0
  65. data/spec/unit/veritas/sql/generator/relation/binary/to_subquery_spec.rb +35 -0
  66. data/spec/unit/veritas/sql/generator/relation/binary/visit_veritas_algebra_join_spec.rb +138 -0
  67. data/spec/unit/veritas/sql/generator/relation/binary/visit_veritas_algebra_product_spec.rb +139 -0
  68. data/spec/unit/veritas/sql/generator/relation/class_methods/subquery_spec.rb +33 -0
  69. data/spec/unit/veritas/sql/generator/relation/class_methods/visit_spec.rb +61 -0
  70. data/spec/unit/veritas/sql/generator/relation/name_spec.rb +30 -0
  71. data/spec/unit/veritas/sql/generator/relation/set/to_s_spec.rb +55 -0
  72. data/spec/unit/veritas/sql/generator/relation/set/to_subquery_spec.rb +55 -0
  73. data/spec/unit/veritas/sql/generator/relation/set/visit_veritas_algebra_difference_spec.rb +138 -0
  74. data/spec/unit/veritas/sql/generator/relation/set/visit_veritas_algebra_intersection_spec.rb +138 -0
  75. data/spec/unit/veritas/sql/generator/relation/set/visit_veritas_algebra_union_spec.rb +138 -0
  76. data/spec/unit/veritas/sql/generator/relation/to_sql_spec.rb +52 -0
  77. data/spec/unit/veritas/sql/generator/relation/unary/to_s_spec.rb +55 -0
  78. data/spec/unit/veritas/sql/generator/relation/unary/to_subquery_spec.rb +75 -0
  79. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_algebra_projection_spec.rb +138 -0
  80. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_algebra_rename_spec.rb +136 -0
  81. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_algebra_restriction_spec.rb +157 -0
  82. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_base_relation_spec.rb +21 -0
  83. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_relation_operation_limit_spec.rb +125 -0
  84. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_relation_operation_offset_spec.rb +125 -0
  85. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_relation_operation_order_spec.rb +136 -0
  86. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_relation_operation_reverse_spec.rb +125 -0
  87. data/spec/unit/veritas/sql/generator/relation/visit_spec.rb +54 -0
  88. data/spec/unit/veritas/sql/generator/relation/visited_spec.rb +35 -0
  89. data/spec/unit/veritas/sql/generator/visitor/class_methods/handler_for_spec.rb +71 -0
  90. data/spec/unit/veritas/sql/generator/visitor/visit_spec.rb +12 -0
  91. data/spec/unit/veritas/sql/generator/visitor/visited_spec.rb +11 -0
  92. data/tasks/quality/ci.rake +2 -0
  93. data/tasks/quality/flay.rake +41 -0
  94. data/tasks/quality/flog.rake +45 -0
  95. data/tasks/quality/heckle.rake +203 -0
  96. data/tasks/quality/metric_fu.rake +26 -0
  97. data/tasks/quality/reek.rake +9 -0
  98. data/tasks/quality/roodi.rake +15 -0
  99. data/tasks/quality/yardstick.rake +23 -0
  100. data/tasks/spec.rake +38 -0
  101. data/tasks/yard.rake +9 -0
  102. data/veritas-sql-generator.gemspec +222 -0
  103. metadata +285 -0
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe SQL::Generator::Logic, '#visit_veritas_logic_predicate_less_than_or_equal_to' do
6
+ subject { object.visit_veritas_logic_predicate_less_than_or_equal_to(less_than_or_equal_to) }
7
+
8
+ let(:described_class) { Class.new(SQL::Generator::Visitor) { include SQL::Generator::Logic } }
9
+ let(:less_than_or_equal_to) { Attribute::Integer.new(:id).lte(1) }
10
+ let(:object) { described_class.new }
11
+
12
+ it_should_behave_like 'a generated SQL expression'
13
+
14
+ its(:to_s) { should eql('"id" <= 1') }
15
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe SQL::Generator::Logic, '#visit_veritas_logic_predicate_less_than' do
6
+ subject { object.visit_veritas_logic_predicate_less_than(less_than) }
7
+
8
+ let(:described_class) { Class.new(SQL::Generator::Visitor) { include SQL::Generator::Logic } }
9
+ let(:less_than) { Attribute::Integer.new(:id).lt(1) }
10
+ let(:object) { described_class.new }
11
+
12
+ it_should_behave_like 'a generated SQL expression'
13
+
14
+ its(:to_s) { should eql('"id" < 1') }
15
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe SQL::Generator::Logic, '#visit_veritas_logic_proposition_contradiction' do
6
+ subject { object.visit_veritas_logic_proposition_contradiction(contradiction) }
7
+
8
+ let(:described_class) { Class.new(SQL::Generator::Visitor) { include SQL::Generator::Logic } }
9
+ let(:contradiction) { Logic::Proposition::Contradiction.instance }
10
+ let(:object) { described_class.new }
11
+
12
+ it_should_behave_like 'a generated SQL expression'
13
+
14
+ its(:to_s) { should eql('1 = 0') }
15
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe SQL::Generator::Logic, '#visit_veritas_logic_proposition_tautology' do
6
+ subject { object.visit_veritas_logic_proposition_tautology(tautology) }
7
+
8
+ let(:described_class) { Class.new(SQL::Generator::Visitor) { include SQL::Generator::Logic } }
9
+ let(:tautology) { Logic::Proposition::Tautology.instance }
10
+ let(:object) { described_class.new }
11
+
12
+ it_should_behave_like 'a generated SQL expression'
13
+
14
+ its(:to_s) { should eql('1 = 1') }
15
+ end
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe SQL::Generator::Relation::Binary::Base, '#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 base relation is visited' do
27
+ before do
28
+ object.visit(base_relation)
29
+ end
30
+
31
+ it_should_behave_like 'a generated SQL expression'
32
+
33
+ its(:to_s) { should eql('"users"') }
34
+ end
35
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe SQL::Generator::Relation::Binary::Base, '#visit_veritas_base_relation' do
6
+ subject { object.visit_veritas_base_relation(base_relation) }
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(:object) { described_class.new }
16
+
17
+ it_should_behave_like 'a generated SQL SELECT query'
18
+
19
+ its(:name) { should eql('users') }
20
+
21
+ its(:to_subquery) { should eql('"users"') }
22
+ end
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe SQL::Generator::Relation::Binary, '.subquery' do
6
+ subject { object.subquery(generator) }
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 }
15
+
16
+ context 'when generator is a base' do
17
+ let(:relation) { base_relation }
18
+ let(:generator) { SQL::Generator::Relation::Binary::Base.new.visit(relation) }
19
+
20
+ it_should_behave_like 'a generated SQL expression'
21
+
22
+ its(:to_s) { should == '"users"' }
23
+ end
24
+
25
+ context 'when generator is a unary' do
26
+ let(:relation) { base_relation.project([ :id ]) }
27
+ let(:generator) { SQL::Generator::Relation::Unary.new.visit(relation) }
28
+
29
+ it_should_behave_like 'a generated SQL expression'
30
+
31
+ its(:to_s) { should eql('(SELECT DISTINCT "id" FROM "users") AS "users"') }
32
+ end
33
+
34
+ context 'when generator is a binary' do
35
+ let(:relation) { base_relation.join(base_relation) }
36
+ let(:generator) { SQL::Generator::Relation::Binary.new.visit(relation) }
37
+
38
+ it_should_behave_like 'a generated SQL expression'
39
+
40
+ its(:to_s) { should eql('(SELECT * FROM "users" NATURAL JOIN "users") AS "users"') }
41
+ end
42
+ end
@@ -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) { 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 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" NATURAL JOIN "users"') }
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) { 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 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" NATURAL JOIN "users"') }
34
+ end
35
+ end
@@ -0,0 +1,138 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe SQL::Generator::Relation::Binary, '#visit_veritas_algebra_join' do
6
+ subject { object.visit_veritas_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) { BaseRelation.new(relation_name, header, body) }
15
+ let(:left) { operand }
16
+ let(:right) { operand }
17
+ let(:join) { left.join(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" NATURAL JOIN "users"') }
26
+ its(:to_subquery) { should eql('SELECT * FROM "users" NATURAL JOIN "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 "id", "name" FROM (SELECT DISTINCT "id", "name" FROM "users") AS "left" NATURAL JOIN (SELECT DISTINCT "id", "name" FROM "users") AS "right"') }
35
+ 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"') }
36
+ end
37
+
38
+ context 'when the operands are rename' 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 "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"') }
44
+ 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"') }
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 (SELECT * FROM "users" WHERE "id" = 1) AS "left" NATURAL JOIN (SELECT * FROM "users" WHERE "id" = 1) AS "right"') }
53
+ 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"') }
54
+ end
55
+
56
+ context 'when the operands are 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 (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "left" NATURAL JOIN (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "right"') }
62
+ 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"') }
63
+ end
64
+
65
+ context 'when the operands are 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 (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"') }
71
+ 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"') }
72
+ end
73
+
74
+ context 'when the operands are 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 (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"') }
80
+ 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"') }
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 (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"') }
89
+ 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"') }
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 ((SELECT * FROM "users") EXCEPT (SELECT * FROM "users")) AS "left" NATURAL JOIN ((SELECT * FROM "users") EXCEPT (SELECT * FROM "users")) AS "right"') }
98
+ its(:to_subquery) { should eql('SELECT * FROM ((SELECT * FROM "users") EXCEPT (SELECT * FROM "users")) AS "left" NATURAL JOIN ((SELECT * FROM "users") EXCEPT (SELECT * FROM "users")) AS "right"') }
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 ((SELECT * FROM "users") INTERSECT (SELECT * FROM "users")) AS "left" NATURAL JOIN ((SELECT * FROM "users") INTERSECT (SELECT * FROM "users")) AS "right"') }
107
+ its(:to_subquery) { should eql('SELECT * FROM ((SELECT * FROM "users") INTERSECT (SELECT * FROM "users")) AS "left" NATURAL JOIN ((SELECT * FROM "users") INTERSECT (SELECT * FROM "users")) AS "right"') }
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 ((SELECT * FROM "users") UNION (SELECT * FROM "users")) AS "left" NATURAL JOIN ((SELECT * FROM "users") UNION (SELECT * FROM "users")) AS "right"') }
116
+ its(:to_subquery) { should eql('SELECT * FROM ((SELECT * FROM "users") UNION (SELECT * FROM "users")) AS "left" NATURAL JOIN ((SELECT * FROM "users") UNION (SELECT * FROM "users")) AS "right"') }
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 (SELECT * FROM "users" NATURAL JOIN "users") AS "left" NATURAL JOIN (SELECT * FROM "users" NATURAL JOIN "users") AS "right"') }
125
+ its(:to_subquery) { should eql('SELECT * FROM (SELECT * FROM "users" NATURAL JOIN "users") AS "left" NATURAL JOIN (SELECT * FROM "users" NATURAL JOIN "users") AS "right"') }
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" NATURAL JOIN "others"') }
136
+ its(:to_subquery) { should eql('SELECT * FROM "users" NATURAL JOIN "others"') }
137
+ end
138
+ end
@@ -0,0 +1,139 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe SQL::Generator::Relation::Binary, '#visit_veritas_algebra_product' do
6
+ subject { object.visit_veritas_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) { BaseRelation.new('users', header, body) }
16
+ let(:other) { BaseRelation.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" CROSS JOIN "other"') }
27
+ its(:to_subquery) { should eql('SELECT * FROM "users" CROSS JOIN "other"') }
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 a rename' do
41
+ let(:left) { users.rename(:id => :user_id) }
42
+ let(:right) { other.rename(:other_id => :other_user_id) }
43
+
44
+ it_should_behave_like 'a generated SQL SELECT query'
45
+
46
+ 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"') }
47
+ 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"') }
48
+ end
49
+
50
+ context 'when the operand is a restriction' do
51
+ let(:left) { users.restrict { |r| r[:id].eq(1) } }
52
+ let(:right) { other.restrict { |r| r[:other_id].eq(1) } }
53
+
54
+ it_should_behave_like 'a generated SQL SELECT query'
55
+
56
+ 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"') }
57
+ 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"') }
58
+ end
59
+
60
+ context 'when the operand is ordered' do
61
+ let(:left) { users.order }
62
+ let(:right) { other.order }
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" ORDER BY "id", "name", "age") AS "left" CROSS JOIN (SELECT * FROM "other" ORDER BY "other_id", "other_name", "other_age") AS "right"') }
67
+ 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"') }
68
+ end
69
+
70
+ context 'when the operand is reversed' do
71
+ let(:left) { users.order.reverse }
72
+ let(:right) { other.order.reverse }
73
+
74
+ it_should_behave_like 'a generated SQL SELECT query'
75
+
76
+ 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"') }
77
+ 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"') }
78
+ end
79
+
80
+ context 'when the operand is limited' do
81
+ let(:left) { users.order.take(1) }
82
+ let(:right) { other.order.take(1) }
83
+
84
+ it_should_behave_like 'a generated SQL SELECT query'
85
+
86
+ 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"') }
87
+ 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"') }
88
+ end
89
+
90
+ context 'when the operand is an offset' do
91
+ let(:left) { users.order.drop(1) }
92
+ let(:right) { other.order.drop(1) }
93
+
94
+ it_should_behave_like 'a generated SQL SELECT query'
95
+
96
+ 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"') }
97
+ 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"') }
98
+ end
99
+
100
+ context 'when the operand is a difference' do
101
+ let(:left) { users.difference(users) }
102
+ let(:right) { other.difference(other) }
103
+
104
+ it_should_behave_like 'a generated SQL SELECT query'
105
+
106
+ its(:to_s) { should eql('SELECT "id", "name", "age", "other_id", "other_name", "other_age" FROM ((SELECT * FROM "users") EXCEPT (SELECT * FROM "users")) AS "left" CROSS JOIN ((SELECT * FROM "other") EXCEPT (SELECT * FROM "other")) AS "right"') }
107
+ its(:to_subquery) { should eql('SELECT * FROM ((SELECT * FROM "users") EXCEPT (SELECT * FROM "users")) AS "left" CROSS JOIN ((SELECT * FROM "other") EXCEPT (SELECT * FROM "other")) AS "right"') }
108
+ end
109
+
110
+ context 'when the operand is a intersection' do
111
+ let(:left) { users.intersect(users) }
112
+ let(:right) { other.intersect(other) }
113
+
114
+ it_should_behave_like 'a generated SQL SELECT query'
115
+
116
+ its(:to_s) { should eql('SELECT "id", "name", "age", "other_id", "other_name", "other_age" FROM ((SELECT * FROM "users") INTERSECT (SELECT * FROM "users")) AS "left" CROSS JOIN ((SELECT * FROM "other") INTERSECT (SELECT * FROM "other")) AS "right"') }
117
+ its(:to_subquery) { should eql('SELECT * FROM ((SELECT * FROM "users") INTERSECT (SELECT * FROM "users")) AS "left" CROSS JOIN ((SELECT * FROM "other") INTERSECT (SELECT * FROM "other")) AS "right"') }
118
+ end
119
+
120
+ context 'when the operand is a union' do
121
+ let(:left) { users.union(users) }
122
+ let(:right) { other.union(other) }
123
+
124
+ it_should_behave_like 'a generated SQL SELECT query'
125
+
126
+ its(:to_s) { should eql('SELECT "id", "name", "age", "other_id", "other_name", "other_age" FROM ((SELECT * FROM "users") UNION (SELECT * FROM "users")) AS "left" CROSS JOIN ((SELECT * FROM "other") UNION (SELECT * FROM "other")) AS "right"') }
127
+ its(:to_subquery) { should eql('SELECT * FROM ((SELECT * FROM "users") UNION (SELECT * FROM "users")) AS "left" CROSS JOIN ((SELECT * FROM "other") UNION (SELECT * FROM "other")) AS "right"') }
128
+ end
129
+
130
+ context 'when the operand is a join' do
131
+ let(:left) { users.join(users) }
132
+ let(:right) { other.join(other) }
133
+
134
+ it_should_behave_like 'a generated SQL SELECT query'
135
+
136
+ its(:to_s) { should eql('SELECT "id", "name", "age", "other_id", "other_name", "other_age" FROM (SELECT * FROM "users" NATURAL JOIN "users") AS "left" CROSS JOIN (SELECT * FROM "other" NATURAL JOIN "other") AS "right"') }
137
+ its(:to_subquery) { should eql('SELECT * FROM (SELECT * FROM "users" NATURAL JOIN "users") AS "left" CROSS JOIN (SELECT * FROM "other" NATURAL JOIN "other") AS "right"') }
138
+ end
139
+ end