veritas-sql-generator 0.0.3 → 0.0.4

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 (117) hide show
  1. data/.gemtest +0 -0
  2. data/.rvmrc +1 -0
  3. data/.travis.yml +8 -0
  4. data/Gemfile +20 -10
  5. data/Guardfile +22 -0
  6. data/README.rdoc +2 -0
  7. data/Rakefile +4 -2
  8. data/TODO +16 -2
  9. data/config/flay.yml +2 -2
  10. data/config/flog.yml +1 -1
  11. data/config/roodi.yml +5 -5
  12. data/config/site.reek +21 -19
  13. data/lib/veritas/sql/generator.rb +25 -2
  14. data/lib/veritas/sql/generator/core_ext/date.rb +20 -0
  15. data/lib/veritas/sql/generator/core_ext/date_time.rb +45 -0
  16. data/lib/veritas/sql/generator/direction.rb +3 -1
  17. data/lib/veritas/sql/generator/function.rb +54 -0
  18. data/lib/veritas/sql/generator/function/aggregate.rb +134 -0
  19. data/lib/veritas/sql/generator/function/connective.rb +53 -0
  20. data/lib/veritas/sql/generator/function/numeric.rb +135 -0
  21. data/lib/veritas/sql/generator/function/predicate.rb +266 -0
  22. data/lib/veritas/sql/generator/function/proposition.rb +38 -0
  23. data/lib/veritas/sql/generator/function/string.rb +29 -0
  24. data/lib/veritas/sql/generator/identifier.rb +2 -1
  25. data/lib/veritas/sql/generator/literal.rb +15 -18
  26. data/lib/veritas/sql/generator/relation.rb +144 -17
  27. data/lib/veritas/sql/generator/relation/binary.rb +16 -64
  28. data/lib/veritas/sql/generator/relation/set.rb +30 -22
  29. data/lib/veritas/sql/generator/relation/unary.rb +131 -78
  30. data/lib/veritas/sql/generator/version.rb +1 -1
  31. data/spec/unit/date/iso8601_spec.rb +23 -0
  32. data/spec/unit/date_time/iso_8601_spec.rb +115 -0
  33. data/spec/unit/veritas/sql/generator/class_methods/parenthesize_spec.rb +18 -0
  34. data/spec/unit/veritas/sql/generator/function/aggregate/visit_veritas_aggregate_count_spec.rb +16 -0
  35. data/spec/unit/veritas/sql/generator/function/aggregate/visit_veritas_aggregate_maximum_spec.rb +16 -0
  36. data/spec/unit/veritas/sql/generator/function/aggregate/visit_veritas_aggregate_mean_spec.rb +16 -0
  37. data/spec/unit/veritas/sql/generator/function/aggregate/visit_veritas_aggregate_minimum_spec.rb +16 -0
  38. data/spec/unit/veritas/sql/generator/function/aggregate/visit_veritas_aggregate_standard_deviation_spec.rb +16 -0
  39. data/spec/unit/veritas/sql/generator/function/aggregate/visit_veritas_aggregate_sum_spec.rb +16 -0
  40. data/spec/unit/veritas/sql/generator/function/aggregate/visit_veritas_aggregate_variance_spec.rb +16 -0
  41. data/spec/unit/veritas/sql/generator/function/connective/visit_veritas_function_connective_conjunction_spec.rb +20 -0
  42. data/spec/unit/veritas/sql/generator/function/connective/visit_veritas_function_connective_disjunction_spec.rb +20 -0
  43. data/spec/unit/veritas/sql/generator/function/connective/visit_veritas_function_connective_negation_spec.rb +20 -0
  44. data/spec/unit/veritas/sql/generator/function/numeric/visit_veritas_function_numeric_absolute_spec.rb +15 -0
  45. data/spec/unit/veritas/sql/generator/function/numeric/visit_veritas_function_numeric_addition_spec.rb +15 -0
  46. data/spec/unit/veritas/sql/generator/function/numeric/visit_veritas_function_numeric_division_spec.rb +15 -0
  47. data/spec/unit/veritas/sql/generator/function/numeric/visit_veritas_function_numeric_exponentiation_spec.rb +15 -0
  48. data/spec/unit/veritas/sql/generator/function/numeric/visit_veritas_function_numeric_modulo_spec.rb +15 -0
  49. data/spec/unit/veritas/sql/generator/function/numeric/visit_veritas_function_numeric_multiplication_spec.rb +15 -0
  50. data/spec/unit/veritas/sql/generator/function/numeric/visit_veritas_function_numeric_square_root_spec.rb +15 -0
  51. data/spec/unit/veritas/sql/generator/function/numeric/visit_veritas_function_numeric_subtraction_spec.rb +15 -0
  52. data/spec/unit/veritas/sql/generator/function/numeric/visit_veritas_function_numeric_unary_minus_spec.rb +15 -0
  53. data/spec/unit/veritas/sql/generator/function/numeric/visit_veritas_function_numeric_unary_plus_spec.rb +15 -0
  54. data/spec/unit/veritas/sql/generator/{logic/visit_veritas_logic_predicate_equality_spec.rb → function/predicate/visit_veritas_function_predicate_equality_spec.rb} +5 -5
  55. data/spec/unit/veritas/sql/generator/{logic/visit_veritas_logic_predicate_exclusion_spec.rb → function/predicate/visit_veritas_function_predicate_exclusion_spec.rb} +10 -6
  56. data/spec/unit/veritas/sql/generator/function/predicate/visit_veritas_function_predicate_greater_than_or_equal_to_spec.rb +15 -0
  57. data/spec/unit/veritas/sql/generator/{logic/visit_veritas_logic_predicate_greater_than_spec.rb → function/predicate/visit_veritas_function_predicate_greater_than_spec.rb} +5 -5
  58. data/spec/unit/veritas/sql/generator/{logic/visit_veritas_logic_predicate_inclusion_spec.rb → function/predicate/visit_veritas_function_predicate_inclusion_spec.rb} +10 -6
  59. data/spec/unit/veritas/sql/generator/{logic/visit_veritas_logic_predicate_inequality_spec.rb → function/predicate/visit_veritas_function_predicate_inequality_spec.rb} +8 -8
  60. data/spec/unit/veritas/sql/generator/function/predicate/visit_veritas_function_predicate_less_than_or_equal_to_spec.rb +15 -0
  61. data/spec/unit/veritas/sql/generator/{logic/visit_veritas_logic_predicate_less_than_spec.rb → function/predicate/visit_veritas_function_predicate_less_than_spec.rb} +5 -5
  62. data/spec/unit/veritas/sql/generator/function/proposition/visit_veritas_function_proposition_contradiction_spec.rb +15 -0
  63. data/spec/unit/veritas/sql/generator/function/proposition/visit_veritas_function_proposition_tautology_spec.rb +15 -0
  64. data/spec/unit/veritas/sql/generator/function/string/visit_veritas_function_string_length_spec.rb +15 -0
  65. data/spec/unit/veritas/sql/generator/literal/class_methods/dup_frozen_spec.rb +2 -2
  66. data/spec/unit/veritas/sql/generator/relation/binary/base/to_subquery_spec.rb +1 -1
  67. data/spec/unit/veritas/sql/generator/relation/binary/base/{visit_veritas_base_relation_spec.rb → visit_veritas_relation_base_spec.rb} +3 -3
  68. data/spec/unit/veritas/sql/generator/relation/binary/to_s_spec.rb +2 -2
  69. data/spec/unit/veritas/sql/generator/relation/binary/to_subquery_spec.rb +2 -2
  70. data/spec/unit/veritas/sql/generator/relation/binary/visit_veritas_algebra_join_spec.rb +74 -33
  71. data/spec/unit/veritas/sql/generator/relation/binary/visit_veritas_algebra_product_spec.rb +63 -19
  72. data/spec/unit/veritas/sql/generator/relation/class_methods/visit_spec.rb +1 -1
  73. data/spec/unit/veritas/sql/generator/relation/set/class_methods/normalize_operand_headers_spec.rb +35 -0
  74. data/spec/unit/veritas/sql/generator/relation/set/to_s_spec.rb +1 -1
  75. data/spec/unit/veritas/sql/generator/relation/set/to_subquery_spec.rb +4 -4
  76. data/spec/unit/veritas/sql/generator/relation/set/visit_veritas_algebra_difference_spec.rb +83 -30
  77. data/spec/unit/veritas/sql/generator/relation/set/visit_veritas_algebra_intersection_spec.rb +80 -30
  78. data/spec/unit/veritas/sql/generator/relation/set/visit_veritas_algebra_union_spec.rb +80 -30
  79. data/spec/unit/veritas/sql/generator/relation/to_s_spec.rb +50 -0
  80. data/spec/unit/veritas/sql/generator/relation/to_subquery_spec.rb +49 -0
  81. data/spec/unit/veritas/sql/generator/relation/unary/to_s_spec.rb +1 -1
  82. data/spec/unit/veritas/sql/generator/relation/unary/to_subquery_spec.rb +6 -6
  83. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_algebra_extension_spec.rb +165 -0
  84. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_algebra_projection_spec.rb +84 -29
  85. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_algebra_rename_spec.rb +69 -27
  86. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_algebra_restriction_spec.rb +64 -22
  87. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_algebra_summarization_spec.rb +652 -0
  88. data/spec/unit/veritas/sql/generator/relation/unary/{visit_veritas_base_relation_spec.rb → visit_veritas_relation_base_spec.rb} +4 -4
  89. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_relation_operation_limit_spec.rb +60 -20
  90. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_relation_operation_offset_spec.rb +60 -20
  91. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_relation_operation_order_spec.rb +63 -23
  92. data/spec/unit/veritas/sql/generator/relation/unary/visit_veritas_relation_operation_reverse_spec.rb +60 -20
  93. data/spec/unit/veritas/sql/generator/relation/visited_spec.rb +1 -1
  94. data/tasks/metrics/ci.rake +7 -0
  95. data/tasks/{quality → metrics}/flay.rake +0 -0
  96. data/tasks/{quality → metrics}/flog.rake +0 -0
  97. data/tasks/{quality → metrics}/heckle.rake +1 -0
  98. data/tasks/{quality → metrics}/metric_fu.rake +3 -0
  99. data/tasks/{quality → metrics}/reek.rake +0 -0
  100. data/tasks/{quality → metrics}/roodi.rake +0 -0
  101. data/tasks/{quality → metrics}/yardstick.rake +0 -0
  102. data/tasks/spec.rake +1 -0
  103. data/veritas-sql-generator.gemspec +82 -114
  104. metadata +137 -125
  105. data/lib/veritas/base_relation.rb +0 -36
  106. data/lib/veritas/sql/generator/logic.rb +0 -349
  107. data/spec/unit/veritas/base_relation/name_spec.rb +0 -45
  108. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_connective_conjunction_spec.rb +0 -16
  109. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_connective_disjunction_spec.rb +0 -16
  110. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_connective_negation_spec.rb +0 -16
  111. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_predicate_greater_than_or_equal_to_spec.rb +0 -15
  112. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_predicate_less_than_or_equal_to_spec.rb +0 -15
  113. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_proposition_contradiction_spec.rb +0 -15
  114. data/spec/unit/veritas/sql/generator/logic/visit_veritas_logic_proposition_tautology_spec.rb +0 -15
  115. data/spec/unit/veritas/sql/generator/relation/binary/class_methods/subquery_spec.rb +0 -42
  116. data/spec/unit/veritas/sql/generator/relation/class_methods/subquery_spec.rb +0 -33
  117. data/tasks/quality/ci.rake +0 -2
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe SQL::Generator::Relation, '#to_subquery' do
6
+ subject { object.to_subquery }
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(:base_relation) { Relation::Base.new('users', header, body) }
15
+ let(:object) { described_class.new }
16
+
17
+ context 'when no object visited' do
18
+ it_should_behave_like 'an idempotent method'
19
+
20
+ it { should respond_to(:to_s) }
21
+
22
+ it { should be_frozen }
23
+
24
+ its(:to_s) { should == '' }
25
+ end
26
+
27
+ context 'when an object is visited' do
28
+ let(:visitable) { mock('Visitable') }
29
+
30
+ before do
31
+ described_class.class_eval do
32
+ def visit_spec_mocks_mock(mock)
33
+ @name = mock.instance_variable_get(:@name)
34
+ @scope = Set.new
35
+ end
36
+
37
+ def generate_sql(columns)
38
+ "SELECT #{columns} FROM #{@name}"
39
+ end
40
+ end
41
+
42
+ object.visit(visitable)
43
+ end
44
+
45
+ it_should_behave_like 'a generated SQL expression'
46
+
47
+ its(:to_s) { should eql('(SELECT * FROM Visitable)') }
48
+ end
49
+ end
@@ -10,7 +10,7 @@ describe SQL::Generator::Relation::Unary, '#to_s' do
10
10
  let(:age) { Attribute::Integer.new(:age, :required => false) }
