sequel 0.2.1.1 → 0.3.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 +76 -0
- data/Rakefile +1 -1
- data/lib/sequel.rb +1 -1
- data/lib/sequel/ado.rb +17 -0
- data/lib/sequel/array_keys.rb +233 -0
- data/lib/sequel/connection_pool.rb +14 -0
- data/lib/sequel/core_ext.rb +3 -3
- data/lib/sequel/database.rb +25 -7
- data/lib/sequel/dataset.rb +46 -15
- data/lib/sequel/dataset/convenience.rb +27 -2
- data/lib/sequel/dataset/sequelizer.rb +2 -2
- data/lib/sequel/dataset/sql.rb +49 -18
- data/lib/sequel/dbi.rb +17 -0
- data/lib/sequel/model.rb +276 -82
- data/lib/sequel/model/base.rb +41 -30
- data/lib/sequel/model/caching.rb +42 -0
- data/lib/sequel/model/hooks.rb +113 -27
- data/lib/sequel/model/record.rb +78 -21
- data/lib/sequel/model/relations.rb +5 -0
- data/lib/sequel/model/schema.rb +11 -1
- data/lib/sequel/mysql.rb +61 -17
- data/lib/sequel/odbc.rb +42 -1
- data/lib/sequel/postgres.rb +45 -0
- data/lib/sequel/pretty_table.rb +14 -11
- data/lib/sequel/schema/schema_generator.rb +9 -3
- data/lib/sequel/sqlite.rb +33 -1
- data/spec/adapters/mysql_spec.rb +69 -15
- data/spec/adapters/postgres_spec.rb +66 -12
- data/spec/adapters/sqlite_spec.rb +113 -1
- data/spec/array_keys_spec.rb +544 -0
- data/spec/connection_pool_spec.rb +83 -0
- data/spec/database_spec.rb +81 -2
- data/spec/dataset_spec.rb +227 -9
- data/spec/model_spec.rb +392 -68
- data/spec/schema_spec.rb +7 -0
- metadata +5 -2
@@ -1,9 +1,12 @@
|
|
1
|
+
# TODO: refactoring...
|
1
2
|
module Sequel
|
2
3
|
class Model
|
4
|
+
|
3
5
|
ONE_TO_ONE_PROC = "proc {i = @values[:%s]; %s[i] if i}".freeze
|
4
6
|
ID_POSTFIX = "_id".freeze
|
5
7
|
FROM_DATASET = "db[%s]".freeze
|
6
8
|
|
9
|
+
# Comprehensive description goes here!
|
7
10
|
def self.one_to_one(name, opts)
|
8
11
|
klass = opts[:class] ? opts[:class] : (FROM_DATASET % name.inspect)
|
9
12
|
key = opts[:key] || (name.to_s + ID_POSTFIX)
|
@@ -12,6 +15,8 @@ module Sequel
|
|
12
15
|
|
13
16
|
ONE_TO_MANY_PROC = "proc {%s.filter(:%s => pkey)}".freeze
|
14
17
|
ONE_TO_MANY_ORDER_PROC = "proc {%s.filter(:%s => pkey).order(%s)}".freeze
|
18
|
+
|
19
|
+
# Comprehensive description goes here!
|
15
20
|
def self.one_to_many(name, opts)
|
16
21
|
klass = opts[:class] ? opts[:class] :
|
17
22
|
(FROM_DATASET % (opts[:table] || name.inspect))
|
data/lib/sequel/model/schema.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
module Sequel
|
2
2
|
class Model
|
3
|
+
# Defines a table schema (see Schema::Generator for more information).
|
4
|
+
#
|
5
|
+
# This is only needed if you want to use the create_table or drop_table
|
6
|
+
# methods.
|
3
7
|
def self.set_schema(name = nil, &block)
|
4
8
|
name ? set_dataset(db[name]) : name = table_name
|
5
9
|
@schema = Schema::Generator.new(db, name, &block)
|
@@ -8,32 +12,38 @@ module Sequel
|
|
8
12
|
end
|
9
13
|
end
|
10
14
|
|
15
|
+
# Returns table schema for direct descendant of Model.
|
11
16
|
def self.schema
|
12
17
|
@schema || ((superclass != Model) && (superclass.schema))
|
13
18
|
end
|
14
19
|
|
20
|
+
# Returns name of table.
|
15
21
|
def self.table_name
|
16
22
|
dataset.opts[:from].first
|
17
23
|
end
|
18
24
|
|
25
|
+
# Returns true if table exists, false otherwise.
|
19
26
|
def self.table_exists?
|
20
27
|
db.table_exists?(table_name)
|
21
28
|
end
|
22
29
|
|
30
|
+
# Creates table.
|
23
31
|
def self.create_table
|
24
32
|
db.create_table_sql_list(*schema.create_info).each {|s| db << s}
|
25
33
|
end
|
26
34
|
|
35
|
+
# Drops table.
|
27
36
|
def self.drop_table
|
28
37
|
db.execute db.drop_table_sql(table_name)
|
29
38
|
end
|
30
39
|
|
40
|
+
# Like create_table but invokes drop_table when table_exists? is true.
|
31
41
|
def self.create_table!
|
32
42
|
drop_table if table_exists?
|
33
43
|
create_table
|
34
|
-
|
35
44
|
end
|
36
45
|
|
46
|
+
# Deprecated, use create_table! instead.
|
37
47
|
def self.recreate_table
|
38
48
|
warn "Model.recreate_table is deprecated. Please use Model.create_table! instead."
|
39
49
|
create_table!
|
data/lib/sequel/mysql.rb
CHANGED
@@ -2,27 +2,40 @@ if !Object.const_defined?('Sequel')
|
|
2
2
|
require File.join(File.dirname(__FILE__), '../sequel')
|
3
3
|
end
|
4
4
|
|
5
|
+
require "bigdecimal"
|
6
|
+
require "bigdecimal/util"
|
5
7
|
require 'mysql'
|
6
8
|
|
7
9
|
# Monkey patch Mysql::Result to yield hashes with symbol keys
|
8
10
|
class Mysql::Result
|
9
11
|
MYSQL_TYPES = {
|
10
|
-
0
|
11
|
-
1
|
12
|
-
2
|
13
|
-
3
|
14
|
-
4
|
15
|
-
5
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
12
|
+
0 => :to_d, # MYSQL_TYPE_DECIMAL
|
13
|
+
1 => :to_i, # MYSQL_TYPE_TINY
|
14
|
+
2 => :to_i, # MYSQL_TYPE_SHORT
|
15
|
+
3 => :to_i, # MYSQL_TYPE_LONG
|
16
|
+
4 => :to_f, # MYSQL_TYPE_FLOAT
|
17
|
+
5 => :to_f, # MYSQL_TYPE_DOUBLE
|
18
|
+
# 6 => ??, # MYSQL_TYPE_NULL
|
19
|
+
7 => :to_time, # MYSQL_TYPE_TIMESTAMP
|
20
|
+
8 => :to_i, # MYSQL_TYPE_LONGLONG
|
21
|
+
9 => :to_i, # MYSQL_TYPE_INT24
|
22
|
+
10 => :to_time, # MYSQL_TYPE_DATE
|
23
|
+
11 => :to_time, # MYSQL_TYPE_TIME
|
24
|
+
12 => :to_time, # MYSQL_TYPE_DATETIME
|
25
|
+
13 => :to_i, # MYSQL_TYPE_YEAR
|
26
|
+
14 => :to_time, # MYSQL_TYPE_NEWDATE
|
27
|
+
# 15 => :to_s # MYSQL_TYPE_VARCHAR
|
28
|
+
# 16 => :to_s, # MYSQL_TYPE_BIT
|
29
|
+
246 => :to_d, # MYSQL_TYPE_NEWDECIMAL
|
30
|
+
247 => :to_i, # MYSQL_TYPE_ENUM
|
31
|
+
248 => :to_i # MYSQL_TYPE_SET
|
32
|
+
# 249 => :to_s, # MYSQL_TYPE_TINY_BLOB
|
33
|
+
# 250 => :to_s, # MYSQL_TYPE_MEDIUM_BLOB
|
34
|
+
# 251 => :to_s, # MYSQL_TYPE_LONG_BLOB
|
35
|
+
# 252 => :to_s, # MYSQL_TYPE_BLOB
|
36
|
+
# 253 => :to_s, # MYSQL_TYPE_VAR_STRING
|
37
|
+
# 254 => :to_s, # MYSQL_TYPE_STRING
|
38
|
+
# 255 => :to_s # MYSQL_TYPE_GEOMETRY
|
26
39
|
}
|
27
40
|
|
28
41
|
def convert_type(v, type)
|
@@ -40,7 +53,20 @@ class Mysql::Result
|
|
40
53
|
@columns
|
41
54
|
end
|
42
55
|
|
43
|
-
def
|
56
|
+
def each_array(with_table = nil)
|
57
|
+
c = columns
|
58
|
+
while row = fetch_row
|
59
|
+
c.each_with_index do |f, i|
|
60
|
+
if (t = MYSQL_TYPES[@column_types[i]]) && (v = row[i])
|
61
|
+
row[i] = v.send(t)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
row.fields = c
|
65
|
+
yield row
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def each_hash(with_table = nil)
|
44
70
|
c = columns
|
45
71
|
while row = fetch_row
|
46
72
|
h = {}
|
@@ -78,6 +104,10 @@ module Sequel
|
|
78
104
|
conn
|
79
105
|
end
|
80
106
|
|
107
|
+
def disconnect
|
108
|
+
@pool.disconnect {|c| c.close}
|
109
|
+
end
|
110
|
+
|
81
111
|
def tables
|
82
112
|
@pool.hold do |conn|
|
83
113
|
conn.list_tables.map {|t| t.to_sym}
|
@@ -166,6 +196,7 @@ module Sequel
|
|
166
196
|
|
167
197
|
def literal(v)
|
168
198
|
case v
|
199
|
+
when LiteralString: quoted_field_name(v)
|
169
200
|
when true: TRUE
|
170
201
|
when false: FALSE
|
171
202
|
else
|
@@ -225,6 +256,19 @@ module Sequel
|
|
225
256
|
end
|
226
257
|
self
|
227
258
|
end
|
259
|
+
|
260
|
+
def array_tuples_fetch_rows(sql, &block)
|
261
|
+
@db.synchronize do
|
262
|
+
r = @db.execute_select(sql)
|
263
|
+
begin
|
264
|
+
@columns = r.columns
|
265
|
+
r.each_array(&block)
|
266
|
+
ensure
|
267
|
+
r.free
|
268
|
+
end
|
269
|
+
end
|
270
|
+
self
|
271
|
+
end
|
228
272
|
end
|
229
273
|
end
|
230
274
|
end
|
data/lib/sequel/odbc.rb
CHANGED
@@ -14,6 +14,10 @@ module Sequel
|
|
14
14
|
conn.autocommit = true
|
15
15
|
conn
|
16
16
|
end
|
17
|
+
|
18
|
+
def disconnect
|
19
|
+
@pool.disconnect {|c| c.disconnect}
|
20
|
+
end
|
17
21
|
|
18
22
|
def dataset(opts = nil)
|
19
23
|
ODBC::Dataset.new(self, opts)
|
@@ -46,7 +50,7 @@ module Sequel
|
|
46
50
|
|
47
51
|
def fetch_rows(sql, &block)
|
48
52
|
@db.synchronize do
|
49
|
-
s = @db.execute sql
|
53
|
+
s = @db.execute select_sql(sql)
|
50
54
|
begin
|
51
55
|
@columns = s.columns(true).map {|c| c.name.to_sym}
|
52
56
|
rows = s.fetch_all
|
@@ -86,6 +90,43 @@ module Sequel
|
|
86
90
|
end
|
87
91
|
end
|
88
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.fields = @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
|
+
|
89
130
|
def insert(*values)
|
90
131
|
@db.do insert_sql(*values)
|
91
132
|
end
|
data/lib/sequel/postgres.rb
CHANGED
@@ -154,6 +154,10 @@ module Sequel
|
|
154
154
|
end
|
155
155
|
conn
|
156
156
|
end
|
157
|
+
|
158
|
+
def disconnect
|
159
|
+
@pool.disconnect {|c| c.close}
|
160
|
+
end
|
157
161
|
|
158
162
|
def dataset(opts = nil)
|
159
163
|
Postgres::Dataset.new(self, opts)
|
@@ -280,6 +284,7 @@ module Sequel
|
|
280
284
|
class Dataset < Sequel::Dataset
|
281
285
|
def literal(v)
|
282
286
|
case v
|
287
|
+
when LiteralString: v
|
283
288
|
when String, Fixnum, Float, TrueClass, FalseClass: PGconn.quote(v)
|
284
289
|
else
|
285
290
|
super
|
@@ -436,6 +441,46 @@ module Sequel
|
|
436
441
|
end
|
437
442
|
eval("lambda {|r| {#{kvs.join(COMMA_SEPARATOR)}}}")
|
438
443
|
end
|
444
|
+
|
445
|
+
def array_tuples_fetch_rows(sql, &block)
|
446
|
+
@db.synchronize do
|
447
|
+
result = @db.execute(sql)
|
448
|
+
begin
|
449
|
+
conv = array_tuples_row_converter(result)
|
450
|
+
result.each {|r| yield conv[r]}
|
451
|
+
ensure
|
452
|
+
result.clear
|
453
|
+
end
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
@@array_tuples_converters_mutex = Mutex.new
|
458
|
+
@@array_tuples_converters = {}
|
459
|
+
|
460
|
+
def array_tuples_row_converter(result)
|
461
|
+
fields = []; translators = []
|
462
|
+
result.fields.each_with_index do |f, idx|
|
463
|
+
fields << f.to_sym
|
464
|
+
translators << PG_TYPES[result.type(idx)]
|
465
|
+
end
|
466
|
+
@columns = fields
|
467
|
+
|
468
|
+
# create result signature and memoize the converter
|
469
|
+
sig = [fields, translators].hash
|
470
|
+
@@array_tuples_converters_mutex.synchronize do
|
471
|
+
@@array_tuples_converters[sig] ||= array_tuples_compile_converter(fields, translators)
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
def array_tuples_compile_converter(fields, translators)
|
476
|
+
tr = []
|
477
|
+
fields.each_with_index do |field, idx|
|
478
|
+
if t = translators[idx]
|
479
|
+
tr << "if (v = r[#{idx}]); r[#{idx}] = v.#{t}; end"
|
480
|
+
end
|
481
|
+
end
|
482
|
+
eval("lambda {|r| r.fields = fields; #{tr.join(';')}; r}")
|
483
|
+
end
|
439
484
|
end
|
440
485
|
end
|
441
486
|
end
|
data/lib/sequel/pretty_table.rb
CHANGED
@@ -1,17 +1,20 @@
|
|
1
|
-
# Print nice-looking plain-text tables
|
2
|
-
# +--+-------+
|
3
|
-
# |id|name |
|
4
|
-
# |--+-------|
|
5
|
-
# |1 |fasdfas|
|
6
|
-
# |2 |test |
|
7
|
-
# +--+-------+
|
8
|
-
|
9
1
|
module Sequel
|
2
|
+
# Prints nice-looking plain-text tables
|
3
|
+
# +--+-------+
|
4
|
+
# |id|name |
|
5
|
+
# |--+-------|
|
6
|
+
# |1 |fasdfas|
|
7
|
+
# |2 |test |
|
8
|
+
# +--+-------+
|
10
9
|
module PrettyTable
|
11
|
-
def self.
|
10
|
+
def self.records_columns(records)
|
12
11
|
columns = []
|
13
12
|
records.each do |r|
|
14
|
-
|
13
|
+
if Array === r && (f = r.fields)
|
14
|
+
return r.fields
|
15
|
+
elsif Hash === r
|
16
|
+
r.keys.each {|k| columns << k unless columns.include?(k)}
|
17
|
+
end
|
15
18
|
end
|
16
19
|
columns
|
17
20
|
end
|
@@ -53,7 +56,7 @@ module Sequel
|
|
53
56
|
end
|
54
57
|
|
55
58
|
def self.print(records, columns = nil) # records is an array of hashes
|
56
|
-
columns ||=
|
59
|
+
columns ||= records_columns(records)
|
57
60
|
sizes = column_sizes(records, columns)
|
58
61
|
|
59
62
|
puts separator_line(columns, sizes)
|
@@ -18,12 +18,18 @@ module Sequel
|
|
18
18
|
@primary_key ? @primary_key[:name] : nil
|
19
19
|
end
|
20
20
|
|
21
|
-
def primary_key(name,
|
21
|
+
def primary_key(name, *args)
|
22
22
|
@primary_key = @db.serial_primary_key_options.merge({
|
23
23
|
:name => name
|
24
24
|
})
|
25
|
-
|
26
|
-
|
25
|
+
|
26
|
+
if opts = args.pop
|
27
|
+
opts = {:type => opts} unless opts.is_a?(Hash)
|
28
|
+
if type = args.pop
|
29
|
+
opts.merge!(:type => type)
|
30
|
+
end
|
31
|
+
@primary_key.merge!(opts)
|
32
|
+
end
|
27
33
|
@primary_key
|
28
34
|
end
|
29
35
|
|
data/lib/sequel/sqlite.rb
CHANGED
@@ -21,6 +21,10 @@ module Sequel
|
|
21
21
|
db.type_translation = true
|
22
22
|
db
|
23
23
|
end
|
24
|
+
|
25
|
+
def disconnect
|
26
|
+
@pool.disconnect {|c| c.close}
|
27
|
+
end
|
24
28
|
|
25
29
|
def dataset(opts = nil)
|
26
30
|
SQLite::Dataset.new(self, opts)
|
@@ -93,18 +97,39 @@ module Sequel
|
|
93
97
|
pragma_set(:temp_store, value)
|
94
98
|
end
|
95
99
|
|
100
|
+
def transaction(&block)
|
101
|
+
@pool.hold do |conn|
|
102
|
+
if conn.transaction_active?
|
103
|
+
return yield(conn)
|
104
|
+
end
|
105
|
+
begin
|
106
|
+
result = nil
|
107
|
+
conn.transaction {result = yield(conn)}
|
108
|
+
result
|
109
|
+
rescue => e
|
110
|
+
raise e unless SequelRollbackError === e
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
96
114
|
end
|
97
115
|
|
98
116
|
class Dataset < Sequel::Dataset
|
99
117
|
def literal(v)
|
100
118
|
case v
|
101
119
|
when Time: literal(v.iso8601)
|
102
|
-
when Date: literal(v.to_s)
|
103
120
|
else
|
104
121
|
super
|
105
122
|
end
|
106
123
|
end
|
107
124
|
|
125
|
+
def insert_sql(*values)
|
126
|
+
if (values.size == 1) && values.first.is_a?(Sequel::Dataset)
|
127
|
+
"INSERT INTO #{@opts[:from]} #{values.first.sql};"
|
128
|
+
else
|
129
|
+
super(*values)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
108
133
|
def fetch_rows(sql, &block)
|
109
134
|
@db.execute_select(sql) do |result|
|
110
135
|
@columns = result.columns.map {|c| c.to_sym}
|
@@ -116,6 +141,13 @@ module Sequel
|
|
116
141
|
end
|
117
142
|
end
|
118
143
|
end
|
144
|
+
|
145
|
+
def array_tuples_fetch_rows(sql, &block)
|
146
|
+
@db.execute_select(sql) do |result|
|
147
|
+
@columns = result.columns.map {|c| c.to_sym}
|
148
|
+
result.each(&block)
|
149
|
+
end
|
150
|
+
end
|
119
151
|
|
120
152
|
def insert(*values)
|
121
153
|
@db.execute_insert insert_sql(*values)
|
data/spec/adapters/mysql_spec.rb
CHANGED
@@ -11,6 +11,19 @@ MYSQL_DB.create_table :items do
|
|
11
11
|
index :value
|
12
12
|
end
|
13
13
|
|
14
|
+
context "A MySQL database" do
|
15
|
+
setup do
|
16
|
+
@db = MYSQL_DB
|
17
|
+
end
|
18
|
+
|
19
|
+
specify "should provide disconnect functionality" do
|
20
|
+
@db.tables
|
21
|
+
@db.pool.size.should == 1
|
22
|
+
@db.disconnect
|
23
|
+
@db.pool.size.should == 0
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
14
27
|
context "A MySQL dataset" do
|
15
28
|
setup do
|
16
29
|
@d = MYSQL_DB[:items]
|
@@ -25,24 +38,19 @@ context "A MySQL dataset" do
|
|
25
38
|
@d.count.should == 3
|
26
39
|
end
|
27
40
|
|
28
|
-
|
29
|
-
|
30
|
-
# id.should == @d.first[:id]
|
31
|
-
# end
|
32
|
-
#
|
33
|
-
|
34
|
-
specify "should return all records" do
|
41
|
+
specify "should return the correct records" do
|
42
|
+
@d.to_a.should == []
|
35
43
|
@d << {:name => 'abc', :value => 123}
|
36
44
|
@d << {:name => 'abc', :value => 456}
|
37
45
|
@d << {:name => 'def', :value => 789}
|
38
|
-
|
39
|
-
@d.order(:value).
|
46
|
+
|
47
|
+
@d.order(:value).to_a.should == [
|
40
48
|
{:name => 'abc', :value => 123},
|
41
49
|
{:name => 'abc', :value => 456},
|
42
50
|
{:name => 'def', :value => 789}
|
43
51
|
]
|
44
52
|
end
|
45
|
-
|
53
|
+
|
46
54
|
specify "should update records correctly" do
|
47
55
|
@d << {:name => 'abc', :value => 123}
|
48
56
|
@d << {:name => 'abc', :value => 456}
|
@@ -74,7 +82,7 @@ context "A MySQL dataset" do
|
|
74
82
|
@d.select(:name).sql.should == \
|
75
83
|
'SELECT `name` FROM items'
|
76
84
|
|
77
|
-
@d.select('COUNT(*)').sql.should == \
|
85
|
+
@d.select('COUNT(*)'.lit).sql.should == \
|
78
86
|
'SELECT COUNT(*) FROM items'
|
79
87
|
|
80
88
|
@d.select(:value.MAX).sql.should == \
|
@@ -89,13 +97,13 @@ context "A MySQL dataset" do
|
|
89
97
|
@d.order(:name.DESC).sql.should == \
|
90
98
|
'SELECT * FROM items ORDER BY `name` DESC'
|
91
99
|
|
92
|
-
@d.select('items.name AS item_name').sql.should == \
|
100
|
+
@d.select('items.name AS item_name'.to_sym).sql.should == \
|
93
101
|
'SELECT items.`name` AS `item_name` FROM items'
|
94
102
|
|
95
|
-
@d.select('`name`').sql.should == \
|
103
|
+
@d.select('`name`'.lit).sql.should == \
|
96
104
|
'SELECT `name` FROM items'
|
97
105
|
|
98
|
-
@d.select('max(items.`name`)
|
106
|
+
@d.select('max(items.`name`) AS `max_name`'.lit).sql.should == \
|
99
107
|
'SELECT max(items.`name`) AS `max_name` FROM items'
|
100
108
|
|
101
109
|
@d.insert_sql(:value => 333).should == \
|
@@ -126,4 +134,50 @@ context "A MySQL dataset" do
|
|
126
134
|
@d.filter(:name => /bc/).count.should == 2
|
127
135
|
@d.filter(:name => /^bc/).count.should == 1
|
128
136
|
end
|
129
|
-
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context "A MySQL dataset in array tuples mode" do
|
140
|
+
setup do
|
141
|
+
@d = MYSQL_DB[:items]
|
142
|
+
@d.delete # remove all records
|
143
|
+
Sequel.use_array_tuples
|
144
|
+
end
|
145
|
+
|
146
|
+
teardown do
|
147
|
+
Sequel.use_hash_tuples
|
148
|
+
end
|
149
|
+
|
150
|
+
specify "should return the correct records" do
|
151
|
+
@d.to_a.should == []
|
152
|
+
@d << {:name => 'abc', :value => 123}
|
153
|
+
@d << {:name => 'abc', :value => 456}
|
154
|
+
@d << {:name => 'def', :value => 789}
|
155
|
+
|
156
|
+
@d.order(:value).select(:name, :value).to_a.should == [
|
157
|
+
['abc', 123],
|
158
|
+
['abc', 456],
|
159
|
+
['def', 789]
|
160
|
+
]
|
161
|
+
end
|
162
|
+
|
163
|
+
specify "should work correctly with transforms" do
|
164
|
+
@d.transform(:value => [proc {|v| v.to_s}, proc {|v| v.to_i}])
|
165
|
+
|
166
|
+
@d.to_a.should == []
|
167
|
+
@d << {:name => 'abc', :value => 123}
|
168
|
+
@d << {:name => 'abc', :value => 456}
|
169
|
+
@d << {:name => 'def', :value => 789}
|
170
|
+
|
171
|
+
@d.order(:value).select(:name, :value).to_a.should == [
|
172
|
+
['abc', '123'],
|
173
|
+
['abc', '456'],
|
174
|
+
['def', '789']
|
175
|
+
]
|
176
|
+
|
177
|
+
a = @d.order(:value).first
|
178
|
+
a.values.should == ['abc', '123']
|
179
|
+
a.keys.should == [:name, :value]
|
180
|
+
a[:name].should == 'abc'
|
181
|
+
a[:value].should == '123'
|
182
|
+
end
|
183
|
+
end
|