sequel 0.3.4.1 → 0.4.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.
Files changed (36) hide show
  1. data/CHANGELOG +24 -0
  2. data/README +2 -0
  3. data/Rakefile +2 -2
  4. data/lib/{sequel → sequel-core}/array_keys.rb +0 -0
  5. data/lib/{sequel → sequel-core}/connection_pool.rb +0 -0
  6. data/lib/{sequel → sequel-core}/core_ext.rb +0 -0
  7. data/lib/{sequel → sequel-core}/core_sql.rb +8 -0
  8. data/lib/{sequel → sequel-core}/database.rb +4 -2
  9. data/lib/{sequel → sequel-core}/dataset.rb +0 -0
  10. data/lib/{sequel → sequel-core}/dataset/convenience.rb +0 -0
  11. data/lib/{sequel → sequel-core}/dataset/sequelizer.rb +0 -0
  12. data/lib/{sequel → sequel-core}/dataset/sql.rb +22 -21
  13. data/lib/{sequel → sequel-core}/error.rb +0 -0
  14. data/lib/{sequel → sequel-core}/migration.rb +0 -0
  15. data/lib/{sequel → sequel-core}/model.rb +5 -0
  16. data/lib/{sequel → sequel-core}/model/base.rb +0 -0
  17. data/lib/{sequel → sequel-core}/model/caching.rb +0 -0
  18. data/lib/{sequel → sequel-core}/model/hooks.rb +0 -0
  19. data/lib/{sequel → sequel-core}/model/record.rb +0 -0
  20. data/lib/{sequel → sequel-core}/model/relations.rb +0 -0
  21. data/lib/{sequel → sequel-core}/model/schema.rb +0 -0
  22. data/lib/{sequel → sequel-core}/pretty_table.rb +0 -0
  23. data/lib/{sequel → sequel-core}/schema.rb +0 -0
  24. data/lib/{sequel → sequel-core}/schema/schema_generator.rb +0 -0
  25. data/lib/{sequel → sequel-core}/schema/schema_sql.rb +0 -0
  26. data/lib/{sequel → sequel-core}/worker.rb +23 -10
  27. data/lib/sequel.rb +3 -1
  28. data/lib/sequel/dbi.rb +33 -0
  29. data/lib/sequel/informix.rb +78 -0
  30. data/lib/sequel/mysql.rb +0 -2
  31. data/lib/sequel/postgres.rb +16 -0
  32. data/spec/adapters/mysql_spec.rb +11 -0
  33. data/spec/adapters/postgres_spec.rb +5 -0
  34. data/spec/dataset_spec.rb +26 -11
  35. data/spec/worker_spec.rb +35 -2
  36. 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
@@ -36,6 +36,8 @@ Sequel currently supports:
36
36
  * PostgreSQL
37
37
  * SQLite 3
38
38
 
39
+ There are also experimental adapters for DB2 and Informix.
40
+
39
41
  == The Sequel Console
40
42
 
41
43
  Sequel includes an IRB console for quick'n'dirty access to databases. You can use it like this:
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ require 'fileutils'
6
6
  include FileUtils
7
7
 
8
8
  NAME = "sequel"
9
- VERS = "0.3.4.1"
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/sequel/**/*.rb']
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
- c = @@adapters[uri.scheme.to_sym]
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
- column = literal(column)
18
- if column =~ QUALIFIED_REGEXP
19
- # column is already qualified
20
- column
21
- else
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
- "#{table}.#{column}"
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
- # fmt = expr.map {|i| compare_expr(i[0], i[1])}.join(AND_SEPARATOR)
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 => true)
137
+ def uniq(*args)
138
+ clone_merge(:distinct => args)
142
139
  end
143
- alias distinct uniq
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).intern if k.is_a?(Symbol)
324
- v = qualified_column_name(v, @opts[:last_joined_table] || @opts[:from].first).intern if v.is_a?(Symbol)
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
- sql = opts[:distinct] ? \
375
- "SELECT DISTINCT #{select_columns}" : \
376
- "SELECT #{select_columns}"
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 << literal(k); vl << literal(v)}
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
@@ -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
- if db
13
- super {db.transaction {t.work}}
14
- else
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
- begin
21
- loop {@cur = @queue.pop; @cur.call; @cur = nil}
22
- rescue WorkerStopError # do nothing
23
- end
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
@@ -2,8 +2,6 @@ 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"
7
5
  require 'mysql'
8
6
 
9
7
  # Monkey patch Mysql::Result to yield hashes with symbol keys
@@ -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
@@ -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 == 'ccc.b'
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, :id => :category_id, :status => 0).sql.should ==
1017
- 'SELECT * FROM items LEFT OUTER JOIN categories ON (categories.id = items.category_id) AND (categories.status = 0)'
1018
- @d.join_table(:left_outer, :categories, :id => :category_id, :categorizable_type => "Post").sql.should ==
1019
- "SELECT * FROM items LEFT OUTER JOIN categories ON (categories.categorizable_type = 'Post') AND (categories.id = items.category_id)"
1020
- @d.join_table(:left_outer, :categories, :id => :category_id, :timestamp => "CURRENT_TIMESTAMP".lit).sql.should ==
1021
- "SELECT * FROM items LEFT OUTER JOIN categories ON (categories.id = items.category_id) AND (categories.timestamp = CURRENT_TIMESTAMP)"
1022
- @d.join_table(:left_outer, :categories, :id => :category_id, :status => [1, 2, 3]).sql.should ==
1023
- "SELECT * FROM items LEFT OUTER JOIN categories ON (categories.id = items.category_id) AND (categories.status IN (1, 2, 3))"
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
- @w = nil
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; execute('BEGIN'); yield; execute('COMMIT'); end
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.3.4.1
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/error.rb
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/worker.rb
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
- test_files: []
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
- extra_rdoc_files:
109
- - README
110
- - CHANGELOG
111
- - COPYING
112
- executables:
113
- - sequel
114
- extensions: []
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
- dependencies:
119
- - !ruby/object:Gem::Dependency
120
- name: metaid
121
- version_requirement:
122
- version_requirements: !ruby/object:Gem::Version::Requirement
123
- requirements:
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
+