11
11
  let(:header) { [ id, name, age ] }
12
12
  let(:body) { [ [ 1, 'Dan Kubb', 35 ] ].each }
13
- let(:base_relation) { BaseRelation.new('users', header, body) }
13
+ let(:base_relation) { Relation::Base.new('users', header, body) }
14
14
  let(:object) { described_class.new }
15
15
 
16
16
  context 'when no object visited' do
@@ -10,7 +10,7 @@ describe SQL::Generator::Relation::Unary, '#to_subquery' do
10
10
  let(:age) { Attribute::Integer.new(:age, :required => false) }
11
11
  let(:header) { [ id, name, age ] }
12
12
  let(:body) { [ [ 1, 'Dan Kubb', 35 ] ].each }
13
- let(:base_relation) { BaseRelation.new('users', header, body) }
13
+ let(:base_relation) { Relation::Base.new('users', header, body) }
14
14
  let(:object) { described_class.new }
15
15
 
16
16
  context 'when no object visited' do
@@ -30,7 +30,7 @@ describe SQL::Generator::Relation::Unary, '#to_subquery' do
30
30
 
31
31
  it_should_behave_like 'a generated SQL expression'
32
32
 
33
- its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM "users"') }
33
+ its(:to_s) { should eql('(SELECT DISTINCT "id", "name" FROM "users")') }
34
34
  end
