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,1019 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
2
|
+
|
3
|
+
unless defined?(MYSQL_USER)
|
4
|
+
MYSQL_USER = 'root'
|
5
|
+
end
|
6
|
+
unless defined?(MYSQL_DB)
|
7
|
+
MYSQL_URL = (ENV['SEQUEL_MY_SPEC_DB']||"mysql://#{MYSQL_USER}@localhost/sandbox") unless defined? MYSQL_URL
|
8
|
+
MYSQL_DB = Sequel.connect(MYSQL_URL)
|
9
|
+
end
|
10
|
+
unless defined?(MYSQL_SOCKET_FILE)
|
11
|
+
MYSQL_SOCKET_FILE = '/tmp/mysql.sock'
|
12
|
+
end
|
13
|
+
INTEGRATION_DB = MYSQL_DB unless defined?(INTEGRATION_DB)
|
14
|
+
|
15
|
+
MYSQL_URI = URI.parse(MYSQL_DB.uri)
|
16
|
+
|
17
|
+
MYSQL_DB.create_table! :test2 do
|
18
|
+
text :name
|
19
|
+
integer :value
|
20
|
+
end
|
21
|
+
def MYSQL_DB.sqls
|
22
|
+
(@sqls ||= [])
|
23
|
+
end
|
24
|
+
logger = Object.new
|
25
|
+
def logger.method_missing(m, msg)
|
26
|
+
MYSQL_DB.sqls << msg
|
27
|
+
end
|
28
|
+
MYSQL_DB.logger = logger
|
29
|
+
MYSQL_DB.drop_table(:items) rescue nil
|
30
|
+
MYSQL_DB.drop_table(:dolls) rescue nil
|
31
|
+
MYSQL_DB.drop_table(:booltest) rescue nil
|
32
|
+
|
33
|
+
SQL_BEGIN = 'BEGIN'
|
34
|
+
SQL_ROLLBACK = 'ROLLBACK'
|
35
|
+
SQL_COMMIT = 'COMMIT'
|
36
|
+
|
37
|
+
context "MySQL", '#create_table' do
|
38
|
+
before do
|
39
|
+
@db = MYSQL_DB
|
40
|
+
MYSQL_DB.sqls.clear
|
41
|
+
end
|
42
|
+
after do
|
43
|
+
@db.drop_table(:dolls) rescue nil
|
44
|
+
end
|
45
|
+
|
46
|
+
specify "should allow to specify options for MySQL" do
|
47
|
+
@db.create_table(:dolls, :engine => 'MyISAM', :charset => 'latin2'){text :name}
|
48
|
+
@db.sqls.should == ["CREATE TABLE dolls (name text) ENGINE=MyISAM DEFAULT CHARSET=latin2"]
|
49
|
+
end
|
50
|
+
|
51
|
+
specify "should create a temporary table" do
|
52
|
+
@db.create_table(:tmp_dolls, :temp => true, :engine => 'MyISAM', :charset => 'latin2'){text :name}
|
53
|
+
@db.sqls.should == ["CREATE TEMPORARY TABLE tmp_dolls (name text) ENGINE=MyISAM DEFAULT CHARSET=latin2"]
|
54
|
+
end
|
55
|
+
|
56
|
+
specify "should not use a default for a String :text=>true type" do
|
57
|
+
@db.create_table(:dolls){String :name, :text=>true, :default=>'blah'}
|
58
|
+
@db.sqls.should == ["CREATE TABLE dolls (name text)"]
|
59
|
+
end
|
60
|
+
|
61
|
+
specify "should not use a default for a File type" do
|
62
|
+
@db.create_table(:dolls){File :name, :default=>'blah'}
|
63
|
+
@db.sqls.should == ["CREATE TABLE dolls (name blob)"]
|
64
|
+
end
|
65
|
+
|
66
|
+
specify "should respect the size option for File type" do
|
67
|
+
@db.create_table(:dolls) do
|
68
|
+
File :n1
|
69
|
+
File :n2, :size=>:tiny
|
70
|
+
File :n3, :size=>:medium
|
71
|
+
File :n4, :size=>:long
|
72
|
+
File :n5, :size=>255
|
73
|
+
end
|
74
|
+
@db.schema(:dolls).map{|k, v| v[:db_type]}.should == %w"blob tinyblob mediumblob longblob blob"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "A MySQL database" do
|
79
|
+
specify "should provide the server version" do
|
80
|
+
MYSQL_DB.server_version.should >= 40000
|
81
|
+
end
|
82
|
+
|
83
|
+
specify "should handle the creation and dropping of an InnoDB table with foreign keys" do
|
84
|
+
proc{MYSQL_DB.create_table!(:test_innodb, :engine=>:InnoDB){primary_key :id; foreign_key :fk, :test_innodb, :key=>:id}}.should_not raise_error
|
85
|
+
end
|
86
|
+
|
87
|
+
specify "should support for_share" do
|
88
|
+
MYSQL_DB.transaction{MYSQL_DB[:test2].for_share.all.should == []}
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
if MYSQL_DB.class.adapter_scheme == :mysql
|
93
|
+
context "Sequel::MySQL.convert_tinyint_to_bool" do
|
94
|
+
before do
|
95
|
+
@db = MYSQL_DB
|
96
|
+
@db.create_table(:booltest){column :b, 'tinyint(1)'; column :i, 'tinyint(4)'}
|
97
|
+
@ds = @db[:booltest]
|
98
|
+
end
|
99
|
+
after do
|
100
|
+
Sequel::MySQL.convert_tinyint_to_bool = true
|
101
|
+
@db.drop_table(:booltest)
|
102
|
+
end
|
103
|
+
|
104
|
+
specify "should consider tinyint(1) datatypes as boolean if set, but not larger tinyints" do
|
105
|
+
@db.schema(:booltest, :reload=>true).should == [[:b, {:type=>:boolean, :allow_null=>true, :primary_key=>false, :default=>nil, :ruby_default=>nil, :db_type=>"tinyint(1)"}, ], [:i, {:type=>:integer, :allow_null=>true, :primary_key=>false, :default=>nil, :ruby_default=>nil, :db_type=>"tinyint(4)"}, ]]
|
106
|
+
Sequel::MySQL.convert_tinyint_to_bool = false
|
107
|
+
@db.schema(:booltest, :reload=>true).should == [[:b, {:type=>:integer, :allow_null=>true, :primary_key=>false, :default=>nil, :ruby_default=>nil, :db_type=>"tinyint(1)"}, ], [:i, {:type=>:integer, :allow_null=>true, :primary_key=>false, :default=>nil, :ruby_default=>nil, :db_type=>"tinyint(4)"}, ]]
|
108
|
+
end
|
109
|
+
|
110
|
+
specify "should return tinyints as bools when set" do
|
111
|
+
@ds.delete
|
112
|
+
@ds << {:b=>true, :i=>10}
|
113
|
+
@ds.all.should == [{:b=>true, :i=>true}]
|
114
|
+
@ds.delete
|
115
|
+
@ds << {:b=>false, :i=>0}
|
116
|
+
@ds.all.should == [{:b=>false, :i=>false}]
|
117
|
+
|
118
|
+
Sequel::MySQL.convert_tinyint_to_bool = false
|
119
|
+
@ds.delete
|
120
|
+
@ds << {:b=>true, :i=>10}
|
121
|
+
@ds.all.should == [{:b=>1, :i=>10}]
|
122
|
+
@ds.delete
|
123
|
+
@ds << {:b=>false, :i=>0}
|
124
|
+
@ds.all.should == [{:b=>0, :i=>0}]
|
125
|
+
|
126
|
+
@ds.delete
|
127
|
+
@ds << {:b=>1, :i=>10}
|
128
|
+
@ds.all.should == [{:b=>1, :i=>10}]
|
129
|
+
@ds.delete
|
130
|
+
@ds << {:b=>0, :i=>0}
|
131
|
+
@ds.all.should == [{:b=>0, :i=>0}]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context "A MySQL dataset" do
|
137
|
+
before do
|
138
|
+
MYSQL_DB.create_table(:items){String :name; Integer :value}
|
139
|
+
@d = MYSQL_DB[:items]
|
140
|
+
MYSQL_DB.sqls.clear
|
141
|
+
end
|
142
|
+
after do
|
143
|
+
MYSQL_DB.drop_table(:items)
|
144
|
+
end
|
145
|
+
|
146
|
+
specify "should quote columns and tables using back-ticks if quoting identifiers" do
|
147
|
+
@d.quote_identifiers = true
|
148
|
+
@d.select(:name).sql.should == \
|
149
|
+
'SELECT `name` FROM `items`'
|
150
|
+
|
151
|
+
@d.select('COUNT(*)'.lit).sql.should == \
|
152
|
+
'SELECT COUNT(*) FROM `items`'
|
153
|
+
|
154
|
+
@d.select(:max.sql_function(:value)).sql.should == \
|
155
|
+
'SELECT max(`value`) FROM `items`'
|
156
|
+
|
157
|
+
@d.select(:NOW.sql_function).sql.should == \
|
158
|
+
'SELECT NOW() FROM `items`'
|
159
|
+
|
160
|
+
@d.select(:max.sql_function(:items__value)).sql.should == \
|
161
|
+
'SELECT max(`items`.`value`) FROM `items`'
|
162
|
+
|
163
|
+
@d.order(:name.desc).sql.should == \
|
164
|
+
'SELECT * FROM `items` ORDER BY `name` DESC'
|
165
|
+
|
166
|
+
@d.select('items.name AS item_name'.lit).sql.should == \
|
167
|
+
'SELECT items.name AS item_name FROM `items`'
|
168
|
+
|
169
|
+
@d.select('`name`'.lit).sql.should == \
|
170
|
+
'SELECT `name` FROM `items`'
|
171
|
+
|
172
|
+
@d.select('max(items.`name`) AS `max_name`'.lit).sql.should == \
|
173
|
+
'SELECT max(items.`name`) AS `max_name` FROM `items`'
|
174
|
+
|
175
|
+
@d.select(:test.sql_function(:abc, 'hello')).sql.should == \
|
176
|
+
"SELECT test(`abc`, 'hello') FROM `items`"
|
177
|
+
|
178
|
+
@d.select(:test.sql_function(:abc__def, 'hello')).sql.should == \
|
179
|
+
"SELECT test(`abc`.`def`, 'hello') FROM `items`"
|
180
|
+
|
181
|
+
@d.select(:test.sql_function(:abc__def, 'hello').as(:x2)).sql.should == \
|
182
|
+
"SELECT test(`abc`.`def`, 'hello') AS `x2` FROM `items`"
|
183
|
+
|
184
|
+
@d.insert_sql(:value => 333).should == \
|
185
|
+
'INSERT INTO `items` (`value`) VALUES (333)'
|
186
|
+
|
187
|
+
@d.insert_sql(:x => :y).should == \
|
188
|
+
'INSERT INTO `items` (`x`) VALUES (`y`)'
|
189
|
+
end
|
190
|
+
|
191
|
+
specify "should quote fields correctly when reversing the order" do
|
192
|
+
@d.quote_identifiers = true
|
193
|
+
@d.reverse_order(:name).sql.should == \
|
194
|
+
'SELECT * FROM `items` ORDER BY `name` DESC'
|
195
|
+
|
196
|
+
@d.reverse_order(:name.desc).sql.should == \
|
197
|
+
'SELECT * FROM `items` ORDER BY `name` ASC'
|
198
|
+
|
199
|
+
@d.reverse_order(:name, :test.desc).sql.should == \
|
200
|
+
'SELECT * FROM `items` ORDER BY `name` DESC, `test` ASC'
|
201
|
+
|
202
|
+
@d.reverse_order(:name.desc, :test).sql.should == \
|
203
|
+
'SELECT * FROM `items` ORDER BY `name` ASC, `test` DESC'
|
204
|
+
end
|
205
|
+
|
206
|
+
specify "should support ORDER clause in UPDATE statements" do
|
207
|
+
@d.order(:name).update_sql(:value => 1).should == \
|
208
|
+
'UPDATE items SET value = 1 ORDER BY name'
|
209
|
+
end
|
210
|
+
|
211
|
+
specify "should support LIMIT clause in UPDATE statements" do
|
212
|
+
@d.limit(10).update_sql(:value => 1).should == \
|
213
|
+
'UPDATE items SET value = 1 LIMIT 10'
|
214
|
+
end
|
215
|
+
|
216
|
+
specify "should support regexps" do
|
217
|
+
@d << {:name => 'abc', :value => 1}
|
218
|
+
@d << {:name => 'bcd', :value => 2}
|
219
|
+
@d.filter(:name => /bc/).count.should == 2
|
220
|
+
@d.filter(:name => /^bc/).count.should == 1
|
221
|
+
end
|
222
|
+
|
223
|
+
specify "should correctly literalize strings with comment backslashes in them" do
|
224
|
+
@d.delete
|
225
|
+
proc {@d << {:name => ':\\'}}.should_not raise_error
|
226
|
+
|
227
|
+
@d.first[:name].should == ':\\'
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
context "MySQL datasets" do
|
232
|
+
before do
|
233
|
+
@d = MYSQL_DB[:orders]
|
234
|
+
end
|
235
|
+
|
236
|
+
specify "should correctly quote column references" do
|
237
|
+
@d.quote_identifiers = true
|
238
|
+
market = 'ICE'
|
239
|
+
ack_stamp = Time.now - 15 * 60 # 15 minutes ago
|
240
|
+
@d.select(:market, :minute.sql_function(:from_unixtime.sql_function(:ack)).as(:minute)).
|
241
|
+
where{|o|(:ack.sql_number > ack_stamp) & {:market => market}}.
|
242
|
+
group_by(:minute.sql_function(:from_unixtime.sql_function(:ack))).sql.should == \
|
243
|
+
"SELECT `market`, minute(from_unixtime(`ack`)) AS `minute` FROM `orders` WHERE ((`ack` > #{@d.literal(ack_stamp)}) AND (`market` = 'ICE')) GROUP BY minute(from_unixtime(`ack`))"
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
describe "Dataset#distinct" do
|
248
|
+
before do
|
249
|
+
@db = MYSQL_DB
|
250
|
+
@db.create_table!(:a) do
|
251
|
+
Integer :a
|
252
|
+
Integer :b
|
253
|
+
end
|
254
|
+
@ds = @db[:a]
|
255
|
+
end
|
256
|
+
after do
|
257
|
+
@db.drop_table(:a)
|
258
|
+
end
|
259
|
+
|
260
|
+
it "#distinct with arguments should return results distinct on those arguments" do
|
261
|
+
@ds.insert(20, 10)
|
262
|
+
@ds.insert(30, 10)
|
263
|
+
@ds.order(:b, :a).distinct.map(:a).should == [20, 30]
|
264
|
+
@ds.order(:b, :a.desc).distinct.map(:a).should == [30, 20]
|
265
|
+
# MySQL doesn't respect orders when using the nonstandard GROUP BY
|
266
|
+
[[20], [30]].should include(@ds.order(:b, :a).distinct(:b).map(:a))
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
context "MySQL join expressions" do
|
271
|
+
before do
|
272
|
+
@ds = MYSQL_DB[:nodes]
|
273
|
+
@ds.db.meta_def(:server_version) {50014}
|
274
|
+
end
|
275
|
+
|
276
|
+
specify "should raise error for :full_outer join requests." do
|
277
|
+
lambda{@ds.join_table(:full_outer, :nodes)}.should raise_error(Sequel::Error)
|
278
|
+
end
|
279
|
+
specify "should support natural left joins" do
|
280
|
+
@ds.join_table(:natural_left, :nodes).sql.should == \
|
281
|
+
'SELECT * FROM nodes NATURAL LEFT JOIN nodes'
|
282
|
+
end
|
283
|
+
specify "should support natural right joins" do
|
284
|
+
@ds.join_table(:natural_right, :nodes).sql.should == \
|
285
|
+
'SELECT * FROM nodes NATURAL RIGHT JOIN nodes'
|
286
|
+
end
|
287
|
+
specify "should support natural left outer joins" do
|
288
|
+
@ds.join_table(:natural_left_outer, :nodes).sql.should == \
|
289
|
+
'SELECT * FROM nodes NATURAL LEFT OUTER JOIN nodes'
|
290
|
+
end
|
291
|
+
specify "should support natural right outer joins" do
|
292
|
+
@ds.join_table(:natural_right_outer, :nodes).sql.should == \
|
293
|
+
'SELECT * FROM nodes NATURAL RIGHT OUTER JOIN nodes'
|
294
|
+
end
|
295
|
+
specify "should support natural inner joins" do
|
296
|
+
@ds.join_table(:natural_inner, :nodes).sql.should == \
|
297
|
+
'SELECT * FROM nodes NATURAL LEFT JOIN nodes'
|
298
|
+
end
|
299
|
+
specify "should support cross joins" do
|
300
|
+
@ds.join_table(:cross, :nodes).sql.should == \
|
301
|
+
'SELECT * FROM nodes CROSS JOIN nodes'
|
302
|
+
end
|
303
|
+
specify "should support cross joins as inner joins if conditions are used" do
|
304
|
+
@ds.join_table(:cross, :nodes, :id=>:id).sql.should == \
|
305
|
+
'SELECT * FROM nodes INNER JOIN nodes ON (nodes.id = nodes.id)'
|
306
|
+
end
|
307
|
+
specify "should support straight joins (force left table to be read before right)" do
|
308
|
+
@ds.join_table(:straight, :nodes).sql.should == \
|
309
|
+
'SELECT * FROM nodes STRAIGHT_JOIN nodes'
|
310
|
+
end
|
311
|
+
specify "should support natural joins on multiple tables." do
|
312
|
+
@ds.join_table(:natural_left_outer, [:nodes, :branches]).sql.should == \
|
313
|
+
'SELECT * FROM nodes NATURAL LEFT OUTER JOIN (nodes, branches)'
|
314
|
+
end
|
315
|
+
specify "should support straight joins on multiple tables." do
|
316
|
+
@ds.join_table(:straight, [:nodes,:branches]).sql.should == \
|
317
|
+
'SELECT * FROM nodes STRAIGHT_JOIN (nodes, branches)'
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
context "Joined MySQL dataset" do
|
322
|
+
before do
|
323
|
+
@ds = MYSQL_DB[:nodes]
|
324
|
+
end
|
325
|
+
|
326
|
+
specify "should quote fields correctly" do
|
327
|
+
@ds.quote_identifiers = true
|
328
|
+
@ds.join(:attributes, :node_id => :id).sql.should == \
|
329
|
+
"SELECT * FROM `nodes` INNER JOIN `attributes` ON (`attributes`.`node_id` = `nodes`.`id`)"
|
330
|
+
end
|
331
|
+
|
332
|
+
specify "should allow a having clause on ungrouped datasets" do
|
333
|
+
proc {@ds.having('blah')}.should_not raise_error
|
334
|
+
|
335
|
+
@ds.having('blah').sql.should == \
|
336
|
+
"SELECT * FROM nodes HAVING (blah)"
|
337
|
+
end
|
338
|
+
|
339
|
+
specify "should put a having clause before an order by clause" do
|
340
|
+
@ds.order(:aaa).having(:bbb => :ccc).sql.should == \
|
341
|
+
"SELECT * FROM nodes HAVING (bbb = ccc) ORDER BY aaa"
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
context "A MySQL database" do
|
346
|
+
before do
|
347
|
+
@db = MYSQL_DB
|
348
|
+
end
|
349
|
+
|
350
|
+
specify "should support add_column operations" do
|
351
|
+
@db.add_column :test2, :xyz, :text
|
352
|
+
|
353
|
+
@db[:test2].columns.should == [:name, :value, :xyz]
|
354
|
+
@db[:test2] << {:name => 'mmm', :value => 111, :xyz => '000'}
|
355
|
+
@db[:test2].first[:xyz].should == '000'
|
356
|
+
end
|
357
|
+
|
358
|
+
specify "should support drop_column operations" do
|
359
|
+
@db[:test2].columns.should == [:name, :value, :xyz]
|
360
|
+
@db.drop_column :test2, :xyz
|
361
|
+
|
362
|
+
@db[:test2].columns.should == [:name, :value]
|
363
|
+
end
|
364
|
+
|
365
|
+
specify "should support rename_column operations" do
|
366
|
+
@db[:test2].delete
|
367
|
+
@db.add_column :test2, :xyz, :text
|
368
|
+
@db[:test2] << {:name => 'mmm', :value => 111, :xyz => 'qqqq'}
|
369
|
+
|
370
|
+
@db[:test2].columns.should == [:name, :value, :xyz]
|
371
|
+
@db.rename_column :test2, :xyz, :zyx, :type => :text
|
372
|
+
@db[:test2].columns.should == [:name, :value, :zyx]
|
373
|
+
@db[:test2].first[:zyx].should == 'qqqq'
|
374
|
+
end
|
375
|
+
|
376
|
+
specify "should support rename_column operations with types like varchar(255)" do
|
377
|
+
@db[:test2].delete
|
378
|
+
@db.add_column :test2, :tre, :text
|
379
|
+
@db[:test2] << {:name => 'mmm', :value => 111, :tre => 'qqqq'}
|
380
|
+
|
381
|
+
@db[:test2].columns.should == [:name, :value, :zyx, :tre]
|
382
|
+
@db.rename_column :test2, :tre, :ert, :type => :varchar, :size=>255
|
383
|
+
@db[:test2].columns.should == [:name, :value, :zyx, :ert]
|
384
|
+
@db[:test2].first[:ert].should == 'qqqq'
|
385
|
+
end
|
386
|
+
|
387
|
+
specify "should support set_column_type operations" do
|
388
|
+
@db.add_column :test2, :xyz, :float
|
389
|
+
@db[:test2].delete
|
390
|
+
@db[:test2] << {:name => 'mmm', :value => 111, :xyz => 56.78}
|
391
|
+
@db.set_column_type :test2, :xyz, :integer
|
392
|
+
|
393
|
+
@db[:test2].first[:xyz].should == 57
|
394
|
+
end
|
395
|
+
|
396
|
+
specify "should support add_index" do
|
397
|
+
@db.add_index :test2, :value
|
398
|
+
end
|
399
|
+
|
400
|
+
specify "should support drop_index" do
|
401
|
+
@db.drop_index :test2, :value
|
402
|
+
end
|
403
|
+
|
404
|
+
specify "should support add_foreign_key" do
|
405
|
+
@db.alter_table :test2 do
|
406
|
+
add_foreign_key :value2, :test2, :key=>:value
|
407
|
+
end
|
408
|
+
@db[:test2].columns.should == [:name, :value, :zyx, :ert, :xyz, :value2]
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
context "A MySQL database with table options" do
|
413
|
+
before do
|
414
|
+
@options = {:engine=>'MyISAM', :charset=>'latin1', :collate => 'latin1_swedish_ci'}
|
415
|
+
|
416
|
+
Sequel::MySQL.default_engine = 'InnoDB'
|
417
|
+
Sequel::MySQL.default_charset = 'utf8'
|
418
|
+
Sequel::MySQL.default_collate = 'utf8_general_ci'
|
419
|
+
|
420
|
+
@db = MYSQL_DB
|
421
|
+
@db.drop_table(:items) rescue nil
|
422
|
+
|
423
|
+
MYSQL_DB.sqls.clear
|
424
|
+
end
|
425
|
+
after do
|
426
|
+
@db.drop_table(:items) rescue nil
|
427
|
+
Sequel::MySQL.default_engine = nil
|
428
|
+
Sequel::MySQL.default_charset = nil
|
429
|
+
Sequel::MySQL.default_collate = nil
|
430
|
+
end
|
431
|
+
|
432
|
+
specify "should allow to pass custom options (engine, charset, collate) for table creation" do
|
433
|
+
@db.create_table(:items, @options){Integer :size; text :name}
|
434
|
+
@db.sqls.should == ["CREATE TABLE items (size integer, name text) ENGINE=MyISAM DEFAULT CHARSET=latin1 DEFAULT COLLATE=latin1_swedish_ci"]
|
435
|
+
end
|
436
|
+
|
437
|
+
specify "should use default options if specified (engine, charset, collate) for table creation" do
|
438
|
+
@db.create_table(:items){Integer :size; text :name}
|
439
|
+
@db.sqls.should == ["CREATE TABLE items (size integer, name text) ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_general_ci"]
|
440
|
+
end
|
441
|
+
|
442
|
+
specify "should not use default if option has a nil value" do
|
443
|
+
@db.create_table(:items, :engine=>nil, :charset=>nil, :collate=>nil){Integer :size; text :name}
|
444
|
+
@db.sqls.should == ["CREATE TABLE items (size integer, name text)"]
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
context "A MySQL database" do
|
449
|
+
before do
|
450
|
+
@db = MYSQL_DB
|
451
|
+
@db.drop_table(:items) rescue nil
|
452
|
+
MYSQL_DB.sqls.clear
|
453
|
+
end
|
454
|
+
after do
|
455
|
+
@db.drop_table(:items) rescue nil
|
456
|
+
end
|
457
|
+
|
458
|
+
specify "should support defaults for boolean columns" do
|
459
|
+
@db.create_table(:items){TrueClass :active1, :default=>true; FalseClass :active2, :default => false}
|
460
|
+
@db.sqls.should == ["CREATE TABLE items (active1 tinyint(1) DEFAULT 1, active2 tinyint(1) DEFAULT 0)"]
|
461
|
+
end
|
462
|
+
|
463
|
+
specify "should correctly format CREATE TABLE statements with foreign keys" do
|
464
|
+
@db.create_table(:items){Integer :id; foreign_key :p_id, :items, :key => :id, :null => false, :on_delete => :cascade}
|
465
|
+
@db.sqls.should == ["CREATE TABLE items (id integer, p_id integer NOT NULL, FOREIGN KEY (p_id) REFERENCES items(id) ON DELETE CASCADE)"]
|
466
|
+
end
|
467
|
+
|
468
|
+
specify "should correctly format ALTER TABLE statements with foreign keys" do
|
469
|
+
@db.create_table(:items){Integer :id}
|
470
|
+
@db.alter_table(:items){add_foreign_key :p_id, :users, :key => :id, :null => false, :on_delete => :cascade}
|
471
|
+
@db.sqls.should == ["CREATE TABLE items (id integer)", "ALTER TABLE items ADD COLUMN p_id integer NOT NULL", "ALTER TABLE items ADD FOREIGN KEY (p_id) REFERENCES users(id) ON DELETE CASCADE"]
|
472
|
+
end
|
473
|
+
|
474
|
+
specify "should have rename_column support keep existing options" do
|
475
|
+
@db.create_table(:items){String :id, :null=>false, :default=>'blah'}
|
476
|
+
@db.alter_table(:items){rename_column :id, :nid}
|
477
|
+
@db.sqls.should == ["CREATE TABLE items (id varchar(255) NOT NULL DEFAULT 'blah')", "DESCRIBE items", "ALTER TABLE items CHANGE COLUMN id nid varchar(255) NOT NULL DEFAULT 'blah'"]
|
478
|
+
@db[:items].insert
|
479
|
+
@db[:items].all.should == [{:nid=>'blah'}]
|
480
|
+
proc{@db[:items].insert(:nid=>nil)}.should raise_error(Sequel::DatabaseError)
|
481
|
+
end
|
482
|
+
|
483
|
+
specify "should have set_column_type support keep existing options" do
|
484
|
+
@db.create_table(:items){Integer :id, :null=>false, :default=>5}
|
485
|
+
@db.alter_table(:items){set_column_type :id, Bignum}
|
486
|
+
@db.sqls.should == ["CREATE TABLE items (id integer NOT NULL DEFAULT 5)", "DESCRIBE items", "ALTER TABLE items CHANGE COLUMN id id bigint NOT NULL DEFAULT 5"]
|
487
|
+
@db[:items].insert
|
488
|
+
@db[:items].all.should == [{:id=>5}]
|
489
|
+
proc{@db[:items].insert(:id=>nil)}.should raise_error(Sequel::DatabaseError)
|
490
|
+
@db[:items].delete
|
491
|
+
@db[:items].insert(2**40)
|
492
|
+
@db[:items].all.should == [{:id=>2**40}]
|
493
|
+
end
|
494
|
+
|
495
|
+
specify "should have set_column_type pass through options" do
|
496
|
+
@db.create_table(:items){integer :id; enum :list, :elements=>%w[one]}
|
497
|
+
@db.alter_table(:items){set_column_type :id, :int, :unsigned=>true, :size=>8; set_column_type :list, :enum, :elements=>%w[two]}
|
498
|
+
@db.sqls.should == ["CREATE TABLE items (id integer, list enum('one'))", "DESCRIBE items", "ALTER TABLE items CHANGE COLUMN id id int(8) UNSIGNED NULL", "ALTER TABLE items CHANGE COLUMN list list enum('two') NULL"]
|
499
|
+
end
|
500
|
+
|
501
|
+
specify "should have set_column_default support keep existing options" do
|
502
|
+
@db.create_table(:items){Integer :id, :null=>false, :default=>5}
|
503
|
+
@db.alter_table(:items){set_column_default :id, 6}
|
504
|
+
@db.sqls.should == ["CREATE TABLE items (id integer NOT NULL DEFAULT 5)", "DESCRIBE items", "ALTER TABLE items CHANGE COLUMN id id int(11) NOT NULL DEFAULT 6"]
|
505
|
+
@db[:items].insert
|
506
|
+
@db[:items].all.should == [{:id=>6}]
|
507
|
+
proc{@db[:items].insert(:id=>nil)}.should raise_error(Sequel::DatabaseError)
|
508
|
+
end
|
509
|
+
|
510
|
+
specify "should have set_column_allow_null support keep existing options" do
|
511
|
+
@db.create_table(:items){Integer :id, :null=>false, :default=>5}
|
512
|
+
@db.alter_table(:items){set_column_allow_null :id, true}
|
513
|
+
@db.sqls.should == ["CREATE TABLE items (id integer NOT NULL DEFAULT 5)", "DESCRIBE items", "ALTER TABLE items CHANGE COLUMN id id int(11) NULL DEFAULT 5"]
|
514
|
+
@db[:items].insert
|
515
|
+
@db[:items].all.should == [{:id=>5}]
|
516
|
+
proc{@db[:items].insert(:id=>nil)}.should_not
|
517
|
+
end
|
518
|
+
|
519
|
+
specify "should accept repeated raw sql statements using Database#<<" do
|
520
|
+
@db.create_table(:items){String :name; Integer :value}
|
521
|
+
@db << 'DELETE FROM items'
|
522
|
+
@db[:items].count.should == 0
|
523
|
+
|
524
|
+
@db << "INSERT INTO items (name, value) VALUES ('tutu', 1234)"
|
525
|
+
@db[:items].first.should == {:name => 'tutu', :value => 1234}
|
526
|
+
|
527
|
+
@db << 'DELETE FROM items'
|
528
|
+
@db[:items].first.should == nil
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
532
|
+
# Socket tests should only be run if the MySQL server is on localhost
|
533
|
+
if %w'localhost 127.0.0.1 ::1'.include?(MYSQL_URI.host) and MYSQL_DB.class.adapter_scheme == :mysql
|
534
|
+
context "A MySQL database" do
|
535
|
+
specify "should accept a socket option" do
|
536
|
+
db = Sequel.mysql(MYSQL_DB.opts[:database], :host => 'localhost', :user => MYSQL_DB.opts[:user], :password => MYSQL_DB.opts[:password], :socket => MYSQL_SOCKET_FILE)
|
537
|
+
proc {db.test_connection}.should_not raise_error
|
538
|
+
end
|
539
|
+
|
540
|
+
specify "should accept a socket option without host option" do
|
541
|
+
db = Sequel.mysql(MYSQL_DB.opts[:database], :user => MYSQL_DB.opts[:user], :password => MYSQL_DB.opts[:password], :socket => MYSQL_SOCKET_FILE)
|
542
|
+
proc {db.test_connection}.should_not raise_error
|
543
|
+
end
|
544
|
+
|
545
|
+
specify "should fail to connect with invalid socket" do
|
546
|
+
db = Sequel.mysql(MYSQL_DB.opts[:database], :user => MYSQL_DB.opts[:user], :password => MYSQL_DB.opts[:password], :socket =>'blah')
|
547
|
+
proc {db.test_connection}.should raise_error
|
548
|
+
end
|
549
|
+
end
|
550
|
+
end
|
551
|
+
|
552
|
+
context "A grouped MySQL dataset" do
|
553
|
+
before do
|
554
|
+
MYSQL_DB[:test2].delete
|
555
|
+
MYSQL_DB[:test2] << {:name => '11', :value => 10}
|
556
|
+
MYSQL_DB[:test2] << {:name => '11', :value => 20}
|
557
|
+
MYSQL_DB[:test2] << {:name => '11', :value => 30}
|
558
|
+
MYSQL_DB[:test2] << {:name => '12', :value => 10}
|
559
|
+
MYSQL_DB[:test2] << {:name => '12', :value => 20}
|
560
|
+
MYSQL_DB[:test2] << {:name => '13', :value => 10}
|
561
|
+
end
|
562
|
+
|
563
|
+
specify "should return the correct count for raw sql query" do
|
564
|
+
ds = MYSQL_DB["select name FROM test2 WHERE name = '11' GROUP BY name"]
|
565
|
+
ds.count.should == 1
|
566
|
+
end
|
567
|
+
|
568
|
+
specify "should return the correct count for a normal dataset" do
|
569
|
+
ds = MYSQL_DB[:test2].select(:name).where(:name => '11').group(:name)
|
570
|
+
ds.count.should == 1
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
574
|
+
context "A MySQL database" do
|
575
|
+
before do
|
576
|
+
@db = MYSQL_DB
|
577
|
+
@db.drop_table(:posts) rescue nil
|
578
|
+
@db.sqls.clear
|
579
|
+
end
|
580
|
+
after do
|
581
|
+
@db.drop_table(:posts) rescue nil
|
582
|
+
end
|
583
|
+
|
584
|
+
specify "should support fulltext indexes and full_text_search" do
|
585
|
+
@db.create_table(:posts){text :title; text :body; full_text_index :title; full_text_index [:title, :body]}
|
586
|
+
@db.sqls.should == [
|
587
|
+
"CREATE TABLE posts (title text, body text)",
|
588
|
+
"CREATE FULLTEXT INDEX posts_title_index ON posts (title)",
|
589
|
+
"CREATE FULLTEXT INDEX posts_title_body_index ON posts (title, body)"
|
590
|
+
]
|
591
|
+
|
592
|
+
@db[:posts].insert(:title=>'ruby rails', :body=>'y')
|
593
|
+
@db[:posts].insert(:title=>'sequel', :body=>'ruby')
|
594
|
+
@db[:posts].insert(:title=>'ruby scooby', :body=>'x')
|
595
|
+
@db.sqls.clear
|
596
|
+
|
597
|
+
@db[:posts].full_text_search(:title, 'rails').all.should == [{:title=>'ruby rails', :body=>'y'}]
|
598
|
+
@db[:posts].full_text_search([:title, :body], ['sequel', 'ruby']).all.should == [{:title=>'sequel', :body=>'ruby'}]
|
599
|
+
@db[:posts].full_text_search(:title, '+ruby -rails', :boolean => true).all.should == [{:title=>'ruby scooby', :body=>'x'}]
|
600
|
+
@db.sqls.should == [
|
601
|
+
"SELECT * FROM posts WHERE (MATCH (title) AGAINST ('rails'))",
|
602
|
+
"SELECT * FROM posts WHERE (MATCH (title, body) AGAINST ('sequel ruby'))",
|
603
|
+
"SELECT * FROM posts WHERE (MATCH (title) AGAINST ('+ruby -rails' IN BOOLEAN MODE))"]
|
604
|
+
end
|
605
|
+
|
606
|
+
specify "should support spatial indexes" do
|
607
|
+
@db.create_table(:posts){point :geom, :null=>false; spatial_index [:geom]}
|
608
|
+
@db.sqls.should == [
|
609
|
+
"CREATE TABLE posts (geom point NOT NULL)",
|
610
|
+
"CREATE SPATIAL INDEX posts_geom_index ON posts (geom)"
|
611
|
+
]
|
612
|
+
end
|
613
|
+
|
614
|
+
specify "should support indexes with index type" do
|
615
|
+
@db.create_table(:posts){Integer :id; index :id, :type => :btree}
|
616
|
+
@db.sqls.should == [
|
617
|
+
"CREATE TABLE posts (id integer)",
|
618
|
+
"CREATE INDEX posts_id_index USING btree ON posts (id)"
|
619
|
+
]
|
620
|
+
end
|
621
|
+
|
622
|
+
specify "should support unique indexes with index type" do
|
623
|
+
@db.create_table(:posts){Integer :id; index :id, :type => :btree, :unique => true}
|
624
|
+
@db.sqls.should == [
|
625
|
+
"CREATE TABLE posts (id integer)",
|
626
|
+
"CREATE UNIQUE INDEX posts_id_index USING btree ON posts (id)"
|
627
|
+
]
|
628
|
+
end
|
629
|
+
|
630
|
+
specify "should not dump partial indexes" do
|
631
|
+
@db.create_table(:posts){text :id}
|
632
|
+
@db << "CREATE INDEX posts_id_index ON posts (id(10))"
|
633
|
+
@db.indexes(:posts).should == {}
|
634
|
+
end
|
635
|
+
end
|
636
|
+
|
637
|
+
context "MySQL::Dataset#insert and related methods" do
|
638
|
+
before do
|
639
|
+
MYSQL_DB.create_table(:items){String :name; Integer :value}
|
640
|
+
@d = MYSQL_DB[:items]
|
641
|
+
MYSQL_DB.sqls.clear
|
642
|
+
end
|
643
|
+
after do
|
644
|
+
MYSQL_DB.drop_table(:items)
|
645
|
+
end
|
646
|
+
|
647
|
+
specify "#insert should insert record with default values when no arguments given" do
|
648
|
+
@d.insert
|
649
|
+
|
650
|
+
MYSQL_DB.sqls.should == [
|
651
|
+
"INSERT INTO items () VALUES ()"
|
652
|
+
]
|
653
|
+
|
654
|
+
@d.all.should == [
|
655
|
+
{:name => nil, :value => nil}
|
656
|
+
]
|
657
|
+
end
|
658
|
+
|
659
|
+
specify "#insert should insert record with default values when empty hash given" do
|
660
|
+
@d.insert({})
|
661
|
+
|
662
|
+
MYSQL_DB.sqls.should == [
|
663
|
+
"INSERT INTO items () VALUES ()"
|
664
|
+
]
|
665
|
+
|
666
|
+
@d.all.should == [
|
667
|
+
{:name => nil, :value => nil}
|
668
|
+
]
|
669
|
+
end
|
670
|
+
|
671
|
+
specify "#insert should insert record with default values when empty array given" do
|
672
|
+
@d.insert []
|
673
|
+
|
674
|
+
MYSQL_DB.sqls.should == [
|
675
|
+
"INSERT INTO items () VALUES ()"
|
676
|
+
]
|
677
|
+
|
678
|
+
@d.all.should == [
|
679
|
+
{:name => nil, :value => nil}
|
680
|
+
]
|
681
|
+
end
|
682
|
+
|
683
|
+
specify "#on_duplicate_key_update should work with regular inserts" do
|
684
|
+
MYSQL_DB.add_index :items, :name, :unique=>true
|
685
|
+
MYSQL_DB.sqls.clear
|
686
|
+
@d.insert(:name => 'abc', :value => 1)
|
687
|
+
@d.on_duplicate_key_update(:name, :value => 6).insert(:name => 'abc', :value => 1)
|
688
|
+
@d.on_duplicate_key_update(:name, :value => 6).insert(:name => 'def', :value => 2)
|
689
|
+
|
690
|
+
MYSQL_DB.sqls.length.should == 3
|
691
|
+
MYSQL_DB.sqls[0].should =~ /\AINSERT INTO items \((name|value), (name|value)\) VALUES \(('abc'|1), (1|'abc')\)\z/
|
692
|
+
MYSQL_DB.sqls[1].should =~ /\AINSERT INTO items \((name|value), (name|value)\) VALUES \(('abc'|1), (1|'abc')\) ON DUPLICATE KEY UPDATE name=VALUES\(name\), value=6\z/
|
693
|
+
MYSQL_DB.sqls[2].should =~ /\AINSERT INTO items \((name|value), (name|value)\) VALUES \(('def'|2), (2|'def')\) ON DUPLICATE KEY UPDATE name=VALUES\(name\), value=6\z/
|
694
|
+
|
695
|
+
@d.all.should == [{:name => 'abc', :value => 6}, {:name => 'def', :value => 2}]
|
696
|
+
end
|
697
|
+
|
698
|
+
specify "#multi_insert should insert multiple records in a single statement" do
|
699
|
+
@d.multi_insert([{:name => 'abc'}, {:name => 'def'}])
|
700
|
+
|
701
|
+
MYSQL_DB.sqls.should == [
|
702
|
+
SQL_BEGIN,
|
703
|
+
"INSERT INTO items (name) VALUES ('abc'), ('def')",
|
704
|
+
SQL_COMMIT
|
705
|
+
]
|
706
|
+
|
707
|
+
@d.all.should == [
|
708
|
+
{:name => 'abc', :value => nil}, {:name => 'def', :value => nil}
|
709
|
+
]
|
710
|
+
end
|
711
|
+
|
712
|
+
specify "#multi_insert should split the list of records into batches if :commit_every option is given" do
|
713
|
+
@d.multi_insert([{:value => 1}, {:value => 2}, {:value => 3}, {:value => 4}],
|
714
|
+
:commit_every => 2)
|
715
|
+
|
716
|
+
MYSQL_DB.sqls.should == [
|
717
|
+
SQL_BEGIN,
|
718
|
+
"INSERT INTO items (value) VALUES (1), (2)",
|
719
|
+
SQL_COMMIT,
|
720
|
+
SQL_BEGIN,
|
721
|
+
"INSERT INTO items (value) VALUES (3), (4)",
|
722
|
+
SQL_COMMIT
|
723
|
+
]
|
724
|
+
|
725
|
+
@d.all.should == [
|
726
|
+
{:name => nil, :value => 1},
|
727
|
+
{:name => nil, :value => 2},
|
728
|
+
{:name => nil, :value => 3},
|
729
|
+
{:name => nil, :value => 4}
|
730
|
+
]
|
731
|
+
end
|
732
|
+
|
733
|
+
specify "#multi_insert should split the list of records into batches if :slice option is given" do
|
734
|
+
@d.multi_insert([{:value => 1}, {:value => 2}, {:value => 3}, {:value => 4}],
|
735
|
+
:slice => 2)
|
736
|
+
|
737
|
+
MYSQL_DB.sqls.should == [
|
738
|
+
SQL_BEGIN,
|
739
|
+
"INSERT INTO items (value) VALUES (1), (2)",
|
740
|
+
SQL_COMMIT,
|
741
|
+
SQL_BEGIN,
|
742
|
+
"INSERT INTO items (value) VALUES (3), (4)",
|
743
|
+
SQL_COMMIT
|
744
|
+
]
|
745
|
+
|
746
|
+
@d.all.should == [
|
747
|
+
{:name => nil, :value => 1},
|
748
|
+
{:name => nil, :value => 2},
|
749
|
+
{:name => nil, :value => 3},
|
750
|
+
{:name => nil, :value => 4}
|
751
|
+
]
|
752
|
+
end
|
753
|
+
|
754
|
+
specify "#import should support inserting using columns and values arrays" do
|
755
|
+
@d.import([:name, :value], [['abc', 1], ['def', 2]])
|
756
|
+
|
757
|
+
MYSQL_DB.sqls.should == [
|
758
|
+
SQL_BEGIN,
|
759
|
+
"INSERT INTO items (name, value) VALUES ('abc', 1), ('def', 2)",
|
760
|
+
SQL_COMMIT
|
761
|
+
]
|
762
|
+
|
763
|
+
@d.all.should == [
|
764
|
+
{:name => 'abc', :value => 1},
|
765
|
+
{:name => 'def', :value => 2}
|
766
|
+
]
|
767
|
+
end
|
768
|
+
|
769
|
+
specify "#insert_ignore should add the IGNORE keyword when inserting" do
|
770
|
+
@d.insert_ignore.multi_insert([{:name => 'abc'}, {:name => 'def'}])
|
771
|
+
|
772
|
+
MYSQL_DB.sqls.should == [
|
773
|
+
SQL_BEGIN,
|
774
|
+
"INSERT IGNORE INTO items (name) VALUES ('abc'), ('def')",
|
775
|
+
SQL_COMMIT
|
776
|
+
]
|
777
|
+
|
778
|
+
@d.all.should == [
|
779
|
+
{:name => 'abc', :value => nil}, {:name => 'def', :value => nil}
|
780
|
+
]
|
781
|
+
end
|
782
|
+
|
783
|
+
specify "#insert_ignore should add the IGNORE keyword for single inserts" do
|
784
|
+
@d.insert_ignore.insert(:name => 'ghi')
|
785
|
+
MYSQL_DB.sqls.should == ["INSERT IGNORE INTO items (name) VALUES ('ghi')"]
|
786
|
+
@d.all.should == [{:name => 'ghi', :value => nil}]
|
787
|
+
end
|
788
|
+
|
789
|
+
specify "#on_duplicate_key_update should add the ON DUPLICATE KEY UPDATE and ALL columns when no args given" do
|
790
|
+
@d.on_duplicate_key_update.import([:name,:value], [['abc', 1], ['def',2]])
|
791
|
+
|
792
|
+
MYSQL_DB.sqls.should == [
|
793
|
+
"SELECT * FROM items LIMIT 1",
|
794
|
+
SQL_BEGIN,
|
795
|
+
"INSERT INTO items (name, value) VALUES ('abc', 1), ('def', 2) ON DUPLICATE KEY UPDATE name=VALUES(name), value=VALUES(value)",
|
796
|
+
SQL_COMMIT
|
797
|
+
]
|
798
|
+
|
799
|
+
@d.all.should == [
|
800
|
+
{:name => 'abc', :value => 1}, {:name => 'def', :value => 2}
|
801
|
+
]
|
802
|
+
end
|
803
|
+
|
804
|
+
specify "#on_duplicate_key_update should add the ON DUPLICATE KEY UPDATE and columns specified when args are given" do
|
805
|
+
@d.on_duplicate_key_update(:value).import([:name,:value],
|
806
|
+
[['abc', 1], ['def',2]]
|
807
|
+
)
|
808
|
+
|
809
|
+
MYSQL_DB.sqls.should == [
|
810
|
+
SQL_BEGIN,
|
811
|
+
"INSERT INTO items (name, value) VALUES ('abc', 1), ('def', 2) ON DUPLICATE KEY UPDATE value=VALUES(value)",
|
812
|
+
SQL_COMMIT
|
813
|
+
]
|
814
|
+
|
815
|
+
@d.all.should == [
|
816
|
+
{:name => 'abc', :value => 1}, {:name => 'def', :value => 2}
|
817
|
+
]
|
818
|
+
end
|
819
|
+
|
820
|
+
end
|
821
|
+
|
822
|
+
context "MySQL::Dataset#replace" do
|
823
|
+
before do
|
824
|
+
MYSQL_DB.create_table(:items){Integer :id, :unique=>true; Integer :value}
|
825
|
+
@d = MYSQL_DB[:items]
|
826
|
+
MYSQL_DB.sqls.clear
|
827
|
+
end
|
828
|
+
after do
|
829
|
+
MYSQL_DB.drop_table(:items)
|
830
|
+
end
|
831
|
+
|
832
|
+
specify "should use default values if they exist" do
|
833
|
+
MYSQL_DB.alter_table(:items){set_column_default :id, 1; set_column_default :value, 2}
|
834
|
+
@d.replace
|
835
|
+
@d.all.should == [{:id=>1, :value=>2}]
|
836
|
+
@d.replace([])
|
837
|
+
@d.all.should == [{:id=>1, :value=>2}]
|
838
|
+
@d.replace({})
|
839
|
+
@d.all.should == [{:id=>1, :value=>2}]
|
840
|
+
end
|
841
|
+
|
842
|
+
specify "should use support arrays, datasets, and multiple values" do
|
843
|
+
@d.replace([1, 2])
|
844
|
+
@d.all.should == [{:id=>1, :value=>2}]
|
845
|
+
@d.replace(1, 2)
|
846
|
+
@d.all.should == [{:id=>1, :value=>2}]
|
847
|
+
@d.replace(@d)
|
848
|
+
@d.all.should == [{:id=>1, :value=>2}]
|
849
|
+
end
|
850
|
+
|
851
|
+
specify "should create a record if the condition is not met" do
|
852
|
+
@d.replace(:id => 111, :value => 333)
|
853
|
+
@d.all.should == [{:id => 111, :value => 333}]
|
854
|
+
end
|
855
|
+
|
856
|
+
specify "should update a record if the condition is met" do
|
857
|
+
@d << {:id => 111}
|
858
|
+
@d.all.should == [{:id => 111, :value => nil}]
|
859
|
+
@d.replace(:id => 111, :value => 333)
|
860
|
+
@d.all.should == [{:id => 111, :value => 333}]
|
861
|
+
end
|
862
|
+
end
|
863
|
+
|
864
|
+
context "MySQL::Dataset#complex_expression_sql" do
|
865
|
+
before do
|
866
|
+
@d = MYSQL_DB.dataset
|
867
|
+
end
|
868
|
+
|
869
|
+
specify "should handle pattern matches correctly" do
|
870
|
+
@d.literal(:x.like('a')).should == "(x LIKE BINARY 'a')"
|
871
|
+
@d.literal(~:x.like('a')).should == "(x NOT LIKE BINARY 'a')"
|
872
|
+
@d.literal(:x.ilike('a')).should == "(x LIKE 'a')"
|
873
|
+
@d.literal(~:x.ilike('a')).should == "(x NOT LIKE 'a')"
|
874
|
+
@d.literal(:x.like(/a/)).should == "(x REGEXP BINARY 'a')"
|
875
|
+
@d.literal(~:x.like(/a/)).should == "(x NOT REGEXP BINARY 'a')"
|
876
|
+
@d.literal(:x.like(/a/i)).should == "(x REGEXP 'a')"
|
877
|
+
@d.literal(~:x.like(/a/i)).should == "(x NOT REGEXP 'a')"
|
878
|
+
end
|
879
|
+
|
880
|
+
specify "should handle string concatenation with CONCAT if more than one record" do
|
881
|
+
@d.literal([:x, :y].sql_string_join).should == "CONCAT(x, y)"
|
882
|
+
@d.literal([:x, :y].sql_string_join(' ')).should == "CONCAT(x, ' ', y)"
|
883
|
+
@d.literal([:x.sql_function(:y), 1, 'z'.lit].sql_string_join(:y.sql_subscript(1))).should == "CONCAT(x(y), y[1], '1', y[1], z)"
|
884
|
+
end
|
885
|
+
|
886
|
+
specify "should handle string concatenation as simple string if just one record" do
|
887
|
+
@d.literal([:x].sql_string_join).should == "x"
|
888
|
+
@d.literal([:x].sql_string_join(' ')).should == "x"
|
889
|
+
end
|
890
|
+
end
|
891
|
+
|
892
|
+
unless MYSQL_DB.class.adapter_scheme == :do
|
893
|
+
context "MySQL Stored Procedures" do
|
894
|
+
before do
|
895
|
+
MYSQL_DB.create_table(:items){Integer :id; Integer :value}
|
896
|
+
@d = MYSQL_DB[:items]
|
897
|
+
MYSQL_DB.sqls.clear
|
898
|
+
end
|
899
|
+
after do
|
900
|
+
MYSQL_DB.drop_table(:items)
|
901
|
+
MYSQL_DB.execute('DROP PROCEDURE test_sproc')
|
902
|
+
end
|
903
|
+
|
904
|
+
specify "should be callable on the database object" do
|
905
|
+
MYSQL_DB.execute('CREATE PROCEDURE test_sproc() BEGIN DELETE FROM items; END')
|
906
|
+
MYSQL_DB[:items].delete
|
907
|
+
MYSQL_DB[:items].insert(:value=>1)
|
908
|
+
MYSQL_DB[:items].count.should == 1
|
909
|
+
MYSQL_DB.call_sproc(:test_sproc)
|
910
|
+
MYSQL_DB[:items].count.should == 0
|
911
|
+
end
|
912
|
+
|
913
|
+
specify "should be callable on the dataset object" do
|
914
|
+
MYSQL_DB.execute('CREATE PROCEDURE test_sproc(a INTEGER) BEGIN SELECT *, a AS b FROM items; END')
|
915
|
+
MYSQL_DB[:items].delete
|
916
|
+
@d = MYSQL_DB[:items]
|
917
|
+
@d.call_sproc(:select, :test_sproc, 3).should == []
|
918
|
+
@d.insert(:value=>1)
|
919
|
+
@d.call_sproc(:select, :test_sproc, 4).should == [{:id=>nil, :value=>1, :b=>4}]
|
920
|
+
@d.row_proc = proc{|r| r.keys.each{|k| r[k] *= 2 if r[k].is_a?(Integer)}; r}
|
921
|
+
@d.call_sproc(:select, :test_sproc, 3).should == [{:id=>nil, :value=>2, :b=>6}]
|
922
|
+
end
|
923
|
+
|
924
|
+
specify "should be callable on the dataset object with multiple arguments" do
|
925
|
+
MYSQL_DB.execute('CREATE PROCEDURE test_sproc(a INTEGER, c INTEGER) BEGIN SELECT *, a AS b, c AS d FROM items; END')
|
926
|
+
MYSQL_DB[:items].delete
|
927
|
+
@d = MYSQL_DB[:items]
|
928
|
+
@d.call_sproc(:select, :test_sproc, 3, 4).should == []
|
929
|
+
@d.insert(:value=>1)
|
930
|
+
@d.call_sproc(:select, :test_sproc, 4, 5).should == [{:id=>nil, :value=>1, :b=>4, :d=>5}]
|
931
|
+
@d.row_proc = proc{|r| r.keys.each{|k| r[k] *= 2 if r[k].is_a?(Integer)}; r}
|
932
|
+
@d.call_sproc(:select, :test_sproc, 3, 4).should == [{:id=>nil, :value=>2, :b=>6, :d => 8}]
|
933
|
+
end
|
934
|
+
end
|
935
|
+
end
|
936
|
+
|
937
|
+
if MYSQL_DB.class.adapter_scheme == :mysql
|
938
|
+
context "MySQL bad date/time conversions" do
|
939
|
+
after do
|
940
|
+
Sequel::MySQL.convert_invalid_date_time = false
|
941
|
+
end
|
942
|
+
|
943
|
+
specify "should raise an exception when a bad date/time is used and convert_invalid_date_time is false" do
|
944
|
+
Sequel::MySQL.convert_invalid_date_time = false
|
945
|
+
proc{MYSQL_DB["SELECT CAST('0000-00-00' AS date)"].single_value}.should raise_error(Sequel::InvalidValue)
|
946
|
+
proc{MYSQL_DB["SELECT CAST('0000-00-00 00:00:00' AS datetime)"].single_value}.should raise_error(Sequel::InvalidValue)
|
947
|
+
proc{MYSQL_DB["SELECT CAST('25:00:00' AS time)"].single_value}.should raise_error(Sequel::InvalidValue)
|
948
|
+
end
|
949
|
+
|
950
|
+
specify "should not use a nil value bad date/time is used and convert_invalid_date_time is nil or :nil" do
|
951
|
+
Sequel::MySQL.convert_invalid_date_time = nil
|
952
|
+
MYSQL_DB["SELECT CAST('0000-00-00' AS date)"].single_value.should == nil
|
953
|
+
MYSQL_DB["SELECT CAST('0000-00-00 00:00:00' AS datetime)"].single_value.should == nil
|
954
|
+
MYSQL_DB["SELECT CAST('25:00:00' AS time)"].single_value.should == nil
|
955
|
+
Sequel::MySQL.convert_invalid_date_time = :nil
|
956
|
+
MYSQL_DB["SELECT CAST('0000-00-00' AS date)"].single_value.should == nil
|
957
|
+
MYSQL_DB["SELECT CAST('0000-00-00 00:00:00' AS datetime)"].single_value.should == nil
|
958
|
+
MYSQL_DB["SELECT CAST('25:00:00' AS time)"].single_value.should == nil
|
959
|
+
end
|
960
|
+
|
961
|
+
specify "should not use a nil value bad date/time is used and convert_invalid_date_time is :string" do
|
962
|
+
Sequel::MySQL.convert_invalid_date_time = :string
|
963
|
+
MYSQL_DB["SELECT CAST('0000-00-00' AS date)"].single_value.should == '0000-00-00'
|
964
|
+
MYSQL_DB["SELECT CAST('0000-00-00 00:00:00' AS datetime)"].single_value.should == '0000-00-00 00:00:00'
|
965
|
+
MYSQL_DB["SELECT CAST('25:00:00' AS time)"].single_value.should == '25:00:00'
|
966
|
+
end
|
967
|
+
end
|
968
|
+
|
969
|
+
context "MySQL multiple result sets" do
|
970
|
+
before do
|
971
|
+
MYSQL_DB.create_table!(:a){Integer :a}
|
972
|
+
MYSQL_DB.create_table!(:b){Integer :b}
|
973
|
+
@ds = MYSQL_DB['SELECT * FROM a; SELECT * FROM b']
|
974
|
+
MYSQL_DB[:a].insert(10)
|
975
|
+
MYSQL_DB[:a].insert(15)
|
976
|
+
MYSQL_DB[:b].insert(20)
|
977
|
+
MYSQL_DB[:b].insert(25)
|
978
|
+
end
|
979
|
+
after do
|
980
|
+
MYSQL_DB.drop_table(:a, :b)
|
981
|
+
end
|
982
|
+
|
983
|
+
specify "should combine all results by default" do
|
984
|
+
@ds.all.should == [{:a=>10}, {:a=>15}, {:b=>20}, {:b=>25}]
|
985
|
+
end
|
986
|
+
|
987
|
+
specify "should work with Database#run" do
|
988
|
+
proc{MYSQL_DB.run('SELECT * FROM a; SELECT * FROM b')}.should_not raise_error
|
989
|
+
proc{MYSQL_DB.run('SELECT * FROM a; SELECT * FROM b')}.should_not raise_error
|
990
|
+
end
|
991
|
+
|
992
|
+
specify "should work with Database#run and other statements" do
|
993
|
+
proc{MYSQL_DB.run('UPDATE a SET a = 1; SELECT * FROM a; DELETE FROM b')}.should_not raise_error
|
994
|
+
MYSQL_DB[:a].select_order_map(:a).should == [1, 1]
|
995
|
+
MYSQL_DB[:b].all.should == []
|
996
|
+
end
|
997
|
+
|
998
|
+
specify "should split results returned into arrays if split_multiple_result_sets is used" do
|
999
|
+
@ds.split_multiple_result_sets.all.should == [[{:a=>10}, {:a=>15}], [{:b=>20}, {:b=>25}]]
|
1000
|
+
end
|
1001
|
+
|
1002
|
+
specify "should have regular row_procs work when splitting multiple result sets" do
|
1003
|
+
@ds.row_proc = proc{|x| x[x.keys.first] *= 2; x}
|
1004
|
+
@ds.split_multiple_result_sets.all.should == [[{:a=>20}, {:a=>30}], [{:b=>40}, {:b=>50}]]
|
1005
|
+
end
|
1006
|
+
|
1007
|
+
specify "should use the columns from the first result set when splitting result sets" do
|
1008
|
+
@ds.split_multiple_result_sets.columns.should == [:a]
|
1009
|
+
end
|
1010
|
+
|
1011
|
+
specify "should not allow graphing a dataset that splits multiple statements" do
|
1012
|
+
proc{@ds.split_multiple_result_sets.graph(:b, :b=>:a)}.should raise_error(Sequel::Error)
|
1013
|
+
end
|
1014
|
+
|
1015
|
+
specify "should not allow splitting a graphed dataset" do
|
1016
|
+
proc{MYSQL_DB[:a].graph(:b, :b=>:a).split_multiple_result_sets}.should raise_error(Sequel::Error)
|
1017
|
+
end
|
1018
|
+
end
|
1019
|
+
end
|