sequel_core 1.0.0.1 → 1.0.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.
- data/CHANGELOG +14 -0
- data/COPYING +1 -1
- data/Rakefile +4 -1
- data/lib/sequel_core/adapters/mysql.rb +9 -2
- data/lib/sequel_core/adapters/oracle.rb +103 -4
- data/lib/sequel_core/adapters/postgres.rb +2 -0
- data/lib/sequel_core/database.rb +9 -3
- data/lib/sequel_core/dataset/sequelizer.rb +20 -9
- data/lib/sequel_core/dataset/sql.rb +9 -12
- data/lib/sequel_core/model.rb +1 -1
- data/spec/adapters/mysql_spec.rb +17 -0
- data/spec/adapters/oracle_spec.rb +157 -11
- data/spec/adapters/postgres_spec.rb +58 -0
- data/spec/adapters/sqlite_spec.rb +17 -3
- data/spec/database_spec.rb +26 -0
- data/spec/dataset_spec.rb +11 -1
- data/spec/sequelizer_spec.rb +153 -113
- metadata +3 -2
data/CHANGELOG
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
=== 1.0.1 (2008-01-12)
|
2
|
+
|
3
|
+
* Changed postgres adapter to quote column references using double quotes.
|
4
|
+
|
5
|
+
* Applied patch for oracle adapter: fix behavior of limit and offset, transactions, #table_exists?, #tables and additional specs (thanks Liming Lian #122).
|
6
|
+
|
7
|
+
* Allow for additional filters on a grouped dataset (#119 and #120)
|
8
|
+
|
9
|
+
* Changed mysql adapter to default to localhost if :host option is not specified (#114).
|
10
|
+
|
11
|
+
* Refactored Sequelizer to use Proc#to_sexp (method provided by r2r).
|
12
|
+
|
13
|
+
* Enhanced Database.connect to accept options with string keys, so it can now accept options loaded from YAML files. Database.connect also automatically converts :username option into :user for compatibility with existing YAML configuration files for AR and DataMapper.
|
14
|
+
|
1
15
|
=== 1.0.0.1 (2008-01-03)
|
2
16
|
|
3
17
|
* Changed MySQL adapter to support specifying socket option.
|
data/COPYING
CHANGED
data/Rakefile
CHANGED
@@ -9,7 +9,7 @@ include FileUtils
|
|
9
9
|
# Configuration
|
10
10
|
##############################################################################
|
11
11
|
NAME = "sequel_core"
|
12
|
-
VERS = "1.0.
|
12
|
+
VERS = "1.0.1"
|
13
13
|
CLEAN.include ["**/.*.sw?", "pkg/*", ".config", "doc/*", "coverage/*"]
|
14
14
|
RDOC_OPTS = [
|
15
15
|
"--quiet",
|
@@ -105,6 +105,9 @@ end
|
|
105
105
|
|
106
106
|
task :tag do
|
107
107
|
cwd = FileUtils.pwd
|
108
|
+
sh %{rm -rf doc/*}
|
109
|
+
sh %{rm -rf pkg/*}
|
110
|
+
sh %{rm -rf coverage/*}
|
108
111
|
sh %{cd ../.. && svn copy #{cwd} tags/#{NAME}-#{VERS} && svn commit -m "#{NAME}-#{VERS} tag." tags}
|
109
112
|
end
|
110
113
|
|
@@ -86,8 +86,15 @@ module Sequel
|
|
86
86
|
end
|
87
87
|
|
88
88
|
def connect
|
89
|
-
conn = Mysql.real_connect(
|
90
|
-
|
89
|
+
conn = Mysql.real_connect(
|
90
|
+
@opts[:host] || 'localhost',
|
91
|
+
@opts[:user],
|
92
|
+
@opts[:password],
|
93
|
+
@opts[:database],
|
94
|
+
@opts[:port],
|
95
|
+
@opts[:socket],
|
96
|
+
Mysql::CLIENT_MULTI_RESULTS
|
97
|
+
)
|
91
98
|
conn.query_with_result = false
|
92
99
|
if encoding = @opts[:encoding] || @opts[:charset]
|
93
100
|
conn.query("set character_set_connection = '#{encoding}'")
|
@@ -38,6 +38,39 @@ module Sequel
|
|
38
38
|
end
|
39
39
|
|
40
40
|
alias_method :do, :execute
|
41
|
+
|
42
|
+
def tables
|
43
|
+
from(:tab).select(:tname).filter(:tabtype => 'TABLE').map do |r|
|
44
|
+
r[:tname].downcase.to_sym
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def table_exists?(name)
|
49
|
+
from(:tab).filter(:tname => name.to_s.upcase, :tabtype => 'TABLE').count > 0
|
50
|
+
end
|
51
|
+
|
52
|
+
def transaction
|
53
|
+
@pool.hold do |conn|
|
54
|
+
@transactions ||= []
|
55
|
+
if @transactions.include? Thread.current
|
56
|
+
return yield(conn)
|
57
|
+
end
|
58
|
+
|
59
|
+
conn.autocommit = false
|
60
|
+
begin
|
61
|
+
@transactions << Thread.current
|
62
|
+
result = yield(conn)
|
63
|
+
conn.commit
|
64
|
+
result
|
65
|
+
rescue => e
|
66
|
+
conn.rollback
|
67
|
+
raise e unless SequelRollbackError === e
|
68
|
+
ensure
|
69
|
+
conn.autocommit = true
|
70
|
+
@transactions.delete(Thread.current)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
41
74
|
end
|
42
75
|
|
43
76
|
class Dataset < Sequel::Dataset
|
@@ -54,10 +87,10 @@ module Sequel
|
|
54
87
|
@db.synchronize do
|
55
88
|
cursor = @db.execute sql
|
56
89
|
begin
|
57
|
-
@columns = cursor.get_col_names.map {|c| c.to_sym}
|
90
|
+
@columns = cursor.get_col_names.map {|c| c.downcase.to_sym}
|
58
91
|
while r = cursor.fetch
|
59
92
|
row = {}
|
60
|
-
r.each_with_index {|v, i| row[
|
93
|
+
r.each_with_index {|v, i| row[columns[i]] = v unless columns[i] == :raw_rnum_}
|
61
94
|
yield row
|
62
95
|
end
|
63
96
|
ensure
|
@@ -71,9 +104,11 @@ module Sequel
|
|
71
104
|
@db.synchronize do
|
72
105
|
cursor = @db.execute sql
|
73
106
|
begin
|
74
|
-
@columns = cursor.get_col_names.map {|c| c.to_sym}
|
107
|
+
@columns = cursor.get_col_names.map {|c| c.downcase.to_sym}
|
108
|
+
raw_rnum_index = columns.index(:raw_rnum_)
|
75
109
|
while r = cursor.fetch
|
76
|
-
r.
|
110
|
+
r.delete_at(raw_rnum_index) if raw_rnum_index
|
111
|
+
r.keys = columns.delete_if{|x| x == :raw_rnum_}
|
77
112
|
yield r
|
78
113
|
end
|
79
114
|
ensure
|
@@ -94,6 +129,70 @@ module Sequel
|
|
94
129
|
def delete(opts = nil)
|
95
130
|
@db.do delete_sql(opts)
|
96
131
|
end
|
132
|
+
|
133
|
+
|
134
|
+
# Formats a SELECT statement using the given options and the dataset
|
135
|
+
# options.
|
136
|
+
def select_sql(opts = nil)
|
137
|
+
opts = opts ? @opts.merge(opts) : @opts
|
138
|
+
|
139
|
+
if sql = opts[:sql]
|
140
|
+
return sql
|
141
|
+
end
|
142
|
+
|
143
|
+
columns = opts[:select]
|
144
|
+
select_columns = columns ? column_list(columns) : WILDCARD
|
145
|
+
sql = opts[:distinct] ? \
|
146
|
+
"SELECT DISTINCT #{select_columns}" : \
|
147
|
+
"SELECT #{select_columns}"
|
148
|
+
|
149
|
+
if opts[:from]
|
150
|
+
sql << " FROM #{source_list(opts[:from])}"
|
151
|
+
end
|
152
|
+
|
153
|
+
if join = opts[:join]
|
154
|
+
sql << join
|
155
|
+
end
|
156
|
+
|
157
|
+
if where = opts[:where]
|
158
|
+
sql << " WHERE #{where}"
|
159
|
+
end
|
160
|
+
|
161
|
+
if group = opts[:group]
|
162
|
+
sql << " GROUP BY #{column_list(group)}"
|
163
|
+
end
|
164
|
+
|
165
|
+
if having = opts[:having]
|
166
|
+
sql << " HAVING #{having}"
|
167
|
+
end
|
168
|
+
|
169
|
+
if union = opts[:union]
|
170
|
+
sql << (opts[:union_all] ? \
|
171
|
+
" UNION ALL #{union.sql}" : " UNION #{union.sql}")
|
172
|
+
elsif intersect = opts[:intersect]
|
173
|
+
sql << (opts[:intersect_all] ? \
|
174
|
+
" INTERSECT ALL #{intersect.sql}" : " INTERSECT #{intersect.sql}")
|
175
|
+
elsif except = opts[:except]
|
176
|
+
sql << (opts[:except_all] ? \
|
177
|
+
" EXCEPT ALL #{except.sql}" : " EXCEPT #{except.sql}")
|
178
|
+
end
|
179
|
+
|
180
|
+
if order = opts[:order]
|
181
|
+
sql << " ORDER BY #{column_list(order)}"
|
182
|
+
end
|
183
|
+
|
184
|
+
if limit = opts[:limit]
|
185
|
+
if (offset = opts[:offset]) && (offset > 0)
|
186
|
+
sql = "SELECT * FROM (SELECT raw_sql_.*, ROWNUM raw_rnum_ FROM(#{sql}) raw_sql_ WHERE ROWNUM <= #{limit + offset}) WHERE raw_rnum_ > #{offset}"
|
187
|
+
else
|
188
|
+
sql = "SELECT * FROM (#{sql}) WHERE ROWNUM <= #{limit}"
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
sql
|
193
|
+
end
|
194
|
+
|
195
|
+
alias sql select_sql
|
97
196
|
end
|
98
197
|
end
|
99
198
|
end
|
data/lib/sequel_core/database.rb
CHANGED
@@ -414,12 +414,18 @@ module Sequel
|
|
414
414
|
scheme = uri.scheme
|
415
415
|
scheme = :dbi if scheme =~ /^dbi-(.+)/
|
416
416
|
c = adapter_class(scheme)
|
417
|
-
c.
|
417
|
+
opts = c.uri_to_options(uri).merge(opts || {})
|
418
418
|
else
|
419
419
|
opts = conn_string.merge(opts || {})
|
420
|
-
c = adapter_class(opts[:adapter])
|
421
|
-
c.new(opts)
|
420
|
+
c = adapter_class(opts[:adapter] || opts['adapter'])
|
422
421
|
end
|
422
|
+
# process opts a bit
|
423
|
+
opts = opts.inject({}) do |m, kv| k, v = *kv
|
424
|
+
k = :user if k == 'username'
|
425
|
+
m[k.to_sym] = v
|
426
|
+
m
|
427
|
+
end
|
428
|
+
c.new(opts)
|
423
429
|
end
|
424
430
|
|
425
431
|
@@single_threaded = false
|
@@ -251,8 +251,8 @@ class Sequel::Dataset
|
|
251
251
|
eval("$#{e[1]}", b)
|
252
252
|
when :lvar # local context
|
253
253
|
if e[1] == :block
|
254
|
-
|
255
|
-
|
254
|
+
sub_proc = eval(e[1].to_s, b)
|
255
|
+
sub_proc.to_sql(self)
|
256
256
|
else
|
257
257
|
eval(e[1].to_s, b)
|
258
258
|
end
|
@@ -324,20 +324,20 @@ class Sequel::Dataset
|
|
324
324
|
end
|
325
325
|
end
|
326
326
|
end
|
327
|
+
end
|
328
|
+
end
|
327
329
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
pt_expr(ParseTree.translate(c, :m)[2][2], proc.binding, opts)
|
332
|
-
end
|
330
|
+
class Proc
|
331
|
+
def to_sql(dataset, opts = {})
|
332
|
+
dataset.pt_expr(to_sexp[2], self.binding, opts)
|
333
333
|
end
|
334
334
|
end
|
335
335
|
|
336
336
|
begin
|
337
337
|
require 'parse_tree'
|
338
338
|
rescue Exception
|
339
|
-
|
340
|
-
def
|
339
|
+
class Proc
|
340
|
+
def to_sql(*args)
|
341
341
|
raise Sequel::Error, "You must have the ParseTree gem installed in order to use block filters."
|
342
342
|
end
|
343
343
|
end
|
@@ -352,3 +352,14 @@ rescue Exception
|
|
352
352
|
end
|
353
353
|
end
|
354
354
|
end
|
355
|
+
|
356
|
+
class Proc
|
357
|
+
# replacement for Proc#to_sexp, if it's not available
|
358
|
+
unless instance_methods.include?('to_sexp')
|
359
|
+
def to_sexp
|
360
|
+
block = self
|
361
|
+
c = Class.new {define_method(:m, &block)}
|
362
|
+
ParseTree.translate(c, :m)[2]
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
@@ -128,7 +128,7 @@ module Sequel
|
|
128
128
|
when Array
|
129
129
|
fmt = expr.shift.gsub(QUESTION_MARK) {literal(expr.shift)}
|
130
130
|
when Proc
|
131
|
-
fmt =
|
131
|
+
fmt = expr.to_sql(self)
|
132
132
|
else
|
133
133
|
# if the expression is compound, it should be parenthesized in order for
|
134
134
|
# things to be predictable (when using #or and #and.)
|
@@ -223,14 +223,14 @@ module Sequel
|
|
223
223
|
# software.filter {price < 100}.sql #=>
|
224
224
|
# "SELECT * FROM items WHERE (category = 'software') AND (price < 100)"
|
225
225
|
def filter(*cond, &block)
|
226
|
-
clause = (@opts[:
|
226
|
+
clause = (@opts[:having] ? :having : :where)
|
227
227
|
cond = cond.first if cond.size == 1
|
228
228
|
if cond === true || cond === false
|
229
229
|
raise Error::InvalidFilter, "Invalid filter specified. Did you mean to supply a block?"
|
230
230
|
end
|
231
231
|
parenthesize = !(cond.is_a?(Hash) || cond.is_a?(Array))
|
232
232
|
filter = cond.is_a?(Hash) && cond
|
233
|
-
if @opts[clause]
|
233
|
+
if !@opts[clause].nil? and @opts[clause].any?
|
234
234
|
l = expression_list(@opts[clause])
|
235
235
|
r = expression_list(block || cond, parenthesize)
|
236
236
|
clone_merge(clause => "#{l} AND #{r}")
|
@@ -242,7 +242,7 @@ module Sequel
|
|
242
242
|
# Adds an alternate filter to an existing filter using OR. If no filter
|
243
243
|
# exists an error is raised.
|
244
244
|
def or(*cond, &block)
|
245
|
-
clause = (@opts[:
|
245
|
+
clause = (@opts[:having] ? :having : :where)
|
246
246
|
cond = cond.first if cond.size == 1
|
247
247
|
parenthesize = !(cond.is_a?(Hash) || cond.is_a?(Array))
|
248
248
|
if @opts[clause]
|
@@ -258,7 +258,7 @@ module Sequel
|
|
258
258
|
# exists an error is raised. This method is identical to #filter except
|
259
259
|
# it expects an existing filter.
|
260
260
|
def and(*cond, &block)
|
261
|
-
clause = (@opts[:
|
261
|
+
clause = (@opts[:having] ? :having : :where)
|
262
262
|
unless @opts[clause]
|
263
263
|
raise Error::NoExistingFilter, "No existing filter found."
|
264
264
|
end
|
@@ -270,7 +270,7 @@ module Sequel
|
|
270
270
|
# dataset.exclude(:category => 'software').sql #=>
|
271
271
|
# "SELECT * FROM items WHERE NOT (category = 'software')"
|
272
272
|
def exclude(*cond, &block)
|
273
|
-
clause = (@opts[:
|
273
|
+
clause = (@opts[:having] ? :having : :where)
|
274
274
|
cond = cond.first if cond.size == 1
|
275
275
|
parenthesize = !(cond.is_a?(Hash) || cond.is_a?(Array))
|
276
276
|
if @opts[clause]
|
@@ -286,11 +286,7 @@ module Sequel
|
|
286
286
|
# Returns a copy of the dataset with the where conditions changed. Raises
|
287
287
|
# if the dataset has been grouped. See also #filter.
|
288
288
|
def where(*cond, &block)
|
289
|
-
|
290
|
-
raise Error, "Can't specify a WHERE clause once the dataset has been grouped"
|
291
|
-
else
|
292
|
-
filter(*cond, &block)
|
293
|
-
end
|
289
|
+
filter(*cond, &block)
|
294
290
|
end
|
295
291
|
|
296
292
|
# Returns a copy of the dataset with the having conditions changed. Raises
|
@@ -299,6 +295,7 @@ module Sequel
|
|
299
295
|
unless @opts[:group]
|
300
296
|
raise Error, "Can only specify a HAVING clause on a grouped dataset"
|
301
297
|
else
|
298
|
+
@opts[:having] = {}
|
302
299
|
filter(*cond, &block)
|
303
300
|
end
|
304
301
|
end
|
@@ -501,7 +498,7 @@ module Sequel
|
|
501
498
|
|
502
499
|
sql = "UPDATE #{@opts[:from]} SET "
|
503
500
|
if block
|
504
|
-
sql <<
|
501
|
+
sql << block.to_sql(self, :comma_separated => true)
|
505
502
|
else
|
506
503
|
# check if array with keys
|
507
504
|
values = values.to_hash if values.is_a?(Array) && values.keys
|
data/lib/sequel_core/model.rb
CHANGED
data/spec/adapters/mysql_spec.rb
CHANGED
@@ -24,6 +24,18 @@ context "A MySQL database" do
|
|
24
24
|
@db.disconnect
|
25
25
|
@db.pool.size.should == 0
|
26
26
|
end
|
27
|
+
|
28
|
+
specify "should support sequential primary keys" do
|
29
|
+
@db.create_table!(:with_pk) {primary_key :id; text :name}
|
30
|
+
@db[:with_pk] << {:name => 'abc'}
|
31
|
+
@db[:with_pk] << {:name => 'def'}
|
32
|
+
@db[:with_pk] << {:name => 'ghi'}
|
33
|
+
@db[:with_pk].order(:name).all.should == [
|
34
|
+
{:id => 1, :name => 'abc'},
|
35
|
+
{:id => 2, :name => 'def'},
|
36
|
+
{:id => 3, :name => 'ghi'}
|
37
|
+
]
|
38
|
+
end
|
27
39
|
end
|
28
40
|
|
29
41
|
context "A MySQL dataset" do
|
@@ -335,6 +347,11 @@ context "A MySQL database" do
|
|
335
347
|
proc {db.test_connection}.should_not raise_error
|
336
348
|
end
|
337
349
|
|
350
|
+
specify "should accept a socket option without host option" do
|
351
|
+
db = Sequel.mysql('sandbox', :user => 'root', :socket => '/tmp/mysql.sock')
|
352
|
+
proc {db.test_connection}.should_not raise_error
|
353
|
+
end
|
354
|
+
|
338
355
|
specify "should fail to connect with invalid socket" do
|
339
356
|
db = Sequel.mysql('sandbox', :host => 'localhost', :user => 'root', :socket => 'blah')
|
340
357
|
proc {db.test_connection}.should raise_error
|
@@ -1,17 +1,35 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), '../../lib/sequel_core')
|
2
2
|
|
3
|
-
ORACLE_DB = Sequel('oracle://hr:hr@
|
4
|
-
|
5
|
-
|
3
|
+
ORACLE_DB = Sequel('oracle://hr:hr@localhost/XE')
|
4
|
+
|
5
|
+
if ORACLE_DB.table_exists?(:items)
|
6
|
+
ORACLE_DB.drop_table :items
|
6
7
|
end
|
7
|
-
ORACLE_DB.create_table :
|
8
|
-
|
9
|
-
|
8
|
+
ORACLE_DB.create_table :items do
|
9
|
+
varchar2 :name, :size => 50
|
10
|
+
number :value, :size => 38
|
10
11
|
|
11
12
|
index :value
|
12
13
|
end
|
13
14
|
|
14
|
-
|
15
|
+
if ORACLE_DB.table_exists?(:books)
|
16
|
+
ORACLE_DB.drop_table :books
|
17
|
+
end
|
18
|
+
ORACLE_DB.create_table :books do
|
19
|
+
number :id, :size => 38
|
20
|
+
varchar2 :title, :size => 50
|
21
|
+
number :category_id, :size => 38
|
22
|
+
end
|
23
|
+
|
24
|
+
if ORACLE_DB.table_exists?(:categories)
|
25
|
+
ORACLE_DB.drop_table :categories
|
26
|
+
end
|
27
|
+
ORACLE_DB.create_table :categories do
|
28
|
+
number :id, :size => 38
|
29
|
+
varchar2 :cat_name, :size => 50
|
30
|
+
end
|
31
|
+
|
32
|
+
context "An Oracle database" do
|
15
33
|
specify "should provide disconnect functionality" do
|
16
34
|
ORACLE_DB.execute("select user from dual")
|
17
35
|
ORACLE_DB.pool.size.should == 1
|
@@ -20,9 +38,9 @@ context "A Oracle database" do
|
|
20
38
|
end
|
21
39
|
end
|
22
40
|
|
23
|
-
context "
|
41
|
+
context "An Oracle dataset" do
|
24
42
|
setup do
|
25
|
-
@d = ORACLE_DB[:
|
43
|
+
@d = ORACLE_DB[:items]
|
26
44
|
@d.delete # remove all records
|
27
45
|
end
|
28
46
|
|
@@ -45,6 +63,83 @@ context "A Oracle dataset" do
|
|
45
63
|
{:name => 'abc', :value => 456},
|
46
64
|
{:name => 'def', :value => 789}
|
47
65
|
]
|
66
|
+
|
67
|
+
@d.select(:name).uniq.order_by(:name).to_a.should == [
|
68
|
+
{:name => 'abc'},
|
69
|
+
{:name => 'def'}
|
70
|
+
]
|
71
|
+
|
72
|
+
@d.order(:value.DESC).limit(1).to_a.should == [
|
73
|
+
{:name => 'def', :value => 789}
|
74
|
+
]
|
75
|
+
|
76
|
+
@d.filter(:name => 'abc').to_a.should == [
|
77
|
+
{:name => 'abc', :value => 123},
|
78
|
+
{:name => 'abc', :value => 456}
|
79
|
+
]
|
80
|
+
|
81
|
+
@d.order(:value.DESC).filter(:name => 'abc').to_a.should == [
|
82
|
+
{:name => 'abc', :value => 456},
|
83
|
+
{:name => 'abc', :value => 123}
|
84
|
+
]
|
85
|
+
|
86
|
+
@d.filter(:name => 'abc').limit(1).to_a.should == [
|
87
|
+
{:name => 'abc', :value => 123}
|
88
|
+
]
|
89
|
+
|
90
|
+
@d.filter(:name => 'abc').order(:value.DESC).limit(1).to_a.should == [
|
91
|
+
{:name => 'abc', :value => 456}
|
92
|
+
]
|
93
|
+
|
94
|
+
@d.filter(:name => 'abc').order(:value).limit(1).to_a.should == [
|
95
|
+
{:name => 'abc', :value => 123}
|
96
|
+
]
|
97
|
+
|
98
|
+
@d.order(:value).limit(1).to_a.should == [
|
99
|
+
{:name => 'abc', :value => 123}
|
100
|
+
]
|
101
|
+
|
102
|
+
@d.order(:value).limit(1, 1).to_a.should == [
|
103
|
+
{:name => 'abc', :value => 456}
|
104
|
+
]
|
105
|
+
|
106
|
+
@d.order(:value).limit(1, 2).to_a.should == [
|
107
|
+
{:name => 'def', :value => 789}
|
108
|
+
]
|
109
|
+
|
110
|
+
@d.avg(:value).to_i.should == (789+123+456)/3
|
111
|
+
|
112
|
+
@d.max(:value).to_i.should == 789
|
113
|
+
|
114
|
+
@d.select(:name, :AVG[:value]).filter(:name => 'abc').group(:name).to_a.should == [
|
115
|
+
{:name => 'abc', :"avg(value)" => (456+123)/2.0}
|
116
|
+
]
|
117
|
+
|
118
|
+
@d.select(:AVG[:value]).group(:name).order(:name).limit(1).to_a.should == [
|
119
|
+
{:"avg(value)" => (456+123)/2.0}
|
120
|
+
]
|
121
|
+
|
122
|
+
@d.select(:name, :AVG[:value]).group(:name).order(:name).to_a.should == [
|
123
|
+
{:name => 'abc', :"avg(value)" => (456+123)/2.0},
|
124
|
+
{:name => 'def', :"avg(value)" => 789*1.0}
|
125
|
+
]
|
126
|
+
|
127
|
+
@d.select(:name, :AVG[:value]).group(:name).order(:name).to_a.should == [
|
128
|
+
{:name => 'abc', :"avg(value)" => (456+123)/2.0},
|
129
|
+
{:name => 'def', :"avg(value)" => 789*1.0}
|
130
|
+
]
|
131
|
+
|
132
|
+
@d.select(:name, :AVG[:value]).group(:name).having(:name => ['abc', 'def']).order(:name).to_a.should == [
|
133
|
+
{:name => 'abc', :"avg(value)" => (456+123)/2.0},
|
134
|
+
{:name => 'def', :"avg(value)" => 789*1.0}
|
135
|
+
]
|
136
|
+
|
137
|
+
@d.select(:name, :value).filter(:name => 'abc').union(@d.select(:name, :value).filter(:name => 'def')).order(:value).to_a.should == [
|
138
|
+
{:name => 'abc', :value => 123},
|
139
|
+
{:name => 'abc', :value => 456},
|
140
|
+
{:name => 'def', :value => 789}
|
141
|
+
]
|
142
|
+
|
48
143
|
end
|
49
144
|
|
50
145
|
specify "should update records correctly" do
|
@@ -83,9 +178,51 @@ context "A Oracle dataset" do
|
|
83
178
|
end
|
84
179
|
end
|
85
180
|
|
86
|
-
context "
|
181
|
+
context "Joined Oracle dataset" do
|
182
|
+
setup do
|
183
|
+
@d1 = ORACLE_DB[:books]
|
184
|
+
@d1.delete # remove all records
|
185
|
+
@d1 << {:id => 1, :title => 'aaa', :category_id => 100}
|
186
|
+
@d1 << {:id => 2, :title => 'bbb', :category_id => 100}
|
187
|
+
@d1 << {:id => 3, :title => 'ccc', :category_id => 101}
|
188
|
+
@d1 << {:id => 4, :title => 'ddd', :category_id => 102}
|
189
|
+
|
190
|
+
@d2 = ORACLE_DB[:categories]
|
191
|
+
@d2.delete # remove all records
|
192
|
+
@d2 << {:id => 100, :cat_name => 'ruby'}
|
193
|
+
@d2 << {:id => 101, :cat_name => 'rails'}
|
194
|
+
end
|
195
|
+
|
196
|
+
specify "should return correct result" do
|
197
|
+
@d1.join(:categories, :id => :category_id).select(:books__id, :title, :cat_name).order(:books__id).to_a.should == [
|
198
|
+
{:id => 1, :title => 'aaa', :cat_name => 'ruby'},
|
199
|
+
{:id => 2, :title => 'bbb', :cat_name => 'ruby'},
|
200
|
+
{:id => 3, :title => 'ccc', :cat_name => 'rails'}
|
201
|
+
]
|
202
|
+
|
203
|
+
@d1.join(:categories, :id => :category_id).select(:books__id, :title, :cat_name).order(:books__id).limit(2, 1).to_a.should == [
|
204
|
+
{:id => 2, :title => 'bbb', :cat_name => 'ruby'},
|
205
|
+
{:id => 3, :title => 'ccc', :cat_name => 'rails'},
|
206
|
+
]
|
207
|
+
|
208
|
+
@d1.left_outer_join(:categories, :id => :category_id).select(:books__id, :title, :cat_name).order(:books__id).to_a.should == [
|
209
|
+
{:id => 1, :title => 'aaa', :cat_name => 'ruby'},
|
210
|
+
{:id => 2, :title => 'bbb', :cat_name => 'ruby'},
|
211
|
+
{:id => 3, :title => 'ccc', :cat_name => 'rails'},
|
212
|
+
{:id => 4, :title => 'ddd', :cat_name => nil}
|
213
|
+
]
|
214
|
+
|
215
|
+
@d1.left_outer_join(:categories, :id => :category_id).select(:books__id, :title, :cat_name).order(:books__id.DESC).limit(2, 0).to_a.should == [
|
216
|
+
{:id => 4, :title => 'ddd', :cat_name => nil},
|
217
|
+
{:id => 3, :title => 'ccc', :cat_name => 'rails'}
|
218
|
+
]
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
|
223
|
+
context "An Oracle dataset in array tuples mode" do
|
87
224
|
setup do
|
88
|
-
@d = ORACLE_DB[:
|
225
|
+
@d = ORACLE_DB[:items]
|
89
226
|
@d.delete # remove all records
|
90
227
|
Sequel.use_array_tuples
|
91
228
|
end
|
@@ -105,6 +242,15 @@ context "A Oracle dataset in array tuples mode" do
|
|
105
242
|
['abc', 456],
|
106
243
|
['def', 789]
|
107
244
|
]
|
245
|
+
|
246
|
+
@d.order(:value).select(:name, :value).limit(1).to_a.should == [
|
247
|
+
['abc',123]
|
248
|
+
]
|
249
|
+
|
250
|
+
@d.order(:value).select(:name, :value).limit(2,1).to_a.should == [
|
251
|
+
['abc',456],
|
252
|
+
['def',789]
|
253
|
+
]
|
108
254
|
end
|
109
255
|
|
110
256
|
specify "should work correctly with transforms" do
|