35
35
 
36
36
  context 'when a rename is visited' do
@@ -40,7 +40,7 @@ describe SQL::Generator::Relation::Unary, '#to_subquery' do
40
40
 
41
41
  it_should_behave_like 'a generated SQL expression'
42
42
 
43
- its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users"') }
43
+ its(:to_s) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM "users")') }
44
44
  end
45
45
 
46
46
  context 'when a restriction is visited' do
@@ -50,7 +50,7 @@ describe SQL::Generator::Relation::Unary, '#to_subquery' do
50
50
 
51
51
  it_should_behave_like 'a generated SQL expression'
52
52
 
53
- its(:to_s) { should eql('SELECT * FROM "users" WHERE "id" = 1') }
53
+ its(:to_s) { should eql('(SELECT * FROM "users" WHERE "id" = 1)') }
54
54
  end
55
55
 
56
56
  context 'when a limit is visited' do
@@ -60,7 +60,7 @@ describe SQL::Generator::Relation::Unary, '#to_subquery' do
60
60
 
61
61
  it_should_behave_like 'a generated SQL expression'
62
62
 
63
- its(:to_s) { should eql('SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1') }
63
+ its(:to_s) { should eql('(SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1)') }
64
64
  end
65
65
 
66
66
  context 'when an offset is visited' do
