sequel_core 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/CHANGELOG +1003 -0
  2. data/COPYING +18 -0
  3. data/README +81 -0
  4. data/Rakefile +176 -0
  5. data/bin/sequel +41 -0
  6. data/lib/sequel_core.rb +59 -0
  7. data/lib/sequel_core/adapters/adapter_skeleton.rb +68 -0
  8. data/lib/sequel_core/adapters/ado.rb +100 -0
  9. data/lib/sequel_core/adapters/db2.rb +158 -0
  10. data/lib/sequel_core/adapters/dbi.rb +126 -0
  11. data/lib/sequel_core/adapters/informix.rb +87 -0
  12. data/lib/sequel_core/adapters/jdbc.rb +108 -0
  13. data/lib/sequel_core/adapters/mysql.rb +269 -0
  14. data/lib/sequel_core/adapters/odbc.rb +145 -0
  15. data/lib/sequel_core/adapters/odbc_mssql.rb +93 -0
  16. data/lib/sequel_core/adapters/openbase.rb +90 -0
  17. data/lib/sequel_core/adapters/oracle.rb +99 -0
  18. data/lib/sequel_core/adapters/postgres.rb +519 -0
  19. data/lib/sequel_core/adapters/sqlite.rb +192 -0
  20. data/lib/sequel_core/array_keys.rb +296 -0
  21. data/lib/sequel_core/connection_pool.rb +152 -0
  22. data/lib/sequel_core/core_ext.rb +59 -0
  23. data/lib/sequel_core/core_sql.rb +191 -0
  24. data/lib/sequel_core/database.rb +433 -0
  25. data/lib/sequel_core/dataset.rb +409 -0
  26. data/lib/sequel_core/dataset/convenience.rb +321 -0
  27. data/lib/sequel_core/dataset/sequelizer.rb +354 -0
  28. data/lib/sequel_core/dataset/sql.rb +586 -0
  29. data/lib/sequel_core/exceptions.rb +45 -0
  30. data/lib/sequel_core/migration.rb +191 -0
  31. data/lib/sequel_core/model.rb +8 -0
  32. data/lib/sequel_core/pretty_table.rb +73 -0
  33. data/lib/sequel_core/schema.rb +8 -0
  34. data/lib/sequel_core/schema/schema_generator.rb +131 -0
  35. data/lib/sequel_core/schema/schema_sql.rb +131 -0
  36. data/lib/sequel_core/worker.rb +58 -0
  37. data/spec/adapters/informix_spec.rb +139 -0
  38. data/spec/adapters/mysql_spec.rb +330 -0
  39. data/spec/adapters/oracle_spec.rb +130 -0
  40. data/spec/adapters/postgres_spec.rb +189 -0
  41. data/spec/adapters/sqlite_spec.rb +345 -0
  42. data/spec/array_keys_spec.rb +679 -0
  43. data/spec/connection_pool_spec.rb +356 -0
  44. data/spec/core_ext_spec.rb +67 -0
  45. data/spec/core_sql_spec.rb +301 -0
  46. data/spec/database_spec.rb +812 -0
  47. data/spec/dataset_spec.rb +2381 -0
  48. data/spec/migration_spec.rb +261 -0
  49. data/spec/pretty_table_spec.rb +66 -0
  50. data/spec/rcov.opts +4 -0
  51. data/spec/schema_generator_spec.rb +86 -0
  52. data/spec/schema_spec.rb +230 -0
  53. data/spec/sequelizer_spec.rb +448 -0
  54. data/spec/spec.opts +5 -0
  55. data/spec/spec_helper.rb +44 -0
  56. data/spec/worker_spec.rb +96 -0
  57. metadata +162 -0
