veritas-sql-generator 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -12,6 +12,27 @@ module Veritas
12
12
  INTERSECTION = 'INTERSECT'.freeze
13
13
  UNION = 'UNION'.freeze
14
14
 
15
+ # Normalize the headers of the operands
16
+ #
17
+ # This is necessary to make sure the columns are in the correct
18
+ # order when generating SQL.
19
+ #
20
+ # @param [Relation::Operation::Set] relation
21
+ #
22
+ # @return [Relation::Operation::Set]
23
+ #
24
+ # @api private
25
+ def self.normalize_operand_headers(relation)
26
+ left = relation.left
27
+ right = relation.right
28
+ left_header = left.header
29
+ if left_header.to_a != right.header.to_a
30
+ relation.class.new(left, right.project(left_header))
31
+ else
32
+ relation
33
+ end
34
+ end
35
+
15
36
  # Visit a Union
16
37
  #
17
38
  # @param [Algebra::Union] union
@@ -54,39 +75,26 @@ module Veritas
54
75
  self
55
76
  end
56
77
 
57
- # Return the SQL for the set relation
58
- #
59
- # @example
60
- # sql = set_relation.to_s
61
- #
62
- # @return [#to_s]
63
- #
64
- # @api public
65
- def to_s
66
- generate_sql(:to_s)
67
- end
78
+ private
68
79
 
69
- # Return the SQL suitable for an subquery
80
+ # Generate the SQL using the supplied method
70
81
  #
71
82
  # @return [#to_s]
72
83
  #
73
84
  # @api private
74
- def to_subquery
75
- generate_sql(:to_subquery)
85
+ def generate_sql(*)
86
+ "(#{@left}) #{@operation} (#{@right})"
76
87
  end
77
88
 
78
- private
79
-
80
- # Generate the SQL using the supplied method
89
+ # Set the operands from the relation
81
90
  #
82
- # @param [Symbol] method
91
+ # @param [Relation::Operation::Set] relation
83
92
  #
84
- # @return [#to_s]
93
+ # @return [undefined]
85
94
  #
86
95
  # @api private
87
- def generate_sql(method)
88
- return EMPTY_STRING unless visited?
89
- "(#{@left.send(method)}) #{@operation} (#{@right.send(method)})"
96
+ def set_operands(relation)
97
+ super self.class.normalize_operand_headers(relation)
90
98
  end
91
99
 
92
100
  # Generates an SQL statement for base relation set operands
@@ -8,19 +8,30 @@ module Veritas
8
8
  # Generates an SQL statement for a unary relation
9
9
  class Unary < Relation
10
10
  extend Aliasable
11
- include Direction, Literal, Logic
11
+ include Direction,
12
+ Literal,
13
+ Function::Aggregate,
14
+ Function::Connective,
15
+ Function::Predicate,
16
+ Function::Proposition,
17
+ Function::String,
18
+ Function::Numeric
12
19
 
13
20
  inheritable_alias(:visit_veritas_relation_operation_reverse => :visit_veritas_relation_operation_order)
14
21
 