@@ -70,6 +70,6 @@ describe SQL::Generator::Relation::Unary, '#to_subquery' do
70
70
 
71
71
  it_should_behave_like 'a generated SQL expression'
72
72
 
73
- its(:to_s) { should eql('SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1') }
73
+ its(:to_s) { should eql('(SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1)') }
74
74
  end
75
75
  end
@@ -0,0 +1,165 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_extension' do
6
+ subject { object.visit_veritas_algebra_extension(extension) }
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(:extension) { operand.extend { |r| r.add(:one, 1) } }
16
+ let(:object) { described_class.new }
17
+
18
+ context 'when the operand is a base relation' do
19
+ let(:operand) { base_relation }
20
+
21
+ it_should_behave_like 'a generated SQL SELECT query'
22
+
23
+ its(:to_s) { should eql('SELECT "id", "name", "age", 1 AS "one" FROM "users"') }
24
+ its(:to_subquery) { should eql('(SELECT *, 1 AS "one" 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", 1 AS "one" FROM "users"') }
33
+ its(:to_subquery) { should eql('(SELECT DISTINCT "id", "name", 1 AS "one" FROM "users")') }
34
+ end
35
+
36
+ context 'when the operand is an extension' do
37
+ let(:operand) { base_relation.extend { |r| r.add(:two, 2) } }
38
+
39
+ it_should_behave_like 'a generated SQL SELECT query'
40
+
41
+ its(:to_s) { should eql('SELECT "id", "name", "age", "two", 1 AS "one" FROM (SELECT *, 2 AS "two" FROM "users") AS "users"') }
42
+ its(:to_subquery) { should eql('(SELECT *, 1 AS "one" FROM (SELECT *, 2 AS "two" FROM "users") AS "users")') }
43
+ end
44
+
45
+ context 'when the operand is a rename' do
46
+ let(:operand) { base_relation.rename(:id => :user_id) }
47
+
48
+ it_should_behave_like 'a generated SQL SELECT query'
49
+
50
+ its(:to_s) { should eql('SELECT "user_id", "name", "age", 1 AS "one" FROM (SELECT "id" AS "user_id", "name", "age" FROM "users") AS "users"') }
51
+ its(:to_subquery) { should eql('(SELECT *, 1 AS "one" FROM (SELECT "id" AS "user_id", "name", "age" FROM "users") AS "users")') }
52
+ end
53
+
54
+ context 'when the operand is a restriction' do
55
+ let(:operand) { base_relation.restrict { |r| r[:id].eq(1) } }
56
+
57
+ it_should_behave_like 'a generated SQL SELECT query'
58
+
59
+ its(:to_s) { should eql('SELECT "id", "name", "age", 1 AS "one" FROM "users" WHERE "id" = 1') }
60
+ its(:to_subquery) { should eql('(SELECT *, 1 AS "one" FROM "users" WHERE "id" = 1)') }
61
+ end
62
+
63
+ context 'when the operand is a summarization' do
64
+ context 'summarize per table dee' do
65
+ let(:summarize_per) { TABLE_DEE }
66
+ let(:operand) { base_relation.summarize(summarize_per) { |r| r.add(:count, r[:id].count) } }
67
+
68
+ it_should_behave_like 'a generated SQL SELECT query'
69
+
70
+ its(:to_s) { should eql('SELECT "count", 1 AS "one" FROM (SELECT COUNT ("id") AS "count" FROM "users") AS "users"') }
71
+ its(:to_subquery) { should eql('(SELECT *, 1 AS "one" FROM (SELECT COUNT ("id") AS "count" FROM "users") AS "users")') }
72
+ end
73
+
74
+ context 'summarize per table dum' do
75
+ let(:summarize_per) { TABLE_DUM }
76
+ let(:operand) { base_relation.summarize(summarize_per) { |r| r.add(:count, r[:id].count) } }
77
+
78
+ it_should_behave_like 'a generated SQL SELECT query'
79
+
80
+ its(:to_s) { should eql('SELECT "count", 1 AS "one" FROM (SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE) AS "users"') }
81
+ its(:to_subquery) { should eql('(SELECT *, 1 AS "one" FROM (SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE) AS "users")') }
82
+ end
83
+
84
+ context 'summarize by a subset of the operand header' do
85
+ let(:operand) { base_relation.summarize([ :id, :name ]) { |r| r.add(:count, r[:age].count) } }
86
+
87
+ it_should_behave_like 'a generated SQL SELECT query'
88
+
89
+ its(:to_s) { should eql('SELECT "id", "name", "count", 1 AS "one" FROM (SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0) AS "users"') }
90
+ its(:to_subquery) { should eql('(SELECT *, 1 AS "one" FROM (SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0) AS "users")') }
91
+ end
92
+ end
93
+
94
+ context 'when the operand is ordered' do
95
+ let(:operand) { base_relation.order }
96
+
97
+ it_should_behave_like 'a generated SQL SELECT query'
98
+
99
+ its(:to_s) { should eql('SELECT "id", "name", "age", 1 AS "one" FROM "users" ORDER BY "id", "name", "age"') }
100
+ its(:to_subquery) { should eql('(SELECT *, 1 AS "one" FROM "users" ORDER BY "id", "name", "age")') }
101
+ end
102
+
103
+ context 'when the operand is reversed' do
104
+ let(:operand) { base_relation.order.reverse }
105
+
106
+ it_should_behave_like 'a generated SQL SELECT query'
107
+
108
+ its(:to_s) { should eql('SELECT "id", "name", "age", 1 AS "one" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC') }
109
+ its(:to_subquery) { should eql('(SELECT *, 1 AS "one" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC)') }
110
+ end
111
+
112
+ context 'when the operand is limited' do
113
+ let(:operand) { base_relation.order.take(1) }
114
+
115
+ it_should_behave_like 'a generated SQL SELECT query'
116
+
117
+ its(:to_s) { should eql('SELECT "id", "name", "age", 1 AS "one" FROM "users" ORDER BY "id", "name", "age" LIMIT 1') }
118
+ its(:to_subquery) { should eql('(SELECT *, 1 AS "one" FROM "users" ORDER BY "id", "name", "age" LIMIT 1)') }
119
+ end
120
+
121
+ context 'when the operand is an offset' do
122
+ let(:operand) { base_relation.order.drop(1) }
123
+
124
+ it_should_behave_like 'a generated SQL SELECT query'
125
+
126
+ its(:to_s) { should eql('SELECT "id", "name", "age", 1 AS "one" FROM "users" ORDER BY "id", "name", "age" OFFSET 1') }
127
+ its(:to_subquery) { should eql('(SELECT *, 1 AS "one" FROM "users" ORDER BY "id", "name", "age" OFFSET 1)') }
128
+ end
129
+
130
+ context 'when the operand is a difference' do
131
+ let(:operand) { base_relation.difference(base_relation) }
132
+
133
+ it_should_behave_like 'a generated SQL SELECT query'
134
+
135
+ its(:to_s) { should eql('SELECT "id", "name", "age", 1 AS "one" FROM ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "users"') }
136
+ its(:to_subquery) { should eql('(SELECT *, 1 AS "one" FROM ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "users")') }
137
+ end
138
+
139
+ context 'when the operand is an intersection' do
140
+ let(:operand) { base_relation.intersect(base_relation) }
141
+
142
+ it_should_behave_like 'a generated SQL SELECT query'
143
+
144
+ its(:to_s) { should eql('SELECT "id", "name", "age", 1 AS "one" FROM ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "users"') }
145
+ its(:to_subquery) { should eql('(SELECT *, 1 AS "one" FROM ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "users")') }
146
+ end
147
+
148
+ context 'when the operand is a union' do
149
+ let(:operand) { base_relation.union(base_relation) }
150
+
151
+ it_should_behave_like 'a generated SQL SELECT query'
152
+
153
+ its(:to_s) { should eql('SELECT "id", "name", "age", 1 AS "one" FROM ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "users"') }
154
+ its(:to_subquery) { should eql('(SELECT *, 1 AS "one" FROM ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "users")') }
155
+ end
156
+
157
+ context 'when the operand is a join' do
158
+ let(:operand) { base_relation.join(base_relation) }
159
+
160
+ it_should_behave_like 'a generated SQL SELECT query'
161
+
162
+ its(:to_s) { should eql('SELECT "id", "name", "age", 1 AS "one" FROM (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "users"') }
163
+ its(:to_subquery) { should eql('(SELECT *, 1 AS "one" FROM (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "users")') }
164
+ end
165
+ end
@@ -11,7 +11,7 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_projection' do
11
11
  let(:age) { Attribute::Integer.new(:age, :required => false) }
