sequel 0.3.4.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +24 -0
- data/README +2 -0
- data/Rakefile +2 -2
- data/lib/{sequel → sequel-core}/array_keys.rb +0 -0
- data/lib/{sequel → sequel-core}/connection_pool.rb +0 -0
- data/lib/{sequel → sequel-core}/core_ext.rb +0 -0
- data/lib/{sequel → sequel-core}/core_sql.rb +8 -0
- data/lib/{sequel → sequel-core}/database.rb +4 -2
- data/lib/{sequel → sequel-core}/dataset.rb +0 -0
- data/lib/{sequel → sequel-core}/dataset/convenience.rb +0 -0
- data/lib/{sequel → sequel-core}/dataset/sequelizer.rb +0 -0
- data/lib/{sequel → sequel-core}/dataset/sql.rb +22 -21
- data/lib/{sequel → sequel-core}/error.rb +0 -0
- data/lib/{sequel → sequel-core}/migration.rb +0 -0
- data/lib/{sequel → sequel-core}/model.rb +5 -0
- data/lib/{sequel → sequel-core}/model/base.rb +0 -0
- data/lib/{sequel → sequel-core}/model/caching.rb +0 -0
- data/lib/{sequel → sequel-core}/model/hooks.rb +0 -0
- data/lib/{sequel → sequel-core}/model/record.rb +0 -0
- data/lib/{sequel → sequel-core}/model/relations.rb +0 -0
- data/lib/{sequel → sequel-core}/model/schema.rb +0 -0
- data/lib/{sequel → sequel-core}/pretty_table.rb +0 -0
- data/lib/{sequel → sequel-core}/schema.rb +0 -0
- data/lib/{sequel → sequel-core}/schema/schema_generator.rb +0 -0
- data/lib/{sequel → sequel-core}/schema/schema_sql.rb +0 -0
- data/lib/{sequel → sequel-core}/worker.rb +23 -10
- data/lib/sequel.rb +3 -1
- data/lib/sequel/dbi.rb +33 -0
- data/lib/sequel/informix.rb +78 -0
- data/lib/sequel/mysql.rb +0 -2
- data/lib/sequel/postgres.rb +16 -0
- data/spec/adapters/mysql_spec.rb +11 -0
- data/spec/adapters/postgres_spec.rb +5 -0
- data/spec/dataset_spec.rb +26 -11
- data/spec/worker_spec.rb +35 -2
- metadata +97 -88
data/CHANGELOG
CHANGED
@@ -1,3 +1,27 @@
|
|
1
|
+
=== 0.4.0 (2007-11-24)
|
2
|
+
|
3
|
+
* Reorganized lib directory structure.
|
4
|
+
|
5
|
+
* Added support for dbi-xxx URI schemes (#86).
|
6
|
+
|
7
|
+
* Fixed problem in Database#uri where setting the password would raise an error (#87).
|
8
|
+
|
9
|
+
* Improved Dataset#insert_sql to correctly handle string keys (#92).
|
10
|
+
|
11
|
+
* Improved error-handling for worker threads. Errors are saved to an array and are accessible through #errors (#91).
|
12
|
+
|
13
|
+
* Dataset#uniq/distinct can now accept a column list for DISTINCT ON clauses.
|
14
|
+
|
15
|
+
* Fixed Model.all.
|
16
|
+
|
17
|
+
* Fixed literalization of strings with escape sequences in postgres adapter (#90).
|
18
|
+
|
19
|
+
* Added support for literalizing BigDecimal values (#89).
|
20
|
+
|
21
|
+
* Fixed column qualification for joined datasets (thanks Christian).
|
22
|
+
|
23
|
+
* Implemented experimental informix adapter.
|
24
|
+
|
1
25
|
=== 0.3.4.1 (2007-11-10)
|
2
26
|
|
3
27
|
* Changed Dataset#select_sql to support queries without a FROM clause.
|
data/README
CHANGED
data/Rakefile
CHANGED
@@ -6,7 +6,7 @@ require 'fileutils'
|
|
6
6
|
include FileUtils
|
7
7
|
|
8
8
|
NAME = "sequel"
|
9
|
-
VERS = "0.
|
9
|
+
VERS = "0.4.0"
|
10
10
|
CLEAN.include ['**/.*.sw?', 'pkg/*', '.config', 'doc/*', 'coverage/*']
|
11
11
|
RDOC_OPTS = ['--quiet', '--title', "Sequel: Concise ORM for Ruby",
|
12
12
|
"--opname", "index.html",
|
@@ -25,7 +25,7 @@ Rake::RDocTask.new do |rdoc|
|
|
25
25
|
rdoc.options += RDOC_OPTS
|
26
26
|
rdoc.main = "README"
|
27
27
|
rdoc.title = "Sequel: Lightweight ORM library for Ruby"
|
28
|
-
rdoc.rdoc_files.add ['README', 'COPYING', 'lib/sequel.rb', 'lib
|
28
|
+
rdoc.rdoc_files.add ['README', 'COPYING', 'lib/sequel.rb', 'lib/**/*.rb']
|
29
29
|
end
|
30
30
|
|
31
31
|
spec = Gem::Specification.new do |s|
|
File without changes
|
File without changes
|
File without changes
|
@@ -68,6 +68,14 @@ module Sequel
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
+
class QualifiedColumnRef < Expression
|
72
|
+
def initialize(t, c); @t, @c = t, c; end
|
73
|
+
|
74
|
+
def to_s(ds)
|
75
|
+
"#{@t}.#{ds.literal(@c)}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
71
79
|
class Function < Expression
|
72
80
|
def initialize(f, *args); @f, @args = f, args; end
|
73
81
|
|
@@ -64,7 +64,7 @@ module Sequel
|
|
64
64
|
nil
|
65
65
|
)
|
66
66
|
uri.user = @opts[:user]
|
67
|
-
uri.password = @opts[:password]
|
67
|
+
uri.password = @opts[:password] if uri.user
|
68
68
|
uri.to_s
|
69
69
|
end
|
70
70
|
alias url uri # Because I don't care much for the semantic difference.
|
@@ -285,7 +285,9 @@ module Sequel
|
|
285
285
|
# DB = Sequel.open 'sqlite:///blog.db'
|
286
286
|
def self.connect(conn_string, more_opts = nil)
|
287
287
|
uri = URI.parse(conn_string)
|
288
|
-
|
288
|
+
scheme = uri.scheme
|
289
|
+
scheme = :dbi if scheme =~ /^dbi-(.+)/
|
290
|
+
c = @@adapters[scheme.to_sym]
|
289
291
|
raise SequelError, "Invalid database scheme" unless c
|
290
292
|
c.new(c.uri_to_options(uri).merge(more_opts || {}))
|
291
293
|
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -14,16 +14,15 @@ module Sequel
|
|
14
14
|
# Returns a qualified column name (including a table name) if the column
|
15
15
|
# name isn't already qualified.
|
16
16
|
def qualified_column_name(column, table)
|
17
|
-
|
18
|
-
if
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
# check if the table is aliased
|
23
|
-
if table =~ ALIASED_REGEXP
|
17
|
+
s = literal(column)
|
18
|
+
if s =~ QUALIFIED_REGEXP
|
19
|
+
return column
|
20
|
+
else
|
21
|
+
if (table =~ ALIASED_REGEXP)
|
24
22
|
table = $2
|
25
23
|
end
|
26
|
-
|
24
|
+
Sequel::SQL::QualifiedColumnRef.new(table, column)
|
25
|
+
# "#{table}.#{column}"
|
27
26
|
end
|
28
27
|
end
|
29
28
|
|
@@ -86,6 +85,7 @@ module Sequel
|
|
86
85
|
when LiteralString: v
|
87
86
|
when String: "'#{v.gsub(/'/, "''")}'"
|
88
87
|
when Integer, Float: v.to_s
|
88
|
+
when BigDecimal: v.to_s("F")
|
89
89
|
when NilClass: NULL
|
90
90
|
when TrueClass: TRUE
|
91
91
|
when FalseClass: FALSE
|
@@ -109,10 +109,7 @@ module Sequel
|
|
109
109
|
case expr
|
110
110
|
when Hash:
|
111
111
|
parenthesize = false if expr.size == 1
|
112
|
-
|
113
|
-
# N.B.: We convert this to an array and sort it in order to have a fixed order for testability.
|
114
|
-
# Hash in Ruby 1.8 has no order, so Hash#map is indeterminate, which makes it hard to test.
|
115
|
-
fmt = expr.to_a.sort_by { |k, v| k.to_s }.map {|i| compare_expr(i[0], i[1])}.join(AND_SEPARATOR)
|
112
|
+
fmt = expr.map {|i| compare_expr(i[0], i[1])}.join(AND_SEPARATOR)
|
116
113
|
when Array:
|
117
114
|
fmt = expr.shift.gsub(QUESTION_MARK) {literal(expr.shift)}
|
118
115
|
when Proc:
|
@@ -137,10 +134,10 @@ module Sequel
|
|
137
134
|
end
|
138
135
|
|
139
136
|
# Returns a copy of the dataset with the distinct option.
|
140
|
-
def uniq
|
141
|
-
clone_merge(:distinct =>
|
137
|
+
def uniq(*args)
|
138
|
+
clone_merge(:distinct => args)
|
142
139
|
end
|
143
|
-
|
140
|
+
alias_method :distinct, :uniq
|
144
141
|
|
145
142
|
# Returns a copy of the dataset with the order changed.
|
146
143
|
def order(*order)
|
@@ -320,8 +317,8 @@ module Sequel
|
|
320
317
|
|
321
318
|
join_conditions = {}
|
322
319
|
expr.each do |k, v|
|
323
|
-
k = qualified_column_name(k, table)
|
324
|
-
v = qualified_column_name(v, @opts[:last_joined_table] || @opts[:from].first)
|
320
|
+
k = qualified_column_name(k, table) if k.is_a?(Symbol)
|
321
|
+
v = qualified_column_name(v, @opts[:last_joined_table] || @opts[:from].first) if v.is_a?(Symbol)
|
325
322
|
join_conditions[k] = v
|
326
323
|
end
|
327
324
|
" #{join_type} #{table} ON #{expression_list(join_conditions)}"
|
@@ -371,9 +368,13 @@ module Sequel
|
|
371
368
|
|
372
369
|
columns = opts[:select]
|
373
370
|
select_columns = columns ? column_list(columns) : WILDCARD
|
374
|
-
|
375
|
-
|
376
|
-
|
371
|
+
|
372
|
+
if distinct = opts[:distinct]
|
373
|
+
distinct_clause = distinct.empty? ? "DISTINCT" : "DISTINCT ON (#{column_list(distinct)})"
|
374
|
+
sql = "SELECT #{distinct_clause} #{select_columns}"
|
375
|
+
else
|
376
|
+
sql = "SELECT #{select_columns}"
|
377
|
+
end
|
377
378
|
|
378
379
|
if opts[:from]
|
379
380
|
sql << " FROM #{source_list(opts[:from])}"
|
@@ -453,7 +454,7 @@ module Sequel
|
|
453
454
|
"INSERT INTO #{@opts[:from]} DEFAULT VALUES"
|
454
455
|
else
|
455
456
|
fl, vl = [], []
|
456
|
-
values.each {|k, v| fl <<
|
457
|
+
values.each {|k, v| fl << k.to_s; vl << literal(v)}
|
457
458
|
"INSERT INTO #{@opts[:from]} (#{fl.join(COMMA_SEPARATOR)}) VALUES (#{vl.join(COMMA_SEPARATOR)})"
|
458
459
|
end
|
459
460
|
when Dataset
|
File without changes
|
File without changes
|
@@ -305,6 +305,11 @@ module Sequel
|
|
305
305
|
table_name = dataset.opts[:from].first
|
306
306
|
dataset.join(*args).select(table_name.to_sym.ALL)
|
307
307
|
end
|
308
|
+
|
309
|
+
# Returns an array containing all model records
|
310
|
+
def self.all
|
311
|
+
dataset.all
|
312
|
+
end
|
308
313
|
|
309
314
|
# Returns value of attribute.
|
310
315
|
def [](column)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -5,22 +5,22 @@ module Sequel
|
|
5
5
|
class WorkerStopError < RuntimeError; end
|
6
6
|
|
7
7
|
attr_reader :queue
|
8
|
+
attr_reader :errors
|
8
9
|
|
9
10
|
def initialize(db = nil)
|
10
11
|
@queue = Queue.new
|
12
|
+
@errors = []
|
11
13
|
t = self
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
super {t.work}
|
16
|
-
end
|
14
|
+
t.abort_on_exception = true
|
15
|
+
@transaction = !db.nil?
|
16
|
+
db ? super {db.transaction {t.work}} : super {t.work}
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def work
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
loop {next_job}
|
21
|
+
rescue WorkerStopError # signals the worker thread to stop
|
22
|
+
ensure
|
23
|
+
rollback! if @transaction && !@errors.empty?
|
24
24
|
end
|
25
25
|
|
26
26
|
def busy?
|
@@ -29,6 +29,7 @@ module Sequel
|
|
29
29
|
|
30
30
|
def async(proc = nil, &block)
|
31
31
|
@queue << (proc || block)
|
32
|
+
self
|
32
33
|
end
|
33
34
|
alias_method :add, :async
|
34
35
|
alias_method :<<, :async
|
@@ -40,5 +41,17 @@ module Sequel
|
|
40
41
|
self.raise WorkerStopError
|
41
42
|
super
|
42
43
|
end
|
44
|
+
|
45
|
+
private
|
46
|
+
def next_job
|
47
|
+
@cur = @queue.pop
|
48
|
+
@cur.call
|
49
|
+
rescue WorkerStopError => e
|
50
|
+
raise e
|
51
|
+
rescue Exception => e
|
52
|
+
@errors << e
|
53
|
+
ensure
|
54
|
+
@cur = nil
|
55
|
+
end
|
43
56
|
end
|
44
57
|
end
|
data/lib/sequel.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
require 'metaid'
|
2
|
+
require 'bigdecimal'
|
3
|
+
require 'bigdecimal/util'
|
2
4
|
|
3
5
|
files = %w[
|
4
6
|
core_ext core_sql array_keys error connection_pool pretty_table
|
5
7
|
dataset migration model schema database worker
|
6
8
|
]
|
7
|
-
dir = File.join(File.dirname(__FILE__), 'sequel')
|
9
|
+
dir = File.join(File.dirname(__FILE__), 'sequel-core')
|
8
10
|
files.each {|f| require(File.join(dir, f))}
|
9
11
|
|
10
12
|
module Sequel #:nodoc:
|
data/lib/sequel/dbi.rb
CHANGED
@@ -8,6 +8,39 @@ module Sequel
|
|
8
8
|
module DBI
|
9
9
|
class Database < Sequel::Database
|
10
10
|
set_adapter_scheme :dbi
|
11
|
+
|
12
|
+
DBI_ADAPTERS = {
|
13
|
+
:ado => "ADO",
|
14
|
+
:db2 => "DB2",
|
15
|
+
:frontbase => "FrontBase",
|
16
|
+
:interbase => "InterBase",
|
17
|
+
:msql => "Msql",
|
18
|
+
:mysql => "Mysql",
|
19
|
+
:odbc => "ODBC",
|
20
|
+
:oracle => "Oracle",
|
21
|
+
:pg => "Pg",
|
22
|
+
:proxy => "Proxy",
|
23
|
+
:sqlite => "SQLite",
|
24
|
+
:sqlrelay => "SQLRelay"
|
25
|
+
}
|
26
|
+
|
27
|
+
# Converts a uri to an options hash. These options are then passed
|
28
|
+
# to a newly created database object.
|
29
|
+
def self.uri_to_options(uri)
|
30
|
+
database = (uri.path =~ /\/(.*)/) && ($1)
|
31
|
+
if uri.scheme =~ /dbi-(.+)/
|
32
|
+
adapter = DBI_ADAPTERS[$1.to_sym] || $1
|
33
|
+
database = "#{adapter}:#{database}"
|
34
|
+
end
|
35
|
+
{
|
36
|
+
:user => uri.user,
|
37
|
+
:password => uri.password,
|
38
|
+
:host => uri.host,
|
39
|
+
:port => uri.port,
|
40
|
+
:database => database
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
11
44
|
|
12
45
|
def connect
|
13
46
|
dbname = @opts[:database]
|
@@ -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
|
data/lib/sequel/mysql.rb
CHANGED
data/lib/sequel/postgres.rb
CHANGED
@@ -18,6 +18,22 @@ class PGconn
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
+
class << self
|
22
|
+
# The postgres gem's string quoting doesn't render string literals properly, which this fixes.
|
23
|
+
#
|
24
|
+
# "a basic string" #=> 'a basic string'
|
25
|
+
# "this\or that" #=> E'this\\or that'
|
26
|
+
#
|
27
|
+
# See <http://www.postgresql.org/docs/8.2/static/sql-syntax-lexical.html> for details.
|
28
|
+
def quote_with_proper_escaping(s)
|
29
|
+
value = quote_without_proper_escaping(s)
|
30
|
+
value = "E#{value}" if value =~ /\\/
|
31
|
+
return value
|
32
|
+
end
|
33
|
+
alias_method :quote_without_proper_escaping, :quote
|
34
|
+
alias_method :quote, :quote_with_proper_escaping
|
35
|
+
end
|
36
|
+
|
21
37
|
def connected?
|
22
38
|
status == PGconn::CONNECTION_OK
|
23
39
|
end
|
data/spec/adapters/mysql_spec.rb
CHANGED
@@ -234,3 +234,14 @@ context "Simple stored procedure test" do
|
|
234
234
|
@server_id_by_sp.should == @server_id # compare it to output from stored procedure
|
235
235
|
end
|
236
236
|
end
|
237
|
+
|
238
|
+
context "Joiמed MySQL dataset" do
|
239
|
+
setup do
|
240
|
+
@ds = MYSQL_DB[:nodes].join(:attributes, :node_id => :id)
|
241
|
+
end
|
242
|
+
|
243
|
+
specify "should quote fields correctly" do
|
244
|
+
@ds.sql.should == \
|
245
|
+
"SELECT * FROM nodes INNER JOIN attributes ON (attributes.`node_id` = nodes.`id`)"
|
246
|
+
end
|
247
|
+
end
|
@@ -92,6 +92,11 @@ context "A PostgreSQL dataset" do
|
|
92
92
|
@d.filter(:name => /bc/).count.should == 2
|
93
93
|
@d.filter(:name => /^bc/).count.should == 1
|
94
94
|
end
|
95
|
+
|
96
|
+
specify "should consider strings containing backslashes to be escaped string literals" do
|
97
|
+
PGconn.quote("\\dingo").should == "E'\\\\dingo'" # literally, E'\\dingo'
|
98
|
+
PGconn.quote("dingo").should == "'dingo'"
|
99
|
+
end
|
95
100
|
end
|
96
101
|
|
97
102
|
context "A PostgreSQL dataset in array tuples mode" do
|
data/spec/dataset_spec.rb
CHANGED
@@ -119,6 +119,11 @@ context "A simple dataset" do
|
|
119
119
|
@dataset.insert_sql(v).should == "INSERT INTO test DEFAULT VALUES"
|
120
120
|
end
|
121
121
|
|
122
|
+
specify "should format an insert statement with string keys" do
|
123
|
+
@dataset.insert_sql('name' => 'wxyz', 'price' => 342).
|
124
|
+
should match(/INSERT INTO test \(name, price\) VALUES \('wxyz', 342\)|INSERT INTO test \(price, name\) VALUES \(342, 'wxyz'\)/)
|
125
|
+
end
|
126
|
+
|
122
127
|
specify "should format an insert statement with a model instance" do
|
123
128
|
dbb = Sequel::Database.new
|
124
129
|
|
@@ -573,6 +578,10 @@ context "Dataset#literal" do
|
|
573
578
|
@dataset.update_sql(:a => 'a + 2'.expr).should ==
|
574
579
|
'UPDATE test SET a = a + 2'
|
575
580
|
end
|
581
|
+
|
582
|
+
specify "should literalize BigDecimal instances correctly" do
|
583
|
+
@dataset.literal(BigDecimal.new("80")).should == "80.0"
|
584
|
+
end
|
576
585
|
end
|
577
586
|
|
578
587
|
context "Dataset#from" do
|
@@ -796,12 +805,12 @@ context "Dataset#qualified_column_name" do
|
|
796
805
|
|
797
806
|
specify "should return the same if already qualified" do
|
798
807
|
@dataset.qualified_column_name('test.a'.lit, :items).should == 'test.a'
|
799
|
-
@dataset.qualified_column_name(:ccc__b, :items).should ==
|
808
|
+
@dataset.qualified_column_name(:ccc__b, :items).should == :ccc__b
|
800
809
|
end
|
801
810
|
|
802
811
|
specify "should qualify the column with the supplied table name" do
|
803
|
-
@dataset.qualified_column_name('a'.lit, :items).should == 'items.a'
|
804
|
-
@dataset.qualified_column_name(:b1, :items).should == 'items.b1'
|
812
|
+
@dataset.qualified_column_name('a'.lit, :items).to_s(@dataset).should == 'items.a'
|
813
|
+
@dataset.qualified_column_name(:b1, :items).to_s(@dataset).should == 'items.b1'
|
805
814
|
end
|
806
815
|
end
|
807
816
|
|
@@ -857,6 +866,12 @@ context "Dataset#uniq" do
|
|
857
866
|
specify "should be aliased by Dataset#distinct" do
|
858
867
|
@dataset.distinct.sql.should == 'SELECT DISTINCT name FROM test'
|
859
868
|
end
|
869
|
+
|
870
|
+
specify "should accept an expression list" do
|
871
|
+
@dataset.uniq(:a, :b).sql.should == 'SELECT DISTINCT ON (a, b) name FROM test'
|
872
|
+
|
873
|
+
@dataset.uniq(:stamp.cast_as(:integer), :node_id).sql.should == 'SELECT DISTINCT ON (cast(stamp AS integer), node_id) name FROM test'
|
874
|
+
end
|
860
875
|
end
|
861
876
|
|
862
877
|
context "Dataset#count" do
|
@@ -1013,14 +1028,14 @@ context "Dataset#join_table" do
|
|
1013
1028
|
end
|
1014
1029
|
|
1015
1030
|
specify "should allow for arbitrary conditions in the JOIN clause" do
|
1016
|
-
@d.join_table(:left_outer, :categories, :
|
1017
|
-
'SELECT * FROM items LEFT OUTER JOIN categories ON (categories.
|
1018
|
-
@d.join_table(:left_outer, :categories, :
|
1019
|
-
"SELECT * FROM items LEFT OUTER JOIN categories ON (categories.categorizable_type = 'Post')
|
1020
|
-
@d.join_table(:left_outer, :categories, :
|
1021
|
-
"SELECT * FROM items LEFT OUTER JOIN categories ON (categories.
|
1022
|
-
@d.join_table(:left_outer, :categories, :
|
1023
|
-
"SELECT * FROM items LEFT OUTER JOIN categories ON (categories.
|
1031
|
+
@d.join_table(:left_outer, :categories, :status => 0).sql.should ==
|
1032
|
+
'SELECT * FROM items LEFT OUTER JOIN categories ON (categories.status = 0)'
|
1033
|
+
@d.join_table(:left_outer, :categories, :categorizable_type => "Post").sql.should ==
|
1034
|
+
"SELECT * FROM items LEFT OUTER JOIN categories ON (categories.categorizable_type = 'Post')"
|
1035
|
+
@d.join_table(:left_outer, :categories, :timestamp => "CURRENT_TIMESTAMP".lit).sql.should ==
|
1036
|
+
"SELECT * FROM items LEFT OUTER JOIN categories ON (categories.timestamp = CURRENT_TIMESTAMP)"
|
1037
|
+
@d.join_table(:left_outer, :categories, :status => [1, 2, 3]).sql.should ==
|
1038
|
+
"SELECT * FROM items LEFT OUTER JOIN categories ON (categories.status IN (1, 2, 3))"
|
1024
1039
|
end
|
1025
1040
|
end
|
1026
1041
|
|
data/spec/worker_spec.rb
CHANGED
@@ -32,7 +32,19 @@ context "A worker" do
|
|
32
32
|
|
33
33
|
@w.join
|
34
34
|
values.should == [1, 2, 3]
|
35
|
-
|
35
|
+
end
|
36
|
+
|
37
|
+
specify "should isolate errors and hold them in #errors" do
|
38
|
+
values = []
|
39
|
+
@w.add {values << 1}
|
40
|
+
@w.async {values << 2}
|
41
|
+
@w.async {raise "bad bad bad"}
|
42
|
+
@w << proc {values << 3}
|
43
|
+
|
44
|
+
@w.join
|
45
|
+
values.should == [1, 2, 3]
|
46
|
+
@w.errors.size.should == 1
|
47
|
+
@w.errors.first.message.should == 'bad bad bad'
|
36
48
|
end
|
37
49
|
end
|
38
50
|
|
@@ -40,7 +52,13 @@ context "A worker with a given db" do
|
|
40
52
|
setup do
|
41
53
|
@db = MockDatabase.new
|
42
54
|
@m = Module.new do
|
43
|
-
def transaction
|
55
|
+
def transaction
|
56
|
+
execute('BEGIN')
|
57
|
+
yield
|
58
|
+
execute('COMMIT')
|
59
|
+
rescue
|
60
|
+
execute('ROLLBACK')
|
61
|
+
end
|
44
62
|
end
|
45
63
|
@db.extend(@m)
|
46
64
|
@w = Sequel::Worker.new(@db)
|
@@ -60,4 +78,19 @@ context "A worker with a given db" do
|
|
60
78
|
'COMMIT'
|
61
79
|
]
|
62
80
|
end
|
81
|
+
|
82
|
+
specify "should rollback the transaction if any error is raised" do
|
83
|
+
@w.async {@db[:items] << {:x => 1}}
|
84
|
+
@w.async {sleep 0.2; raise "that's bad"}
|
85
|
+
@w.async {@db[:items] << {:x => 2}}
|
86
|
+
@w.join
|
87
|
+
@db.sqls.should == [
|
88
|
+
'BEGIN',
|
89
|
+
'INSERT INTO items (x) VALUES (1)',
|
90
|
+
'INSERT INTO items (x) VALUES (2)',
|
91
|
+
'ROLLBACK'
|
92
|
+
]
|
93
|
+
@w.errors.size.should == 1
|
94
|
+
@w.errors.first.message.should == "that's bad"
|
95
|
+
end
|
63
96
|
end
|
metadata
CHANGED
@@ -1,33 +1,54 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.4
|
3
|
-
specification_version: 1
|
4
2
|
name: sequel
|
5
3
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2007-11-10 00:00:00 +02:00
|
8
|
-
summary: Lightweight ORM library for Ruby
|
9
|
-
require_paths:
|
10
|
-
- lib
|
11
|
-
email: ciconia@gmail.com
|
12
|
-
homepage: http://sequel.rubyforge.org
|
13
|
-
rubyforge_project:
|
14
|
-
description: Lightweight ORM library for Ruby
|
15
|
-
autorequire:
|
16
|
-
default_executable:
|
17
|
-
bindir: bin
|
18
|
-
has_rdoc: true
|
19
|
-
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">="
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 1.8.4
|
24
|
-
version:
|
4
|
+
version: 0.4.0
|
25
5
|
platform: ruby
|
26
|
-
signing_key:
|
27
|
-
cert_chain:
|
28
|
-
post_install_message:
|
29
6
|
authors:
|
30
7
|
- Sharon Rosner
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2007-11-24 00:00:00 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: metaid
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: "0"
|
23
|
+
version:
|
24
|
+
- !ruby/object:Gem::Dependency
|
25
|
+
name: ParseTree
|
26
|
+
version_requirement:
|
27
|
+
version_requirements: !ruby/object:Gem::Requirement
|
28
|
+
requirements:
|
29
|
+
- - ">="
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: 2.0.0
|
32
|
+
version:
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: ruby2ruby
|
35
|
+
version_requirement:
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: "0"
|
41
|
+
version:
|
42
|
+
description: Lightweight ORM library for Ruby
|
43
|
+
email: ciconia@gmail.com
|
44
|
+
executables:
|
45
|
+
- sequel
|
46
|
+
extensions: []
|
47
|
+
|
48
|
+
extra_rdoc_files:
|
49
|
+
- README
|
50
|
+
- CHANGELOG
|
51
|
+
- COPYING
|
31
52
|
files:
|
32
53
|
- COPYING
|
33
54
|
- README
|
@@ -54,43 +75,46 @@ files:
|
|
54
75
|
- spec/worker_spec.rb
|
55
76
|
- lib/sequel
|
56
77
|
- lib/sequel/ado.rb
|
57
|
-
- lib/sequel/array_keys.rb
|
58
|
-
- lib/sequel/connection_pool.rb
|
59
|
-
- lib/sequel/core_ext.rb
|
60
|
-
- lib/sequel/core_sql.rb
|
61
|
-
- lib/sequel/database.rb
|
62
|
-
- lib/sequel/dataset
|
63
|
-
- lib/sequel/dataset/convenience.rb
|
64
|
-
- lib/sequel/dataset/sequelizer.rb
|
65
|
-
- lib/sequel/dataset/sql.rb
|
66
|
-
- lib/sequel/dataset.rb
|
67
78
|
- lib/sequel/db2.rb
|
68
79
|
- lib/sequel/dbi.rb
|
69
|
-
- lib/sequel/
|
70
|
-
- lib/sequel/migration.rb
|
71
|
-
- lib/sequel/model
|
72
|
-
- lib/sequel/model/base.rb
|
73
|
-
- lib/sequel/model/caching.rb
|
74
|
-
- lib/sequel/model/hooks.rb
|
75
|
-
- lib/sequel/model/record.rb
|
76
|
-
- lib/sequel/model/relations.rb
|
77
|
-
- lib/sequel/model/schema.rb
|
78
|
-
- lib/sequel/model.rb
|
80
|
+
- lib/sequel/informix.rb
|
79
81
|
- lib/sequel/mysql.rb
|
80
82
|
- lib/sequel/odbc.rb
|
81
83
|
- lib/sequel/oracle.rb
|
82
84
|
- lib/sequel/postgres.rb
|
83
|
-
- lib/sequel/pretty_table.rb
|
84
|
-
- lib/sequel/schema
|
85
|
-
- lib/sequel/schema/schema_generator.rb
|
86
|
-
- lib/sequel/schema/schema_sql.rb
|
87
|
-
- lib/sequel/schema.rb
|
88
85
|
- lib/sequel/sqlite.rb
|
89
|
-
- lib/sequel
|
86
|
+
- lib/sequel-core
|
87
|
+
- lib/sequel-core/array_keys.rb
|
88
|
+
- lib/sequel-core/connection_pool.rb
|
89
|
+
- lib/sequel-core/core_ext.rb
|
90
|
+
- lib/sequel-core/core_sql.rb
|
91
|
+
- lib/sequel-core/database.rb
|
92
|
+
- lib/sequel-core/dataset
|
93
|
+
- lib/sequel-core/dataset/convenience.rb
|
94
|
+
- lib/sequel-core/dataset/sequelizer.rb
|
95
|
+
- lib/sequel-core/dataset/sql.rb
|
96
|
+
- lib/sequel-core/dataset.rb
|
97
|
+
- lib/sequel-core/error.rb
|
98
|
+
- lib/sequel-core/migration.rb
|
99
|
+
- lib/sequel-core/model
|
100
|
+
- lib/sequel-core/model/base.rb
|
101
|
+
- lib/sequel-core/model/caching.rb
|
102
|
+
- lib/sequel-core/model/hooks.rb
|
103
|
+
- lib/sequel-core/model/record.rb
|
104
|
+
- lib/sequel-core/model/relations.rb
|
105
|
+
- lib/sequel-core/model/schema.rb
|
106
|
+
- lib/sequel-core/model.rb
|
107
|
+
- lib/sequel-core/pretty_table.rb
|
108
|
+
- lib/sequel-core/schema
|
109
|
+
- lib/sequel-core/schema/schema_generator.rb
|
110
|
+
- lib/sequel-core/schema/schema_sql.rb
|
111
|
+
- lib/sequel-core/schema.rb
|
112
|
+
- lib/sequel-core/worker.rb
|
90
113
|
- lib/sequel.rb
|
91
114
|
- CHANGELOG
|
92
|
-
|
93
|
-
|
115
|
+
has_rdoc: true
|
116
|
+
homepage: http://sequel.rubyforge.org
|
117
|
+
post_install_message:
|
94
118
|
rdoc_options:
|
95
119
|
- --quiet
|
96
120
|
- --title
|
@@ -105,41 +129,26 @@ rdoc_options:
|
|
105
129
|
- ^(examples|extras)\/
|
106
130
|
- --exclude
|
107
131
|
- lib/sequel.rb
|
108
|
-
|
109
|
-
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
-
|
114
|
-
|
115
|
-
|
132
|
+
require_paths:
|
133
|
+
- lib
|
134
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 1.8.4
|
139
|
+
version:
|
140
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: "0"
|
145
|
+
version:
|
116
146
|
requirements: []
|
117
147
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
- !ruby/object:Gem::Version
|
126
|
-
version: 0.0.0
|
127
|
-
version:
|
128
|
-
- !ruby/object:Gem::Dependency
|
129
|
-
name: ParseTree
|
130
|
-
version_requirement:
|
131
|
-
version_requirements: !ruby/object:Gem::Version::Requirement
|
132
|
-
requirements:
|
133
|
-
- - ">="
|
134
|
-
- !ruby/object:Gem::Version
|
135
|
-
version: 2.0.0
|
136
|
-
version:
|
137
|
-
- !ruby/object:Gem::Dependency
|
138
|
-
name: ruby2ruby
|
139
|
-
version_requirement:
|
140
|
-
version_requirements: !ruby/object:Gem::Version::Requirement
|
141
|
-
requirements:
|
142
|
-
- - ">"
|
143
|
-
- !ruby/object:Gem::Version
|
144
|
-
version: 0.0.0
|
145
|
-
version:
|
148
|
+
rubyforge_project:
|
149
|
+
rubygems_version: 0.9.5
|
150
|
+
signing_key:
|
151
|
+
specification_version: 2
|
152
|
+
summary: Lightweight ORM library for Ruby
|
153
|
+
test_files: []
|
154
|
+
|