axiom-sql-generator 0.1.0

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 (136) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/.gitignore +37 -0
  4. data/.rspec +4 -0
  5. data/.rvmrc +1 -0
  6. data/.travis.yml +35 -0
  7. data/CONTRIBUTING.md +11 -0
  8. data/Gemfile +8 -0
  9. data/Gemfile.devtools +57 -0
  10. data/Guardfile +23 -0
  11. data/LICENSE +20 -0
  12. data/README.md +70 -0
  13. data/Rakefile +5 -0
  14. data/TODO +34 -0
  15. data/axiom-sql-generator.gemspec +25 -0
  16. data/config/flay.yml +3 -0
  17. data/config/flog.yml +2 -0
  18. data/config/mutant.yml +3 -0
  19. data/config/reek.yml +165 -0
  20. data/config/yardstick.yml +2 -0
  21. data/lib/axiom-sql-generator.rb +3 -0
  22. data/lib/axiom/sql/generator.rb +61 -0
  23. data/lib/axiom/sql/generator/attribute.rb +25 -0
  24. data/lib/axiom/sql/generator/core_ext/date.rb +20 -0
  25. data/lib/axiom/sql/generator/core_ext/date_time.rb +46 -0
  26. data/lib/axiom/sql/generator/direction.rb +38 -0
  27. data/lib/axiom/sql/generator/function.rb +55 -0
  28. data/lib/axiom/sql/generator/function/aggregate.rb +134 -0
  29. data/lib/axiom/sql/generator/function/connective.rb +53 -0
  30. data/lib/axiom/sql/generator/function/numeric.rb +135 -0
  31. data/lib/axiom/sql/generator/function/predicate.rb +266 -0
  32. data/lib/axiom/sql/generator/function/proposition.rb +38 -0
  33. data/lib/axiom/sql/generator/function/string.rb +29 -0
  34. data/lib/axiom/sql/generator/identifier.rb +28 -0
  35. data/lib/axiom/sql/generator/literal.rb +157 -0
  36. data/lib/axiom/sql/generator/relation.rb +240 -0
  37. data/lib/axiom/sql/generator/relation/base.rb +14 -0
  38. data/lib/axiom/sql/generator/relation/binary.rb +136 -0
  39. data/lib/axiom/sql/generator/relation/insertion.rb +62 -0
  40. data/lib/axiom/sql/generator/relation/materialized.rb +60 -0
  41. data/lib/axiom/sql/generator/relation/set.rb +107 -0
  42. data/lib/axiom/sql/generator/relation/unary.rb +379 -0
  43. data/lib/axiom/sql/generator/version.rb +12 -0
  44. data/lib/axiom/sql/generator/visitor.rb +121 -0
  45. data/spec/rcov.opts +7 -0
  46. data/spec/shared/generated_sql_behavior.rb +15 -0
  47. data/spec/spec_helper.rb +33 -0
  48. data/spec/support/config_alias.rb +3 -0
  49. data/spec/unit/axiom/sql/generator/attribute/visit_axiom_attribute_spec.rb +15 -0
  50. data/spec/unit/axiom/sql/generator/class_methods/parenthesize_spec.rb +18 -0
  51. data/spec/unit/axiom/sql/generator/direction/visit_axiom_relation_operation_order_ascending_spec.rb +15 -0
  52. data/spec/unit/axiom/sql/generator/direction/visit_axiom_relation_operation_order_descending_spec.rb +15 -0
  53. data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_count_spec.rb +16 -0
  54. data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_maximum_spec.rb +16 -0
  55. data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_mean_spec.rb +16 -0
  56. data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_minimum_spec.rb +16 -0
  57. data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_standard_deviation_spec.rb +16 -0
  58. data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_sum_spec.rb +16 -0
  59. data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_variance_spec.rb +16 -0
  60. data/spec/unit/axiom/sql/generator/function/connective/visit_axiom_function_connective_conjunction_spec.rb +20 -0
  61. data/spec/unit/axiom/sql/generator/function/connective/visit_axiom_function_connective_disjunction_spec.rb +20 -0
  62. data/spec/unit/axiom/sql/generator/function/connective/visit_axiom_function_connective_negation_spec.rb +20 -0
  63. data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_absolute_spec.rb +15 -0
  64. data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_addition_spec.rb +15 -0
  65. data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_division_spec.rb +15 -0
  66. data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_exponentiation_spec.rb +15 -0
  67. data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_modulo_spec.rb +15 -0
  68. data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_multiplication_spec.rb +15 -0
  69. data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_square_root_spec.rb +15 -0
  70. data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_subtraction_spec.rb +15 -0
  71. data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_unary_minus_spec.rb +15 -0
  72. data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_unary_plus_spec.rb +15 -0
  73. data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_equality_spec.rb +27 -0
  74. data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_exclusion_spec.rb +47 -0
  75. data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_greater_than_or_equal_to_spec.rb +15 -0
  76. data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_greater_than_spec.rb +15 -0
  77. data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_inclusion_spec.rb +47 -0
  78. data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_inequality_spec.rb +55 -0
  79. data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_less_than_or_equal_to_spec.rb +15 -0
  80. data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_less_than_spec.rb +15 -0
  81. data/spec/unit/axiom/sql/generator/function/proposition/visit_axiom_function_proposition_contradiction_spec.rb +15 -0
  82. data/spec/unit/axiom/sql/generator/function/proposition/visit_axiom_function_proposition_tautology_spec.rb +15 -0
  83. data/spec/unit/axiom/sql/generator/function/string/visit_axiom_function_string_length_spec.rb +15 -0
  84. data/spec/unit/axiom/sql/generator/identifier/visit_identifier_spec.rb +26 -0
  85. data/spec/unit/axiom/sql/generator/literal/class_methods/dup_frozen_spec.rb +23 -0
  86. data/spec/unit/axiom/sql/generator/literal/visit_class_spec.rb +31 -0
  87. data/spec/unit/axiom/sql/generator/literal/visit_date_spec.rb +15 -0
  88. data/spec/unit/axiom/sql/generator/literal/visit_date_time_spec.rb +55 -0
  89. data/spec/unit/axiom/sql/generator/literal/visit_enumerable_spec.rb +15 -0
  90. data/spec/unit/axiom/sql/generator/literal/visit_false_class_spec.rb +14 -0
  91. data/spec/unit/axiom/sql/generator/literal/visit_nil_class_spec.rb +14 -0
  92. data/spec/unit/axiom/sql/generator/literal/visit_numeric_spec.rb +34 -0
  93. data/spec/unit/axiom/sql/generator/literal/visit_string_spec.rb +26 -0
  94. data/spec/unit/axiom/sql/generator/literal/visit_time_spec.rb +97 -0
  95. data/spec/unit/axiom/sql/generator/literal/visit_true_class_spec.rb +14 -0
  96. data/spec/unit/axiom/sql/generator/relation/binary/base/to_subquery_spec.rb +35 -0
  97. data/spec/unit/axiom/sql/generator/relation/binary/base/visit_axiom_relation_base_spec.rb +22 -0
  98. data/spec/unit/axiom/sql/generator/relation/binary/to_s_spec.rb +35 -0
  99. data/spec/unit/axiom/sql/generator/relation/binary/to_subquery_spec.rb +35 -0
  100. data/spec/unit/axiom/sql/generator/relation/binary/visit_axiom_algebra_join_spec.rb +179 -0
  101. data/spec/unit/axiom/sql/generator/relation/binary/visit_axiom_algebra_product_spec.rb +183 -0
  102. data/spec/unit/axiom/sql/generator/relation/class_methods/visit_spec.rb +71 -0
  103. data/spec/unit/axiom/sql/generator/relation/insertion/to_subquery_spec.rb +15 -0
  104. data/spec/unit/axiom/sql/generator/relation/insertion/visit_axiom_relation_operation_insertion_spec.rb +187 -0
  105. data/spec/unit/axiom/sql/generator/relation/materialized/visit_axiom_relation_materialized_spec.rb +28 -0
  106. data/spec/unit/axiom/sql/generator/relation/materialized/visited_spec.rb +26 -0
  107. data/spec/unit/axiom/sql/generator/relation/name_spec.rb +30 -0
  108. data/spec/unit/axiom/sql/generator/relation/set/class_methods/normalize_operand_headers_spec.rb +35 -0
  109. data/spec/unit/axiom/sql/generator/relation/set/to_s_spec.rb +55 -0
  110. data/spec/unit/axiom/sql/generator/relation/set/to_subquery_spec.rb +55 -0
  111. data/spec/unit/axiom/sql/generator/relation/set/visit_axiom_algebra_difference_spec.rb +191 -0
  112. data/spec/unit/axiom/sql/generator/relation/set/visit_axiom_algebra_intersection_spec.rb +188 -0
  113. data/spec/unit/axiom/sql/generator/relation/set/visit_axiom_algebra_union_spec.rb +188 -0
  114. data/spec/unit/axiom/sql/generator/relation/to_s_spec.rb +50 -0
  115. data/spec/unit/axiom/sql/generator/relation/to_sql_spec.rb +52 -0
  116. data/spec/unit/axiom/sql/generator/relation/to_subquery_spec.rb +49 -0
  117. data/spec/unit/axiom/sql/generator/relation/unary/to_s_spec.rb +55 -0
  118. data/spec/unit/axiom/sql/generator/relation/unary/to_subquery_spec.rb +75 -0
  119. data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_algebra_extension_spec.rb +165 -0
  120. data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_algebra_projection_spec.rb +193 -0
  121. data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_algebra_rename_spec.rb +178 -0
  122. data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_algebra_restriction_spec.rb +199 -0
  123. data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_algebra_summarization_spec.rb +652 -0
  124. data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_relation_base_spec.rb +21 -0
  125. data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_relation_operation_limit_spec.rb +165 -0
  126. data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_relation_operation_offset_spec.rb +165 -0
  127. data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_relation_operation_order_spec.rb +183 -0
  128. data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_relation_operation_reverse_spec.rb +165 -0
  129. data/spec/unit/axiom/sql/generator/relation/visit_spec.rb +54 -0
  130. data/spec/unit/axiom/sql/generator/relation/visited_spec.rb +35 -0
  131. data/spec/unit/axiom/sql/generator/visitor/class_methods/handler_for_spec.rb +71 -0
  132. data/spec/unit/axiom/sql/generator/visitor/visit_spec.rb +12 -0
  133. data/spec/unit/axiom/sql/generator/visitor/visited_spec.rb +11 -0
  134. data/spec/unit/date/iso8601_spec.rb +23 -0
  135. data/spec/unit/date_time/iso8601_spec.rb +112 -0
  136. metadata +325 -0