12
12
  let(:header) { [ id, name, age ] }
13
13
  let(:body) { [ [ 1, 'Dan Kubb', 35 ] ].each }
14
- let(:base_relation) { BaseRelation.new(relation_name, header, body) }
14
+ let(:base_relation) { Relation::Base.new(relation_name, header, body) }
15
15
  let(:projection) { operand.project([ :id, :name ]) }
16
16
  let(:object) { described_class.new }
17
17
 
@@ -20,8 +20,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_projection' do
20
20
 
21
21
  it_should_behave_like 'a generated SQL SELECT query'
22
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"') }
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
25
  end
26
26
 
27
27
  context 'when the operand is a projection' do
@@ -29,14 +29,37 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_projection' do
29
29
 
30
30
  it_should_behave_like 'a generated SQL SELECT query'
31
31
 
32
- its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM "users"') }
33
- its(:to_subquery) { should eql('SELECT DISTINCT "id", "name" FROM "users"') }
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 an extension' do
37
+ let(:operand) { base_relation.extend { |r| r.add(:one, 1) } }
38
+
39
+ context 'when the projection includes the extended column' do
40
+ let(:projection) { operand.project([ :id, :name, :one ]) }
41
+
42
+ it_should_behave_like 'a generated SQL SELECT query'
43
+
44
+ its(:to_s) { pending { should eql('SELECT DISTINCT "id", "name", 1 AS "one" FROM "users"') } }
45
+ its(:to_subquery) { pending { should eql('SELECT DISTINCT "id", "name", 1 AS "one" FROM "users"') } }
46
+ end
47
+
48
+ context 'when the projection does not include the extended column' do
49
+ let(:projection) { operand.project([ :id, :name ]) }
50
+
51
+ it_should_behave_like 'a generated SQL SELECT query'
52
+
53
+ its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM (SELECT *, 1 AS "one" FROM "users") AS "users"') }
54
+ its(:to_subquery) { should eql('(SELECT DISTINCT "id", "name" FROM (SELECT *, 1 AS "one" FROM "users") AS "users")') }
55
+ end
34
56
  end
