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.
- checksums.yaml +7 -0
- data/.gemtest +0 -0
- data/.gitignore +37 -0
- data/.rspec +4 -0
- data/.rvmrc +1 -0
- data/.travis.yml +35 -0
- data/CONTRIBUTING.md +11 -0
- data/Gemfile +8 -0
- data/Gemfile.devtools +57 -0
- data/Guardfile +23 -0
- data/LICENSE +20 -0
- data/README.md +70 -0
- data/Rakefile +5 -0
- data/TODO +34 -0
- data/axiom-sql-generator.gemspec +25 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/mutant.yml +3 -0
- data/config/reek.yml +165 -0
- data/config/yardstick.yml +2 -0
- data/lib/axiom-sql-generator.rb +3 -0
- data/lib/axiom/sql/generator.rb +61 -0
- data/lib/axiom/sql/generator/attribute.rb +25 -0
- data/lib/axiom/sql/generator/core_ext/date.rb +20 -0
- data/lib/axiom/sql/generator/core_ext/date_time.rb +46 -0
- data/lib/axiom/sql/generator/direction.rb +38 -0
- data/lib/axiom/sql/generator/function.rb +55 -0
- data/lib/axiom/sql/generator/function/aggregate.rb +134 -0
- data/lib/axiom/sql/generator/function/connective.rb +53 -0
- data/lib/axiom/sql/generator/function/numeric.rb +135 -0
- data/lib/axiom/sql/generator/function/predicate.rb +266 -0
- data/lib/axiom/sql/generator/function/proposition.rb +38 -0
- data/lib/axiom/sql/generator/function/string.rb +29 -0
- data/lib/axiom/sql/generator/identifier.rb +28 -0
- data/lib/axiom/sql/generator/literal.rb +157 -0
- data/lib/axiom/sql/generator/relation.rb +240 -0
- data/lib/axiom/sql/generator/relation/base.rb +14 -0
- data/lib/axiom/sql/generator/relation/binary.rb +136 -0
- data/lib/axiom/sql/generator/relation/insertion.rb +62 -0
- data/lib/axiom/sql/generator/relation/materialized.rb +60 -0
- data/lib/axiom/sql/generator/relation/set.rb +107 -0
- data/lib/axiom/sql/generator/relation/unary.rb +379 -0
- data/lib/axiom/sql/generator/version.rb +12 -0
- data/lib/axiom/sql/generator/visitor.rb +121 -0
- data/spec/rcov.opts +7 -0
- data/spec/shared/generated_sql_behavior.rb +15 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/support/config_alias.rb +3 -0
- data/spec/unit/axiom/sql/generator/attribute/visit_axiom_attribute_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/class_methods/parenthesize_spec.rb +18 -0
- data/spec/unit/axiom/sql/generator/direction/visit_axiom_relation_operation_order_ascending_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/direction/visit_axiom_relation_operation_order_descending_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_count_spec.rb +16 -0
- data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_maximum_spec.rb +16 -0
- data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_mean_spec.rb +16 -0
- data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_minimum_spec.rb +16 -0
- data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_standard_deviation_spec.rb +16 -0
- data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_sum_spec.rb +16 -0
- data/spec/unit/axiom/sql/generator/function/aggregate/visit_axiom_aggregate_variance_spec.rb +16 -0
- data/spec/unit/axiom/sql/generator/function/connective/visit_axiom_function_connective_conjunction_spec.rb +20 -0
- data/spec/unit/axiom/sql/generator/function/connective/visit_axiom_function_connective_disjunction_spec.rb +20 -0
- data/spec/unit/axiom/sql/generator/function/connective/visit_axiom_function_connective_negation_spec.rb +20 -0
- data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_absolute_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_addition_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_division_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_exponentiation_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_modulo_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_multiplication_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_square_root_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_subtraction_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_unary_minus_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/numeric/visit_axiom_function_numeric_unary_plus_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_equality_spec.rb +27 -0
- data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_exclusion_spec.rb +47 -0
- data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_greater_than_or_equal_to_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_greater_than_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_inclusion_spec.rb +47 -0
- data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_inequality_spec.rb +55 -0
- data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_less_than_or_equal_to_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/predicate/visit_axiom_function_predicate_less_than_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/proposition/visit_axiom_function_proposition_contradiction_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/proposition/visit_axiom_function_proposition_tautology_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/function/string/visit_axiom_function_string_length_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/identifier/visit_identifier_spec.rb +26 -0
- data/spec/unit/axiom/sql/generator/literal/class_methods/dup_frozen_spec.rb +23 -0
- data/spec/unit/axiom/sql/generator/literal/visit_class_spec.rb +31 -0
- data/spec/unit/axiom/sql/generator/literal/visit_date_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/literal/visit_date_time_spec.rb +55 -0
- data/spec/unit/axiom/sql/generator/literal/visit_enumerable_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/literal/visit_false_class_spec.rb +14 -0
- data/spec/unit/axiom/sql/generator/literal/visit_nil_class_spec.rb +14 -0
- data/spec/unit/axiom/sql/generator/literal/visit_numeric_spec.rb +34 -0
- data/spec/unit/axiom/sql/generator/literal/visit_string_spec.rb +26 -0
- data/spec/unit/axiom/sql/generator/literal/visit_time_spec.rb +97 -0
- data/spec/unit/axiom/sql/generator/literal/visit_true_class_spec.rb +14 -0
- data/spec/unit/axiom/sql/generator/relation/binary/base/to_subquery_spec.rb +35 -0
- data/spec/unit/axiom/sql/generator/relation/binary/base/visit_axiom_relation_base_spec.rb +22 -0
- data/spec/unit/axiom/sql/generator/relation/binary/to_s_spec.rb +35 -0
- data/spec/unit/axiom/sql/generator/relation/binary/to_subquery_spec.rb +35 -0
- data/spec/unit/axiom/sql/generator/relation/binary/visit_axiom_algebra_join_spec.rb +179 -0
- data/spec/unit/axiom/sql/generator/relation/binary/visit_axiom_algebra_product_spec.rb +183 -0
- data/spec/unit/axiom/sql/generator/relation/class_methods/visit_spec.rb +71 -0
- data/spec/unit/axiom/sql/generator/relation/insertion/to_subquery_spec.rb +15 -0
- data/spec/unit/axiom/sql/generator/relation/insertion/visit_axiom_relation_operation_insertion_spec.rb +187 -0
- data/spec/unit/axiom/sql/generator/relation/materialized/visit_axiom_relation_materialized_spec.rb +28 -0
- data/spec/unit/axiom/sql/generator/relation/materialized/visited_spec.rb +26 -0
- data/spec/unit/axiom/sql/generator/relation/name_spec.rb +30 -0
- data/spec/unit/axiom/sql/generator/relation/set/class_methods/normalize_operand_headers_spec.rb +35 -0
- data/spec/unit/axiom/sql/generator/relation/set/to_s_spec.rb +55 -0
- data/spec/unit/axiom/sql/generator/relation/set/to_subquery_spec.rb +55 -0
- data/spec/unit/axiom/sql/generator/relation/set/visit_axiom_algebra_difference_spec.rb +191 -0
- data/spec/unit/axiom/sql/generator/relation/set/visit_axiom_algebra_intersection_spec.rb +188 -0
- data/spec/unit/axiom/sql/generator/relation/set/visit_axiom_algebra_union_spec.rb +188 -0
- data/spec/unit/axiom/sql/generator/relation/to_s_spec.rb +50 -0
- data/spec/unit/axiom/sql/generator/relation/to_sql_spec.rb +52 -0
- data/spec/unit/axiom/sql/generator/relation/to_subquery_spec.rb +49 -0
- data/spec/unit/axiom/sql/generator/relation/unary/to_s_spec.rb +55 -0
- data/spec/unit/axiom/sql/generator/relation/unary/to_subquery_spec.rb +75 -0
- data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_algebra_extension_spec.rb +165 -0
- data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_algebra_projection_spec.rb +193 -0
- data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_algebra_rename_spec.rb +178 -0
- data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_algebra_restriction_spec.rb +199 -0
- data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_algebra_summarization_spec.rb +652 -0
- data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_relation_base_spec.rb +21 -0
- data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_relation_operation_limit_spec.rb +165 -0
- data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_relation_operation_offset_spec.rb +165 -0
- data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_relation_operation_order_spec.rb +183 -0
- data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_relation_operation_reverse_spec.rb +165 -0
- data/spec/unit/axiom/sql/generator/relation/visit_spec.rb +54 -0
- data/spec/unit/axiom/sql/generator/relation/visited_spec.rb +35 -0
- data/spec/unit/axiom/sql/generator/visitor/class_methods/handler_for_spec.rb +71 -0
- data/spec/unit/axiom/sql/generator/visitor/visit_spec.rb +12 -0
- data/spec/unit/axiom/sql/generator/visitor/visited_spec.rb +11 -0
- data/spec/unit/date/iso8601_spec.rb +23 -0
- data/spec/unit/date_time/iso8601_spec.rb +112 -0
- metadata +325 -0
data/spec/unit/axiom/sql/generator/relation/unary/visit_axiom_relation_operation_reverse_spec.rb
ADDED
|
@@ -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
|