sequel 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/CHANGELOG +4 -0
  2. data/README +1 -6
  3. data/Rakefile +1 -1
  4. data/bin/sequel +1 -3
  5. data/lib/sequel.rb +18 -1
  6. data/lib/sequel/adapters/ado.rb +104 -0
  7. data/lib/sequel/adapters/db2.rb +160 -0
  8. data/lib/sequel/adapters/dbi.rb +130 -0
  9. data/lib/sequel/adapters/informix.rb +78 -0
  10. data/lib/sequel/adapters/mysql.rb +256 -0
  11. data/lib/sequel/adapters/odbc.rb +144 -0
  12. data/lib/sequel/adapters/oracle.rb +109 -0
  13. data/lib/sequel/adapters/postgres.rb +507 -0
  14. data/lib/sequel/adapters/sqlite.rb +186 -0
  15. data/lib/sequel/ado.rb +2 -104
  16. data/lib/{sequel-core → sequel}/array_keys.rb +0 -0
  17. data/lib/{sequel-core → sequel}/connection_pool.rb +0 -0
  18. data/lib/{sequel-core → sequel}/core_ext.rb +0 -0
  19. data/lib/{sequel-core → sequel}/core_sql.rb +0 -0
  20. data/lib/{sequel-core → sequel}/database.rb +10 -20
  21. data/lib/{sequel-core → sequel}/dataset.rb +0 -0
  22. data/lib/{sequel-core → sequel}/dataset/convenience.rb +0 -0
  23. data/lib/{sequel-core → sequel}/dataset/sequelizer.rb +0 -0
  24. data/lib/{sequel-core → sequel}/dataset/sql.rb +0 -0
  25. data/lib/sequel/db2.rb +2 -160
  26. data/lib/sequel/dbi.rb +2 -130
  27. data/lib/{sequel-core → sequel}/error.rb +0 -0
  28. data/lib/sequel/informix.rb +2 -78
  29. data/lib/{sequel-core → sequel}/migration.rb +0 -0
  30. data/lib/{sequel-core → sequel}/model.rb +0 -0
  31. data/lib/{sequel-core → sequel}/model/base.rb +0 -0
  32. data/lib/{sequel-core → sequel}/model/caching.rb +0 -0
  33. data/lib/{sequel-core → sequel}/model/hooks.rb +0 -0
  34. data/lib/{sequel-core → sequel}/model/record.rb +0 -0
  35. data/lib/{sequel-core → sequel}/model/relations.rb +0 -0
  36. data/lib/{sequel-core → sequel}/model/schema.rb +0 -0
  37. data/lib/sequel/mysql.rb +2 -256
  38. data/lib/sequel/odbc.rb +2 -144
  39. data/lib/sequel/oracle.rb +2 -109
  40. data/lib/sequel/postgres.rb +2 -507
  41. data/lib/{sequel-core → sequel}/pretty_table.rb +0 -0
  42. data/lib/{sequel-core → sequel}/schema.rb +0 -0
  43. data/lib/{sequel-core → sequel}/schema/schema_generator.rb +0 -0
  44. data/lib/{sequel-core → sequel}/schema/schema_sql.rb +0 -0
  45. data/lib/sequel/sqlite.rb +2 -186
  46. data/lib/{sequel-core → sequel}/worker.rb +0 -0
  47. data/spec/database_spec.rb +7 -9
  48. metadata +39 -29