@@ -0,0 +1,131 @@
1
+ module Sequel
2
+ module Schema
3
+ module SQL
4
+ RESTRICT = 'RESTRICT'.freeze
5
+ CASCADE = 'CASCADE'.freeze
6
+ NO_ACTION = 'NO ACTION'.freeze
7
+ SET_NULL = 'SET NULL'.freeze
8
+ SET_DEFAULT = 'SET DEFAULT'.freeze
9
+
10
+ def on_delete_clause(action)
11
+ case action
12
+ when :restrict
13
+ RESTRICT
14
+ when :cascade
15
+ CASCADE
16
+ when :set_null
17
+ SET_NULL
18
+ when :set_default
19
+ SET_DEFAULT
20
+ else
21
+ NO_ACTION
22
+ end
23
+ end
24
+
25
+ AUTOINCREMENT = 'AUTOINCREMENT'.freeze
26
+
27
+ def auto_increment_sql
28
+ AUTOINCREMENT
29
+ end
30
+
31
+ COMMA_SEPARATOR = ', '.freeze
32
+ UNIQUE = ' UNIQUE'.freeze
33
+ NOT_NULL = ' NOT NULL'.freeze
34
+ PRIMARY_KEY = ' PRIMARY KEY'.freeze
35
+
36
+ TYPES = Hash.new {|h, k| k}
37
+ TYPES[:double] = 'double precision'
38
+
39
+ def schema_utility_dataset
40
+ @schema_utility_dataset ||= dataset
41
+ end
42
+
43
+ def literal(v)
44
+ schema_utility_dataset.literal(v)
45
+ end
46
+
47
+ def column_definition_sql(column)
48
+ sql = "#{literal(column[:name].to_sym)} #{TYPES[column[:type]]}"
49
+ column[:size] ||= 255 if column[:type] == :varchar
50
+ elements = column[:size] || column[:elements]
51
+ sql << "(#{literal(elements)})" if elements
52
+ sql << UNIQUE if column[:unique]
53
+ sql << NOT_NULL if column[:null] == false
54
+ sql << " DEFAULT #{literal(column[:default])}" if column.include?(:default)
55
+ sql << PRIMARY_KEY if column[:primary_key]
56
+ if column[:table]
57
+ sql << " REFERENCES #{column[:table]}"
58
+ sql << "(#{column[:key]})" if column[:key]
59
+ end
60
+ sql << " ON DELETE #{on_delete_clause(column[:on_delete])}" if column[:on_delete]
61
+ sql << " #{auto_increment_sql}" if column[:auto_increment]
62
+ sql
63
+ end
64
+
65
+ def column_list_sql(columns)
66
+ columns.map {|c| column_definition_sql(c)}.join(COMMA_SEPARATOR)
67
+ end
68
+
69
+ UNDERSCORE = '_'.freeze
70
+
71
+ def default_index_name(table_name, columns)
72
+ "#{table_name}_#{columns.join(UNDERSCORE)}_index"
73
+ end
74
+
75
+ def index_definition_sql(table_name, index)
76
+ index_name = index[:name] || default_index_name(table_name, index[:columns])
77
+ if index[:unique]
78
+ "CREATE UNIQUE INDEX #{index_name} ON #{table_name} (#{literal(index[:columns])})"
79
+ else
80
+ "CREATE INDEX #{index_name} ON #{table_name} (#{literal(index[:columns])})"
81
+ end
82
+ end
83
+
84
+ def index_list_sql_list(table_name, indexes)
85
+ indexes.map {|i| index_definition_sql(table_name, i)}
86
+ end
87
+
88
+ def create_table_sql_list(name, columns, indexes = nil)
89
+ sql = ["CREATE TABLE #{name} (#{column_list_sql(columns)})"]
90
+ if indexes && !indexes.empty?
91
+ sql.concat(index_list_sql_list(name, indexes))
92
+ end
93
+ sql
94
+ end
95
+
96
+ def drop_table_sql(name)
97
+ "DROP TABLE #{name}"
98
+ end
99
+
100
+ def rename_table_sql(name, new_name)
101
+ "ALTER TABLE #{name} RENAME TO #{new_name}"
102
+ end
103
+
104
+ def alter_table_sql_list(table, operations)
105
+ operations.map {|op| alter_table_sql(table, op)}
106
+ end
107
+
108
+ def alter_table_sql(table, op)
109
+ case op[:op]
110
+ when :add_column
111
+ "ALTER TABLE #{table} ADD COLUMN #{column_definition_sql(op)}"
112
+ when :drop_column
113
+ "ALTER TABLE #{table} DROP COLUMN #{literal(op[:name])}"
114
+ when :rename_column
115
+ "ALTER TABLE #{table} RENAME COLUMN #{literal(op[:name])} TO #{literal(op[:new_name])}"
116
+ when :set_column_type
117
+ "ALTER TABLE #{table} ALTER COLUMN #{literal(op[:name])} TYPE #{op[:type]}"
118
+ when :set_column_default
119
+ "ALTER TABLE #{table} ALTER COLUMN #{literal(op[:name])} SET DEFAULT #{literal(op[:default])}"
120
+ when :add_index
121
+ index_definition_sql(table, op)
122
+ when :drop_index
123
+ "DROP INDEX #{default_index_name(table, op[:columns])}"
124
+ else
125
+ raise Error, "Unsupported ALTER TABLE operation"
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
131
+
@@ -0,0 +1,58 @@
1
+ require "thread"
2
+
3
+ module Sequel
4
+
5
+ class Worker < Thread
6
+
7
+ attr_reader :queue
8
+ attr_reader :errors
9
+
10
+ def initialize(db = nil)
11
+ @queue = Queue.new
12
+ @errors = []
13
+ t = self
14
+ t.abort_on_exception = true
15
+ @transaction = !db.nil?
16
+ db ? super {db.transaction {t.work}} : super {t.work}
17
+ end
18
+
19
+ def work
20
+ loop {next_job}
21
+ rescue Sequel::Error::WorkerStop # signals the worker thread to stop
22
+ ensure
23
+ rollback! if @transaction && !@errors.empty?
24
+ end
25
+
26
+ def busy?
27
+ @cur || !@queue.empty?
28
+ end
29
+
30
+ def async(proc = nil, &block)
31
+ @queue << (proc || block)
32
+ self
33
+ end
34
+ alias_method :add, :async
35
+ alias_method :<<, :async
36
+
37
+ def join
38
+ while busy?
39
+ sleep 0.1
40
+ end
41
+ self.raise Error::WorkerStop
42
+ super
43
+ end
44
+
45
+ private
46
+ def next_job
47
+ @cur = @queue.pop
48
+ @cur.call
49
+ rescue Error::WorkerStop => e
50
+ raise e
51
+ rescue Exception => e
52
+ @errors << e
53
+ ensure
54
+ @cur = nil
55
+ end
56
+ end
57
+
58
+ end
@@ -0,0 +1,139 @@
1
+ require File.join(File.dirname(__FILE__), '../../lib/sequel')
2
+
3
+ INFORMIX_DB = Sequel('informix://localhost/mydb')
4
+ if INFORMIX_DB.table_exists?(:test)
5
+ INFORMIX_DB.drop_table :test
6
+ end
7
+ INFORMIX_DB.create_table :test do
8
+ text :name
9
+ integer :value
10
+
11
+ index :value
12
+ end
13
+
14
+ context "A Informix database" do
15
+ specify "should provide disconnect functionality" do
16
+ INFORMIX_DB.execute("select user from dual")
17
+ INFORMIX_DB.pool.size.should == 1
18
+ INFORMIX_DB.disconnect
19
+ INFORMIX_DB.pool.size.should == 0
20
+ end
21
+ end
22
+
23
+ context "A Informix dataset" do
24
+ setup do
25
+ @d = INFORMIX_DB[:test]
26
+ @d.delete # remove all records
27
+ end
28
+
29
+ specify "should return the correct record count" do
30
+ @d.count.should == 0
31
+ @d << {:name => 'abc', :value => 123}
32
+ @d << {:name => 'abc', :value => 456}
33
+ @d << {:name => 'def', :value => 789}
34
+ @d.count.should == 3
35
+ end
36
+
37
+ specify "should return the correct records" do
38
+ @d.to_a.should == []
39
+ @d << {:name => 'abc', :value => 123}
40
+ @d << {:name => 'abc', :value => 456}
41
+ @d << {:name => 'def', :value => 789}
42
+
43
+ @d.order(:value).to_a.should == [
44
+ {:name => 'abc', :value => 123},
45
+ {:name => 'abc', :value => 456},
46
+ {:name => 'def', :value => 789}
47
+ ]
48
+ end
49
+
50
+ specify "should update records correctly" do
51
+ @d << {:name => 'abc', :value => 123}
52
+ @d << {:name => 'abc', :value => 456}
53
+ @d << {:name => 'def', :value => 789}
54
+ @d.filter(:name => 'abc').update(:value => 530)
55
+
56
+ # the third record should stay the same
57
+ # floating-point precision bullshit
58
+ @d[:name => 'def'][:value].should == 789
59
+ @d.filter(:value => 530).count.should == 2
60
+ end
61
+
62
+ specify "should delete records correctly" do
63
+ @d << {:name => 'abc', :value => 123}
64
+ @d << {:name => 'abc', :value => 456}
65
+ @d << {:name => 'def', :value => 789}
66
+ @d.filter(:name => 'abc').delete
67
+
68
+ @d.count.should == 1
69
+ @d.first[:name].should == 'def'
70
+ end
71
+
72
+ specify "should be able to literalize booleans" do
73
+ proc {@d.literal(true)}.should_not raise_error
74
+ proc {@d.literal(false)}.should_not raise_error
75
+ end
76
+
77
+ specify "should support transactions" do
78
+ INFORMIX_DB.transaction do
79
+ @d << {:name => 'abc', :value => 1}
80
+ end
81
+
82
+ @d.count.should == 1
83
+ end
84
+
85
+ specify "should support #first and #last" do
86
+ @d << {:name => 'abc', :value => 123}
87
+ @d << {:name => 'abc', :value => 456}
88
+ @d << {:name => 'def', :value => 789}
89
+
90
+ @d.order(:value).first.should == {:name => 'abc', :value => 123}
91
+ @d.order(:value).last.should == {:name => 'def', :value => 789}
92
+ end
93
+ end
94
+
95
+ context "A Informix dataset in array tuples mode" do
96
+ setup do
97
+ @d = INFORMIX_DB[:test]
98
+ @d.delete # remove all records
99
+ Sequel.use_array_tuples
100
+ end
101
+
102
+ teardown do
103
+ Sequel.use_hash_tuples
104
+ end
105
+
106
+ specify "should return the correct records" do
107
+ @d.to_a.should == []
108
+ @d << {:name => 'abc', :value => 123}
109
+ @d << {:name => 'abc', :value => 456}
110
+ @d << {:name => 'def', :value => 789}
111
+
112
+ @d.order(:value).select(:name, :value).to_a.should == [
113
+ ['abc', 123],
114
+ ['abc', 456],
115
+ ['def', 789]
116
+ ]
117
+ end
118
+
119
+ specify "should work correctly with transforms" do
120
+ @d.transform(:value => [proc {|v| v.to_s}, proc {|v| v.to_i}])
121
+
122
+ @d.to_a.should == []
123
+ @d << {:name => 'abc', :value => 123}
124
+ @d << {:name => 'abc', :value => 456}
125
+ @d << {:name => 'def', :value => 789}
126
+
127
+ @d.order(:value).select(:name, :value).to_a.should == [
128
+ ['abc', '123'],
129
+ ['abc', '456'],
130
+ ['def', '789']
131
+ ]
132
+
133
+ a = @d.order(:value).first
134
+ a.values.should == ['abc', '123']
135
+ a.keys.should == [:name, :value]
136
+ a[:name].should == 'abc'
137
+ a[:value].should == '123'
138
+ end
139
+ end
@@ -0,0 +1,330 @@
1
+ require File.join(File.dirname(__FILE__), '../../lib/sequel')
2
+ require 'logger'
3
+
4
+ MYSQL_DB = Sequel('mysql://root@localhost/sandbox')
5
+ MYSQL_DB.drop_table(:items) if MYSQL_DB.table_exists?(:items)
6
+ MYSQL_DB.drop_table(:test2) if MYSQL_DB.table_exists?(:test2)
7
+ MYSQL_DB.create_table :items do
8
+ text :name
9
+ integer :value, :index => true
10
+ end
11
+ MYSQL_DB.create_table :test2 do
12
+ text :name
13
+ integer :value
14
+ end
15
+
16
+ context "A MySQL database" do
17
+ setup do
18
+ @db = MYSQL_DB
19
+ end
20
+
21
+ specify "should provide disconnect functionality" do
22
+ @db.tables
23
+ @db.pool.size.should == 1
24
+ @db.disconnect
25
+ @db.pool.size.should == 0
26
+ end
27
+ end
28
+
29
+ context "A MySQL dataset" do
30
+ setup do
31
+ @d = MYSQL_DB[:items]
32
+ @d.delete # remove all records
33
+ end
34
+
35
+ specify "should return the correct record count" do
36
+ @d.count.should == 0
37
+ @d << {:name => 'abc', :value => 123}
38
+ @d << {:name => 'abc', :value => 456}
39
+ @d << {:name => 'def', :value => 789}
40
+ @d.count.should == 3
41
+ end
42
+
43
+ specify "should return the correct records" do
44
+ @d.to_a.should == []
45
+ @d << {:name => 'abc', :value => 123}
46
+ @d << {:name => 'abc', :value => 456}
47
+ @d << {:name => 'def', :value => 789}
48
+
49
+ @d.order(:value).to_a.should == [
50
+ {:name => 'abc', :value => 123},
51
+ {:name => 'abc', :value => 456},
52
+ {:name => 'def', :value => 789}
53
+ ]
54
+ end
55
+
56
+ specify "should update records correctly" do
57
+ @d << {:name => 'abc', :value => 123}
58
+ @d << {:name => 'abc', :value => 456}
59
+ @d << {:name => 'def', :value => 789}
60
+ @d.filter(:name => 'abc').update(:value => 530)
61
+
62
+ # the third record should stay the same
63
+ # floating-point precision bullshit
64
+ @d[:name => 'def'][:value].should == 789
65
+ @d.filter(:value => 530).count.should == 2
66
+ end
67
+
68
+ specify "should delete records correctly" do
69
+ @d << {:name => 'abc', :value => 123}
70
+ @d << {:name => 'abc', :value => 456}
71
+ @d << {:name => 'def', :value => 789}
72
+ @d.filter(:name => 'abc').delete
73
+
74
+ @d.count.should == 1
75
+ @d.first[:name].should == 'def'
76
+ end
77
+
78
+ specify "should be able to literalize booleans" do
79
+ proc {@d.literal(true)}.should_not raise_error
80
+ proc {@d.literal(false)}.should_not raise_error
81
+ end
82
+
83
+ specify "should quote columns using back-ticks" do
84
+ @d.select(:name).sql.should == \
85
+ 'SELECT `name` FROM items'
86
+
87
+ @d.select('COUNT(*)'.lit).sql.should == \
88
+ 'SELECT COUNT(*) FROM items'
89
+
90
+ @d.select(:value.MAX).sql.should == \
91
+ 'SELECT max(`value`) FROM items'
92
+
93
+ @d.select(:NOW[]).sql.should == \
94
+ 'SELECT NOW() FROM items'
95
+
96
+ @d.select(:items__value.MAX).sql.should == \
97
+ 'SELECT max(items.`value`) FROM items'
98
+
99
+ @d.order(:name.DESC).sql.should == \
100
+ 'SELECT * FROM items ORDER BY `name` DESC'
101
+
102
+ @d.select('items.name AS item_name'.lit).sql.should == \
103
+ 'SELECT items.name AS item_name FROM items'
104
+
105
+ @d.select('`name`'.lit).sql.should == \
106
+ 'SELECT `name` FROM items'
107
+
108
+ @d.select('max(items.`name`) AS `max_name`'.lit).sql.should == \
109
+ 'SELECT max(items.`name`) AS `max_name` FROM items'
110
+
111
+ @d.select(:test[:abc, 'hello']).sql.should == \
112
+ "SELECT test(`abc`, 'hello') FROM items"
113
+
114
+ @d.select(:test[:abc__def, 'hello']).sql.should == \
115
+ "SELECT test(abc.`def`, 'hello') FROM items"
116
+
117
+ @d.select(:test[:abc__def, 'hello'].as(:x2)).sql.should == \
118
+ "SELECT test(abc.`def`, 'hello') AS `x2` FROM items"
119
+
120
+ @d.insert_sql(:value => 333).should == \
121
+ 'INSERT INTO items (`value`) VALUES (333)'
122
+
123
+ @d.insert_sql(:x => :y).should == \
124
+ 'INSERT INTO items (`x`) VALUES (`y`)'
125
+ end
126
+
127
+ specify "should quote fields correctly when reversing the order" do
128
+ @d.reverse_order(:name).sql.should == \
129
+ 'SELECT * FROM items ORDER BY `name` DESC'
130
+
131
+ @d.reverse_order(:name.DESC).sql.should == \
132
+ 'SELECT * FROM items ORDER BY `name`'
133
+
134
+ @d.reverse_order(:name, :test.DESC).sql.should == \
135
+ 'SELECT * FROM items ORDER BY `name` DESC, `test`'
136
+
137
+ @d.reverse_order(:name.DESC, :test).sql.should == \
138
+ 'SELECT * FROM items ORDER BY `name`, `test` DESC'
139
+ end
140
+
141
+ specify "should support ORDER clause in UPDATE statements" do
142
+ @d.order(:name).update_sql(:value => 1).should == \
143
+ 'UPDATE items SET `value` = 1 ORDER BY `name`'
144
+ end
145
+
146
+ specify "should support LIMIT clause in UPDATE statements" do
147
+ @d.limit(10).update_sql(:value => 1).should == \
148
+ 'UPDATE items SET `value` = 1 LIMIT 10'
149
+ end
150
+
151
+ specify "should support transactions" do
152
+ MYSQL_DB.transaction do
153
+ @d << {:name => 'abc', :value => 1}
154
+ end
155
+
156
+ @d.count.should == 1
157
+ end
158
+
159
+ specify "should support regexps" do
160
+ @d << {:name => 'abc', :value => 1}
161
+ @d << {:name => 'bcd', :value => 2}
162
+ @d.filter(:name => /bc/).count.should == 2
163
+ @d.filter(:name => /^bc/).count.should == 1
164
+ end
165
+
166
+ specify "should correctly literalize strings with comment backslashes in them" do
167
+ @d.delete
168
+ proc {@d << {:name => ':\\'}}.should_not raise_error
169
+
170
+ @d.first[:name].should == ':\\'
171
+ end
172
+ end
173
+
174
+ context "A MySQL dataset in array tuples mode" do
175
+ setup do
176
+ @d = MYSQL_DB[:items]
177
+ @d.delete # remove all records
178
+ Sequel.use_array_tuples
179
+ end
180
+
181
+ teardown do
182
+ Sequel.use_hash_tuples
183
+ end
184
+
185
+ specify "should return the correct records" do
186
+ @d.to_a.should == []
187
+ @d << {:name => 'abc', :value => 123}
188
+ @d << {:name => 'abc', :value => 456}
189
+ @d << {:name => 'def', :value => 789}
190
+
191
+ @d.order(:value).select(:name, :value).to_a.should == [
192
+ ['abc', 123],
193
+ ['abc', 456],
194
+ ['def', 789]
195
+ ]
196
+ end
197
+
198
+ specify "should work correctly with transforms" do
199
+ @d.transform(:value => [proc {|v| v.to_s}, proc {|v| v.to_i}])
200
+
201
+ @d.to_a.should == []
202
+ @d << {:name => 'abc', :value => 123}
203
+ @d << {:name => 'abc', :value => 456}
204
+ @d << {:name => 'def', :value => 789}
205
+
206
+ @d.order(:value).select(:name, :value).to_a.should == [
207
+ ['abc', '123'],
208
+ ['abc', '456'],
209
+ ['def', '789']
210
+ ]
211
+
212
+ a = @d.order(:value).first
213
+ a.values.should == ['abc', '123']
214
+ a.keys.should == [:name, :value]
215
+ a[:name].should == 'abc'
216
+ a[:value].should == '123'
217
+ end
218
+ end
219
+
220
+ context "MySQL datasets" do
221
+ setup do
222
+ @d = MYSQL_DB[:orders]
223
+ end
224
+
225
+ specify "should correctly quote column references" do
226
+ market = 'ICE'
227
+ ack_stamp = Time.now - 15 * 60 # 15 minutes ago
228
+ @d.query do
229
+ select :market, :minute[:from_unixtime[:ack]].as(:minute)
230
+ where do
231
+ :ack > ack_stamp
232
+ :market == market
233
+ end
234
+ group_by :minute[:from_unixtime[:ack]]
235
+ end.sql.should == \
236
+ "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`))"
237
+ end
238
+ end
239
+
240
+ # # Commented out because it was causing subsequent examples to fail for some reason
241
+ # context "Simple stored procedure test" do
242
+ # setup do
243
+ # # Create a simple stored procedure but drop it first if there
244
+ # MYSQL_DB.execute("DROP PROCEDURE IF EXISTS sp_get_server_id;")
245
+ # MYSQL_DB.execute("CREATE PROCEDURE sp_get_server_id() SQL SECURITY DEFINER SELECT @@SERVER_ID as server_id;")
246
+ # end
247
+ #
248
+ # specify "should return the server-id via a stored procedure call" do
249
+ # @server_id = MYSQL_DB["SELECT @@SERVER_ID as server_id;"].first[:server_id] # grab the server_id via a simple query
250
+ # @server_id_by_sp = MYSQL_DB["CALL sp_get_server_id();"].first[:server_id]
251
+ # @server_id_by_sp.should == @server_id # compare it to output from stored procedure
252
+ # end
253
+ # end
254
+ #
255
+ context "Joiמed MySQL dataset" do
256
+ setup do
257
+ @ds = MYSQL_DB[:nodes].join(:attributes, :node_id => :id)
258
+ end
259
+
260
+ specify "should quote fields correctly" do
261
+ @ds.sql.should == \
262
+ "SELECT * FROM nodes INNER JOIN attributes ON (attributes.`node_id` = nodes.`id`)"
263
+ end
264
+ end
265
+
266
+ context "A MySQL database" do
267
+ setup do
268
+ @db = MYSQL_DB
269
+ end
270
+
271
+ specify "should support add_column operations" do
272
+ @db.add_column :test2, :xyz, :text
273
+
274
+ @db[:test2].columns.should == [:name, :value, :xyz]
275
+ @db[:test2] << {:name => 'mmm', :value => 111, :xyz => '000'}
276
+ @db[:test2].first[:xyz].should == '000'
277
+ end
278
+
279
+ specify "should support drop_column operations" do
280
+ @db[:test2].columns.should == [:name, :value, :xyz]
281
+ @db.drop_column :test2, :xyz
282
+
283
+ @db[:test2].columns.should == [:name, :value]
284
+ end
285
+
286
+ specify "should support rename_column operations" do
287
+ @db[:test2].delete
288
+ @db.add_column :test2, :xyz, :text
289
+ @db[:test2] << {:name => 'mmm', :value => 111, :xyz => 'qqqq'}
290
+
291
+ @db[:test2].columns.should == [:name, :value, :xyz]
292
+ @db.rename_column :test2, :xyz, :zyx, :type => :text
293
+ @db[:test2].columns.should == [:name, :value, :zyx]
294
+ @db[:test2].first[:zyx].should == 'qqqq'
295
+ end
296
+
297
+ specify "should support set_column_type operations" do
298
+ @db.add_column :test2, :xyz, :float
299
+ @db[:test2].delete
300
+ @db[:test2] << {:name => 'mmm', :value => 111, :xyz => 56.78}
301
+ @db.set_column_type :test2, :xyz, :integer
302
+
303
+ @db[:test2].first[:xyz].should == 57
304
+ end
305
+
306
+ specify "should support add_index" do
307
+ @db.add_index :test2, :value
308
+ end
309
+
310
+ specify "should support drop_index" do
311
+ @db.drop_index :test2, :value
312
+ end
313
+ end
314
+
315
+ context "A MySQL database" do
316
+ setup do
317
+ @db = MYSQL_DB
318
+ end
319
+
320
+ specify "should support defaults for boolean columns" do
321
+ g = Sequel::Schema::Generator.new(@db) do
322
+ boolean :active1, :default => true
323
+ boolean :active2, :default => false
324
+ end
325
+ statements = @db.create_table_sql_list(:items, *g.create_info)
326
+ statements.should == [
327
+ "CREATE TABLE items (`active1` boolean DEFAULT 1, `active2` boolean DEFAULT 0)"
328
+ ]
329
+ end
330
+ end