@@ -0,0 +1,165 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe SQL::Generator::Relation::Unary, '#visit_axiom_relation_operation_reverse' do
6
+ subject { object.visit_axiom_relation_operation_reverse(order) }
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(:order) { operand.reverse }
16
+ let(:object) { described_class.new }
17
+
18
+ context 'when the operand is a base relation' do
19
+ let(:operand) { base_relation.sort_by { |r| [ r.id, r.name, r.age ] } }
20
+
21
+ it_should_behave_like 'a generated SQL SELECT query'
22
+
23
+ its(:to_s) { should eql('SELECT "id", "name", "age" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC') }
24
+ its(:to_subquery) { should eql('(SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC)') }
25
+ end
26
+
27
+ context 'when the operand is a projection' do
28
+ let(:operand) { base_relation.project([ :id, :name ]).sort_by { |r| [ r.id, r.name ] } }
29
+
30
+ it_should_behave_like 'a generated SQL SELECT query'
31
+
32
+ its(:to_s) { should eql('SELECT DISTINCT "id", "name" FROM "users" ORDER BY "id" DESC, "name" DESC') }
33
+ its(:to_subquery) { should eql('(SELECT DISTINCT "id", "name" FROM "users" ORDER BY "id" DESC, "name" DESC)') }
34
+ end
35
+
36
+ context 'when the operand is an extension' do
37
+ let(:operand) { base_relation.extend { |r| r.add(:one, 1) }.sort_by { |r| [ r.id, r.name, r.age, r.one ] } }
38
+
39
+ it_should_behave_like 'a generated SQL SELECT query'
40
+
41
+ its(:to_s) { should eql('SELECT "id", "name", "age", 1 AS "one" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC, "one" DESC') }
42
+ its(:to_subquery) { should eql('(SELECT *, 1 AS "one" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC, "one" DESC)') }
43
+ end
44
+
45
+ context 'when the operand is a rename' do
46
+ let(:operand) { base_relation.sort_by { |r| [ r.id, r.name, r.age ] }.rename(:id => :user_id) }
47
+
48
+ it_should_behave_like 'a generated SQL SELECT query'
49
+
50
+ its(:to_s) { should eql('SELECT "id" AS "user_id", "name", "age" FROM "users" ORDER BY "user_id" DESC, "name" DESC, "age" DESC') }
51
+ its(:to_subquery) { should eql('(SELECT "id" AS "user_id", "name", "age" FROM "users" ORDER BY "user_id" DESC, "name" DESC, "age" DESC)') }
52
+ end
53
+
54
+ context 'when the operand is a restriction' do
55
+ let(:operand) { base_relation.restrict { |r| r.id.eq(1) }.sort_by { |r| [ r.id, r.name, r.age ] } }
56
+
57
+ it_should_behave_like 'a generated SQL SELECT query'
58
+
59
+ its(:to_s) { should eql('SELECT "id", "name", "age" FROM "users" WHERE "id" = 1 ORDER BY "id" DESC, "name" DESC, "age" DESC') }
60
+ its(:to_subquery) { should eql('(SELECT * FROM "users" WHERE "id" = 1 ORDER BY "id" DESC, "name" DESC, "age" DESC)') }
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) }.sort_by { |r| r.count } }
67
+
68
+ it_should_behave_like 'a generated SQL SELECT query'
69
+
70
+ its(:to_s) { should eql('SELECT COUNT ("id") AS "count" FROM "users" ORDER BY "count" DESC') }
71
+ its(:to_subquery) { should eql('(SELECT COUNT ("id") AS "count" FROM "users" ORDER BY "count" DESC)') }
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) }.sort_by { |r| r.count } }
77
+
78
+ it_should_behave_like 'a generated SQL SELECT query'
79
+
80
+ its(:to_s) { should eql('SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE ORDER BY "count" DESC') }
81
+ its(:to_subquery) { should eql('(SELECT COUNT ("id") AS "count" FROM "users" HAVING FALSE ORDER BY "count" DESC)') }
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) }.sort_by { |r| [ r.id, r.name, r.count ] } }
86
+
87
+ it_should_behave_like 'a generated SQL SELECT query'
88
+
89
+ its(:to_s) { should eql('SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0 ORDER BY "id" DESC, "name" DESC, "count" DESC') }
90
+ its(:to_subquery) { should eql('(SELECT "id", "name", COUNT ("age") AS "count" FROM "users" GROUP BY "id", "name" HAVING COUNT (*) > 0 ORDER BY "id" DESC, "name" DESC, "count" DESC)') }
91
+ end
92
+ end
93
+
94
+ context 'when the operand is ordered' do
95
+ let(:operand) { base_relation.sort_by { |r| [ r.id, r.name, r.age ] } }
96
+
97
+ it_should_behave_like 'a generated SQL SELECT query'
98
+
99
+ its(:to_s) { should eql('SELECT "id", "name", "age" FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC') }
100
+ its(:to_subquery) { should eql('(SELECT * FROM "users" ORDER BY "id" DESC, "name" DESC, "age" DESC)') }
101
+ end
102
+
103
+ context 'when the operand is reversed' do
104
+ let(:operand) { base_relation.sort_by { |r| [ r.id, r.name, r.age ] }.reverse }
105
+
106
+ it_should_behave_like 'a generated SQL SELECT query'
107
+
108
+ its(:to_s) { should eql('SELECT "id", "name", "age" FROM "users" ORDER BY "id", "name", "age"') }
109
+ its(:to_subquery) { should eql('(SELECT * FROM "users" ORDER BY "id", "name", "age")') }
110
+ end
111
+
112
+ context 'when the operand is limited' do
113
+ let(:operand) { base_relation.sort_by { |r| [ r.id, r.name, r.age ] }.take(1) }
114
+
115
+ it_should_behave_like 'a generated SQL SELECT query'
116
+
117
+ its(:to_s) { should eql('SELECT "id", "name", "age" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "users" ORDER BY "id" DESC, "name" DESC, "age" DESC') }
118
+ its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" LIMIT 1) AS "users" ORDER BY "id" DESC, "name" DESC, "age" DESC)') }
119
+ end
120
+
121
+ context 'when the operand is an offset' do
122
+ let(:operand) { base_relation.sort_by { |r| [ r.id, r.name, r.age ] }.drop(1) }
123
+
124
+ it_should_behave_like 'a generated SQL SELECT query'
125
+
126
+ its(:to_s) { should eql('SELECT "id", "name", "age" FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "users" ORDER BY "id" DESC, "name" DESC, "age" DESC') }
127
+ its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" ORDER BY "id", "name", "age" OFFSET 1) AS "users" ORDER BY "id" DESC, "name" DESC, "age" DESC)') }
128
+ end
129
+
130
+ context 'when the operand is a difference' do
131
+ let(:operand) { base_relation.difference(base_relation).sort_by { |r| [ r.id, r.name, r.age ] } }
132
+
133
+ it_should_behave_like 'a generated SQL SELECT query'
134
+
135
+ its(:to_s) { should eql('SELECT "id", "name", "age" FROM ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "users" ORDER BY "id" DESC, "name" DESC, "age" DESC') }
136
+ its(:to_subquery) { should eql('(SELECT * FROM ((SELECT "id", "name", "age" FROM "users") EXCEPT (SELECT "id", "name", "age" FROM "users")) AS "users" ORDER BY "id" DESC, "name" DESC, "age" DESC)') }
137
+ end
138
+
139
+ context 'when the operand is an intersection' do
140
+ let(:operand) { base_relation.intersect(base_relation).sort_by { |r| [ r.id, r.name, r.age ] } }
141
+
142
+ it_should_behave_like 'a generated SQL SELECT query'
143
+
144
+ its(:to_s) { should eql('SELECT "id", "name", "age" FROM ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "users" ORDER BY "id" DESC, "name" DESC, "age" DESC') }
145
+ its(:to_subquery) { should eql('(SELECT * FROM ((SELECT "id", "name", "age" FROM "users") INTERSECT (SELECT "id", "name", "age" FROM "users")) AS "users" ORDER BY "id" DESC, "name" DESC, "age" DESC)') }
146
+ end
147
+
148
+ context 'when the operand is a union' do
149
+ let(:operand) { base_relation.union(base_relation).sort_by { |r| [ r.id, r.name, r.age ] } }
150
+
151
+ it_should_behave_like 'a generated SQL SELECT query'
152
+
153
+ its(:to_s) { should eql('SELECT "id", "name", "age" FROM ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "users" ORDER BY "id" DESC, "name" DESC, "age" DESC') }
154
+ its(:to_subquery) { should eql('(SELECT * FROM ((SELECT "id", "name", "age" FROM "users") UNION (SELECT "id", "name", "age" FROM "users")) AS "users" ORDER BY "id" DESC, "name" DESC, "age" DESC)') }
155
+ end
156
+
157
+ context 'when the operand is a join' do
158
+ let(:operand) { base_relation.join(base_relation).sort_by { |r| [ r.id, r.name, r.age ] } }
159
+
160
+ it_should_behave_like 'a generated SQL SELECT query'
161
+
162
+ its(:to_s) { should eql('SELECT "id", "name", "age" FROM (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "users" ORDER BY "id" DESC, "name" DESC, "age" DESC') }
163
+ its(:to_subquery) { should eql('(SELECT * FROM (SELECT * FROM "users" AS "left" NATURAL JOIN "users" AS "right") AS "users" ORDER BY "id" DESC, "name" DESC, "age" DESC)') }
164
+ end
165
+ end
@@ -0,0 +1,54 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe SQL::Generator::Relation, '#visit' do
6
+ subject { object.visit(visitable) }
7
+
8
+ let(:described_class) { Class.new(SQL::Generator::Relation) }
9
+ let(:object) { described_class.new }
10
+
11
+ context 'with a handled object' do
12
+ let(:visitable) { mock('Visitable') }
13
+
14
+ before do
15
+ described_class.class_eval do
16
+ def visit_rspec_mocks_mock(mock)
17
+ mock
18
+ end
19
+ end
20
+ end
21
+
22
+ it_should_behave_like 'a command method'
23
+
24
+ specify { expect { subject }.to change(object, :frozen?).from(false).to(true) }
25
+ end
26
+
27
+ context 'with a handled object more than once' do
28
+ let(:visitable) { mock('Visitable') }
29
+
30
+ before do
31
+ described_class.class_eval do
32
+ def visit_rspec_mocks_mock(mock)
33
+ mock
34
+ end
35
+ end
36
+ end
37
+
38
+ before do
39
+ object.visit(visitable)
40
+ end
41
+
42
+ if RUBY_VERSION >= '1.9'
43
+ specify { expect { subject }.to raise_error(RuntimeError) }
44
+ else
45
+ specify { expect { subject }.to raise_error(TypeError) }
46
+ end
47
+ end
48
+
49
+ context 'with an unhandled object' do
50
+ let(:visitable) { mock('Not Handled') }
51
+
52
+ specify { expect { subject }.to raise_error(SQL::Generator::Visitor::UnknownObject, "No handler for #{visitable.class} in #{object.class}") }
53
+ end
54
+ end
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe SQL::Generator::Relation, '#visited?' do
6
+ subject { object.visited? }
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) { Relation::Base.new('users', header, body) }
14
+ let(:object) { described_class.new }
15
+
16
+ context 'when name is nil' do
17
+ it_should_behave_like 'an idempotent method'
18
+
19
+ it { should be(false) }
20
+ end
21
+
22
+ context 'when name is set' do
23
+ let(:name) { 'test' }
24
+
25
+ before do
26
+ # subclasses set @name, but nothing in this class
27
+ # does does so simulate it being set
28
+ object.instance_variable_set(:@name, name)
29
+ end
30
+
31
+ it_should_behave_like 'an idempotent method'
32
+
33
+ it { should be(true) }
34
+ end
35
+ end
@@ -0,0 +1,71 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe SQL::Generator::Visitor, '.handler_for' do
6
+ subject { object.handler_for(visitable_class) }
7
+
8
+ let(:object) { Class.new(SQL::Generator::Visitor) }
9
+
10
+ before :all do
11
+ module ::MySpec
12
+ class Visitable; end
13
+ end
14
+ end
15
+
16
+ after :all do
17
+ MySpec.class_eval { remove_const(:Visitable) }
18
+ Object.class_eval { remove_const(:MySpec) }
19
+ end
20
+
21
+ context 'with an object handled by a public method' do
22
+ let(:visitable_class) { MySpec::Visitable }
23
+
24
+ before do
25
+ object.class_eval do
26
+ remove_instance_variable(:@handlers) if instance_variable_defined?(:@handlers)
27
+ define_method(:visit_my_spec_visitable) {}
28
+ end
29
+ end
30
+
31
+ after do
32
+ object.class_eval do
33
+ remove_instance_variable(:@handlers)
34
+ remove_method(:visit_my_spec_visitable)
35
+ end
36
+ end
37
+
38
+ it_should_behave_like 'an idempotent method'
39
+
40
+ it { should == :visit_my_spec_visitable }
41
+ end
42
+
43
+ context 'with an object handled by a private method' do
44
+ let(:visitable_class) { MySpec::Visitable }
45
+
46
+ before do
47
+ object.class_eval do
48
+ remove_instance_variable(:@handlers) if instance_variable_defined?(:@handlers)
49
+ define_method(:visit_my_spec_visitable) {}
50
+ private :visit_my_spec_visitable
51
+ end
52
+ end
53
+
54
+ after do
55
+ object.class_eval do
56
+ remove_instance_variable(:@handlers)
57
+ remove_method(:visit_my_spec_visitable)
58
+ end
59
+ end
60
+
61
+ it_should_behave_like 'an idempotent method'
62
+
63
+ it { should == :visit_my_spec_visitable }
64
+ end
65
+
66
+ context 'with an unhandled object' do
67
+ let(:visitable_class) { Class.new }
68
+
69
+ specify { expect { subject }.to raise_error(object::UnknownObject, "No handler for #{visitable_class} in #{object}") }
70
+ end
71
+ end
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe SQL::Generator::Visitor, '#visit' do
6
+ subject { object.visit(visitable) }
7
+
8
+ let(:visitable) { mock('handled object') }
9
+ let(:object) { described_class.new }
10
+
11
+ specify { expect { subject }.to raise_error(NotImplementedError, "#{described_class}#visit must be implemented") }
12
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe SQL::Generator::Visitor, '#visited?' do
6
+ subject { object.visited? }
7
+
8
+ let(:object) { described_class.new }
9
+
10
+ specify { expect { subject }.to raise_error(NotImplementedError, "#{described_class}#visited? must be implemented") }
11
+ end
@@ -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
@@ -0,0 +1,112 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe DateTime, '#iso8601' do
6
+
7
+ # ruby 1.9.3 has problems with fractional nanoseconds
8
+ def self.it_supports_nanoseconds(message = 'returns the expected date-time', &block)
9
+ if RUBY_VERSION >= '1.9.3'
10
+ it(message) { pending('Fix rounding error in 1.9.3', &block) }
11
+ else
12
+ it(message, &block)
13
+ end
14
+ end
15
+
16
+ let(:object) { described_class.new(2010, 12, 31, 23, 59, 59 + nsec_in_seconds) }
17
+ let(:nsec_in_seconds) { 1 - Rational(1, 10**9) }
18
+
19
+ context 'with no arguments' do
20
+ subject { object.iso8601 }
21
+
22
+ context 'when the datetime is frozen' do
23
+ before do
24
+ object.freeze
25
+ end
26
+
27
+ it { should respond_to(:to_s) }
28
+
29
+ it_supports_nanoseconds do
30
+ should == '2010-12-31T23:59:59+00:00'
31
+ end
32
+ end
33
+
34
+ context 'when the datetime is not frozen' do
35
+ it { should respond_to(:to_s) }
36
+
37
+ it { should == '2010-12-31T23:59:59+00:00' }
38
+ end
39
+ end
40
+
41
+ context 'with a time scale of 0' do
42
+ subject { object.iso8601(time_scale) }
43
+
44
+ let(:time_scale) { 0 }
45
+
46
+ context 'when the datetime is frozen' do
47
+ before do
48
+ object.freeze
49
+ end
50
+
51
+ it { should respond_to(:to_s) }
52
+
53
+ it_supports_nanoseconds do
54
+ should == '2010-12-31T23:59:59+00:00'
55
+ end
56
+ end
57
+
58
+ context 'when the datetime is not frozen' do
59
+ it { should respond_to(:to_s) }
60
+
61
+ it { should == '2010-12-31T23:59:59+00:00' }
62
+ end
63
+ end
64
+
65
+ context 'with a time scale of 1' do
66
+ subject { object.iso8601(time_scale) }
67
+
68
+ let(:time_scale) { 1 }
69
+
70
+ context 'when the datetime is frozen' do
71
+ before do
72
+ object.freeze
73
+ end
74
+
75
+ it { should respond_to(:to_s) }
76
+
77
+ it_supports_nanoseconds do
78
+ should == '2010-12-31T23:59:59.9+00:00'
79
+ end
80
+ end
81
+
82
+ context 'when the datetime is not frozen' do
83
+ it { should respond_to(:to_s) }
84
+
85
+ it { should == '2010-12-31T23:59:59.9+00:00' }
86
+ end
87
+ end
88
+
89
+ context 'with a time scale of 9' do
90
+ subject { object.iso8601(time_scale) }
91
+
92
+ let(:time_scale) { 9 }
93
+
94
+ context 'when the datetime is frozen' do
95
+ before do
96
+ object.freeze
97
+ end
98
+
99
+ it { should respond_to(:to_s) }
100
+
101
+ it_supports_nanoseconds do
102
+ should == '2010-12-31T23:59:59.999999999+00:00'
103
+ end
104
+ end
105
+
106
+ context 'when the datetime is not frozen' do
107
+ it { should respond_to(:to_s) }
108
+
109
+ it { should == '2010-12-31T23:59:59.999999999+00:00' }
110
+ end
111
+ end
112
+ end