35
57
 
36
58
  context 'when the operand is a rename' do
59
+ let(:operand) { base_relation.rename(:id => :user_id) }
60
+
37
61
  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 ]) }
62
+ let(:projection) { operand.project([ :user_id, :name ]) }
40
63
 
41
64
  it_should_behave_like 'a generated SQL SELECT query'
42
65
 
@@ -45,13 +68,12 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_projection' do
45
68
  end
46
69
 
47
70
  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 ]) }
71
+ let(:projection) { operand.project([ :name, :age ]) }
50
72
 
51
73
  it_should_behave_like 'a generated SQL SELECT query'
52
74
 
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"') }
75
+ its(:to_s) { should eql('SELECT DISTINCT "name", "age" FROM (SELECT "id" AS "user_id", "name", "age" FROM "users") AS "users"') }
76
+ its(:to_subquery) { should eql('(SELECT DISTINCT "name", "age" FROM (SELECT "id" AS "user_id", "name", "age" FROM "users") AS "users")') }
55
77
  end
56
78
  end
57
79
 
@@ -60,8 +82,41 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_projection' do
60
82
 
61
83
  it_should_behave_like 'a generated SQL SELECT query'
62
84
 
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') }
85
+ its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM "users" WHERE "id" = 1') }
86
+ its(:to_subquery) { should eql('(SELECT DISTINCT "id", "name" FROM "users" WHERE "id" = 1)') }
87
+ end
88
+
89
+ context 'when the operand is a summarization' do
90
+ context 'summarize per table dee' do
91
+ let(:summarize_per) { TABLE_DEE }
92
+ let(:operand) { base_relation.summarize(summarize_per) { |r| r.add(:count, r[:id].count) } }
93
+ let(:projection) { operand.project([ :count ]) }
94
+
95
+ it_should_behave_like 'a generated SQL SELECT query'
96
+
97
+ its(:to_s) { should eql('SELECT DISTINCT "count" FROM (SELECT COUNT ("id") AS "count" FROM "users") AS "users"') }
98
+ its(:to_subquery) { should eql('(SELECT DISTINCT "count" FROM (SELECT COUNT ("id") AS "count" FROM "users") AS "users")') }
99
+ end
100
+
101
+ context 'summarize per table dum' do
102
+ let(:summarize_per) { TABLE_DUM }
103
+ let(:operand) { base_relation.summarize(summarize_per) { |r| r.add(:count, r[:id].count) } }
104
+ let(:projection) { operand.project([ :count ]) }
105
+
106
+ it_should_behave_like 'a generated SQL SELECT query'
107
+
108
+ its(:to_s) { should eql('SELECT DISTINCT "count" FROM (SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE) AS "users"') }
109
+ its(:to_subquery) { should eql('(SELECT DISTINCT "count" FROM (SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE) AS "users")') }
110
+ end
111
+
112
+ context 'summarize by a subset of the operand header' do
113
+ let(:operand) { base_relation.summarize([ :id, :name ]) { |r| r.add(:count, r[:age].count) } }
114
+
115
+ it_should_behave_like 'a generated SQL SELECT query'
116
+
117
+ its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM (SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0) AS "users"') }
118
+ its(:to_subquery) { should eql('(SELECT DISTINCT "id", "name" FROM (SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0) AS "users")') }
119
+ end
65
120
  end
