sequel 0.2.1.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|