@@ -0,0 +1,78 @@
1
+ if !Object.const_defined?('Sequel')
2
+ require File.join(File.dirname(__FILE__), '../../sequel')
3
+ end
4
+
5
+ require 'informix'
6
+
7
+ module Sequel
8
+ module Informix
9
+ class Database < Sequel::Database
10
+ set_adapter_scheme :informix
11
+
12
+ # AUTO_INCREMENT = 'IDENTITY(1,1)'.freeze
13
+ #
14
+ # def auto_increment_sql
15
+ # AUTO_INCREMENT
16
+ # end
17
+
18
+ def connect
19
+ ::Informix.connect(@opts[:database], @opts[:user], @opts[:password])
20
+ end
21
+
22
+ def disconnect
23
+ @pool.disconnect {|c| c.close}
24
+ end
25
+
26
+ def dataset(opts = nil)
27
+ Sequel::Informix::Dataset.new(self, opts)
28
+ end
29
+
30
+ # Returns number of rows affected
31
+ def execute(sql)
32
+ @logger.info(sql) if @logger
33
+ @pool.hold {|c| c.do(sql)}
34
+ end
35
+ alias_method :do, :execute
36
+
37
+ def query(sql, &block)
38
+ @logger.info(sql) if @logger
39
+ @pool.hold {|c| block[c.cursor(sql)]}
40
+ end
41
+ end
42
+
43
+ class Dataset < Sequel::Dataset
44
+ def literal(v)
45
+ case v
46
+ when Time: literal(v.iso8601)
47
+ else
48
+ super
49
+ end
50
+ end
51
+
52
+ def fetch_rows(sql, &block)
53
+ @db.synchronize do
54
+ @db.query(sql) do |cursor|
55
+ begin
56
+ cursor.open.each_hash {|r| block[r]}
57
+ ensure
58
+ cursor.drop
59
+ end
60
+ end
61
+ end
62
+ self
63
+ end
64
+
65
+ def insert(*values)
66
+ @db.do insert_sql(*values)
67
+ end
68
+
69
+ def update(values, opts = nil)
70
+ @db.do update_sql(values, opts)
71
+ end
72
+
73
+ def delete(opts = nil)
74
+ @db.do delete_sql(opts)
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,256 @@
1
+ if !Object.const_defined?('Sequel')
2
+ require File.join(File.dirname(__FILE__), '../../sequel')
3
+ end
4
+
5
+ require 'mysql'
6
+
7
+ # Monkey patch Mysql::Result to yield hashes with symbol keys
8
+ class Mysql::Result
9
+ MYSQL_TYPES = {
10
+ 0 => :to_d, # MYSQL_TYPE_DECIMAL
11
+ 1 => :to_i, # MYSQL_TYPE_TINY
12
+ 2 => :to_i, # MYSQL_TYPE_SHORT
13
+ 3 => :to_i, # MYSQL_TYPE_LONG
14
+ 4 => :to_f, # MYSQL_TYPE_FLOAT
15
+ 5 => :to_f, # MYSQL_TYPE_DOUBLE
16
+ # 6 => ??, # MYSQL_TYPE_NULL
17
+ 7 => :to_time, # MYSQL_TYPE_TIMESTAMP
18
+ 8 => :to_i, # MYSQL_TYPE_LONGLONG
19
+ 9 => :to_i, # MYSQL_TYPE_INT24
20
+ 10 => :to_time, # MYSQL_TYPE_DATE
21
+ 11 => :to_time, # MYSQL_TYPE_TIME
22
+ 12 => :to_time, # MYSQL_TYPE_DATETIME
23
+ 13 => :to_i, # MYSQL_TYPE_YEAR
24
+ 14 => :to_time, # MYSQL_TYPE_NEWDATE
25
+ # 15 => :to_s # MYSQL_TYPE_VARCHAR
26
+ # 16 => :to_s, # MYSQL_TYPE_BIT
27
+ 246 => :to_d, # MYSQL_TYPE_NEWDECIMAL
28
+ 247 => :to_i, # MYSQL_TYPE_ENUM
29
+ 248 => :to_i # MYSQL_TYPE_SET
30
+ # 249 => :to_s, # MYSQL_TYPE_TINY_BLOB
31
+ # 250 => :to_s, # MYSQL_TYPE_MEDIUM_BLOB
32
+ # 251 => :to_s, # MYSQL_TYPE_LONG_BLOB
33
+ # 252 => :to_s, # MYSQL_TYPE_BLOB
34
+ # 253 => :to_s, # MYSQL_TYPE_VAR_STRING
35
+ # 254 => :to_s, # MYSQL_TYPE_STRING
36
+ # 255 => :to_s # MYSQL_TYPE_GEOMETRY
37
+ }
38
+
39
+ def convert_type(v, type)
40
+ v ? ((t = MYSQL_TYPES[type]) ? v.send(t) : v) : nil
41
+ end
42
+
43
+ def columns(with_table = nil)
44
+ unless @columns
45
+ @column_types = []
46
+ @columns = fetch_fields.map do |f|
47
+ @column_types << f.type
48
+ (with_table ? (f.table + "." + f.name) : f.name).to_sym
49
+ end
50
+ end
51
+ @columns
52
+ end
53
+
54
+ def each_array(with_table = nil)
55
+ c = columns
56
+ while row = fetch_row
57
+ c.each_with_index do |f, i|
58
+ if (t = MYSQL_TYPES[@column_types[i]]) && (v = row[i])
59
+ row[i] = v.send(t)
60
+ end
61
+ end
62
+ row.keys = c
63
+ yield row
64
+ end
65
+ end
66
+
67
+ def each_hash(with_table = nil)
68
+ c = columns
69
+ while row = fetch_row
70
+ h = {}
71
+ c.each_with_index {|f, i| h[f] = convert_type(row[i], @column_types[i])}
72
+ yield h
73
+ end
74
+ end
75
+ end
76
+
77
+ module Sequel
78
+ module MySQL
79
+ class Database < Sequel::Database
80
+ set_adapter_scheme :mysql
81
+
82
+ def serial_primary_key_options
83
+ {:primary_key => true, :type => :integer, :auto_increment => true}
84
+ end
85
+
86
+ AUTO_INCREMENT = 'AUTO_INCREMENT'.freeze
87
+
88
+ def auto_increment_sql
89
+ AUTO_INCREMENT
90
+ end
91
+
92
+ def connect
93
+ conn = Mysql.real_connect(@opts[:host], @opts[:user], @opts[:password],
94
+ @opts[:database], @opts[:port], nil, Mysql::CLIENT_MULTI_RESULTS)
95
+ conn.query_with_result = false
96
+ if encoding = @opts[:encoding] || @opts[:charset]
97
+ conn.query("set character_set_connection = '#{encoding}'")
98
+ conn.query("set character_set_client = '#{encoding}'")
99
+ conn.query("set character_set_results = '#{encoding}'")
100
+ end
101
+ conn.reconnect = true
102
+ conn
103
+ end
104
+
105
+ def disconnect
106
+ @pool.disconnect {|c| c.close}
107
+ end
108
+
109
+ def tables
110
+ @pool.hold do |conn|
111
+ conn.list_tables.map {|t| t.to_sym}
112
+ end
113
+ end
114
+
115
+ def dataset(opts = nil)
116
+ MySQL::Dataset.new(self, opts)
117
+ end
118
+
119
+ def execute(sql)
120
+ @logger.info(sql) if @logger
121
+ @pool.hold do |conn|
122
+ conn.query(sql)
123
+ end
124
+ end
125
+
126
+ def execute_select(sql)
127
+ @logger.info(sql) if @logger
128
+ @pool.hold do |conn|
129
+ conn.query(sql)
130
+ conn.use_result
131
+ end
132
+ end
133
+
134
+ def execute_insert(sql)
135
+ @logger.info(sql) if @logger
136
+ @pool.hold do |conn|
137
+ conn.query(sql)
138
+ conn.insert_id
139
+ end
140
+ end
141
+
142
+ def execute_affected(sql)
143
+ @logger.info(sql) if @logger
144
+ @pool.hold do |conn|
145
+ conn.query(sql)
146
+ conn.affected_rows
147
+ end
148
+ end
149
+
150
+ def transaction
151
+ @pool.hold do |conn|
152
+ @transactions ||= []
153
+ if @transactions.include? Thread.current
154
+ return yield(conn)
155
+ end
156
+ conn.query(SQL_BEGIN)
157
+ begin
158
+ @transactions << Thread.current
159
+ result = yield(conn)
160
+ conn.query(SQL_COMMIT)
161
+ result
162
+ rescue => e
163
+ conn.query(SQL_ROLLBACK)
164
+ raise e unless SequelRollbackError === e
165
+ ensure
166
+ @transactions.delete(Thread.current)
167
+ end
168
+ end
169
+ end
170
+ end
171
+
172
+ class Dataset < Sequel::Dataset
173
+ def quote_column_ref(c); "`#{c}`"; end
174
+
175
+ TRUE = '1'
176
+ FALSE = '0'
177
+
178
+ def literal(v)
179
+ case v
180
+ when LiteralString: v
181
+ when String: "'#{v.gsub(/'|\\/, '\&\&')}'"
182
+ when true: TRUE
183
+ when false: FALSE
184
+ else
185
+ super
186
+ end
187
+ end
188
+
189
+ def match_expr(l, r)
190
+ case r
191
+ when Regexp:
192
+ r.casefold? ? \
193
+ "(#{literal(l)} REGEXP #{literal(r.source)})" :
194
+ "(#{literal(l)} REGEXP BINARY #{literal(r.source)})"
195
+ else
196
+ super
197
+ end
198
+ end
199
+
200
+ # MySQL supports ORDER and LIMIT clauses in UPDATE statements.
201
+ def update_sql(values, opts = nil)
202
+ sql = super
203
+
204
+ opts = opts ? @opts.merge(opts) : @opts
205
+
206
+ if order = opts[:order]
207
+ sql << " ORDER BY #{column_list(order)}"
208
+ end
209
+
210
+ if limit = opts[:limit]
211
+ sql << " LIMIT #{limit}"
212
+ end
213
+
214
+ sql
215
+ end
216
+
217
+ def insert(*values)
218
+ @db.execute_insert(insert_sql(*values))
219
+ end
220
+
221
+ def update(values, opts = nil)
222
+ @db.execute_affected(update_sql(values, opts))
223
+ end
224
+
225
+ def delete(opts = nil)
226
+ @db.execute_affected(delete_sql(opts))
227
+ end
228
+
229
+ def fetch_rows(sql)
230
+ @db.synchronize do
231
+ r = @db.execute_select(sql)
232
+ begin
233
+ @columns = r.columns
234
+ r.each_hash {|row| yield row}
235
+ ensure
236
+ r.free
237
+ end
238
+ end
239
+ self
240
+ end
241
+
242
+ def array_tuples_fetch_rows(sql, &block)
243
+ @db.synchronize do
244
+ r = @db.execute_select(sql)
245
+ begin
246
+ @columns = r.columns
247
+ r.each_array(&block)
248
+ ensure
249
+ r.free
250
+ end
251
+ end
252
+ self
253
+ end
254
+ end
255
+ end
256
+ end
@@ -0,0 +1,144 @@
1
+ if !Object.const_defined?('Sequel')
2
+ require File.join(File.dirname(__FILE__), '../../sequel')
3
+ end
4
+
5
+ require 'odbc'
6
+
7
+ module Sequel
8
+ module ODBC
9
+ class Database < Sequel::Database
10
+ set_adapter_scheme :odbc
11
+
12
+ def connect
13
+ conn = ::ODBC::connect(@opts[:database], @opts[:user], @opts[:password])
14
+ conn.autocommit = true
15
+ conn
16
+ end
17
+
18
+ def disconnect
19
+ @pool.disconnect {|c| c.disconnect}
20
+ end
21
+
22
+ def dataset(opts = nil)
23
+ ODBC::Dataset.new(self, opts)
24
+ end
25
+
26
+ def execute(sql)
27
+ @logger.info(sql) if @logger
28
+ @pool.hold do |conn|
29
+ conn.run(sql)
30
+ end
31
+ end
32
+
33
+ def do(sql)
34
+ @logger.info(sql) if @logger
35
+ @pool.hold do |conn|
36
+ conn.do(sql)
37
+ end
38
+ end
39
+ end
40
+
41
+ class Dataset < Sequel::Dataset
42
+ def literal(v)
43
+ case v
44
+ when true: '1'
45
+ when false: '0'
46
+ else
47
+ super
48
+ end
49
+ end
50
+
51
+ def fetch_rows(sql, &block)
52
+ @db.synchronize do
53
+ s = @db.execute select_sql(sql)
54
+ begin
55
+ @columns = s.columns(true).map {|c| c.name.to_sym}
56
+ rows = s.fetch_all
57
+ rows.each {|row| yield hash_row(row)}
58
+ ensure
59
+ s.drop unless s.nil? rescue nil
60
+ end
61
+ end
62
+ self
63
+ end
64
+
65
+ def hash_row(row)
66
+ hash = {}
67
+ row.each_with_index do |v, idx|
68
+ hash[@columns[idx]] = convert_odbc_value(v)
69
+ end
70
+ hash
71
+ end
72
+
73
+ def convert_odbc_value(v)
74
+ # When fetching a result set, the Ruby ODBC driver converts all ODBC
75
+ # SQL types to an equivalent Ruby type; with the exception of
76
+ # SQL_TYPE_DATE, SQL_TYPE_TIME and SQL_TYPE_TIMESTAMP.
77
+ #
78
+ # The conversions below are consistent with the mappings in
79
+ # ODBCColumn#mapSqlTypeToGenericType and Column#klass.
80
+ case v
81
+ when ::ODBC::TimeStamp
82
+ DateTime.new(v.year, v.month, v.day, v.hour, v.minute, v.second)
83
+ when ::ODBC::Time
84
+ DateTime.now
85
+ Time.gm(now.year, now.month, now.day, v.hour, v.minute, v.second)
86
+ when ::ODBC::Date
87
+ Date.new(v.year, v.month, v.day)
88
+ else
89
+ v
90
+ end
91
+ end
92
+
93
+ def array_tuples_fetch_rows(sql, &block)
94
+ @db.synchronize do
95
+ s = @db.execute sql
96
+ begin
97
+ @columns = s.columns(true).map {|c| c.name.to_sym}
98
+ rows = s.fetch_all
99
+ rows.each {|r| yield array_tuples_make_row(r)}
100
+ ensure
101
+ s.drop unless s.nil? rescue nil
102
+ end
103
+ end
104
+ self
105
+ end
106
+
107
+ def array_tuples_make_row(row)
108
+ row.keys = @columns
109
+ row.each_with_index do |v, idx|
110
+ # When fetching a result set, the Ruby ODBC driver converts all ODBC
111
+ # SQL types to an equivalent Ruby type; with the exception of
112
+ # SQL_TYPE_DATE, SQL_TYPE_TIME and SQL_TYPE_TIMESTAMP.
113
+ #
114
+ # The conversions below are consistent with the mappings in
115
+ # ODBCColumn#mapSqlTypeToGenericType and Column#klass.
116
+ case v
117
+ when ::ODBC::TimeStamp
118
+ row[idx] = DateTime.new(v.year, v.month, v.day, v.hour, v.minute, v.second)
119
+ when ::ODBC::Time
120
+ now = DateTime.now
121
+ row[idx] = Time.gm(now.year, now.month, now.day, v.hour, v.minute, v.second)
122
+ when ::ODBC::Date
123
+ row[idx] = Date.new(v.year, v.month, v.day)
124
+ end
125
+ end
126
+ row
127
+ end
128
+
129
+
130
+ def insert(*values)
131
+ @db.do insert_sql(*values)
132
+ end
133
+
134
+ def update(values, opts = nil)
135
+ @db.do update_sql(values, opts)
136
+ self
137
+ end
138
+
139
+ def delete(opts = nil)
140
+ @db.do delete_sql(opts)
141
+ end
142
+ end
143
+ end
144
+ end