15
- DISTINCT = 'DISTINCT '.freeze
16
- COLLAPSIBLE = {
17
- Algebra::Projection => Set[ Algebra::Projection, Algebra::Restriction, ].freeze,
18
- Algebra::Restriction => Set[ Algebra::Projection, Veritas::Relation::Operation::Order, Veritas::Relation::Operation::Reverse, ].freeze,
19
- Veritas::Relation::Operation::Order => Set[ Algebra::Projection, Algebra::Restriction, Veritas::Relation::Operation::Order, Veritas::Relation::Operation::Reverse, Algebra::Rename ].freeze,
20
- Veritas::Relation::Operation::Reverse => Set[ Algebra::Projection, Algebra::Restriction, Veritas::Relation::Operation::Order, Veritas::Relation::Operation::Reverse, Algebra::Rename ].freeze,
21
- Veritas::Relation::Operation::Offset => Set[ Algebra::Projection, Algebra::Restriction, Veritas::Relation::Operation::Order, Veritas::Relation::Operation::Reverse, Algebra::Rename ].freeze,
22
- Veritas::Relation::Operation::Limit => Set[ Algebra::Projection, Algebra::Restriction, Veritas::Relation::Operation::Order, Veritas::Relation::Operation::Reverse, Veritas::Relation::Operation::Offset, Algebra::Rename ].freeze,
23
- Algebra::Rename => Set[ Algebra::Projection, Algebra::Restriction, Veritas::Relation::Operation::Order, Veritas::Relation::Operation::Reverse, Veritas::Relation::Operation::Offset, Veritas::Relation::Operation::Limit ].freeze,
22
+ DISTINCT = 'DISTINCT '.freeze
23
+ NO_ROWS = ' HAVING FALSE'.freeze
24
+ ANY_ROWS = ' HAVING COUNT (*) > 0'
25
+ COLLAPSIBLE = {
26
+ Algebra::Summarization => Set[ ].freeze,
27
+ Algebra::Projection => Set[ Algebra::Projection, Algebra::Restriction, ].freeze,
28
+ Algebra::Extension => Set[ Algebra::Projection, Algebra::Restriction, Veritas::Relation::Operation::Order, Veritas::Relation::Operation::Reverse, Veritas::Relation::Operation::Offset, Veritas::Relation::Operation::Limit ].freeze,
29
+ Algebra::Rename => Set[ Algebra::Projection, Algebra::Restriction, Veritas::Relation::Operation::Order, Veritas::Relation::Operation::Reverse, Veritas::Relation::Operation::Offset, Veritas::Relation::Operation::Limit ].freeze,
30
+ Algebra::Restriction => Set[ Algebra::Projection, Veritas::Relation::Operation::Order, Veritas::Relation::Operation::Reverse, ].freeze,
31
+ Veritas::Relation::Operation::Order => Set[ Algebra::Projection, Algebra::Extension, Algebra::Rename, Algebra::Restriction, Algebra::Summarization, Veritas::Relation::Operation::Order, Veritas::Relation::Operation::Reverse, ].freeze,
32
+ Veritas::Relation::Operation::Reverse => Set[ Algebra::Projection, Algebra::Extension, Algebra::Rename, Algebra::Restriction, Algebra::Summarization, Veritas::Relation::Operation::Order, Veritas::Relation::Operation::Reverse, ].freeze,
33
+ Veritas::Relation::Operation::Offset => Set[ Algebra::Projection, Algebra::Extension, Algebra::Rename, Algebra::Restriction, Algebra::Summarization, Veritas::Relation::Operation::Order, Veritas::Relation::Operation::Reverse, ].freeze,
34
+ Veritas::Relation::Operation::Limit => Set[ Algebra::Projection, Algebra::Extension, Algebra::Rename, Algebra::Restriction, Algebra::Summarization, Veritas::Relation::Operation::Order, Veritas::Relation::Operation::Reverse, Veritas::Relation::Operation::Offset, ].freeze,
24
35
  }.freeze
25
36
 
26
37
  # Initialize a Unary relation SQL generator
@@ -35,14 +46,15 @@ module Veritas
35
46
 
36
47
  # Visit a Base Relation
37
48
  #
38
- # @param [BaseRelation] base_relation
49
+ # @param [Relation::Base] base_relation
39
50
  #
40
51
  # @return [self]
41
52
  #
42
53
  # @api private
43
- def visit_veritas_base_relation(base_relation)
54
+ def visit_veritas_relation_base(base_relation)
44
55
  @name = base_relation.name
45
56
  @from = visit_identifier(@name)
57
+ @header = base_relation.header
46
58
  @columns = columns_for(base_relation)
47
59
  self
48
60
  end
@@ -57,11 +69,28 @@ module Veritas
57
69
  def visit_veritas_algebra_projection(projection)
58
70
  @from = subquery_for(projection)
59
71
  @distinct = DISTINCT
72
+ @header = projection.header
60
73
  @columns = columns_for(projection)
61
74
  scope_query(projection)
62
75
  self
63
76
  end
64
77
 
78
+ # Visit an Extension
79
+ #
80
+ # @param [Algebra::Extension] extension
81
+ #
82
+ # @return [self]
83
+ #
84
+ # @api private
85
+ def visit_veritas_algebra_extension(extension)
86
+ @from = subquery_for(extension)
87
+ @header = extension.header
88
+ @columns ||= columns_for(extension.operand)
89
+ add_extensions(extension.extensions)
90
+ scope_query(extension)
91
+ self
92
+ end
93
+
65
94
  # Visit a Rename
66
95
  #
67
96
  # @param [Algebra::Rename] rename
@@ -71,6 +100,7 @@ module Veritas
71
100
  # @api private
72
101
  def visit_veritas_algebra_rename(rename)
73
102
  @from = subquery_for(rename)
103
+ @header = rename.header
74
104
  @columns = columns_for(rename.operand, rename.aliases.to_hash)
75
105
  scope_query(rename)
76
106
  self
@@ -85,12 +115,32 @@ module Veritas
85
115
  # @api private
86
116
  def visit_veritas_algebra_restriction(restriction)
87
117
  @from = subquery_for(restriction)
88
- @where = dispatch(restriction.predicate)
118
+ @where = " WHERE #{dispatch(restriction.predicate)}"
119
+ @header = restriction.header
89
120
  @columns ||= columns_for(restriction)
90
121
  scope_query(restriction)
91
122
  self
92
123
  end
93
124
 
125
+ # Visit a Summarization
126
+ #
127
+ # @param [Algebra::Summarization] summarization
128
+ #
129
+ # @return [self]
130
+ #
131
+ # @api private
132
+ def visit_veritas_algebra_summarization(summarization)
133
+ summarize_per = summarization.summarize_per
134
+ @from = subquery_for(summarization)
135
+ @header = summarization.header
136
+ @columns = columns_for(summarize_per)
137
+ summarize_per(summarize_per)
138
+ group_by_columns
139
+ add_extensions(summarization.summarizers)
140
+ scope_query(summarization)
141
+ self
142
+ end
143
+
94
144
  # Visit an Order
95
145
  #
96
146
  # @param [Relation::Operation::Order] order
@@ -100,7 +150,8 @@ module Veritas
100
150
  # @api private
101
151
  def visit_veritas_relation_operation_order(order)
102
152
  @from = subquery_for(order)
103
- @order = order_for(order.directions)
153
+ @order = " ORDER BY #{order_for(order.directions)}"
154
+ @header = order.header
104
155
  @columns ||= columns_for(order)
105
156
  scope_query(order)
106
157
  self
@@ -115,7 +166,8 @@ module Veritas
115
166
  # @api private
116
167
  def visit_veritas_relation_operation_limit(limit)
117
168
  @from = subquery_for(limit)
118
- @limit = limit.limit
169
+ @limit = " LIMIT #{limit.limit}"
170
+ @header = limit.header
119
171
  @columns ||= columns_for(limit)
120
172
  scope_query(limit)
121
173
  self
@@ -130,108 +182,117 @@ module Veritas
130
182
  # @api private
131
183
  def visit_veritas_relation_operation_offset(offset)
132
184
  @from = subquery_for(offset)
133
- @offset = offset.offset
185
+ @offset = " OFFSET #{offset.offset}"
186
+ @header = offset.header
134
187
  @columns ||= columns_for(offset)
135
188
  scope_query(offset)
136
189
  self
137
190
  end
138
191
 
139
- # Return the SQL for the unary relation
192
+ private
193
+
194
+ # Generate the SQL using the supplied columns
140
195
  #
141
- # @example
142
- # sql = unary_relation.to_s
196
+ # @param [String] columns
143
197
  #
144
198
  # @return [#to_s]
145
199
  #
146
- # @api public
147
- def to_s
148
- generate_sql(@columns)
200
+ # @api private
201
+ def generate_sql(columns)
202
+ [ "SELECT #{columns} FROM #{@from}", @where, @group, @having, @order, @limit, @offset ].join
149
203
  end
150
204
 
151
- # Return the SQL suitable for an subquery
205
+ # Return the columns to use in a query
152
206
  #
153
207
  # @return [#to_s]
154
208
  #
155
209
  # @api private
156
- def to_subquery
157
- generate_sql(all_columns? ? ALL_COLUMNS : @columns)
210
+ def query_columns
211
+ explicit_columns
158
212
  end
159
213
 
160
- private
161
-
162
- # Generate the SQL using the supplied columns
163
- #
164
- # @param [String] columns
214
+ # Return the columns to use in a subquery
165
215
  #
166
216
  # @return [#to_s]
167
217
  #
168
218
  # @api private
169
- def generate_sql(columns)
170
- return EMPTY_STRING unless visited?
171
- sql = "SELECT #{@distinct}#{columns} FROM #{@from}"
172
- sql << " WHERE #{@where}" if @where
173
- sql << " ORDER BY #{@order}" if @order
174
- sql << " LIMIT #{@limit}" if @limit
175
- sql << " OFFSET #{@offset}" if @offset
176
- sql
219
+ def subquery_columns
220
+ explicit_columns_in_subquery? ? explicit_columns : super
177
221
  end
178
222
 
179
- # Return a list of columns in a header
223
+ # Test if the subquery should use "*" and not specify columns explicitly
180
224
  #
181
- # @param [Veritas::Relation] relation
225
+ # @return [Boolean]
182
226
  #
183
- # @param [#[]] aliases
184
- # optional aliases for the columns
227
+ # @api private
228
+ def explicit_columns_in_subquery?
229
+ @scope.include?(Algebra::Projection) ||
230
+ @scope.include?(Algebra::Rename) ||
231
+ @scope.include?(Algebra::Summarization)
232
+ end
233
+
234
+ # Return a list of columns for ordering
235
+ #
236
+ # @param [DirectionSet] directions
185
237
  #
186
238
  # @return [#to_s]
187
239
  #
188
240
  # @api private
189
- def columns_for(relation, aliases = {})
190
- relation.header.map { |attribute| column_for(attribute, aliases) }.join(SEPARATOR)
241
+ def order_for(directions)
242
+ directions.map { |direction| dispatch(direction) }.join(SEPARATOR)
191
243
  end
192
244
 
193
- # Return the column for an attribute
245
+ # Summarize the operand over the provided relation
194
246
  #
195
- # @param [Attribute] attribute
196
- #
197
- # @param [#[]] aliases
198
- # aliases for the columns
247
+ # @param [Relation] relation
199
248
  #
200
- # @return [#to_s]
249
+ # @return [undefined]
201
250
  #
202
251
  # @api private
203
- def column_for(attribute, aliases)
204
- column = dispatch(attribute)
205
- if aliases.key?(attribute)
206
- alias_for(column, aliases[attribute])
252
+ def summarize_per(relation)
253
+ return if relation.eql?(TABLE_DEE)
254
+
255
+ if relation.eql?(TABLE_DUM) then summarize_per_table_dum
256
+ elsif (generator = Binary.visit(relation)).name.eql?(name) then summarize_per_subset
207
257
  else
208
- column
258
+ summarize_per_relation(generator)
209
259
  end
210
260
  end
211
261
 
212
- # Return the column alias for an attribute
262
+ # Summarize the operand using table dee
213
263
  #
214
- # @param [#to_s] column
264
+ # @return [undefined]
215
265
  #
216
- # @param [Attribute, nil] alias_attribute
217
- # attribute to use for the alias
266
+ # @api private
267
+ def summarize_per_table_dum
268
+ @having = NO_ROWS
269
+ end
270
+
271
+ # Summarize the operand using a subset
218
272
  #
219
- # @return [#to_s]
273
+ # @return [undefined]
220
274
  #
221
275
  # @api private
222
- def alias_for(column, alias_attribute)
223
- "#{column} AS #{visit_identifier(alias_attribute.name)}"
276
+ def summarize_per_subset
277
+ @having = ANY_ROWS
224
278
  end
225
279
 
226
- # Return a list of columns for ordering
280
+ # Summarize the operand using another relation
227
281
  #
228
- # @param [DirectionSet] directions
282
+ # @return [undefined]
229
283
  #
230
- # @return [#to_s]
284
+ # @api private
285
+ def summarize_per_relation(generator)
286
+ @from = "#{generator.to_subquery} AS #{visit_identifier(generator.name)} NATURAL LEFT JOIN #{@from}"
287
+ end
288
+
289
+ # Group by the columns
290
+ #
291
+ # @return [undefined]
231
292
  #
232
293
  # @api private
233
- def order_for(directions)
234
- directions.map { |direction| dispatch(direction) }.join(SEPARATOR)
294
+ def group_by_columns
295
+ @group = " GROUP BY #{column_list_for(@columns)}" if @columns.any?
235
296
  end
236
297
 
237
298
  # Return an expression that can be used for the FROM
@@ -262,15 +323,6 @@ module Veritas
262
323
  @scope << operand.class
263
324
  end
264
325
 
265
- # Test if the query should use "*" and not specify columns explicitly
266
- #
267
- # @return [Boolean]
268
- #
269
- # @api private
270
- def all_columns?
271
- !@scope.include?(Algebra::Projection) && !@scope.include?(Algebra::Rename)
272
- end
273
-
274
326
  # Test if the relation should be collapsed
275
327
  #
276
328
  # @param [Relation] relation
@@ -290,7 +342,7 @@ module Veritas
290
342
  #
291
343
  # @api private
292
344
  def aliased_subquery(subquery)
293
- self.class.subquery(subquery)
345
+ "#{subquery.to_subquery} AS #{visit_identifier(subquery.name)}"
294
346
  ensure
295
347
  reset_query_state
296
348
  end
@@ -316,7 +368,8 @@ module Veritas
316
368
  # @api private
317
369
  def reset_query_state
318
370
  @scope.clear
319
- @distinct = @columns = @where = @order = @limit = @offset = nil
371
+ @extensions.clear
372
+ @distinct = @columns = @where = @order = @limit = @offset = @group = @having = nil
320
373
  end
321
374
 
322
375
  end # class Unary
@@ -3,7 +3,7 @@
3
3
  module Veritas
4
4
  module SQL
5
5
  module Generator
6
- VERSION = '0.0.3'
6
+ VERSION = '0.0.4'
7
7
  end # module Generator
8
8
  end # module SQL
9
9
  end # module Veritas
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Date, '#iso8601' do
6
+ subject { object.iso8601 }
7
+
8
+ context 'when the date is frozen' do
9
+ let(:object) { described_class.new(2010, 12, 31).freeze }
10
+
11
+ it { should respond_to(:to_s) }
12
+
13
+ it { should == '2010-12-31' }
14
+ end
15
+
16
+ context 'when the date is not frozen' do
17
+ let(:object) { described_class.new(2010, 12, 31) }
18
+
19
+ it { should respond_to(:to_s) }
20
+
21
+ it { should == '2010-12-31' }
22
+ end
23
+ end