66
121
 
67
122
  context 'when the operand is ordered' do
@@ -69,8 +124,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_projection' do
69
124
 
70
125
  it_should_behave_like 'a generated SQL SELECT query'
71
126
 
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"') }
127
+ its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "users"') }
128
+ its(:to_subquery) { should eql('(SELECT DISTINCT "id", "name" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age") AS "users")') }
74
129
  end
75
130
 
76
131
  context 'when the operand is reversed' do
@@ -78,8 +133,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_projection' do
78
133
 
79
134
  it_should_behave_like 'a generated SQL SELECT query'
80
135
 
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"') }
136
+ its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) AS "users"') }
137
+ its(:to_subquery) { should eql('(SELECT DISTINCT "id", "name" FROM (SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC) AS "users")') }
83
138
  end
84
139
 
85
140
  context 'when the operand is limited' do
@@ -87,8 +142,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_projection' do
87
142
 
88
143
  it_should_behave_like 'a generated SQL SELECT query'
89
144
 
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"') }
145
+ its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "users"') }
146
+ its(:to_subquery) { should eql('(SELECT DISTINCT "id", "name" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "users")') }
92
147
  end
93
148
 
94
149
  context 'when the operand is an offset' do
@@ -96,8 +151,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_projection' do
96
151
 
97
152
  it_should_behave_like 'a generated SQL SELECT query'
