sequel 0.4.0 → 0.4.1

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.
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