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
@@ -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