98
153
 
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"') }
154
+ its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "users"') }
155
+ its(:to_subquery) { should eql('(SELECT DISTINCT "id", "name" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "users")') }
101
156
  end
102
157
 
103
158
  context 'when the operand is a difference' do
@@ -105,8 +160,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_projection' do
105
160
 
106
161
  it_should_behave_like 'a generated SQL SELECT query'
107
162
 
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"') }
163
+ its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "users"') }
164
+ its(:to_subquery) { should eql('(SELECT DISTINCT "id", "name" FROM ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "users")') }
110
165
  end
111
166
 
112
167
  context 'when the operand is an intersection' do
@@ -114,8 +169,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_projection' do
114
169
 
115
170
  it_should_behave_like 'a generated SQL SELECT query'
116
171
 
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"') }
172
+ its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "users"') }
173
+ its(:to_subquery) { should eql('(SELECT DISTINCT "id", "name" FROM ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "users")') }
119
174
  end
120
175
 
121
176
  context 'when the operand is a union' do
@@ -123,8 +178,8 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_projection' do
123
178
 
124
179
  it_should_behave_like 'a generated SQL SELECT query'
125
180
 
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"') }
181
+ its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "users"') }
182
+ its(:to_subquery) { should eql('(SELECT DISTINCT "id", "name" FROM ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "users")') }
128
183
  end
129
184
 
130
185
  context 'when the operand is a join' do
@@ -132,7 +187,7 @@ describe SQL::Generator::Relation::Unary, '#visit_veritas_algebra_projection' do
132
187
 
133
188
  it_should_behave_like 'a generated SQL SELECT query'
134
189
 
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"') }
190
+ its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "users"') }
191
+ its(:to_subquery) { should eql('(SELECT DISTINCT "id", "name" FROM (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "users")') }
137
192
  end
138
193
  end