viking-sequel 3.10.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.
- data/CHANGELOG +3134 -0
- data/COPYING +19 -0
- data/README.rdoc +723 -0
- data/Rakefile +193 -0
- data/bin/sequel +196 -0
- data/doc/advanced_associations.rdoc +644 -0
- data/doc/cheat_sheet.rdoc +218 -0
- data/doc/dataset_basics.rdoc +106 -0
- data/doc/dataset_filtering.rdoc +158 -0
- data/doc/opening_databases.rdoc +296 -0
- data/doc/prepared_statements.rdoc +104 -0
- data/doc/reflection.rdoc +84 -0
- data/doc/release_notes/1.0.txt +38 -0
- data/doc/release_notes/1.1.txt +143 -0
- data/doc/release_notes/1.3.txt +101 -0
- data/doc/release_notes/1.4.0.txt +53 -0
- data/doc/release_notes/1.5.0.txt +155 -0
- data/doc/release_notes/2.0.0.txt +298 -0
- data/doc/release_notes/2.1.0.txt +271 -0
- data/doc/release_notes/2.10.0.txt +328 -0
- data/doc/release_notes/2.11.0.txt +215 -0
- data/doc/release_notes/2.12.0.txt +534 -0
- data/doc/release_notes/2.2.0.txt +253 -0
- data/doc/release_notes/2.3.0.txt +88 -0
- data/doc/release_notes/2.4.0.txt +106 -0
- data/doc/release_notes/2.5.0.txt +137 -0
- data/doc/release_notes/2.6.0.txt +157 -0
- data/doc/release_notes/2.7.0.txt +166 -0
- data/doc/release_notes/2.8.0.txt +171 -0
- data/doc/release_notes/2.9.0.txt +97 -0
- data/doc/release_notes/3.0.0.txt +221 -0
- data/doc/release_notes/3.1.0.txt +406 -0
- data/doc/release_notes/3.10.0.txt +286 -0
- data/doc/release_notes/3.2.0.txt +268 -0
- data/doc/release_notes/3.3.0.txt +192 -0
- data/doc/release_notes/3.4.0.txt +325 -0
- data/doc/release_notes/3.5.0.txt +510 -0
- data/doc/release_notes/3.6.0.txt +366 -0
- data/doc/release_notes/3.7.0.txt +179 -0
- data/doc/release_notes/3.8.0.txt +151 -0
- data/doc/release_notes/3.9.0.txt +233 -0
- data/doc/schema.rdoc +36 -0
- data/doc/sharding.rdoc +113 -0
- data/doc/virtual_rows.rdoc +205 -0
- data/lib/sequel.rb +1 -0
- data/lib/sequel/adapters/ado.rb +90 -0
- data/lib/sequel/adapters/ado/mssql.rb +30 -0
- data/lib/sequel/adapters/amalgalite.rb +176 -0
- data/lib/sequel/adapters/db2.rb +139 -0
- data/lib/sequel/adapters/dbi.rb +113 -0
- data/lib/sequel/adapters/do.rb +188 -0
- data/lib/sequel/adapters/do/mysql.rb +49 -0
- data/lib/sequel/adapters/do/postgres.rb +91 -0
- data/lib/sequel/adapters/do/sqlite.rb +40 -0
- data/lib/sequel/adapters/firebird.rb +283 -0
- data/lib/sequel/adapters/informix.rb +77 -0
- data/lib/sequel/adapters/jdbc.rb +587 -0
- data/lib/sequel/adapters/jdbc/as400.rb +58 -0
- data/lib/sequel/adapters/jdbc/h2.rb +133 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +57 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +78 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +50 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +108 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +55 -0
- data/lib/sequel/adapters/mysql.rb +421 -0
- data/lib/sequel/adapters/odbc.rb +143 -0
- data/lib/sequel/adapters/odbc/mssql.rb +42 -0
- data/lib/sequel/adapters/openbase.rb +64 -0
- data/lib/sequel/adapters/oracle.rb +131 -0
- data/lib/sequel/adapters/postgres.rb +504 -0
- data/lib/sequel/adapters/shared/mssql.rb +490 -0
- data/lib/sequel/adapters/shared/mysql.rb +498 -0
- data/lib/sequel/adapters/shared/oracle.rb +195 -0
- data/lib/sequel/adapters/shared/postgres.rb +830 -0
- data/lib/sequel/adapters/shared/progress.rb +44 -0
- data/lib/sequel/adapters/shared/sqlite.rb +389 -0
- data/lib/sequel/adapters/sqlite.rb +224 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +84 -0
- data/lib/sequel/connection_pool.rb +99 -0
- data/lib/sequel/connection_pool/sharded_single.rb +84 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +211 -0
- data/lib/sequel/connection_pool/single.rb +29 -0
- data/lib/sequel/connection_pool/threaded.rb +150 -0
- data/lib/sequel/core.rb +293 -0
- data/lib/sequel/core_sql.rb +241 -0
- data/lib/sequel/database.rb +1079 -0
- data/lib/sequel/database/schema_generator.rb +327 -0
- data/lib/sequel/database/schema_methods.rb +203 -0
- data/lib/sequel/database/schema_sql.rb +320 -0
- data/lib/sequel/dataset.rb +32 -0
- data/lib/sequel/dataset/actions.rb +441 -0
- data/lib/sequel/dataset/features.rb +86 -0
- data/lib/sequel/dataset/graph.rb +254 -0
- data/lib/sequel/dataset/misc.rb +119 -0
- data/lib/sequel/dataset/mutation.rb +64 -0
- data/lib/sequel/dataset/prepared_statements.rb +227 -0
- data/lib/sequel/dataset/query.rb +709 -0
- data/lib/sequel/dataset/sql.rb +996 -0
- data/lib/sequel/exceptions.rb +51 -0
- data/lib/sequel/extensions/blank.rb +43 -0
- data/lib/sequel/extensions/inflector.rb +242 -0
- data/lib/sequel/extensions/looser_typecasting.rb +21 -0
- data/lib/sequel/extensions/migration.rb +239 -0
- data/lib/sequel/extensions/named_timezones.rb +61 -0
- data/lib/sequel/extensions/pagination.rb +100 -0
- data/lib/sequel/extensions/pretty_table.rb +82 -0
- data/lib/sequel/extensions/query.rb +52 -0
- data/lib/sequel/extensions/schema_dumper.rb +271 -0
- data/lib/sequel/extensions/sql_expr.rb +122 -0
- data/lib/sequel/extensions/string_date_time.rb +46 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +48 -0
- data/lib/sequel/metaprogramming.rb +9 -0
- data/lib/sequel/model.rb +120 -0
- data/lib/sequel/model/associations.rb +1514 -0
- data/lib/sequel/model/base.rb +1069 -0
- data/lib/sequel/model/default_inflections.rb +45 -0
- data/lib/sequel/model/errors.rb +39 -0
- data/lib/sequel/model/exceptions.rb +21 -0
- data/lib/sequel/model/inflections.rb +162 -0
- data/lib/sequel/model/plugins.rb +70 -0
- data/lib/sequel/plugins/active_model.rb +59 -0
- data/lib/sequel/plugins/association_dependencies.rb +103 -0
- data/lib/sequel/plugins/association_proxies.rb +41 -0
- data/lib/sequel/plugins/boolean_readers.rb +53 -0
- data/lib/sequel/plugins/caching.rb +141 -0
- data/lib/sequel/plugins/class_table_inheritance.rb +214 -0
- data/lib/sequel/plugins/composition.rb +138 -0
- data/lib/sequel/plugins/force_encoding.rb +72 -0
- data/lib/sequel/plugins/hook_class_methods.rb +126 -0
- data/lib/sequel/plugins/identity_map.rb +116 -0
- data/lib/sequel/plugins/instance_filters.rb +98 -0
- data/lib/sequel/plugins/instance_hooks.rb +57 -0
- data/lib/sequel/plugins/lazy_attributes.rb +77 -0
- data/lib/sequel/plugins/many_through_many.rb +208 -0
- data/lib/sequel/plugins/nested_attributes.rb +206 -0
- data/lib/sequel/plugins/optimistic_locking.rb +81 -0
- data/lib/sequel/plugins/rcte_tree.rb +281 -0
- data/lib/sequel/plugins/schema.rb +66 -0
- data/lib/sequel/plugins/serialization.rb +166 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +74 -0
- data/lib/sequel/plugins/subclasses.rb +45 -0
- data/lib/sequel/plugins/tactical_eager_loading.rb +61 -0
- data/lib/sequel/plugins/timestamps.rb +87 -0
- data/lib/sequel/plugins/touch.rb +118 -0
- data/lib/sequel/plugins/typecast_on_load.rb +72 -0
- data/lib/sequel/plugins/validation_class_methods.rb +405 -0
- data/lib/sequel/plugins/validation_helpers.rb +223 -0
- data/lib/sequel/sql.rb +1020 -0
- data/lib/sequel/timezones.rb +161 -0
- data/lib/sequel/version.rb +12 -0
- data/lib/sequel_core.rb +1 -0
- data/lib/sequel_model.rb +1 -0
- data/spec/adapters/firebird_spec.rb +407 -0
- data/spec/adapters/informix_spec.rb +97 -0
- data/spec/adapters/mssql_spec.rb +403 -0
- data/spec/adapters/mysql_spec.rb +1019 -0
- data/spec/adapters/oracle_spec.rb +286 -0
- data/spec/adapters/postgres_spec.rb +969 -0
- data/spec/adapters/spec_helper.rb +51 -0
- data/spec/adapters/sqlite_spec.rb +432 -0
- data/spec/core/connection_pool_spec.rb +808 -0
- data/spec/core/core_sql_spec.rb +417 -0
- data/spec/core/database_spec.rb +1662 -0
- data/spec/core/dataset_spec.rb +3827 -0
- data/spec/core/expression_filters_spec.rb +595 -0
- data/spec/core/object_graph_spec.rb +296 -0
- data/spec/core/schema_generator_spec.rb +159 -0
- data/spec/core/schema_spec.rb +830 -0
- data/spec/core/spec_helper.rb +56 -0
- data/spec/core/version_spec.rb +7 -0
- data/spec/extensions/active_model_spec.rb +76 -0
- data/spec/extensions/association_dependencies_spec.rb +127 -0
- data/spec/extensions/association_proxies_spec.rb +50 -0
- data/spec/extensions/blank_spec.rb +67 -0
- data/spec/extensions/boolean_readers_spec.rb +92 -0
- data/spec/extensions/caching_spec.rb +250 -0
- data/spec/extensions/class_table_inheritance_spec.rb +252 -0
- data/spec/extensions/composition_spec.rb +194 -0
- data/spec/extensions/force_encoding_spec.rb +117 -0
- data/spec/extensions/hook_class_methods_spec.rb +470 -0
- data/spec/extensions/identity_map_spec.rb +202 -0
- data/spec/extensions/inflector_spec.rb +181 -0
- data/spec/extensions/instance_filters_spec.rb +55 -0
- data/spec/extensions/instance_hooks_spec.rb +133 -0
- data/spec/extensions/lazy_attributes_spec.rb +153 -0
- data/spec/extensions/looser_typecasting_spec.rb +39 -0
- data/spec/extensions/many_through_many_spec.rb +884 -0
- data/spec/extensions/migration_spec.rb +332 -0
- data/spec/extensions/named_timezones_spec.rb +72 -0
- data/spec/extensions/nested_attributes_spec.rb +396 -0
- data/spec/extensions/optimistic_locking_spec.rb +100 -0
- data/spec/extensions/pagination_spec.rb +99 -0
- data/spec/extensions/pretty_table_spec.rb +91 -0
- data/spec/extensions/query_spec.rb +85 -0
- data/spec/extensions/rcte_tree_spec.rb +205 -0
- data/spec/extensions/schema_dumper_spec.rb +357 -0
- data/spec/extensions/schema_spec.rb +127 -0
- data/spec/extensions/serialization_spec.rb +209 -0
- data/spec/extensions/single_table_inheritance_spec.rb +96 -0
- data/spec/extensions/spec_helper.rb +91 -0
- data/spec/extensions/sql_expr_spec.rb +89 -0
- data/spec/extensions/string_date_time_spec.rb +93 -0
- data/spec/extensions/subclasses_spec.rb +52 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +65 -0
- data/spec/extensions/thread_local_timezones_spec.rb +45 -0
- data/spec/extensions/timestamps_spec.rb +150 -0
- data/spec/extensions/touch_spec.rb +155 -0
- data/spec/extensions/typecast_on_load_spec.rb +69 -0
- data/spec/extensions/validation_class_methods_spec.rb +984 -0
- data/spec/extensions/validation_helpers_spec.rb +438 -0
- data/spec/integration/associations_test.rb +281 -0
- data/spec/integration/database_test.rb +26 -0
- data/spec/integration/dataset_test.rb +963 -0
- data/spec/integration/eager_loader_test.rb +734 -0
- data/spec/integration/model_test.rb +130 -0
- data/spec/integration/plugin_test.rb +814 -0
- data/spec/integration/prepared_statement_test.rb +213 -0
- data/spec/integration/schema_test.rb +361 -0
- data/spec/integration/spec_helper.rb +73 -0
- data/spec/integration/timezone_test.rb +55 -0
- data/spec/integration/transaction_test.rb +122 -0
- data/spec/integration/type_test.rb +96 -0
- data/spec/model/association_reflection_spec.rb +175 -0
- data/spec/model/associations_spec.rb +2633 -0
- data/spec/model/base_spec.rb +418 -0
- data/spec/model/dataset_methods_spec.rb +78 -0
- data/spec/model/eager_loading_spec.rb +1391 -0
- data/spec/model/hooks_spec.rb +240 -0
- data/spec/model/inflector_spec.rb +26 -0
- data/spec/model/model_spec.rb +593 -0
- data/spec/model/plugins_spec.rb +236 -0
- data/spec/model/record_spec.rb +1500 -0
- data/spec/model/spec_helper.rb +97 -0
- data/spec/model/validations_spec.rb +153 -0
- data/spec/rcov.opts +6 -0
- data/spec/spec_config.rb.example +10 -0
- metadata +346 -0
@@ -0,0 +1,417 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
context "Array#all_two_pairs?" do
|
4
|
+
specify "should return false if empty" do
|
5
|
+
[].all_two_pairs?.should == false
|
6
|
+
end
|
7
|
+
|
8
|
+
specify "should return false if any of the elements is not an array" do
|
9
|
+
[1].all_two_pairs?.should == false
|
10
|
+
[[1,2],1].all_two_pairs?.should == false
|
11
|
+
end
|
12
|
+
|
13
|
+
specify "should return false if any of the elements has a length other than two" do
|
14
|
+
[[1,2],[]].all_two_pairs?.should == false
|
15
|
+
[[1,2],[1]].all_two_pairs?.should == false
|
16
|
+
[[1,2],[1,2,3]].all_two_pairs?.should == false
|
17
|
+
end
|
18
|
+
|
19
|
+
specify "should return true if all of the elements are arrays with a length of two" do
|
20
|
+
[[1,2]].all_two_pairs?.should == true
|
21
|
+
[[1,2],[1,2]].all_two_pairs?.should == true
|
22
|
+
[[1,2],[1,2],[1,2]].all_two_pairs?.should == true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "Array#case and Hash#case" do
|
27
|
+
before do
|
28
|
+
@d = Sequel::Dataset.new(nil)
|
29
|
+
end
|
30
|
+
|
31
|
+
specify "should return SQL CASE expression" do
|
32
|
+
@d.literal({:x=>:y}.case(:z)).should == '(CASE WHEN x THEN y ELSE z END)'
|
33
|
+
@d.literal({:x=>:y}.case(:z, :exp)).should == '(CASE exp WHEN x THEN y ELSE z END)'
|
34
|
+
['(CASE WHEN x THEN y WHEN a THEN b ELSE z END)',
|
35
|
+
'(CASE WHEN a THEN b WHEN x THEN y ELSE z END)'].should(include(@d.literal({:x=>:y, :a=>:b}.case(:z))))
|
36
|
+
@d.literal([[:x, :y]].case(:z)).should == '(CASE WHEN x THEN y ELSE z END)'
|
37
|
+
@d.literal([[:x, :y], [:a, :b]].case(:z)).should == '(CASE WHEN x THEN y WHEN a THEN b ELSE z END)'
|
38
|
+
@d.literal([[:x, :y], [:a, :b]].case(:z, :exp)).should == '(CASE exp WHEN x THEN y WHEN a THEN b ELSE z END)'
|
39
|
+
@d.literal([[:x, :y], [:a, :b]].case(:z, :exp__w)).should == '(CASE exp.w WHEN x THEN y WHEN a THEN b ELSE z END)'
|
40
|
+
end
|
41
|
+
|
42
|
+
specify "should raise an error if an array that isn't all two pairs is used" do
|
43
|
+
proc{[:b].case(:a)}.should raise_error(Sequel::Error)
|
44
|
+
proc{[:b, :c].case(:a)}.should raise_error(Sequel::Error)
|
45
|
+
proc{[[:b, :c], :d].case(:a)}.should raise_error(Sequel::Error)
|
46
|
+
end
|
47
|
+
|
48
|
+
specify "should raise an error if an empty array/hash is used" do
|
49
|
+
proc{[].case(:a)}.should raise_error(Sequel::Error)
|
50
|
+
proc{{}.case(:a)}.should raise_error(Sequel::Error)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "Array#sql_array" do
|
55
|
+
before do
|
56
|
+
@d = Sequel::Dataset.new(nil)
|
57
|
+
end
|
58
|
+
|
59
|
+
specify "should treat the array as an SQL array instead of conditions" do
|
60
|
+
@d.literal([[:x, 1], [:y, 2]]).should == '((x = 1) AND (y = 2))'
|
61
|
+
@d.literal([[:x, 1], [:y, 2]].sql_array).should == '((x, 1), (y, 2))'
|
62
|
+
@d.filter([:a, :b]=>[[:x, 1], [:y, 2]].sql_array).sql.should == 'SELECT * WHERE ((a, b) IN ((x, 1), (y, 2)))'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context "String#lit" do
|
67
|
+
specify "should return an LiteralString object" do
|
68
|
+
'xyz'.lit.should be_a_kind_of(Sequel::LiteralString)
|
69
|
+
'xyz'.lit.to_s.should == 'xyz'
|
70
|
+
end
|
71
|
+
|
72
|
+
specify "should inhibit string literalization" do
|
73
|
+
Sequel::Database.new[:t].update_sql(:stamp => "NOW()".lit).should == \
|
74
|
+
"UPDATE t SET stamp = NOW()"
|
75
|
+
end
|
76
|
+
|
77
|
+
specify "should return a PlaceholderLiteralString object if args are given" do
|
78
|
+
a = 'DISTINCT ?'.lit(:a)
|
79
|
+
a.should be_a_kind_of(Sequel::SQL::PlaceholderLiteralString)
|
80
|
+
ds = MockDatabase.new.dataset
|
81
|
+
ds.literal(a).should == 'DISTINCT a'
|
82
|
+
ds.quote_identifiers = true
|
83
|
+
ds.literal(a).should == 'DISTINCT "a"'
|
84
|
+
end
|
85
|
+
|
86
|
+
specify "should handle named placeholders if given a single argument hash" do
|
87
|
+
a = 'DISTINCT :b'.lit(:b=>:a)
|
88
|
+
a.should be_a_kind_of(Sequel::SQL::PlaceholderLiteralString)
|
89
|
+
ds = MockDatabase.new.dataset
|
90
|
+
ds.literal(a).should == 'DISTINCT a'
|
91
|
+
ds.quote_identifiers = true
|
92
|
+
ds.literal(a).should == 'DISTINCT "a"'
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "String#to_sequel_blob" do
|
97
|
+
specify "should return a Blob object" do
|
98
|
+
'xyz'.to_sequel_blob.should be_a_kind_of(::Sequel::SQL::Blob)
|
99
|
+
'xyz'.to_sequel_blob.should == 'xyz'
|
100
|
+
end
|
101
|
+
|
102
|
+
specify "should retain binary data" do
|
103
|
+
"\1\2\3\4".to_sequel_blob.should == "\1\2\3\4"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context "#desc" do
|
108
|
+
before do
|
109
|
+
@ds = Sequel::Dataset.new(nil)
|
110
|
+
end
|
111
|
+
|
112
|
+
specify "should format a DESC clause for a column ref" do
|
113
|
+
:test.desc.to_s(@ds).should == 'test DESC'
|
114
|
+
|
115
|
+
:items__price.desc.to_s(@ds).should == 'items.price DESC'
|
116
|
+
end
|
117
|
+
|
118
|
+
specify "should format a DESC clause for a function" do
|
119
|
+
:avg.sql_function(:test).desc.to_s(@ds).should == 'avg(test) DESC'
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context "#asc" do
|
124
|
+
before do
|
125
|
+
@ds = Sequel::Dataset.new(nil)
|
126
|
+
end
|
127
|
+
|
128
|
+
specify "should format a ASC clause for a column ref" do
|
129
|
+
:test.asc.to_s(@ds).should == 'test ASC'
|
130
|
+
|
131
|
+
:items__price.asc.to_s(@ds).should == 'items.price ASC'
|
132
|
+
end
|
133
|
+
|
134
|
+
specify "should format a ASC clause for a function" do
|
135
|
+
:avg.sql_function(:test).asc.to_s(@ds).should == 'avg(test) ASC'
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context "#as" do
|
140
|
+
before do
|
141
|
+
@ds = Sequel::Dataset.new(nil)
|
142
|
+
end
|
143
|
+
|
144
|
+
specify "should format a AS clause for a column ref" do
|
145
|
+
:test.as(:t).to_s(@ds).should == 'test AS t'
|
146
|
+
|
147
|
+
:items__price.as(:p).to_s(@ds).should == 'items.price AS p'
|
148
|
+
end
|
149
|
+
|
150
|
+
specify "should format a AS clause for a function" do
|
151
|
+
:avg.sql_function(:test).as(:avg).to_s(@ds).should == 'avg(test) AS avg'
|
152
|
+
end
|
153
|
+
|
154
|
+
specify "should format a AS clause for a literal value" do
|
155
|
+
'abc'.as(:abc).to_s(@ds).should == "'abc' AS abc"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context "Column references" do
|
160
|
+
before do
|
161
|
+
@c = Class.new(Sequel::Dataset) do
|
162
|
+
def quoted_identifier(c); "`#{c}`"; end
|
163
|
+
end
|
164
|
+
@ds = @c.new(MockDatabase.new)
|
165
|
+
@ds.quote_identifiers = true
|
166
|
+
end
|
167
|
+
|
168
|
+
specify "should be quoted properly" do
|
169
|
+
@ds.literal(:xyz).should == "`xyz`"
|
170
|
+
@ds.literal(:xyz__abc).should == "`xyz`.`abc`"
|
171
|
+
|
172
|
+
@ds.literal(:xyz.as(:x)).should == "`xyz` AS `x`"
|
173
|
+
@ds.literal(:xyz__abc.as(:x)).should == "`xyz`.`abc` AS `x`"
|
174
|
+
|
175
|
+
@ds.literal(:xyz___x).should == "`xyz` AS `x`"
|
176
|
+
@ds.literal(:xyz__abc___x).should == "`xyz`.`abc` AS `x`"
|
177
|
+
end
|
178
|
+
|
179
|
+
specify "should be quoted properly in SQL functions" do
|
180
|
+
@ds.literal(:avg.sql_function(:xyz)).should == "avg(`xyz`)"
|
181
|
+
@ds.literal(:avg.sql_function(:xyz, 1)).should == "avg(`xyz`, 1)"
|
182
|
+
@ds.literal(:avg.sql_function(:xyz).as(:a)).should == "avg(`xyz`) AS `a`"
|
183
|
+
end
|
184
|
+
|
185
|
+
specify "should be quoted properly in ASC/DESC clauses" do
|
186
|
+
@ds.literal(:xyz.asc).should == "`xyz` ASC"
|
187
|
+
@ds.literal(:avg.sql_function(:xyz, 1).desc).should == "avg(`xyz`, 1) DESC"
|
188
|
+
end
|
189
|
+
|
190
|
+
specify "should be quoted properly in a cast function" do
|
191
|
+
@ds.literal(:x.cast(:integer)).should == "CAST(`x` AS integer)"
|
192
|
+
@ds.literal(:x__y.cast('varchar(20)')).should == "CAST(`x`.`y` AS varchar(20))"
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
context "Blob" do
|
197
|
+
specify "#to_sequel_blob should return self" do
|
198
|
+
blob = "x".to_sequel_blob
|
199
|
+
blob.to_sequel_blob.object_id.should == blob.object_id
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
if RUBY_VERSION < '1.9.0'
|
204
|
+
context "Symbol#[]" do
|
205
|
+
specify "should format an SQL Function" do
|
206
|
+
ds = Sequel::Dataset.new(nil)
|
207
|
+
ds.literal(:xyz[]).should == 'xyz()'
|
208
|
+
ds.literal(:xyz[1]).should == 'xyz(1)'
|
209
|
+
ds.literal(:xyz[1, 2, :abc[3]]).should == 'xyz(1, 2, abc(3))'
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
context "Symbol#*" do
|
215
|
+
before do
|
216
|
+
@ds = Sequel::Dataset.new(nil)
|
217
|
+
end
|
218
|
+
|
219
|
+
specify "should format a qualified wildcard if no argument" do
|
220
|
+
:xyz.*.to_s(@ds).should == 'xyz.*'
|
221
|
+
:abc.*.to_s(@ds).should == 'abc.*'
|
222
|
+
end
|
223
|
+
|
224
|
+
specify "should format a filter expression if an argument" do
|
225
|
+
:xyz.*(3).to_s(@ds).should == '(xyz * 3)'
|
226
|
+
:abc.*(5).to_s(@ds).should == '(abc * 5)'
|
227
|
+
end
|
228
|
+
|
229
|
+
specify "should support qualified symbols if no argument" do
|
230
|
+
:xyz__abc.*.to_s(@ds).should == 'xyz.abc.*'
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
context "Symbol" do
|
235
|
+
before do
|
236
|
+
@ds = Sequel::Dataset.new(nil)
|
237
|
+
@ds.quote_identifiers = true
|
238
|
+
@ds.identifier_input_method = :upcase
|
239
|
+
end
|
240
|
+
|
241
|
+
specify "#identifier should format an identifier" do
|
242
|
+
@ds.literal(:xyz__abc.identifier).should == '"XYZ__ABC"'
|
243
|
+
end
|
244
|
+
|
245
|
+
specify "#qualify should format a qualified column" do
|
246
|
+
@ds.literal(:xyz.qualify(:abc)).should == '"ABC"."XYZ"'
|
247
|
+
end
|
248
|
+
|
249
|
+
specify "#qualify should work on QualifiedIdentifiers" do
|
250
|
+
@ds.literal(:xyz.qualify(:abc).qualify(:def)).should == '"DEF"."ABC"."XYZ"'
|
251
|
+
end
|
252
|
+
|
253
|
+
specify "should be able to qualify an identifier" do
|
254
|
+
@ds.literal(:xyz.identifier.qualify(:xyz__abc)).should == '"XYZ"."ABC"."XYZ"'
|
255
|
+
end
|
256
|
+
|
257
|
+
specify "should be able to specify a schema.table.column" do
|
258
|
+
@ds.literal(:column.qualify(:table.qualify(:schema))).should == '"SCHEMA"."TABLE"."COLUMN"'
|
259
|
+
@ds.literal(:column.qualify(:table__name.identifier.qualify(:schema))).should == '"SCHEMA"."TABLE__NAME"."COLUMN"'
|
260
|
+
end
|
261
|
+
|
262
|
+
specify "should be able to specify order" do
|
263
|
+
@oe = :xyz.desc
|
264
|
+
@oe.class.should == Sequel::SQL::OrderedExpression
|
265
|
+
@oe.descending.should == true
|
266
|
+
@oe = :xyz.asc
|
267
|
+
@oe.class.should == Sequel::SQL::OrderedExpression
|
268
|
+
@oe.descending.should == false
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
context "Dataset#literal" do
|
273
|
+
before do
|
274
|
+
@ds = MockDataset.new(nil)
|
275
|
+
end
|
276
|
+
|
277
|
+
specify "should convert qualified symbol notation into dot notation" do
|
278
|
+
@ds.literal(:abc__def).should == 'abc.def'
|
279
|
+
end
|
280
|
+
|
281
|
+
specify "should convert AS symbol notation into SQL AS notation" do
|
282
|
+
@ds.literal(:xyz___x).should == 'xyz AS x'
|
283
|
+
@ds.literal(:abc__def___x).should == 'abc.def AS x'
|
284
|
+
end
|
285
|
+
|
286
|
+
specify "should support names with digits" do
|
287
|
+
@ds.literal(:abc2).should == 'abc2'
|
288
|
+
@ds.literal(:xx__yy3).should == 'xx.yy3'
|
289
|
+
@ds.literal(:ab34__temp3_4ax).should == 'ab34.temp3_4ax'
|
290
|
+
@ds.literal(:x1___y2).should == 'x1 AS y2'
|
291
|
+
@ds.literal(:abc2__def3___ggg4).should == 'abc2.def3 AS ggg4'
|
292
|
+
end
|
293
|
+
|
294
|
+
specify "should support upper case and lower case" do
|
295
|
+
@ds.literal(:ABC).should == 'ABC'
|
296
|
+
@ds.literal(:Zvashtoy__aBcD).should == 'Zvashtoy.aBcD'
|
297
|
+
end
|
298
|
+
|
299
|
+
specify "should support spaces inside column names" do
|
300
|
+
@ds.quote_identifiers = true
|
301
|
+
@ds.literal(:"AB C").should == '"AB C"'
|
302
|
+
@ds.literal(:"Zvas htoy__aB cD").should == '"Zvas htoy"."aB cD"'
|
303
|
+
@ds.literal(:"aB cD___XX XX").should == '"aB cD" AS "XX XX"'
|
304
|
+
@ds.literal(:"Zva shtoy__aB cD___XX XX").should == '"Zva shtoy"."aB cD" AS "XX XX"'
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
context "Symbol" do
|
309
|
+
before do
|
310
|
+
@ds = Sequel::Dataset.new(MockDatabase.new)
|
311
|
+
end
|
312
|
+
|
313
|
+
specify "should support upper case outer functions" do
|
314
|
+
:COUNT.sql_function('1').to_s(@ds).should == "COUNT('1')"
|
315
|
+
end
|
316
|
+
|
317
|
+
specify "should inhibit string literalization" do
|
318
|
+
db = Sequel::Database.new
|
319
|
+
ds = db[:t]
|
320
|
+
ds.select(:COUNT.sql_function('1')).sql.should == "SELECT COUNT('1') FROM t"
|
321
|
+
end
|
322
|
+
|
323
|
+
specify "should support cast method" do
|
324
|
+
:abc.cast(:integer).to_s(@ds).should == "CAST(abc AS integer)"
|
325
|
+
end
|
326
|
+
|
327
|
+
specify "should support sql array accesses via sql_subscript" do
|
328
|
+
@ds.literal(:abc.sql_subscript(1)).should == "abc[1]"
|
329
|
+
@ds.literal(:abc__def.sql_subscript(1)).should == "abc.def[1]"
|
330
|
+
@ds.literal(:abc.sql_subscript(1)|2).should == "abc[1, 2]"
|
331
|
+
end
|
332
|
+
|
333
|
+
specify "should support cast_numeric and cast_string" do
|
334
|
+
x = :abc.cast_numeric
|
335
|
+
x.should be_a_kind_of(Sequel::SQL::NumericExpression)
|
336
|
+
x.to_s(@ds).should == "CAST(abc AS integer)"
|
337
|
+
|
338
|
+
x = :abc.cast_numeric(:real)
|
339
|
+
x.should be_a_kind_of(Sequel::SQL::NumericExpression)
|
340
|
+
x.to_s(@ds).should == "CAST(abc AS real)"
|
341
|
+
|
342
|
+
x = :abc.cast_string
|
343
|
+
x.should be_a_kind_of(Sequel::SQL::StringExpression)
|
344
|
+
x.to_s(@ds).should == "CAST(abc AS varchar(255))"
|
345
|
+
|
346
|
+
x = :abc.cast_string(:varchar)
|
347
|
+
x.should be_a_kind_of(Sequel::SQL::StringExpression)
|
348
|
+
x.to_s(@ds).should == "CAST(abc AS varchar(255))"
|
349
|
+
end
|
350
|
+
|
351
|
+
specify "should allow database independent types when casting" do
|
352
|
+
m = MockDatabase.new
|
353
|
+
m.instance_eval do
|
354
|
+
def cast_type_literal(type)
|
355
|
+
return :foo if type == Integer
|
356
|
+
return :bar if type == String
|
357
|
+
type
|
358
|
+
end
|
359
|
+
end
|
360
|
+
@ds2 = Sequel::Dataset.new(m)
|
361
|
+
:abc.cast(String).to_s(@ds).should == "CAST(abc AS varchar(255))"
|
362
|
+
:abc.cast(String).to_s(@ds2).should == "CAST(abc AS bar)"
|
363
|
+
:abc.cast(String).to_s(@ds2).should == "CAST(abc AS bar)"
|
364
|
+
:abc.cast_string.to_s(@ds2).should == "CAST(abc AS bar)"
|
365
|
+
:abc.cast_string(Integer).to_s(@ds2).should == "CAST(abc AS foo)"
|
366
|
+
:abc.cast_numeric.to_s(@ds2).should == "CAST(abc AS foo)"
|
367
|
+
:abc.cast_numeric(String).to_s(@ds2).should == "CAST(abc AS bar)"
|
368
|
+
end
|
369
|
+
|
370
|
+
specify "should support SQL EXTRACT function via #extract " do
|
371
|
+
:abc.extract(:year).to_s(@ds).should == "extract(year FROM abc)"
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
context "Sequel::SQL::Function#==" do
|
376
|
+
specify "should be true for functions with the same name and arguments, false otherwise" do
|
377
|
+
a = :date.sql_function(:t)
|
378
|
+
b = :date.sql_function(:t)
|
379
|
+
a.should == b
|
380
|
+
(a == b).should == true
|
381
|
+
c = :date.sql_function(:c)
|
382
|
+
a.should_not == c
|
383
|
+
(a == c).should == false
|
384
|
+
d = :time.sql_function(:c)
|
385
|
+
a.should_not == d
|
386
|
+
c.should_not == d
|
387
|
+
(a == d).should == false
|
388
|
+
(c == d).should == false
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
context "Sequel::SQL::OrderedExpression" do
|
393
|
+
specify "should #desc" do
|
394
|
+
@oe = :column.asc
|
395
|
+
@oe.descending.should == false
|
396
|
+
@oe.desc.descending.should == true
|
397
|
+
end
|
398
|
+
|
399
|
+
specify "should #asc" do
|
400
|
+
@oe = :column.desc
|
401
|
+
@oe.descending.should == true
|
402
|
+
@oe.asc.descending.should == false
|
403
|
+
end
|
404
|
+
|
405
|
+
specify "should #invert" do
|
406
|
+
@oe = :column.desc
|
407
|
+
@oe.invert.descending.should == false
|
408
|
+
@oe.invert.invert.descending.should == true
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
context "Expression" do
|
413
|
+
specify "should ==" do
|
414
|
+
:column.qualify(:table).cast(:type).*(:numeric_column).asc.should == :column.qualify(:table).cast(:type).*(:numeric_column).asc
|
415
|
+
:other_column.qualify(:table).cast(:type).*(:numeric_column).asc.should_not == :column.qualify(:table).cast(:type).*(:numeric_column).asc
|
416
|
+
end
|
417
|
+
end
|
@@ -0,0 +1,1662 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
context "A new Database" do
|
4
|
+
before do
|
5
|
+
@db = Sequel::Database.new(1 => 2, :logger => 3)
|
6
|
+
end
|
7
|
+
after do
|
8
|
+
Sequel.quote_identifiers = false
|
9
|
+
Sequel.identifier_input_method = nil
|
10
|
+
Sequel.identifier_output_method = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
specify "should receive options" do
|
14
|
+
@db.opts[1].should == 2
|
15
|
+
@db.opts[:logger].should == 3
|
16
|
+
end
|
17
|
+
|
18
|
+
specify "should set the logger from opts[:logger] and opts[:loggers]" do
|
19
|
+
@db.loggers.should == [3]
|
20
|
+
Sequel::Database.new(1 => 2, :loggers => 3).loggers.should == [3]
|
21
|
+
Sequel::Database.new(1 => 2, :loggers => [3]).loggers.should == [3]
|
22
|
+
Sequel::Database.new(1 => 2, :logger => 4, :loggers => 3).loggers.should == [4,3]
|
23
|
+
Sequel::Database.new(1 => 2, :logger => [4], :loggers => [3]).loggers.should == [4,3]
|
24
|
+
end
|
25
|
+
|
26
|
+
specify "should create a connection pool" do
|
27
|
+
@db.pool.should be_a_kind_of(Sequel::ConnectionPool)
|
28
|
+
@db.pool.max_size.should == 4
|
29
|
+
|
30
|
+
Sequel::Database.new(:max_connections => 10).pool.max_size.should == 10
|
31
|
+
end
|
32
|
+
|
33
|
+
specify "should pass the supplied block to the connection pool" do
|
34
|
+
cc = nil
|
35
|
+
d = Sequel::Database.new {1234}
|
36
|
+
d.synchronize {|c| cc = c}
|
37
|
+
cc.should == 1234
|
38
|
+
end
|
39
|
+
|
40
|
+
specify "should respect the :single_threaded option" do
|
41
|
+
db = Sequel::Database.new(:single_threaded=>true){123}
|
42
|
+
db.pool.should be_a_kind_of(Sequel::SingleConnectionPool)
|
43
|
+
db = Sequel::Database.new(:single_threaded=>'t'){123}
|
44
|
+
db.pool.should be_a_kind_of(Sequel::SingleConnectionPool)
|
45
|
+
db = Sequel::Database.new(:single_threaded=>'1'){123}
|
46
|
+
db.pool.should be_a_kind_of(Sequel::SingleConnectionPool)
|
47
|
+
db = Sequel::Database.new(:single_threaded=>false){123}
|
48
|
+
db.pool.should be_a_kind_of(Sequel::ConnectionPool)
|
49
|
+
db = Sequel::Database.new(:single_threaded=>'f'){123}
|
50
|
+
db.pool.should be_a_kind_of(Sequel::ConnectionPool)
|
51
|
+
db = Sequel::Database.new(:single_threaded=>'0'){123}
|
52
|
+
db.pool.should be_a_kind_of(Sequel::ConnectionPool)
|
53
|
+
end
|
54
|
+
|
55
|
+
specify "should respect the :quote_identifiers option" do
|
56
|
+
db = Sequel::Database.new(:quote_identifiers=>false)
|
57
|
+
db.quote_identifiers?.should == false
|
58
|
+
db = Sequel::Database.new(:quote_identifiers=>true)
|
59
|
+
db.quote_identifiers?.should == true
|
60
|
+
end
|
61
|
+
|
62
|
+
specify "should upcase on input and downcase on output by default" do
|
63
|
+
db = Sequel::Database.new
|
64
|
+
db.send(:identifier_input_method_default).should == :upcase
|
65
|
+
db.send(:identifier_output_method_default).should == :downcase
|
66
|
+
end
|
67
|
+
|
68
|
+
specify "should respect the :identifier_input_method option" do
|
69
|
+
Sequel.identifier_input_method = nil
|
70
|
+
Sequel::Database.identifier_input_method.should == ""
|
71
|
+
db = Sequel::Database.new(:identifier_input_method=>nil)
|
72
|
+
db.identifier_input_method.should == nil
|
73
|
+
db.identifier_input_method = :downcase
|
74
|
+
db.identifier_input_method.should == :downcase
|
75
|
+
db = Sequel::Database.new(:identifier_input_method=>:upcase)
|
76
|
+
db.identifier_input_method.should == :upcase
|
77
|
+
db.identifier_input_method = nil
|
78
|
+
db.identifier_input_method.should == nil
|
79
|
+
Sequel.identifier_input_method = :downcase
|
80
|
+
Sequel::Database.identifier_input_method.should == :downcase
|
81
|
+
db = Sequel::Database.new(:identifier_input_method=>nil)
|
82
|
+
db.identifier_input_method.should == nil
|
83
|
+
db.identifier_input_method = :upcase
|
84
|
+
db.identifier_input_method.should == :upcase
|
85
|
+
db = Sequel::Database.new(:identifier_input_method=>:upcase)
|
86
|
+
db.identifier_input_method.should == :upcase
|
87
|
+
db.identifier_input_method = nil
|
88
|
+
db.identifier_input_method.should == nil
|
89
|
+
end
|
90
|
+
|
91
|
+
specify "should respect the :identifier_output_method option" do
|
92
|
+
Sequel.identifier_output_method = nil
|
93
|
+
Sequel::Database.identifier_output_method.should == ""
|
94
|
+
db = Sequel::Database.new(:identifier_output_method=>nil)
|
95
|
+
db.identifier_output_method.should == nil
|
96
|
+
db.identifier_output_method = :downcase
|
97
|
+
db.identifier_output_method.should == :downcase
|
98
|
+
db = Sequel::Database.new(:identifier_output_method=>:upcase)
|
99
|
+
db.identifier_output_method.should == :upcase
|
100
|
+
db.identifier_output_method = nil
|
101
|
+
db.identifier_output_method.should == nil
|
102
|
+
Sequel.identifier_output_method = :downcase
|
103
|
+
Sequel::Database.identifier_output_method.should == :downcase
|
104
|
+
db = Sequel::Database.new(:identifier_output_method=>nil)
|
105
|
+
db.identifier_output_method.should == nil
|
106
|
+
db.identifier_output_method = :upcase
|
107
|
+
db.identifier_output_method.should == :upcase
|
108
|
+
db = Sequel::Database.new(:identifier_output_method=>:upcase)
|
109
|
+
db.identifier_output_method.should == :upcase
|
110
|
+
db.identifier_output_method = nil
|
111
|
+
db.identifier_output_method.should == nil
|
112
|
+
end
|
113
|
+
|
114
|
+
specify "should use the default Sequel.quote_identifiers value" do
|
115
|
+
Sequel.quote_identifiers = true
|
116
|
+
Sequel::Database.new({}).quote_identifiers?.should == true
|
117
|
+
Sequel.quote_identifiers = false
|
118
|
+
Sequel::Database.new({}).quote_identifiers?.should == false
|
119
|
+
Sequel::Database.quote_identifiers = true
|
120
|
+
Sequel::Database.new({}).quote_identifiers?.should == true
|
121
|
+
Sequel::Database.quote_identifiers = false
|
122
|
+
Sequel::Database.new({}).quote_identifiers?.should == false
|
123
|
+
end
|
124
|
+
|
125
|
+
specify "should use the default Sequel.identifier_input_method value" do
|
126
|
+
Sequel.identifier_input_method = :downcase
|
127
|
+
Sequel::Database.new({}).identifier_input_method.should == :downcase
|
128
|
+
Sequel.identifier_input_method = :upcase
|
129
|
+
Sequel::Database.new({}).identifier_input_method.should == :upcase
|
130
|
+
Sequel::Database.identifier_input_method = :downcase
|
131
|
+
Sequel::Database.new({}).identifier_input_method.should == :downcase
|
132
|
+
Sequel::Database.identifier_input_method = :upcase
|
133
|
+
Sequel::Database.new({}).identifier_input_method.should == :upcase
|
134
|
+
end
|
135
|
+
|
136
|
+
specify "should use the default Sequel.identifier_output_method value" do
|
137
|
+
Sequel.identifier_output_method = :downcase
|
138
|
+
Sequel::Database.new({}).identifier_output_method.should == :downcase
|
139
|
+
Sequel.identifier_output_method = :upcase
|
140
|
+
Sequel::Database.new({}).identifier_output_method.should == :upcase
|
141
|
+
Sequel::Database.identifier_output_method = :downcase
|
142
|
+
Sequel::Database.new({}).identifier_output_method.should == :downcase
|
143
|
+
Sequel::Database.identifier_output_method = :upcase
|
144
|
+
Sequel::Database.new({}).identifier_output_method.should == :upcase
|
145
|
+
end
|
146
|
+
|
147
|
+
specify "should respect the quote_indentifiers_default method if Sequel.quote_identifiers = nil" do
|
148
|
+
Sequel.quote_identifiers = nil
|
149
|
+
Sequel::Database.new({}).quote_identifiers?.should == true
|
150
|
+
x = Class.new(Sequel::Database){def quote_identifiers_default; false end}
|
151
|
+
x.new({}).quote_identifiers?.should == false
|
152
|
+
y = Class.new(Sequel::Database){def quote_identifiers_default; true end}
|
153
|
+
y.new({}).quote_identifiers?.should == true
|
154
|
+
end
|
155
|
+
|
156
|
+
specify "should respect the identifier_input_method_default method" do
|
157
|
+
class Sequel::Database
|
158
|
+
@@identifier_input_method = nil
|
159
|
+
end
|
160
|
+
x = Class.new(Sequel::Database){def identifier_input_method_default; :downcase end}
|
161
|
+
x.new({}).identifier_input_method.should == :downcase
|
162
|
+
y = Class.new(Sequel::Database){def identifier_input_method_default; :camelize end}
|
163
|
+
y.new({}).identifier_input_method.should == :camelize
|
164
|
+
end
|
165
|
+
|
166
|
+
specify "should respect the identifier_output_method_default method if Sequel.identifier_output_method is not called" do
|
167
|
+
class Sequel::Database
|
168
|
+
@@identifier_output_method = nil
|
169
|
+
end
|
170
|
+
x = Class.new(Sequel::Database){def identifier_output_method_default; :upcase end}
|
171
|
+
x.new({}).identifier_output_method.should == :upcase
|
172
|
+
y = Class.new(Sequel::Database){def identifier_output_method_default; :underscore end}
|
173
|
+
y.new({}).identifier_output_method.should == :underscore
|
174
|
+
end
|
175
|
+
|
176
|
+
specify "should just use a :uri option for jdbc with the full connection string" do
|
177
|
+
Sequel::Database.should_receive(:adapter_class).once.with(:jdbc).and_return(Sequel::Database)
|
178
|
+
db = Sequel.connect('jdbc:test://host/db_name')
|
179
|
+
db.should be_a_kind_of(Sequel::Database)
|
180
|
+
db.opts[:uri].should == 'jdbc:test://host/db_name'
|
181
|
+
end
|
182
|
+
|
183
|
+
specify "should just use a :uri option for do with the full connection string" do
|
184
|
+
Sequel::Database.should_receive(:adapter_class).once.with(:do).and_return(Sequel::Database)
|
185
|
+
db = Sequel.connect('do:test://host/db_name')
|
186
|
+
db.should be_a_kind_of(Sequel::Database)
|
187
|
+
db.opts[:uri].should == 'do:test://host/db_name'
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context "Database#disconnect" do
|
192
|
+
specify "should call pool.disconnect" do
|
193
|
+
d = Sequel::Database.new
|
194
|
+
p = d.pool
|
195
|
+
p.should_receive(:disconnect).once.with({}).and_return(2)
|
196
|
+
d.disconnect.should == 2
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
context "Sequel.extension" do
|
201
|
+
specify "should attempt to load the given extension" do
|
202
|
+
proc{Sequel.extension :blah}.should raise_error(LoadError)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
context "Database#connect" do
|
207
|
+
specify "should raise NotImplementedError" do
|
208
|
+
proc {Sequel::Database.new.connect(:default)}.should raise_error(NotImplementedError)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
context "Database#log_info" do
|
213
|
+
before do
|
214
|
+
@o = Object.new
|
215
|
+
def @o.logs; @logs || []; end
|
216
|
+
def @o.method_missing(*args); (@logs ||= []) << args; end
|
217
|
+
@db = Sequel::Database.new(:logger=>@o)
|
218
|
+
end
|
219
|
+
|
220
|
+
specify "should log message at info level to all loggers" do
|
221
|
+
@db.log_info('blah')
|
222
|
+
@o.logs.should == [[:info, 'blah']]
|
223
|
+
end
|
224
|
+
|
225
|
+
specify "should log message with args at info level to all loggers" do
|
226
|
+
@db.log_info('blah', [1, 2])
|
227
|
+
@o.logs.should == [[:info, 'blah; [1, 2]']]
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
context "Database#log_yield" do
|
232
|
+
before do
|
233
|
+
@o = Object.new
|
234
|
+
def @o.logs; @logs || []; end
|
235
|
+
def @o.warn(*args); (@logs ||= []) << [:warn] + args; end
|
236
|
+
def @o.method_missing(*args); (@logs ||= []) << args; end
|
237
|
+
@db = Sequel::Database.new(:logger=>@o)
|
238
|
+
end
|
239
|
+
|
240
|
+
specify "should yield to the passed block" do
|
241
|
+
a = nil
|
242
|
+
@db.log_yield('blah'){a = 1}
|
243
|
+
a.should == 1
|
244
|
+
end
|
245
|
+
|
246
|
+
specify "should raise an exception if a block is not passed" do
|
247
|
+
proc{@db.log_yield('blah')}.should raise_error
|
248
|
+
end
|
249
|
+
|
250
|
+
specify "should log message with duration at info level to all loggers" do
|
251
|
+
@db.log_yield('blah'){}
|
252
|
+
@o.logs.length.should == 1
|
253
|
+
@o.logs.first.length.should == 2
|
254
|
+
@o.logs.first.first.should == :info
|
255
|
+
@o.logs.first.last.should =~ /\A\(\d\.\d{6}s\) blah\z/
|
256
|
+
end
|
257
|
+
|
258
|
+
specify "should log message with duration at warn level if duration greater than log_warn_duration" do
|
259
|
+
@db.log_warn_duration = 0
|
260
|
+
@db.log_yield('blah'){}
|
261
|
+
@o.logs.length.should == 1
|
262
|
+
@o.logs.first.length.should == 2
|
263
|
+
@o.logs.first.first.should == :warn
|
264
|
+
@o.logs.first.last.should =~ /\A\(\d\.\d{6}s\) blah\z/
|
265
|
+
end
|
266
|
+
|
267
|
+
specify "should log message with duration at info level if duration less than log_warn_duration" do
|
268
|
+
@db.log_warn_duration = 1000
|
269
|
+
@db.log_yield('blah'){}
|
270
|
+
@o.logs.length.should == 1
|
271
|
+
@o.logs.first.length.should == 2
|
272
|
+
@o.logs.first.first.should == :info
|
273
|
+
@o.logs.first.last.should =~ /\A\(\d\.\d{6}s\) blah\z/
|
274
|
+
end
|
275
|
+
|
276
|
+
specify "should log message at error level if block raises an error" do
|
277
|
+
@db.log_warn_duration = 0
|
278
|
+
proc{@db.log_yield('blah'){raise Sequel::Error, 'adsf'}}.should raise_error
|
279
|
+
@o.logs.length.should == 1
|
280
|
+
@o.logs.first.length.should == 2
|
281
|
+
@o.logs.first.first.should == :error
|
282
|
+
@o.logs.first.last.should =~ /\ASequel::Error: adsf: blah\z/
|
283
|
+
end
|
284
|
+
|
285
|
+
specify "should include args with message if args passed" do
|
286
|
+
@db.log_yield('blah', [1, 2]){}
|
287
|
+
@o.logs.length.should == 1
|
288
|
+
@o.logs.first.length.should == 2
|
289
|
+
@o.logs.first.first.should == :info
|
290
|
+
@o.logs.first.last.should =~ /\A\(\d\.\d{6}s\) blah; \[1, 2\]\z/
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
context "Database#uri" do
|
295
|
+
before do
|
296
|
+
@c = Class.new(Sequel::Database) do
|
297
|
+
set_adapter_scheme :mau
|
298
|
+
end
|
299
|
+
|
300
|
+
@db = Sequel.connect('mau://user:pass@localhost:9876/maumau')
|
301
|
+
end
|
302
|
+
|
303
|
+
specify "should return the connection URI for the database" do
|
304
|
+
@db.uri.should == 'mau://user:pass@localhost:9876/maumau'
|
305
|
+
end
|
306
|
+
|
307
|
+
specify "should be aliased as #url" do
|
308
|
+
@db.url.should == 'mau://user:pass@localhost:9876/maumau'
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
context "Database.adapter_scheme" do
|
313
|
+
specify "should return the database schema" do
|
314
|
+
Sequel::Database.adapter_scheme.should be_nil
|
315
|
+
|
316
|
+
@c = Class.new(Sequel::Database) do
|
317
|
+
set_adapter_scheme :mau
|
318
|
+
end
|
319
|
+
|
320
|
+
@c.adapter_scheme.should == :mau
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
context "Database#dataset" do
|
325
|
+
before do
|
326
|
+
@db = Sequel::Database.new
|
327
|
+
@ds = @db.dataset
|
328
|
+
end
|
329
|
+
|
330
|
+
specify "should provide a blank dataset through #dataset" do
|
331
|
+
@ds.should be_a_kind_of(Sequel::Dataset)
|
332
|
+
@ds.opts.should == {}
|
333
|
+
@ds.db.should be(@db)
|
334
|
+
end
|
335
|
+
|
336
|
+
specify "should provide a #from dataset" do
|
337
|
+
d = @db.from(:mau)
|
338
|
+
d.should be_a_kind_of(Sequel::Dataset)
|
339
|
+
d.sql.should == 'SELECT * FROM mau'
|
340
|
+
|
341
|
+
e = @db[:miu]
|
342
|
+
e.should be_a_kind_of(Sequel::Dataset)
|
343
|
+
e.sql.should == 'SELECT * FROM miu'
|
344
|
+
end
|
345
|
+
|
346
|
+
specify "should provide a filtered #from dataset if a block is given" do
|
347
|
+
d = @db.from(:mau) {:x.sql_number > 100}
|
348
|
+
d.should be_a_kind_of(Sequel::Dataset)
|
349
|
+
d.sql.should == 'SELECT * FROM mau WHERE (x > 100)'
|
350
|
+
end
|
351
|
+
|
352
|
+
specify "should provide a #select dataset" do
|
353
|
+
d = @db.select(:a, :b, :c).from(:mau)
|
354
|
+
d.should be_a_kind_of(Sequel::Dataset)
|
355
|
+
d.sql.should == 'SELECT a, b, c FROM mau'
|
356
|
+
end
|
357
|
+
|
358
|
+
specify "should allow #select to take a block" do
|
359
|
+
d = @db.select(:a, :b){c}.from(:mau)
|
360
|
+
d.should be_a_kind_of(Sequel::Dataset)
|
361
|
+
d.sql.should == 'SELECT a, b, c FROM mau'
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
context "Database#execute" do
|
366
|
+
specify "should raise NotImplementedError" do
|
367
|
+
proc {Sequel::Database.new.execute('blah blah')}.should raise_error(NotImplementedError)
|
368
|
+
proc {Sequel::Database.new << 'blah blah'}.should raise_error(NotImplementedError)
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
context "Database#<< and run" do
|
373
|
+
before do
|
374
|
+
sqls = @sqls = []
|
375
|
+
@c = Class.new(Sequel::Database) do
|
376
|
+
define_method(:execute_ddl){|sql, *opts| sqls.clear; sqls << sql; sqls.concat(opts)}
|
377
|
+
end
|
378
|
+
@db = @c.new({})
|
379
|
+
end
|
380
|
+
|
381
|
+
specify "should pass the supplied sql to #execute_ddl" do
|
382
|
+
(@db << "DELETE FROM items")
|
383
|
+
@sqls.should == ["DELETE FROM items", {}]
|
384
|
+
@db.run("DELETE FROM items2")
|
385
|
+
@sqls.should == ["DELETE FROM items2", {}]
|
386
|
+
end
|
387
|
+
|
388
|
+
specify "should return nil" do
|
389
|
+
(@db << "DELETE FROM items").should == nil
|
390
|
+
@db.run("DELETE FROM items").should == nil
|
391
|
+
end
|
392
|
+
|
393
|
+
specify "should accept options passed to execute_ddl" do
|
394
|
+
@db.run("DELETE FROM items", :server=>:s1)
|
395
|
+
@sqls.should == ["DELETE FROM items", {:server=>:s1}]
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
context "Database#synchronize" do
|
400
|
+
before do
|
401
|
+
@db = Sequel::Database.new(:max_connections => 1){12345}
|
402
|
+
end
|
403
|
+
|
404
|
+
specify "should wrap the supplied block in pool.hold" do
|
405
|
+
stop = false
|
406
|
+
c1, c2 = nil
|
407
|
+
t1 = Thread.new {@db.synchronize {|c| c1 = c; while !stop;sleep 0.1;end}}
|
408
|
+
while !c1;end
|
409
|
+
c1.should == 12345
|
410
|
+
t2 = Thread.new {@db.synchronize {|c| c2 = c}}
|
411
|
+
sleep 0.2
|
412
|
+
@db.pool.available_connections.should be_empty
|
413
|
+
c2.should be_nil
|
414
|
+
stop = true
|
415
|
+
t1.join
|
416
|
+
sleep 0.1
|
417
|
+
c2.should == 12345
|
418
|
+
t2.join
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
context "Database#test_connection" do
|
423
|
+
before do
|
424
|
+
@db = Sequel::Database.new{@test = rand(100)}
|
425
|
+
end
|
426
|
+
|
427
|
+
specify "should pool#hold" do
|
428
|
+
@db.test_connection
|
429
|
+
@test.should_not be_nil
|
430
|
+
end
|
431
|
+
|
432
|
+
specify "should return true if successful" do
|
433
|
+
@db.test_connection.should be_true
|
434
|
+
end
|
435
|
+
|
436
|
+
specify "should raise an error if the attempting to connect raises an error" do
|
437
|
+
proc{Sequel::Database.new{raise Sequel::Error, 'blah'}.test_connection}.should raise_error(Sequel::Error)
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
class DummyDataset < Sequel::Dataset
|
442
|
+
def first
|
443
|
+
raise if @opts[:from] == [:a]
|
444
|
+
true
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
class DummyDatabase < Sequel::Database
|
449
|
+
attr_reader :sqls
|
450
|
+
|
451
|
+
def execute(sql, opts={})
|
452
|
+
@sqls ||= []
|
453
|
+
@sqls << sql
|
454
|
+
end
|
455
|
+
|
456
|
+
def transaction; yield; end
|
457
|
+
|
458
|
+
def dataset
|
459
|
+
DummyDataset.new(self)
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
context "Database#create_table" do
|
464
|
+
before do
|
465
|
+
@db = DummyDatabase.new
|
466
|
+
end
|
467
|
+
|
468
|
+
specify "should construct proper SQL" do
|
469
|
+
@db.create_table :test do
|
470
|
+
primary_key :id, :integer, :null => false
|
471
|
+
column :name, :text
|
472
|
+
index :name, :unique => true
|
473
|
+
end
|
474
|
+
@db.sqls.should == [
|
475
|
+
'CREATE TABLE test (id integer NOT NULL PRIMARY KEY AUTOINCREMENT, name text)',
|
476
|
+
'CREATE UNIQUE INDEX test_name_index ON test (name)'
|
477
|
+
]
|
478
|
+
end
|
479
|
+
|
480
|
+
specify "should create a temporary table" do
|
481
|
+
@db.create_table :test_tmp, :temp => true do
|
482
|
+
primary_key :id, :integer, :null => false
|
483
|
+
column :name, :text
|
484
|
+
index :name, :unique => true
|
485
|
+
end
|
486
|
+
|
487
|
+
@db.sqls.should == [
|
488
|
+
'CREATE TEMPORARY TABLE test_tmp (id integer NOT NULL PRIMARY KEY AUTOINCREMENT, name text)',
|
489
|
+
'CREATE UNIQUE INDEX test_tmp_name_index ON test_tmp (name)'
|
490
|
+
]
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
context "Database#alter_table" do
|
495
|
+
before do
|
496
|
+
@db = DummyDatabase.new
|
497
|
+
end
|
498
|
+
|
499
|
+
specify "should construct proper SQL" do
|
500
|
+
@db.alter_table :xyz do
|
501
|
+
add_column :aaa, :text, :null => false, :unique => true
|
502
|
+
drop_column :bbb
|
503
|
+
rename_column :ccc, :ddd
|
504
|
+
set_column_type :eee, :integer
|
505
|
+
set_column_default :hhh, 'abcd'
|
506
|
+
|
507
|
+
add_index :fff, :unique => true
|
508
|
+
drop_index :ggg
|
509
|
+
end
|
510
|
+
|
511
|
+
@db.sqls.should == [
|
512
|
+
'ALTER TABLE xyz ADD COLUMN aaa text UNIQUE NOT NULL',
|
513
|
+
'ALTER TABLE xyz DROP COLUMN bbb',
|
514
|
+
'ALTER TABLE xyz RENAME COLUMN ccc TO ddd',
|
515
|
+
'ALTER TABLE xyz ALTER COLUMN eee TYPE integer',
|
516
|
+
"ALTER TABLE xyz ALTER COLUMN hhh SET DEFAULT 'abcd'",
|
517
|
+
|
518
|
+
'CREATE UNIQUE INDEX xyz_fff_index ON xyz (fff)',
|
519
|
+
'DROP INDEX xyz_ggg_index'
|
520
|
+
]
|
521
|
+
end
|
522
|
+
end
|
523
|
+
|
524
|
+
context "Database#add_column" do
|
525
|
+
before do
|
526
|
+
@db = DummyDatabase.new
|
527
|
+
end
|
528
|
+
|
529
|
+
specify "should construct proper SQL" do
|
530
|
+
@db.add_column :test, :name, :text, :unique => true
|
531
|
+
@db.sqls.should == [
|
532
|
+
'ALTER TABLE test ADD COLUMN name text UNIQUE'
|
533
|
+
]
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
context "Database#drop_column" do
|
538
|
+
before do
|
539
|
+
@db = DummyDatabase.new
|
540
|
+
end
|
541
|
+
|
542
|
+
specify "should construct proper SQL" do
|
543
|
+
@db.drop_column :test, :name
|
544
|
+
@db.sqls.should == [
|
545
|
+
'ALTER TABLE test DROP COLUMN name'
|
546
|
+
]
|
547
|
+
end
|
548
|
+
end
|
549
|
+
|
550
|
+
context "Database#rename_column" do
|
551
|
+
before do
|
552
|
+
@db = DummyDatabase.new
|
553
|
+
end
|
554
|
+
|
555
|
+
specify "should construct proper SQL" do
|
556
|
+
@db.rename_column :test, :abc, :def
|
557
|
+
@db.sqls.should == [
|
558
|
+
'ALTER TABLE test RENAME COLUMN abc TO def'
|
559
|
+
]
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
context "Database#set_column_type" do
|
564
|
+
before do
|
565
|
+
@db = DummyDatabase.new
|
566
|
+
end
|
567
|
+
|
568
|
+
specify "should construct proper SQL" do
|
569
|
+
@db.set_column_type :test, :name, :integer
|
570
|
+
@db.sqls.should == [
|
571
|
+
'ALTER TABLE test ALTER COLUMN name TYPE integer'
|
572
|
+
]
|
573
|
+
end
|
574
|
+
end
|
575
|
+
|
576
|
+
context "Database#set_column_default" do
|
577
|
+
before do
|
578
|
+
@db = DummyDatabase.new
|
579
|
+
end
|
580
|
+
|
581
|
+
specify "should construct proper SQL" do
|
582
|
+
@db.set_column_default :test, :name, 'zyx'
|
583
|
+
@db.sqls.should == [
|
584
|
+
"ALTER TABLE test ALTER COLUMN name SET DEFAULT 'zyx'"
|
585
|
+
]
|
586
|
+
end
|
587
|
+
end
|
588
|
+
|
589
|
+
context "Database#add_index" do
|
590
|
+
before do
|
591
|
+
@db = DummyDatabase.new
|
592
|
+
end
|
593
|
+
|
594
|
+
specify "should construct proper SQL" do
|
595
|
+
@db.add_index :test, :name, :unique => true
|
596
|
+
@db.sqls.should == [
|
597
|
+
'CREATE UNIQUE INDEX test_name_index ON test (name)'
|
598
|
+
]
|
599
|
+
end
|
600
|
+
|
601
|
+
specify "should accept multiple columns" do
|
602
|
+
@db.add_index :test, [:one, :two]
|
603
|
+
@db.sqls.should == [
|
604
|
+
'CREATE INDEX test_one_two_index ON test (one, two)'
|
605
|
+
]
|
606
|
+
end
|
607
|
+
end
|
608
|
+
|
609
|
+
context "Database#drop_index" do
|
610
|
+
before do
|
611
|
+
@db = DummyDatabase.new
|
612
|
+
end
|
613
|
+
|
614
|
+
specify "should construct proper SQL" do
|
615
|
+
@db.drop_index :test, :name
|
616
|
+
@db.sqls.should == [
|
617
|
+
'DROP INDEX test_name_index'
|
618
|
+
]
|
619
|
+
end
|
620
|
+
|
621
|
+
end
|
622
|
+
|
623
|
+
class Dummy2Database < Sequel::Database
|
624
|
+
attr_reader :sql
|
625
|
+
def execute(sql); @sql = sql; end
|
626
|
+
def transaction; yield; end
|
627
|
+
end
|
628
|
+
|
629
|
+
context "Database#drop_table" do
|
630
|
+
before do
|
631
|
+
@db = DummyDatabase.new
|
632
|
+
end
|
633
|
+
|
634
|
+
specify "should construct proper SQL" do
|
635
|
+
@db.drop_table :test
|
636
|
+
@db.sqls.should == ['DROP TABLE test']
|
637
|
+
end
|
638
|
+
|
639
|
+
specify "should accept multiple table names" do
|
640
|
+
@db.drop_table :a, :bb, :ccc
|
641
|
+
@db.sqls.should == [
|
642
|
+
'DROP TABLE a',
|
643
|
+
'DROP TABLE bb',
|
644
|
+
'DROP TABLE ccc'
|
645
|
+
]
|
646
|
+
end
|
647
|
+
end
|
648
|
+
|
649
|
+
context "Database#rename_table" do
|
650
|
+
before do
|
651
|
+
@db = DummyDatabase.new
|
652
|
+
end
|
653
|
+
|
654
|
+
specify "should construct proper SQL" do
|
655
|
+
@db.rename_table :abc, :xyz
|
656
|
+
@db.sqls.should == ['ALTER TABLE abc RENAME TO xyz']
|
657
|
+
end
|
658
|
+
end
|
659
|
+
|
660
|
+
context "Database#table_exists?" do
|
661
|
+
specify "should try to select the first record from the table's dataset" do
|
662
|
+
db2 = DummyDatabase.new
|
663
|
+
db2.table_exists?(:a).should be_false
|
664
|
+
db2.table_exists?(:b).should be_true
|
665
|
+
end
|
666
|
+
end
|
667
|
+
|
668
|
+
class Dummy3Database < Sequel::Database
|
669
|
+
attr_reader :sql, :transactions
|
670
|
+
def execute(sql, opts={}); @sql ||= []; @sql << sql; end
|
671
|
+
|
672
|
+
class DummyConnection
|
673
|
+
def initialize(db); @db = db; end
|
674
|
+
def execute(sql); @db.execute(sql); end
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|
678
|
+
context "Database#transaction" do
|
679
|
+
before do
|
680
|
+
@db = Dummy3Database.new{Dummy3Database::DummyConnection.new(@db)}
|
681
|
+
end
|
682
|
+
|
683
|
+
specify "should wrap the supplied block with BEGIN + COMMIT statements" do
|
684
|
+
@db.transaction {@db.execute 'DROP TABLE test;'}
|
685
|
+
@db.sql.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
|
686
|
+
end
|
687
|
+
|
688
|
+
specify "should handle returning inside of the block by committing" do
|
689
|
+
def @db.ret_commit
|
690
|
+
transaction do
|
691
|
+
execute 'DROP TABLE test;'
|
692
|
+
return
|
693
|
+
execute 'DROP TABLE test2;';
|
694
|
+
end
|
695
|
+
end
|
696
|
+
@db.ret_commit
|
697
|
+
@db.sql.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
|
698
|
+
end
|
699
|
+
|
700
|
+
specify "should issue ROLLBACK if an exception is raised, and re-raise" do
|
701
|
+
@db.transaction {@db.execute 'DROP TABLE test'; raise RuntimeError} rescue nil
|
702
|
+
@db.sql.should == ['BEGIN', 'DROP TABLE test', 'ROLLBACK']
|
703
|
+
|
704
|
+
proc {@db.transaction {raise RuntimeError}}.should raise_error(RuntimeError)
|
705
|
+
end
|
706
|
+
|
707
|
+
specify "should issue ROLLBACK if Sequel::Rollback is called in the transaction" do
|
708
|
+
@db.transaction do
|
709
|
+
@db.drop_table(:a)
|
710
|
+
raise Sequel::Rollback
|
711
|
+
@db.drop_table(:b)
|
712
|
+
end
|
713
|
+
|
714
|
+
@db.sql.should == ['BEGIN', 'DROP TABLE a', 'ROLLBACK']
|
715
|
+
end
|
716
|
+
|
717
|
+
specify "should raise database errors when commiting a transaction as Sequel::DatabaseError" do
|
718
|
+
@db.meta_def(:commit_transaction){raise ArgumentError}
|
719
|
+
lambda{@db.transaction{}}.should raise_error(ArgumentError)
|
720
|
+
|
721
|
+
@db.meta_def(:database_error_classes){[ArgumentError]}
|
722
|
+
lambda{@db.transaction{}}.should raise_error(Sequel::DatabaseError)
|
723
|
+
end
|
724
|
+
|
725
|
+
specify "should be re-entrant" do
|
726
|
+
stop = false
|
727
|
+
cc = nil
|
728
|
+
t = Thread.new do
|
729
|
+
@db.transaction {@db.transaction {@db.transaction {|c|
|
730
|
+
cc = c
|
731
|
+
while !stop; sleep 0.1; end
|
732
|
+
}}}
|
733
|
+
end
|
734
|
+
while cc.nil?; sleep 0.1; end
|
735
|
+
cc.should be_a_kind_of(Dummy3Database::DummyConnection)
|
736
|
+
@db.transactions.should == [t]
|
737
|
+
stop = true
|
738
|
+
t.join
|
739
|
+
@db.transactions.should be_empty
|
740
|
+
end
|
741
|
+
end
|
742
|
+
|
743
|
+
context "Database#transaction with savepoints" do
|
744
|
+
before do
|
745
|
+
@db = Dummy3Database.new{Dummy3Database::DummyConnection.new(@db)}
|
746
|
+
@db.meta_def(:supports_savepoints?){true}
|
747
|
+
end
|
748
|
+
|
749
|
+
specify "should wrap the supplied block with BEGIN + COMMIT statements" do
|
750
|
+
@db.transaction {@db.execute 'DROP TABLE test;'}
|
751
|
+
@db.sql.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
|
752
|
+
end
|
753
|
+
|
754
|
+
specify "should use savepoints if given the :savepoint option" do
|
755
|
+
@db.transaction{@db.transaction(:savepoint=>true){@db.execute 'DROP TABLE test;'}}
|
756
|
+
@db.sql.should == ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
|
757
|
+
end
|
758
|
+
|
759
|
+
specify "should not use a savepoints if no transaction is in progress" do
|
760
|
+
@db.transaction(:savepoint=>true){@db.execute 'DROP TABLE test;'}
|
761
|
+
@db.sql.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
|
762
|
+
end
|
763
|
+
|
764
|
+
specify "should reuse the current transaction if no :savepoint option is given" do
|
765
|
+
@db.transaction{@db.transaction{@db.execute 'DROP TABLE test;'}}
|
766
|
+
@db.sql.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
|
767
|
+
end
|
768
|
+
|
769
|
+
specify "should handle returning inside of the block by committing" do
|
770
|
+
def @db.ret_commit
|
771
|
+
transaction do
|
772
|
+
execute 'DROP TABLE test;'
|
773
|
+
return
|
774
|
+
execute 'DROP TABLE test2;';
|
775
|
+
end
|
776
|
+
end
|
777
|
+
@db.ret_commit
|
778
|
+
@db.sql.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
|
779
|
+
end
|
780
|
+
|
781
|
+
specify "should handle returning inside of a savepoint by committing" do
|
782
|
+
def @db.ret_commit
|
783
|
+
transaction do
|
784
|
+
transaction(:savepoint=>true) do
|
785
|
+
execute 'DROP TABLE test;'
|
786
|
+
return
|
787
|
+
execute 'DROP TABLE test2;';
|
788
|
+
end
|
789
|
+
end
|
790
|
+
end
|
791
|
+
@db.ret_commit
|
792
|
+
@db.sql.should == ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
|
793
|
+
end
|
794
|
+
|
795
|
+
specify "should issue ROLLBACK if an exception is raised, and re-raise" do
|
796
|
+
@db.transaction {@db.execute 'DROP TABLE test'; raise RuntimeError} rescue nil
|
797
|
+
@db.sql.should == ['BEGIN', 'DROP TABLE test', 'ROLLBACK']
|
798
|
+
|
799
|
+
proc {@db.transaction {raise RuntimeError}}.should raise_error(RuntimeError)
|
800
|
+
end
|
801
|
+
|
802
|
+
specify "should issue ROLLBACK SAVEPOINT if an exception is raised inside a savepoint, and re-raise" do
|
803
|
+
@db.transaction{@db.transaction(:savepoint=>true){@db.execute 'DROP TABLE test'; raise RuntimeError}} rescue nil
|
804
|
+
@db.sql.should == ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE test', 'ROLLBACK TO SAVEPOINT autopoint_1', 'ROLLBACK']
|
805
|
+
|
806
|
+
proc {@db.transaction {raise RuntimeError}}.should raise_error(RuntimeError)
|
807
|
+
end
|
808
|
+
|
809
|
+
specify "should issue ROLLBACK if Sequel::Rollback is called in the transaction" do
|
810
|
+
@db.transaction do
|
811
|
+
@db.drop_table(:a)
|
812
|
+
raise Sequel::Rollback
|
813
|
+
@db.drop_table(:b)
|
814
|
+
end
|
815
|
+
|
816
|
+
@db.sql.should == ['BEGIN', 'DROP TABLE a', 'ROLLBACK']
|
817
|
+
end
|
818
|
+
|
819
|
+
specify "should issue ROLLBACK SAVEPOINT if Sequel::Rollback is called in a savepoint" do
|
820
|
+
@db.transaction do
|
821
|
+
@db.transaction(:savepoint=>true) do
|
822
|
+
@db.drop_table(:a)
|
823
|
+
raise Sequel::Rollback
|
824
|
+
end
|
825
|
+
@db.drop_table(:b)
|
826
|
+
end
|
827
|
+
|
828
|
+
@db.sql.should == ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE a', 'ROLLBACK TO SAVEPOINT autopoint_1', 'DROP TABLE b', 'COMMIT']
|
829
|
+
end
|
830
|
+
|
831
|
+
specify "should raise database errors when commiting a transaction as Sequel::DatabaseError" do
|
832
|
+
@db.meta_def(:commit_transaction){raise ArgumentError}
|
833
|
+
lambda{@db.transaction{}}.should raise_error(ArgumentError)
|
834
|
+
lambda{@db.transaction{@db.transaction(:savepoint=>true){}}}.should raise_error(ArgumentError)
|
835
|
+
|
836
|
+
@db.meta_def(:database_error_classes){[ArgumentError]}
|
837
|
+
lambda{@db.transaction{}}.should raise_error(Sequel::DatabaseError)
|
838
|
+
lambda{@db.transaction{@db.transaction(:savepoint=>true){}}}.should raise_error(Sequel::DatabaseError)
|
839
|
+
end
|
840
|
+
end
|
841
|
+
|
842
|
+
context "A Database adapter with a scheme" do
|
843
|
+
before do
|
844
|
+
class CCC < Sequel::Database
|
845
|
+
if defined?(DISCONNECTS)
|
846
|
+
DISCONNECTS.clear
|
847
|
+
else
|
848
|
+
DISCONNECTS = []
|
849
|
+
end
|
850
|
+
set_adapter_scheme :ccc
|
851
|
+
def disconnect
|
852
|
+
DISCONNECTS << self
|
853
|
+
end
|
854
|
+
end
|
855
|
+
end
|
856
|
+
|
857
|
+
specify "should be registered in the ADAPTER_MAP" do
|
858
|
+
Sequel::ADAPTER_MAP[:ccc].should == CCC
|
859
|
+
end
|
860
|
+
|
861
|
+
specify "should give the database_type as the adapter scheme by default" do
|
862
|
+
CCC.new.database_type.should == :ccc
|
863
|
+
end
|
864
|
+
|
865
|
+
specify "should be instantiated when its scheme is specified" do
|
866
|
+
c = Sequel::Database.connect('ccc://localhost/db')
|
867
|
+
c.should be_a_kind_of(CCC)
|
868
|
+
c.opts[:host].should == 'localhost'
|
869
|
+
c.opts[:database].should == 'db'
|
870
|
+
end
|
871
|
+
|
872
|
+
specify "should be accessible through Sequel.connect" do
|
873
|
+
c = Sequel.connect 'ccc://localhost/db'
|
874
|
+
c.should be_a_kind_of(CCC)
|
875
|
+
c.opts[:host].should == 'localhost'
|
876
|
+
c.opts[:database].should == 'db'
|
877
|
+
end
|
878
|
+
|
879
|
+
specify "should be accessible through Sequel.connect via a block" do
|
880
|
+
x = nil
|
881
|
+
y = nil
|
882
|
+
z = nil
|
883
|
+
returnValue = 'anything'
|
884
|
+
|
885
|
+
p = proc do |c|
|
886
|
+
c.should be_a_kind_of(CCC)
|
887
|
+
c.opts[:host].should == 'localhost'
|
888
|
+
c.opts[:database].should == 'db'
|
889
|
+
z = y
|
890
|
+
y = x
|
891
|
+
x = c
|
892
|
+
returnValue
|
893
|
+
end
|
894
|
+
Sequel::Database.connect('ccc://localhost/db', &p).should == returnValue
|
895
|
+
CCC::DISCONNECTS.should == [x]
|
896
|
+
|
897
|
+
Sequel.connect('ccc://localhost/db', &p).should == returnValue
|
898
|
+
CCC::DISCONNECTS.should == [y, x]
|
899
|
+
|
900
|
+
Sequel.send(:def_adapter_method, :ccc)
|
901
|
+
Sequel.ccc('db', :host=>'localhost', &p).should == returnValue
|
902
|
+
CCC::DISCONNECTS.should == [z, y, x]
|
903
|
+
end
|
904
|
+
|
905
|
+
specify "should be accessible through Sequel.<adapter>" do
|
906
|
+
Sequel.send(:def_adapter_method, :ccc)
|
907
|
+
|
908
|
+
# invalid parameters
|
909
|
+
proc {Sequel.ccc('abc', 'def')}.should raise_error(Sequel::Error)
|
910
|
+
|
911
|
+
c = Sequel.ccc('mydb')
|
912
|
+
p = proc{c.opts.delete_if{|k,v| k == :disconnection_proc || k == :single_threaded}}
|
913
|
+
c.should be_a_kind_of(CCC)
|
914
|
+
p.call.should == {:adapter=>:ccc, :database => 'mydb'}
|
915
|
+
|
916
|
+
c = Sequel.ccc('mydb', :host => 'localhost')
|
917
|
+
c.should be_a_kind_of(CCC)
|
918
|
+
p.call.should == {:adapter=>:ccc, :database => 'mydb', :host => 'localhost'}
|
919
|
+
|
920
|
+
c = Sequel.ccc
|
921
|
+
c.should be_a_kind_of(CCC)
|
922
|
+
p.call.should == {:adapter=>:ccc}
|
923
|
+
|
924
|
+
c = Sequel.ccc(:database => 'mydb', :host => 'localhost')
|
925
|
+
c.should be_a_kind_of(CCC)
|
926
|
+
p.call.should == {:adapter=>:ccc, :database => 'mydb', :host => 'localhost'}
|
927
|
+
end
|
928
|
+
|
929
|
+
specify "should be accessible through Sequel.connect with options" do
|
930
|
+
c = Sequel.connect(:adapter => :ccc, :database => 'mydb')
|
931
|
+
c.should be_a_kind_of(CCC)
|
932
|
+
c.opts[:adapter].should == :ccc
|
933
|
+
end
|
934
|
+
|
935
|
+
specify "should be accessible through Sequel.connect with URL parameters" do
|
936
|
+
c = Sequel.connect 'ccc:///db?host=/tmp&user=test'
|
937
|
+
c.should be_a_kind_of(CCC)
|
938
|
+
c.opts[:host].should == '/tmp'
|
939
|
+
c.opts[:database].should == 'db'
|
940
|
+
c.opts[:user].should == 'test'
|
941
|
+
end
|
942
|
+
|
943
|
+
specify "should have URL parameters take precedence over fixed URL parts" do
|
944
|
+
c = Sequel.connect 'ccc://localhost/db?host=a&database=b'
|
945
|
+
c.should be_a_kind_of(CCC)
|
946
|
+
c.opts[:host].should == 'a'
|
947
|
+
c.opts[:database].should == 'b'
|
948
|
+
end
|
949
|
+
|
950
|
+
specify "should have hash options take predence over URL parameters or parts" do
|
951
|
+
c = Sequel.connect 'ccc://localhost/db?host=/tmp', :host=>'a', :database=>'b', :user=>'c'
|
952
|
+
c.should be_a_kind_of(CCC)
|
953
|
+
c.opts[:host].should == 'a'
|
954
|
+
c.opts[:database].should == 'b'
|
955
|
+
c.opts[:user].should == 'c'
|
956
|
+
end
|
957
|
+
|
958
|
+
specify "should unescape values of URL parameters and parts" do
|
959
|
+
c = Sequel.connect 'ccc:///d%5bb%5d?host=domain%5cinstance'
|
960
|
+
c.should be_a_kind_of(CCC)
|
961
|
+
c.opts[:database].should == 'd[b]'
|
962
|
+
c.opts[:host].should == 'domain\\instance'
|
963
|
+
end
|
964
|
+
|
965
|
+
specify "should test the connection if test parameter is truthy" do
|
966
|
+
proc{Sequel.connect 'ccc:///d%5bb%5d?test=t'}.should raise_error(Sequel::DatabaseConnectionError)
|
967
|
+
proc{Sequel.connect 'ccc:///d%5bb%5d?test=1'}.should raise_error(Sequel::DatabaseConnectionError)
|
968
|
+
proc{Sequel.connect 'ccc:///d%5bb%5d', :test=>true}.should raise_error(Sequel::DatabaseConnectionError)
|
969
|
+
proc{Sequel.connect 'ccc:///d%5bb%5d', :test=>'t'}.should raise_error(Sequel::DatabaseConnectionError)
|
970
|
+
end
|
971
|
+
|
972
|
+
specify "should not test the connection if test parameter is not truthy" do
|
973
|
+
proc{Sequel.connect 'ccc:///d%5bb%5d?test=f'}.should_not raise_error
|
974
|
+
proc{Sequel.connect 'ccc:///d%5bb%5d?test=0'}.should_not raise_error
|
975
|
+
proc{Sequel.connect 'ccc:///d%5bb%5d', :test=>false}.should_not raise_error
|
976
|
+
proc{Sequel.connect 'ccc:///d%5bb%5d', :test=>'f'}.should_not raise_error
|
977
|
+
end
|
978
|
+
end
|
979
|
+
|
980
|
+
context "Sequel::Database.connect" do
|
981
|
+
specify "should raise an Error if not given a String or Hash" do
|
982
|
+
proc{Sequel::Database.connect(nil)}.should raise_error(Sequel::Error)
|
983
|
+
proc{Sequel::Database.connect(Object.new)}.should raise_error(Sequel::Error)
|
984
|
+
end
|
985
|
+
end
|
986
|
+
|
987
|
+
context "An unknown database scheme" do
|
988
|
+
specify "should raise an error in Sequel::Database.connect" do
|
989
|
+
proc {Sequel::Database.connect('ddd://localhost/db')}.should raise_error(Sequel::AdapterNotFound)
|
990
|
+
end
|
991
|
+
|
992
|
+
specify "should raise an error in Sequel.connect" do
|
993
|
+
proc {Sequel.connect('ddd://localhost/db')}.should raise_error(Sequel::AdapterNotFound)
|
994
|
+
end
|
995
|
+
end
|
996
|
+
|
997
|
+
context "A broken adapter (lib is there but the class is not)" do
|
998
|
+
before do
|
999
|
+
@fn = File.join(File.dirname(__FILE__), '../../lib/sequel/adapters/blah.rb')
|
1000
|
+
File.open(@fn,'a'){}
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
after do
|
1004
|
+
File.delete(@fn)
|
1005
|
+
end
|
1006
|
+
|
1007
|
+
specify "should raise an error" do
|
1008
|
+
proc {Sequel.connect('blah://blow')}.should raise_error(Sequel::AdapterNotFound)
|
1009
|
+
end
|
1010
|
+
end
|
1011
|
+
|
1012
|
+
context "A single threaded database" do
|
1013
|
+
after do
|
1014
|
+
Sequel::Database.single_threaded = false
|
1015
|
+
end
|
1016
|
+
|
1017
|
+
specify "should use a SingleConnectionPool instead of a ConnectionPool" do
|
1018
|
+
db = Sequel::Database.new(:single_threaded => true){123}
|
1019
|
+
db.pool.should be_a_kind_of(Sequel::SingleConnectionPool)
|
1020
|
+
end
|
1021
|
+
|
1022
|
+
specify "should be constructable using :single_threaded => true option" do
|
1023
|
+
db = Sequel::Database.new(:single_threaded => true){123}
|
1024
|
+
db.pool.should be_a_kind_of(Sequel::SingleConnectionPool)
|
1025
|
+
end
|
1026
|
+
|
1027
|
+
specify "should be constructable using Database.single_threaded = true" do
|
1028
|
+
Sequel::Database.single_threaded = true
|
1029
|
+
db = Sequel::Database.new{123}
|
1030
|
+
db.pool.should be_a_kind_of(Sequel::SingleConnectionPool)
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
specify "should be constructable using Sequel.single_threaded = true" do
|
1034
|
+
Sequel.single_threaded = true
|
1035
|
+
db = Sequel::Database.new{123}
|
1036
|
+
db.pool.should be_a_kind_of(Sequel::SingleConnectionPool)
|
1037
|
+
end
|
1038
|
+
end
|
1039
|
+
|
1040
|
+
context "A single threaded database" do
|
1041
|
+
before do
|
1042
|
+
conn = 1234567
|
1043
|
+
@db = Sequel::Database.new(:single_threaded => true) do
|
1044
|
+
conn += 1
|
1045
|
+
end
|
1046
|
+
end
|
1047
|
+
|
1048
|
+
specify "should invoke connection_proc only once" do
|
1049
|
+
@db.pool.hold {|c| c.should == 1234568}
|
1050
|
+
@db.pool.hold {|c| c.should == 1234568}
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
specify "should disconnect correctly" do
|
1054
|
+
def @db.disconnect_connection(c); @dc = c end
|
1055
|
+
def @db.dc; @dc end
|
1056
|
+
x = nil
|
1057
|
+
@db.pool.hold{|c| x = c}
|
1058
|
+
@db.pool.hold{|c| c.should == x}
|
1059
|
+
proc{@db.disconnect}.should_not raise_error
|
1060
|
+
@db.dc.should == x
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
specify "should convert an Exception on connection into a DatabaseConnectionError" do
|
1064
|
+
db = Sequel::Database.new(:single_threaded => true, :servers=>{}){raise Exception}
|
1065
|
+
proc {db.pool.hold {|c|}}.should raise_error(Sequel::DatabaseConnectionError)
|
1066
|
+
end
|
1067
|
+
|
1068
|
+
specify "should raise a DatabaseConnectionError if the connection proc returns nil" do
|
1069
|
+
db = Sequel::Database.new(:single_threaded => true, :servers=>{}){nil}
|
1070
|
+
proc {db.pool.hold {|c|}}.should raise_error(Sequel::DatabaseConnectionError)
|
1071
|
+
end
|
1072
|
+
end
|
1073
|
+
|
1074
|
+
context "A database" do
|
1075
|
+
before do
|
1076
|
+
Sequel::Database.single_threaded = false
|
1077
|
+
end
|
1078
|
+
|
1079
|
+
after do
|
1080
|
+
Sequel::Database.single_threaded = false
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
specify "should have single_threaded? respond to true if in single threaded mode" do
|
1084
|
+
db = Sequel::Database.new(:single_threaded => true){1234}
|
1085
|
+
db.should be_single_threaded
|
1086
|
+
|
1087
|
+
db = Sequel::Database.new(:max_options => 1)
|
1088
|
+
db.should_not be_single_threaded
|
1089
|
+
|
1090
|
+
db = Sequel::Database.new
|
1091
|
+
db.should_not be_single_threaded
|
1092
|
+
|
1093
|
+
Sequel::Database.single_threaded = true
|
1094
|
+
|
1095
|
+
db = Sequel::Database.new{123}
|
1096
|
+
db.should be_single_threaded
|
1097
|
+
|
1098
|
+
db = Sequel::Database.new(:max_options => 4){123}
|
1099
|
+
db.should be_single_threaded
|
1100
|
+
end
|
1101
|
+
|
1102
|
+
specify "should be able to set loggers via the logger= and loggers= methods" do
|
1103
|
+
db = Sequel::Database.new
|
1104
|
+
s = "I'm a logger"
|
1105
|
+
db.logger = s
|
1106
|
+
db.loggers.should == [s]
|
1107
|
+
db.logger = nil
|
1108
|
+
db.loggers.should == []
|
1109
|
+
|
1110
|
+
db.loggers = [s]
|
1111
|
+
db.loggers.should == [s]
|
1112
|
+
db.loggers = []
|
1113
|
+
db.loggers.should == []
|
1114
|
+
|
1115
|
+
t = "I'm also a logger"
|
1116
|
+
db.loggers = [s, t]
|
1117
|
+
db.loggers.should == [s,t]
|
1118
|
+
end
|
1119
|
+
end
|
1120
|
+
|
1121
|
+
context "Database#fetch" do
|
1122
|
+
before do
|
1123
|
+
@db = Sequel::Database.new
|
1124
|
+
c = Class.new(Sequel::Dataset) do
|
1125
|
+
def fetch_rows(sql); yield({:sql => sql}); end
|
1126
|
+
end
|
1127
|
+
@db.meta_def(:dataset) {c.new(self)}
|
1128
|
+
end
|
1129
|
+
|
1130
|
+
specify "should create a dataset and invoke its fetch_rows method with the given sql" do
|
1131
|
+
sql = nil
|
1132
|
+
@db.fetch('select * from xyz') {|r| sql = r[:sql]}
|
1133
|
+
sql.should == 'select * from xyz'
|
1134
|
+
end
|
1135
|
+
|
1136
|
+
specify "should format the given sql with any additional arguments" do
|
1137
|
+
sql = nil
|
1138
|
+
@db.fetch('select * from xyz where x = ? and y = ?', 15, 'abc') {|r| sql = r[:sql]}
|
1139
|
+
sql.should == "select * from xyz where x = 15 and y = 'abc'"
|
1140
|
+
|
1141
|
+
@db.fetch('select name from table where name = ? or id in ?', 'aman', [3,4,7]) {|r| sql = r[:sql]}
|
1142
|
+
sql.should == "select name from table where name = 'aman' or id in (3, 4, 7)"
|
1143
|
+
end
|
1144
|
+
|
1145
|
+
specify "should format the given sql with named arguments" do
|
1146
|
+
sql = nil
|
1147
|
+
@db.fetch('select * from xyz where x = :x and y = :y', :x=>15, :y=>'abc') {|r| sql = r[:sql]}
|
1148
|
+
sql.should == "select * from xyz where x = 15 and y = 'abc'"
|
1149
|
+
end
|
1150
|
+
|
1151
|
+
specify "should return the dataset if no block is given" do
|
1152
|
+
@db.fetch('select * from xyz').should be_a_kind_of(Sequel::Dataset)
|
1153
|
+
|
1154
|
+
@db.fetch('select a from b').map {|r| r[:sql]}.should == ['select a from b']
|
1155
|
+
|
1156
|
+
@db.fetch('select c from d').inject([]) {|m, r| m << r; m}.should == \
|
1157
|
+
[{:sql => 'select c from d'}]
|
1158
|
+
end
|
1159
|
+
|
1160
|
+
specify "should return a dataset that always uses the given sql for SELECTs" do
|
1161
|
+
ds = @db.fetch('select * from xyz')
|
1162
|
+
ds.select_sql.should == 'select * from xyz'
|
1163
|
+
ds.sql.should == 'select * from xyz'
|
1164
|
+
|
1165
|
+
ds.filter!(:price.sql_number < 100)
|
1166
|
+
ds.select_sql.should == 'select * from xyz'
|
1167
|
+
ds.sql.should == 'select * from xyz'
|
1168
|
+
end
|
1169
|
+
end
|
1170
|
+
|
1171
|
+
|
1172
|
+
context "Database#[]" do
|
1173
|
+
before do
|
1174
|
+
@db = Sequel::Database.new
|
1175
|
+
end
|
1176
|
+
|
1177
|
+
specify "should return a dataset when symbols are given" do
|
1178
|
+
ds = @db[:items]
|
1179
|
+
ds.class.should == Sequel::Dataset
|
1180
|
+
ds.opts[:from].should == [:items]
|
1181
|
+
end
|
1182
|
+
|
1183
|
+
specify "should return a dataset when a string is given" do
|
1184
|
+
c = Class.new(Sequel::Dataset) do
|
1185
|
+
def fetch_rows(sql); yield({:sql => sql}); end
|
1186
|
+
end
|
1187
|
+
@db.meta_def(:dataset) {c.new(self)}
|
1188
|
+
|
1189
|
+
sql = nil
|
1190
|
+
@db['select * from xyz where x = ? and y = ?', 15, 'abc'].each {|r| sql = r[:sql]}
|
1191
|
+
sql.should == "select * from xyz where x = 15 and y = 'abc'"
|
1192
|
+
end
|
1193
|
+
end
|
1194
|
+
|
1195
|
+
context "Database#create_view" do
|
1196
|
+
before do
|
1197
|
+
@db = DummyDatabase.new
|
1198
|
+
end
|
1199
|
+
|
1200
|
+
specify "should construct proper SQL with raw SQL" do
|
1201
|
+
@db.create_view :test, "SELECT * FROM xyz"
|
1202
|
+
@db.sqls.should == ['CREATE VIEW test AS SELECT * FROM xyz']
|
1203
|
+
@db.sqls.clear
|
1204
|
+
@db.create_view :test.identifier, "SELECT * FROM xyz"
|
1205
|
+
@db.sqls.should == ['CREATE VIEW test AS SELECT * FROM xyz']
|
1206
|
+
end
|
1207
|
+
|
1208
|
+
specify "should construct proper SQL with dataset" do
|
1209
|
+
@db.create_view :test, @db[:items].select(:a, :b).order(:c)
|
1210
|
+
@db.sqls.should == ['CREATE VIEW test AS SELECT a, b FROM items ORDER BY c']
|
1211
|
+
@db.sqls.clear
|
1212
|
+
@db.create_view :test.qualify(:sch), @db[:items].select(:a, :b).order(:c)
|
1213
|
+
@db.sqls.should == ['CREATE VIEW sch.test AS SELECT a, b FROM items ORDER BY c']
|
1214
|
+
end
|
1215
|
+
end
|
1216
|
+
|
1217
|
+
context "Database#create_or_replace_view" do
|
1218
|
+
before do
|
1219
|
+
@db = DummyDatabase.new
|
1220
|
+
end
|
1221
|
+
|
1222
|
+
specify "should construct proper SQL with raw SQL" do
|
1223
|
+
@db.create_or_replace_view :test, "SELECT * FROM xyz"
|
1224
|
+
@db.sqls.should == ['CREATE OR REPLACE VIEW test AS SELECT * FROM xyz']
|
1225
|
+
@db.sqls.clear
|
1226
|
+
@db.create_or_replace_view :sch__test, "SELECT * FROM xyz"
|
1227
|
+
@db.sqls.should == ['CREATE OR REPLACE VIEW sch.test AS SELECT * FROM xyz']
|
1228
|
+
end
|
1229
|
+
|
1230
|
+
specify "should construct proper SQL with dataset" do
|
1231
|
+
@db.create_or_replace_view :test, @db[:items].select(:a, :b).order(:c)
|
1232
|
+
@db.sqls.should == ['CREATE OR REPLACE VIEW test AS SELECT a, b FROM items ORDER BY c']
|
1233
|
+
@db.sqls.clear
|
1234
|
+
@db.create_or_replace_view :test.identifier, @db[:items].select(:a, :b).order(:c)
|
1235
|
+
@db.sqls.should == ['CREATE OR REPLACE VIEW test AS SELECT a, b FROM items ORDER BY c']
|
1236
|
+
end
|
1237
|
+
end
|
1238
|
+
|
1239
|
+
context "Database#drop_view" do
|
1240
|
+
before do
|
1241
|
+
@db = DummyDatabase.new
|
1242
|
+
end
|
1243
|
+
|
1244
|
+
specify "should construct proper SQL" do
|
1245
|
+
@db.drop_view :test
|
1246
|
+
@db.drop_view :test.identifier
|
1247
|
+
@db.drop_view :sch__test
|
1248
|
+
@db.drop_view :test.qualify(:sch)
|
1249
|
+
@db.sqls.should == ['DROP VIEW test', 'DROP VIEW test', 'DROP VIEW sch.test', 'DROP VIEW sch.test']
|
1250
|
+
end
|
1251
|
+
end
|
1252
|
+
|
1253
|
+
context "Database#alter_table_sql" do
|
1254
|
+
before do
|
1255
|
+
@db = DummyDatabase.new
|
1256
|
+
end
|
1257
|
+
|
1258
|
+
specify "should raise error for an invalid op" do
|
1259
|
+
proc {@db.send(:alter_table_sql, :mau, :op => :blah)}.should raise_error(Sequel::Error)
|
1260
|
+
end
|
1261
|
+
end
|
1262
|
+
|
1263
|
+
context "Database#inspect" do
|
1264
|
+
before do
|
1265
|
+
@db = DummyDatabase.new
|
1266
|
+
|
1267
|
+
@db.meta_def(:uri) {'blah://blahblah/blah'}
|
1268
|
+
end
|
1269
|
+
|
1270
|
+
specify "should include the class name and the connection url" do
|
1271
|
+
@db.inspect.should == '#<DummyDatabase: "blah://blahblah/blah">'
|
1272
|
+
end
|
1273
|
+
end
|
1274
|
+
|
1275
|
+
context "Database#get" do
|
1276
|
+
before do
|
1277
|
+
@c = Class.new(DummyDatabase) do
|
1278
|
+
def dataset
|
1279
|
+
ds = super
|
1280
|
+
def ds.get(*args, &block)
|
1281
|
+
@db.execute select(*args, &block).sql
|
1282
|
+
args
|
1283
|
+
end
|
1284
|
+
ds
|
1285
|
+
end
|
1286
|
+
end
|
1287
|
+
|
1288
|
+
@db = @c.new
|
1289
|
+
end
|
1290
|
+
|
1291
|
+
specify "should use Dataset#get to get a single value" do
|
1292
|
+
@db.get(1).should == [1]
|
1293
|
+
@db.sqls.last.should == 'SELECT 1'
|
1294
|
+
|
1295
|
+
@db.get(:version.sql_function)
|
1296
|
+
@db.sqls.last.should == 'SELECT version()'
|
1297
|
+
end
|
1298
|
+
|
1299
|
+
specify "should accept a block" do
|
1300
|
+
@db.get{1}
|
1301
|
+
@db.sqls.last.should == 'SELECT 1'
|
1302
|
+
|
1303
|
+
@db.get{version(1)}
|
1304
|
+
@db.sqls.last.should == 'SELECT version(1)'
|
1305
|
+
end
|
1306
|
+
end
|
1307
|
+
|
1308
|
+
context "Database#call" do
|
1309
|
+
specify "should call the prepared statement with the given name" do
|
1310
|
+
db = MockDatabase.new
|
1311
|
+
db[:items].prepare(:select, :select_all)
|
1312
|
+
db.call(:select_all).should == [{:id => 1, :x => 1}]
|
1313
|
+
db[:items].filter(:n=>:$n).prepare(:select, :select_n)
|
1314
|
+
db.call(:select_n, :n=>1).should == [{:id => 1, :x => 1}]
|
1315
|
+
db.sqls.should == ['SELECT * FROM items', 'SELECT * FROM items WHERE (n = 1)']
|
1316
|
+
end
|
1317
|
+
end
|
1318
|
+
|
1319
|
+
context "Database#server_opts" do
|
1320
|
+
specify "should return the general opts if no :servers option is used" do
|
1321
|
+
opts = {:host=>1, :database=>2}
|
1322
|
+
MockDatabase.new(opts).send(:server_opts, :server1)[:host].should == 1
|
1323
|
+
end
|
1324
|
+
|
1325
|
+
specify "should return the general opts if entry for the server is present in the :servers option" do
|
1326
|
+
opts = {:host=>1, :database=>2, :servers=>{}}
|
1327
|
+
MockDatabase.new(opts).send(:server_opts, :server1)[:host].should == 1
|
1328
|
+
end
|
1329
|
+
|
1330
|
+
specify "should return the general opts merged with the specific opts if given as a hash" do
|
1331
|
+
opts = {:host=>1, :database=>2, :servers=>{:server1=>{:host=>3}}}
|
1332
|
+
MockDatabase.new(opts).send(:server_opts, :server1)[:host].should == 3
|
1333
|
+
end
|
1334
|
+
|
1335
|
+
specify "should return the sgeneral opts merged with the specific opts if given as a proc" do
|
1336
|
+
opts = {:host=>1, :database=>2, :servers=>{:server1=>proc{|db| {:host=>4}}}}
|
1337
|
+
MockDatabase.new(opts).send(:server_opts, :server1)[:host].should == 4
|
1338
|
+
end
|
1339
|
+
|
1340
|
+
specify "should raise an error if the specific opts is not a proc or hash" do
|
1341
|
+
opts = {:host=>1, :database=>2, :servers=>{:server1=>2}}
|
1342
|
+
proc{MockDatabase.new(opts).send(:server_opts, :server1)}.should raise_error(Sequel::Error)
|
1343
|
+
end
|
1344
|
+
end
|
1345
|
+
|
1346
|
+
context "Database#add_servers" do
|
1347
|
+
before do
|
1348
|
+
@db = MockDatabase.new(:host=>1, :database=>2, :servers=>{:server1=>{:host=>3}})
|
1349
|
+
def @db.connect(server)
|
1350
|
+
server_opts(server)
|
1351
|
+
end
|
1352
|
+
def @db.disconnect_connection(c)
|
1353
|
+
end
|
1354
|
+
end
|
1355
|
+
|
1356
|
+
specify "should add new servers to the connection pool" do
|
1357
|
+
@db.synchronize{|c| c[:host].should == 1}
|
1358
|
+
@db.synchronize(:server1){|c| c[:host].should == 3}
|
1359
|
+
@db.synchronize(:server2){|c| c[:host].should == 1}
|
1360
|
+
|
1361
|
+
@db.add_servers(:server2=>{:host=>6})
|
1362
|
+
@db.synchronize{|c| c[:host].should == 1}
|
1363
|
+
@db.synchronize(:server1){|c| c[:host].should == 3}
|
1364
|
+
@db.synchronize(:server2){|c| c[:host].should == 6}
|
1365
|
+
|
1366
|
+
@db.disconnect
|
1367
|
+
@db.synchronize{|c| c[:host].should == 1}
|
1368
|
+
@db.synchronize(:server1){|c| c[:host].should == 3}
|
1369
|
+
@db.synchronize(:server2){|c| c[:host].should == 6}
|
1370
|
+
end
|
1371
|
+
|
1372
|
+
specify "should replace options for future connections to existing servers" do
|
1373
|
+
@db.synchronize{|c| c[:host].should == 1}
|
1374
|
+
@db.synchronize(:server1){|c| c[:host].should == 3}
|
1375
|
+
@db.synchronize(:server2){|c| c[:host].should == 1}
|
1376
|
+
|
1377
|
+
@db.add_servers(:default=>proc{{:host=>4}}, :server1=>{:host=>8})
|
1378
|
+
@db.synchronize{|c| c[:host].should == 1}
|
1379
|
+
@db.synchronize(:server1){|c| c[:host].should == 3}
|
1380
|
+
@db.synchronize(:server2){|c| c[:host].should == 1}
|
1381
|
+
|
1382
|
+
@db.disconnect
|
1383
|
+
@db.synchronize{|c| c[:host].should == 4}
|
1384
|
+
@db.synchronize(:server1){|c| c[:host].should == 8}
|
1385
|
+
@db.synchronize(:server2){|c| c[:host].should == 4}
|
1386
|
+
end
|
1387
|
+
end
|
1388
|
+
|
1389
|
+
context "Database#remove_servers" do
|
1390
|
+
before do
|
1391
|
+
@db = MockDatabase.new(:host=>1, :database=>2, :servers=>{:server1=>{:host=>3}, :server2=>{:host=>4}})
|
1392
|
+
def @db.connect(server)
|
1393
|
+
server_opts(server)
|
1394
|
+
end
|
1395
|
+
def @db.disconnect_connection(c)
|
1396
|
+
end
|
1397
|
+
end
|
1398
|
+
|
1399
|
+
specify "should remove servers from the connection pool" do
|
1400
|
+
@db.synchronize{|c| c[:host].should == 1}
|
1401
|
+
@db.synchronize(:server1){|c| c[:host].should == 3}
|
1402
|
+
@db.synchronize(:server2){|c| c[:host].should == 4}
|
1403
|
+
|
1404
|
+
@db.remove_servers(:server1, :server2)
|
1405
|
+
@db.synchronize{|c| c[:host].should == 1}
|
1406
|
+
@db.synchronize(:server1){|c| c[:host].should == 1}
|
1407
|
+
@db.synchronize(:server2){|c| c[:host].should == 1}
|
1408
|
+
end
|
1409
|
+
|
1410
|
+
specify "should accept arrays of symbols" do
|
1411
|
+
@db.remove_servers([:server1, :server2])
|
1412
|
+
@db.synchronize{|c| c[:host].should == 1}
|
1413
|
+
@db.synchronize(:server1){|c| c[:host].should == 1}
|
1414
|
+
@db.synchronize(:server2){|c| c[:host].should == 1}
|
1415
|
+
end
|
1416
|
+
|
1417
|
+
specify "should allow removal while connections are still open" do
|
1418
|
+
@db.synchronize do |c1|
|
1419
|
+
c1[:host].should == 1
|
1420
|
+
@db.synchronize(:server1) do |c2|
|
1421
|
+
c2[:host].should == 3
|
1422
|
+
@db.synchronize(:server2) do |c3|
|
1423
|
+
c3[:host].should == 4
|
1424
|
+
@db.remove_servers(:server1, :server2)
|
1425
|
+
@db.synchronize(:server1) do |c4|
|
1426
|
+
c4.should_not == c2
|
1427
|
+
c4.should == c1
|
1428
|
+
c4[:host].should == 1
|
1429
|
+
@db.synchronize(:server2) do |c5|
|
1430
|
+
c5.should_not == c3
|
1431
|
+
c5.should == c1
|
1432
|
+
c5[:host].should == 1
|
1433
|
+
end
|
1434
|
+
end
|
1435
|
+
c3[:host].should == 4
|
1436
|
+
end
|
1437
|
+
c2[:host].should == 3
|
1438
|
+
end
|
1439
|
+
c1[:host].should == 1
|
1440
|
+
end
|
1441
|
+
end
|
1442
|
+
end
|
1443
|
+
|
1444
|
+
context "Database#each_server" do
|
1445
|
+
before do
|
1446
|
+
@db = Sequel.connect(:adapter=>:mock, :host=>1, :database=>2, :servers=>{:server1=>{:host=>3}, :server2=>{:host=>4}})
|
1447
|
+
def @db.connect(server)
|
1448
|
+
server_opts(server)
|
1449
|
+
end
|
1450
|
+
def @db.disconnect_connection(c)
|
1451
|
+
end
|
1452
|
+
end
|
1453
|
+
|
1454
|
+
specify "should yield a separate database object for each server" do
|
1455
|
+
hosts = []
|
1456
|
+
@db.each_server do |db|
|
1457
|
+
db.should be_a_kind_of(Sequel::Database)
|
1458
|
+
db.should_not == @db
|
1459
|
+
db.opts[:database].should == 2
|
1460
|
+
hosts << db.opts[:host]
|
1461
|
+
end
|
1462
|
+
hosts.sort.should == [1, 3, 4]
|
1463
|
+
end
|
1464
|
+
|
1465
|
+
specify "should disconnect and remove entry from Sequel::DATABASES after use" do
|
1466
|
+
dbs = []
|
1467
|
+
dcs = []
|
1468
|
+
@db.each_server do |db|
|
1469
|
+
dbs << db
|
1470
|
+
Sequel::DATABASES.should include(db)
|
1471
|
+
db.meta_def(:disconnect){dcs << db}
|
1472
|
+
end
|
1473
|
+
dbs.each do |db|
|
1474
|
+
Sequel::DATABASES.should_not include(db)
|
1475
|
+
end
|
1476
|
+
dbs.should == dcs
|
1477
|
+
end
|
1478
|
+
end
|
1479
|
+
|
1480
|
+
context "Database#raise_error" do
|
1481
|
+
specify "should reraise if the exception class is not in opts[:classes]" do
|
1482
|
+
e = Class.new(StandardError)
|
1483
|
+
proc{MockDatabase.new.send(:raise_error, e.new(''), :classes=>[])}.should raise_error(e)
|
1484
|
+
end
|
1485
|
+
|
1486
|
+
specify "should convert the exception to a DatabaseError if the exception class is not in opts[:classes]" do
|
1487
|
+
proc{MockDatabase.new.send(:raise_error, Interrupt.new(''), :classes=>[Interrupt])}.should raise_error(Sequel::DatabaseError)
|
1488
|
+
end
|
1489
|
+
|
1490
|
+
specify "should convert the exception to a DatabaseError if opts[:classes] if not present" do
|
1491
|
+
proc{MockDatabase.new.send(:raise_error, Interrupt.new(''))}.should raise_error(Sequel::DatabaseError)
|
1492
|
+
end
|
1493
|
+
|
1494
|
+
specify "should convert the exception to a DatabaseDisconnectError if opts[:disconnect] is true" do
|
1495
|
+
proc{MockDatabase.new.send(:raise_error, Interrupt.new(''), :disconnect=>true)}.should raise_error(Sequel::DatabaseDisconnectError)
|
1496
|
+
end
|
1497
|
+
end
|
1498
|
+
|
1499
|
+
context "Database#typecast_value" do
|
1500
|
+
before do
|
1501
|
+
@db = Sequel::Database.new
|
1502
|
+
end
|
1503
|
+
|
1504
|
+
specify "should raise an InvalidValue when given an invalid value" do
|
1505
|
+
proc{@db.typecast_value(:integer, "13a")}.should raise_error(Sequel::InvalidValue)
|
1506
|
+
proc{@db.typecast_value(:float, "4.e2")}.should raise_error(Sequel::InvalidValue)
|
1507
|
+
proc{@db.typecast_value(:decimal, :invalid_value)}.should raise_error(Sequel::InvalidValue)
|
1508
|
+
proc{@db.typecast_value(:date, Object.new)}.should raise_error(Sequel::InvalidValue)
|
1509
|
+
proc{@db.typecast_value(:date, 'a')}.should raise_error(Sequel::InvalidValue)
|
1510
|
+
proc{@db.typecast_value(:time, Date.new)}.should raise_error(Sequel::InvalidValue)
|
1511
|
+
proc{@db.typecast_value(:datetime, 4)}.should raise_error(Sequel::InvalidValue)
|
1512
|
+
end
|
1513
|
+
|
1514
|
+
specify "should have an underlying exception class available at wrapped_exception" do
|
1515
|
+
begin
|
1516
|
+
@db.typecast_value(:date, 'a')
|
1517
|
+
true.should == false
|
1518
|
+
rescue Sequel::InvalidValue => e
|
1519
|
+
e.wrapped_exception.should be_a_kind_of(ArgumentError)
|
1520
|
+
end
|
1521
|
+
end
|
1522
|
+
|
1523
|
+
specify "should include underlying exception class in #inspect" do
|
1524
|
+
begin
|
1525
|
+
@db.typecast_value(:date, 'a')
|
1526
|
+
true.should == false
|
1527
|
+
rescue Sequel::InvalidValue => e
|
1528
|
+
e.inspect.should =~ /\A#<Sequel::InvalidValue: ArgumentError: .*>\z/
|
1529
|
+
end
|
1530
|
+
end
|
1531
|
+
end
|
1532
|
+
|
1533
|
+
context "Database#blank_object?" do
|
1534
|
+
specify "should return whether the object is considered blank" do
|
1535
|
+
db = Sequel::Database.new
|
1536
|
+
c = lambda{|meth, value| Class.new{define_method(meth){value}}.new}
|
1537
|
+
|
1538
|
+
db.send(:blank_object?, "").should == true
|
1539
|
+
db.send(:blank_object?, " ").should == true
|
1540
|
+
db.send(:blank_object?, nil).should == true
|
1541
|
+
db.send(:blank_object?, false).should == true
|
1542
|
+
db.send(:blank_object?, []).should == true
|
1543
|
+
db.send(:blank_object?, {}).should == true
|
1544
|
+
db.send(:blank_object?, c[:empty?, true]).should == true
|
1545
|
+
db.send(:blank_object?, c[:blank?, true]).should == true
|
1546
|
+
|
1547
|
+
db.send(:blank_object?, " a ").should == false
|
1548
|
+
db.send(:blank_object?, 1).should == false
|
1549
|
+
db.send(:blank_object?, 1.0).should == false
|
1550
|
+
db.send(:blank_object?, true).should == false
|
1551
|
+
db.send(:blank_object?, [1]).should == false
|
1552
|
+
db.send(:blank_object?, {1.0=>2.0}).should == false
|
1553
|
+
db.send(:blank_object?, c[:empty?, false]).should == false
|
1554
|
+
db.send(:blank_object?, c[:blank?, false]).should == false
|
1555
|
+
end
|
1556
|
+
end
|
1557
|
+
|
1558
|
+
context "Database#schema_autoincrementing_primary_key?" do
|
1559
|
+
specify "should whether the parsed schema row indicates a primary key" do
|
1560
|
+
m = Sequel::Database.new.method(:schema_autoincrementing_primary_key?)
|
1561
|
+
m.call(:primary_key=>true).should == true
|
1562
|
+
m.call(:primary_key=>false).should == false
|
1563
|
+
end
|
1564
|
+
end
|
1565
|
+
|
1566
|
+
context "Database#supports_savepoints?" do
|
1567
|
+
specify "should be false by default" do
|
1568
|
+
Sequel::Database.new.supports_savepoints?.should == false
|
1569
|
+
end
|
1570
|
+
end
|
1571
|
+
|
1572
|
+
context "Database#input_identifier_meth" do
|
1573
|
+
specify "should be the input_identifer method of a default dataset for this database" do
|
1574
|
+
db = Sequel::Database.new
|
1575
|
+
db.send(:input_identifier_meth).call(:a).should == 'a'
|
1576
|
+
db.identifier_input_method = :upcase
|
1577
|
+
db.send(:input_identifier_meth).call(:a).should == 'A'
|
1578
|
+
end
|
1579
|
+
end
|
1580
|
+
|
1581
|
+
context "Database#output_identifier_meth" do
|
1582
|
+
specify "should be the output_identifer method of a default dataset for this database" do
|
1583
|
+
db = Sequel::Database.new
|
1584
|
+
db.send(:output_identifier_meth).call('A').should == :A
|
1585
|
+
db.identifier_output_method = :downcase
|
1586
|
+
db.send(:output_identifier_meth).call('A').should == :a
|
1587
|
+
end
|
1588
|
+
end
|
1589
|
+
|
1590
|
+
context "Database#metadata_dataset" do
|
1591
|
+
specify "should be a dataset with the default settings for identifier_input_method and identifier_output_method" do
|
1592
|
+
ds = Sequel::Database.new.send(:metadata_dataset)
|
1593
|
+
ds.literal(:a).should == 'A'
|
1594
|
+
ds.send(:output_identifier, 'A').should == :a
|
1595
|
+
end
|
1596
|
+
end
|
1597
|
+
|
1598
|
+
context "Database#column_schema_to_ruby_default" do
|
1599
|
+
specify "should handle converting many default formats" do
|
1600
|
+
db = Sequel::Database.new
|
1601
|
+
m = db.method(:column_schema_to_ruby_default)
|
1602
|
+
p = lambda{|d,t| m.call(d,t)}
|
1603
|
+
p[nil, :integer].should == nil
|
1604
|
+
p['1', :integer].should == 1
|
1605
|
+
p['-1', :integer].should == -1
|
1606
|
+
p['1.0', :float].should == 1.0
|
1607
|
+
p['-1.0', :float].should == -1.0
|
1608
|
+
p['1.0', :decimal].should == BigDecimal.new('1.0')
|
1609
|
+
p['-1.0', :decimal].should == BigDecimal.new('-1.0')
|
1610
|
+
p['1', :boolean].should == true
|
1611
|
+
p['0', :boolean].should == false
|
1612
|
+
p['true', :boolean].should == true
|
1613
|
+
p['false', :boolean].should == false
|
1614
|
+
p["'t'", :boolean].should == true
|
1615
|
+
p["'f'", :boolean].should == false
|
1616
|
+
p["'a'", :string].should == 'a'
|
1617
|
+
p["'a'", :blob].should == 'a'.to_sequel_blob
|
1618
|
+
p["'a'", :blob].should be_a_kind_of(Sequel::SQL::Blob)
|
1619
|
+
p["''", :string].should == ''
|
1620
|
+
p["'\\a''b'", :string].should == "\\a'b"
|
1621
|
+
p["'NULL'", :string].should == "NULL"
|
1622
|
+
p["'2009-10-29'", :date].should == Date.new(2009,10,29)
|
1623
|
+
p["CURRENT_TIMESTAMP", :date].should == nil
|
1624
|
+
p["today()", :date].should == nil
|
1625
|
+
p["'2009-10-29T10:20:30-07:00'", :datetime].should == DateTime.parse('2009-10-29T10:20:30-07:00')
|
1626
|
+
p["'2009-10-29 10:20:30'", :datetime].should == DateTime.parse('2009-10-29 10:20:30')
|
1627
|
+
p["'10:20:30'", :time].should == Time.parse('10:20:30')
|
1628
|
+
p["NaN", :float].should == nil
|
1629
|
+
|
1630
|
+
db.meta_def(:database_type){:postgres}
|
1631
|
+
p["''::text", :string].should == ""
|
1632
|
+
p["'\\a''b'::character varying", :string].should == "\\a'b"
|
1633
|
+
p["'a'::bpchar", :string].should == "a"
|
1634
|
+
p["(-1)", :integer].should == -1
|
1635
|
+
p["(-1.0)", :float].should == -1.0
|
1636
|
+
p['(-1.0)', :decimal].should == BigDecimal.new('-1.0')
|
1637
|
+
p["'a'::bytea", :blob].should == 'a'.to_sequel_blob
|
1638
|
+
p["'a'::bytea", :blob].should be_a_kind_of(Sequel::SQL::Blob)
|
1639
|
+
p["'2009-10-29'::date", :date].should == Date.new(2009,10,29)
|
1640
|
+
p["'2009-10-29 10:20:30.241343'::timestamp without time zone", :datetime].should == DateTime.parse('2009-10-29 10:20:30.241343')
|
1641
|
+
p["'10:20:30'::time without time zone", :time].should == Time.parse('10:20:30')
|
1642
|
+
|
1643
|
+
db.meta_def(:database_type){:mysql}
|
1644
|
+
p["\\a'b", :string].should == "\\a'b"
|
1645
|
+
p["a", :string].should == "a"
|
1646
|
+
p["NULL", :string].should == "NULL"
|
1647
|
+
p["-1", :float].should == -1.0
|
1648
|
+
p['-1', :decimal].should == BigDecimal.new('-1.0')
|
1649
|
+
p["2009-10-29", :date].should == Date.new(2009,10,29)
|
1650
|
+
p["2009-10-29 10:20:30", :datetime].should == DateTime.parse('2009-10-29 10:20:30')
|
1651
|
+
p["10:20:30", :time].should == Time.parse('10:20:30')
|
1652
|
+
p["CURRENT_DATE", :date].should == nil
|
1653
|
+
p["CURRENT_TIMESTAMP", :datetime].should == nil
|
1654
|
+
p["a", :enum].should == "a"
|
1655
|
+
|
1656
|
+
db.meta_def(:database_type){:mssql}
|
1657
|
+
p["(N'a')", :string].should == "a"
|
1658
|
+
p["((-12))", :integer].should == -12
|
1659
|
+
p["((12.1))", :float].should == 12.1
|
1660
|
+
p["((-12.1))", :decimal].should == BigDecimal.new('-12.1')
|
1661
|
+
end
|
1662
|
+
end
|