sequel 0.4.4.1 → 0.4.4.2

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 (45) hide show
  1. data/CHANGELOG +10 -0
  2. data/Rakefile +161 -159
  3. data/lib/sequel.rb +14 -10
  4. data/lib/sequel/adapters/adapter_skeleton.rb +2 -1
  5. data/lib/sequel/adapters/ado.rb +2 -1
  6. data/lib/sequel/adapters/db2.rb +5 -3
  7. data/lib/sequel/adapters/dbi.rb +2 -1
  8. data/lib/sequel/adapters/informix.rb +2 -1
  9. data/lib/sequel/adapters/jdbc.rb +3 -2
  10. data/lib/sequel/adapters/mysql.rb +268 -264
  11. data/lib/sequel/adapters/odbc.rb +7 -2
  12. data/lib/sequel/adapters/odbc_mssql.rb +1 -1
  13. data/lib/sequel/adapters/openbase.rb +2 -1
  14. data/lib/sequel/adapters/oracle.rb +2 -1
  15. data/lib/sequel/adapters/postgres.rb +32 -16
  16. data/lib/sequel/adapters/sqlite.rb +7 -6
  17. data/lib/sequel/array_keys.rb +295 -295
  18. data/lib/sequel/connection_pool.rb +1 -1
  19. data/lib/sequel/core_sql.rb +14 -5
  20. data/lib/sequel/database.rb +4 -4
  21. data/lib/sequel/dataset.rb +12 -10
  22. data/lib/sequel/dataset/convenience.rb +10 -8
  23. data/lib/sequel/dataset/sequelizer.rb +19 -16
  24. data/lib/sequel/dataset/sql.rb +43 -30
  25. data/lib/sequel/exceptions.rb +45 -0
  26. data/lib/sequel/migration.rb +7 -5
  27. data/lib/sequel/model.rb +1 -1
  28. data/lib/sequel/model/base.rb +3 -3
  29. data/lib/sequel/model/hooks.rb +0 -4
  30. data/lib/sequel/model/record.rb +9 -9
  31. data/lib/sequel/model/relations.rb +2 -2
  32. data/lib/sequel/pretty_table.rb +6 -3
  33. data/lib/sequel/schema/schema_sql.rb +11 -6
  34. data/lib/sequel/worker.rb +8 -7
  35. data/spec/adapters/sqlite_spec.rb +3 -3
  36. data/spec/array_keys_spec.rb +543 -543
  37. data/spec/connection_pool_spec.rb +6 -3
  38. data/spec/database_spec.rb +4 -4
  39. data/spec/dataset_spec.rb +25 -25
  40. data/spec/migration_spec.rb +1 -1
  41. data/spec/model_spec.rb +16 -16
  42. data/spec/sequelizer_spec.rb +7 -7
  43. data/spec/spec.opts +8 -0
  44. metadata +5 -5
  45. data/lib/sequel/error.rb +0 -22
@@ -107,7 +107,7 @@ module Sequel
107
107
  if @created_count < @max_size
108
108
  @created_count += 1
109
109
  @connection_proc ? @connection_proc.call : \
110
- (raise SequelError, "No connection proc specified")
110
+ (raise Error, "No connection proc specified")
111
111
  end
112
112
  end
113
113
 
@@ -47,7 +47,12 @@ class String
47
47
 
48
48
  # Converts a string into a Time object.
49
49
  def to_time
50
- Time.parse(self)
50
+ begin
51
+ Time.parse(self)
52
+ rescue Exception => e
53
+ raise Error::InvalidValue, "Invalid time value '#{self}' (#{e.message})"
54
+ end
55
+ # Why does Time.parse('0000-00-00') bork and not return nil or some such?
51
56
  end
52
57
  end
53
58
 
@@ -163,10 +168,14 @@ class Symbol
163
168
  #
164
169
  def to_column_ref(ds)
165
170
  case s = to_s
166
- when COLUMN_REF_RE1: "#{$1}.#{ds.quote_column_ref($2)} AS #{ds.quote_column_ref($3)}"
167
- when COLUMN_REF_RE2: "#{ds.quote_column_ref($1)} AS #{ds.quote_column_ref($2)}"
168
- when COLUMN_REF_RE3: "#{$1}.#{ds.quote_column_ref($2)}"
169
- else ds.quote_column_ref(s)
171
+ when COLUMN_REF_RE1
172
+ "#{$1}.#{ds.quote_column_ref($2)} AS #{ds.quote_column_ref($3)}"
173
+ when COLUMN_REF_RE2
174
+ "#{ds.quote_column_ref($1)} AS #{ds.quote_column_ref($2)}"
175
+ when COLUMN_REF_RE3
176
+ "#{$1}.#{ds.quote_column_ref($2)}"
177
+ else
178
+ ds.quote_column_ref(s)
170
179
  end
171
180
  end
172
181
 
@@ -135,9 +135,9 @@ module Sequel
135
135
  (String === args.first) ? fetch(*args) : from(*args)
136
136
  end
137
137
 
138
- # Raises a NotImplementedError. This method is overriden in descendants.
138
+ # Raises a Sequel::Error::NotImplemented. This method is overriden in descendants.
139
139
  def execute(sql)
140
- raise NotImplementedError
140
+ raise NotImplementedError, "#execute should be overriden by adapters"
141
141
  end
142
142
 
143
143
  # Executes the supplied SQL statement. The SQL can be supplied as a string
@@ -272,7 +272,7 @@ module Sequel
272
272
  result
273
273
  rescue => e
274
274
  conn.execute(SQL_ROLLBACK)
275
- raise e unless SequelRollbackError === e
275
+ raise e unless Error::Rollback === e
276
276
  ensure
277
277
  @transactions.delete(Thread.current)
278
278
  end
@@ -318,7 +318,7 @@ module Sequel
318
318
  require File.join(File.dirname(__FILE__), "adapters/#{scheme}")
319
319
  c = @@adapters[scheme.to_sym]
320
320
  end
321
- raise SequelError, "Invalid database scheme" unless c
321
+ raise Error::InvalidDatabaseScheme, "Invalid database scheme" unless c
322
322
  c
323
323
  end
324
324
 
@@ -226,28 +226,28 @@ module Sequel
226
226
  def set_model(key, *args)
227
227
  # pattern matching
228
228
  case key
229
- when nil: # set_model(nil) => no
229
+ when nil # set_model(nil) => no
230
230
  # no argument provided, so the dataset is denuded
231
231
  @opts.merge!(:naked => true, :models => nil, :polymorphic_key => nil)
232
232
  remove_row_proc
233
233
  # extend_with_stock_each
234
- when Class:
234
+ when Class
235
235
  # isomorphic model
236
236
  @opts.merge!(:naked => nil, :models => {nil => key}, :polymorphic_key => nil)
237
237
  set_row_proc {|h| key.new(h, *args)}
238
238
  extend_with_destroy
239
- when Symbol:
239
+ when Symbol
240
240
  # polymorphic model
241
- hash = args.shift || raise(SequelError, "No class hash supplied for polymorphic model")
241
+ hash = args.shift || raise(ArgumentError, "No class hash supplied for polymorphic model")
242
242
  @opts.merge!(:naked => true, :models => hash, :polymorphic_key => key)
243
243
  set_row_proc do |h|
244
244
  c = hash[h[key]] || hash[nil] || \
245
- raise(SequelError, "No matching model class for record (#{polymorphic_key} => #{h[polymorphic_key].inspect})")
245
+ raise(Error, "No matching model class for record (#{polymorphic_key} => #{h[polymorphic_key].inspect})")
246
246
  c.new(h, *args)
247
247
  end
248
248
  extend_with_destroy
249
249
  else
250
- raise SequelError, "Invalid parameters specified"
250
+ raise ArgumentError, "Invalid model specified"
251
251
  end
252
252
  self
253
253
  end
@@ -300,13 +300,13 @@ module Sequel
300
300
  @transform = t
301
301
  t.each do |k, v|
302
302
  case v
303
- when Array:
303
+ when Array
304
304
  if (v.size != 2) || !v.first.is_a?(Proc) && !v.last.is_a?(Proc)
305
- raise SequelError, "Invalid transform specified"
305
+ raise Error::InvalidTransform, "Invalid transform specified"
306
306
  end
307
307
  else
308
308
  unless v = STOCK_TRANSFORMS[v]
309
- raise SequelError, "Invalid transform specified"
309
+ raise Error::InvalidTransform, "Invalid transform specified"
310
310
  else
311
311
  t[k] = v
312
312
  end
@@ -384,7 +384,9 @@ module Sequel
384
384
  def extend_with_destroy
385
385
  unless respond_to?(:destroy)
386
386
  meta_def(:destroy) do
387
- raise SequelError, 'Dataset not associated with model' unless @opts[:models]
387
+ unless @opts[:models]
388
+ raise Error, "No model associated with this dataset"
389
+ end
388
390
  count = 0
389
391
  @db.transaction {each {|r| count += 1; r.destroy}}
390
392
  count
@@ -38,8 +38,10 @@ module Sequel
38
38
  end
39
39
  args = args.empty? ? 1 : (args.size == 1) ? args.first : args
40
40
  case args
41
- when 1: single_record(:limit => 1)
42
- when Fixnum: limit(args).all
41
+ when 1
42
+ single_record(:limit => 1)
43
+ when Fixnum
44
+ limit(args).all
43
45
  else
44
46
  filter(args, &block).single_record(:limit => 1)
45
47
  end
@@ -59,13 +61,13 @@ module Sequel
59
61
  # record is returned. Otherwise an array is returned with the last
60
62
  # <i>num</i> records.
61
63
  def last(*args)
62
- raise SequelError, 'No order specified' unless
64
+ raise Error, 'No order specified' unless
63
65
  @opts[:order] || (opts && opts[:order])
64
66
 
65
67
  args = args.empty? ? 1 : (args.size == 1) ? args.first : args
66
68
 
67
69
  case args
68
- when Fixnum:
70
+ when Fixnum
69
71
  l = {:limit => args}
70
72
  opts = {:order => invert_order(@opts[:order])}. \
71
73
  merge(opts ? opts.merge(l) : l)
@@ -238,10 +240,10 @@ module Sequel
238
240
  end
239
241
 
240
242
  module QueryBlockCopy #:nodoc:
241
- def each(*args); raise SequelError, "#each cannot be invoked inside a query block."; end
242
- def insert(*args); raise SequelError, "#insert cannot be invoked inside a query block."; end
243
- def update(*args); raise SequelError, "#update cannot be invoked inside a query block."; end
244
- def delete(*args); raise SequelError, "#delete cannot be invoked inside a query block."; end
243
+ def each(*args); raise Error, "#each cannot be invoked inside a query block."; end
244
+ def insert(*args); raise Error, "#insert cannot be invoked inside a query block."; end
245
+ def update(*args); raise Error, "#update cannot be invoked inside a query block."; end
246
+ def delete(*args); raise Error, "#delete cannot be invoked inside a query block."; end
245
247
 
246
248
  def clone_merge(opts)
247
249
  @opts.merge!(opts)
@@ -38,17 +38,17 @@ class Sequel::Dataset
38
38
  # "(id = 3)"
39
39
  def compare_expr(l, r)
40
40
  case r
41
- when Range:
41
+ when Range
42
42
  r.exclude_end? ? \
43
43
  "(#{literal(l)} >= #{literal(r.begin)} AND #{literal(l)} < #{literal(r.end)})" : \
44
44
  "(#{literal(l)} >= #{literal(r.begin)} AND #{literal(l)} <= #{literal(r.end)})"
45
- when Array:
45
+ when Array
46
46
  "(#{literal(l)} IN (#{literal(r)}))"
47
- when Sequel::Dataset:
47
+ when Sequel::Dataset
48
48
  "(#{literal(l)} IN (#{r.sql}))"
49
- when NilClass:
49
+ when NilClass
50
50
  "(#{literal(l)} IS NULL)"
51
- when Regexp:
51
+ when Regexp
52
52
  match_expr(l, r)
53
53
  else
54
54
  "(#{literal(l)} = #{literal(r)})"
@@ -60,10 +60,10 @@ class Sequel::Dataset
60
60
  # can override this method to provide support for regular expressions.
61
61
  def match_expr(l, r)
62
62
  case r
63
- when String:
63
+ when String
64
64
  "(#{literal(l)} LIKE #{literal(r)})"
65
65
  else
66
- raise SequelError, "Unsupported match pattern class (#{r.class})."
66
+ raise Sequel::Error, "Unsupported match pattern class (#{r.class})."
67
67
  end
68
68
  end
69
69
 
@@ -250,9 +250,9 @@ class Sequel::Dataset
250
250
  vcall_expr(e, b, opts)
251
251
  when :ivar, :cvar, :dvar, :const, :gvar # local ref
252
252
  eval(e[1].to_s, b)
253
- when :nth_ref:
253
+ when :nth_ref
254
254
  eval("$#{e[1]}", b)
255
- when :lvar: # local context
255
+ when :lvar # local context
256
256
  if e[1] == :block
257
257
  pr = eval(e[1].to_s, b)
258
258
  "#{proc_to_sql(pr)}"
@@ -267,9 +267,12 @@ class Sequel::Dataset
267
267
  eval_expr(e[1], b, opts)...eval_expr(e[2], b, opts)
268
268
  when :colon2 # qualified constant ref
269
269
  eval_expr(e[1], b, opts).const_get(e[2])
270
- when :false: false
271
- when :true: true
272
- when :nil: nil
270
+ when :false
271
+ false
272
+ when :true
273
+ true
274
+ when :nil
275
+ nil
273
276
  when :array
274
277
  # array
275
278
  e[1..-1].map {|i| eval_expr(i, b, opts)}
@@ -284,11 +287,11 @@ class Sequel::Dataset
284
287
  # assignment
285
288
  l = e[1]
286
289
  r = eval_expr(e[2], b, opts)
287
- raise SequelError, "Invalid expression #{l} = #{r}. Did you mean :#{l} == #{r}?"
290
+ raise Sequel::Error::InvalidExpression, "#{l} = #{r}. Did you mean :#{l} == #{r}?"
288
291
  when :if, :dstr
289
292
  ext_expr(e, b, opts)
290
293
  else
291
- raise SequelError, "Invalid expression tree: #{e.inspect}"
294
+ raise Sequel::Error::InvalidExpression, "Invalid expression tree: #{e.inspect}"
292
295
  end
293
296
  end
294
297
 
@@ -338,7 +341,7 @@ begin
338
341
  rescue Exception
339
342
  module Sequel::Dataset::Sequelizer
340
343
  def proc_to_sql(proc)
341
- raise SequelError, "You must have the ParseTree gem installed in order to use block filters."
344
+ raise Sequel::Error, "You must have the ParseTree gem installed in order to use block filters."
342
345
  end
343
346
  end
344
347
  end
@@ -348,7 +351,7 @@ begin
348
351
  rescue Exception
349
352
  module Sequel::Dataset::Sequelizer
350
353
  def ext_expr(e)
351
- raise SequelError, "You must have the Ruby2Ruby gem installed in order to use this block filter."
354
+ raise Sequel::Error, "You must have the Ruby2Ruby gem installed in order to use this block filter."
352
355
  end
353
356
  end
354
357
  end
@@ -45,15 +45,15 @@ module Sequel
45
45
  # Converts an array of sources names into into a comma separated list.
46
46
  def source_list(source)
47
47
  if source.nil? || source.empty?
48
- raise SequelError, 'No source specified for query'
48
+ raise Error, 'No source specified for query'
49
49
  end
50
50
  auto_alias_count = 0
51
51
  m = source.map do |i|
52
52
  case i
53
- when Dataset:
53
+ when Dataset
54
54
  auto_alias_count += 1
55
55
  i.to_table_reference(auto_alias_count)
56
- when Hash:
56
+ when Hash
57
57
  i.map {|k, v| "#{k.is_a?(Dataset) ? k.to_table_reference : k} #{v}"}.
58
58
  join(COMMA_SEPARATOR)
59
59
  else
@@ -84,21 +84,34 @@ module Sequel
84
84
  # If an unsupported object is given, an exception is raised.
85
85
  def literal(v)
86
86
  case v
87
- when LiteralString: v
88
- when String: "'#{v.gsub(/'/, "''")}'"
89
- when Integer, Float: v.to_s
90
- when BigDecimal: v.to_s("F")
91
- when NilClass: NULL
92
- when TrueClass: TRUE
93
- when FalseClass: FALSE
94
- when Symbol: v.to_column_ref(self)
95
- when Sequel::SQL::Expression: v.to_s(self)
96
- when Array: v.empty? ? NULL : v.map {|i| literal(i)}.join(COMMA_SEPARATOR)
97
- when Time: v.strftime(TIMESTAMP_FORMAT)
98
- when Date: v.strftime(DATE_FORMAT)
99
- when Dataset: "(#{v.sql})"
87
+ when LiteralString
88
+ v
89
+ when String
90
+ "'#{v.gsub(/'/, "''")}'"
91
+ when Integer, Float
92
+ v.to_s
93
+ when BigDecimal
94
+ v.to_s("F")
95
+ when NilClass
96
+ NULL
97
+ when TrueClass
98
+ TRUE
99
+ when FalseClass
100
+ FALSE
101
+ when Symbol
102
+ v.to_column_ref(self)
103
+ when Sequel::SQL::Expression
104
+ v.to_s(self)
105
+ when Array
106
+ v.empty? ? NULL : v.map {|i| literal(i)}.join(COMMA_SEPARATOR)
107
+ when Time
108
+ v.strftime(TIMESTAMP_FORMAT)
109
+ when Date
110
+ v.strftime(DATE_FORMAT)
111
+ when Dataset
112
+ "(#{v.sql})"
100
113
  else
101
- raise SequelError, "can't express #{v.inspect} as a SQL literal"
114
+ raise Error, "can't express #{v.inspect} as a SQL literal"
102
115
  end
103
116
  end
104
117
 
@@ -109,12 +122,12 @@ module Sequel
109
122
  # generated clause will be enclosed in a set of parentheses.
110
123
  def expression_list(expr, parenthesize = false)
111
124
  case expr
112
- when Hash:
125
+ when Hash
113
126
  parenthesize = false if expr.size == 1
114
127
  fmt = expr.map {|i| compare_expr(i[0], i[1])}.join(AND_SEPARATOR)
115
- when Array:
128
+ when Array
116
129
  fmt = expr.shift.gsub(QUESTION_MARK) {literal(expr.shift)}
117
- when Proc:
130
+ when Proc
118
131
  fmt = proc_to_sql(expr)
119
132
  else
120
133
  # if the expression is compound, it should be parenthesized in order for
@@ -204,7 +217,7 @@ module Sequel
204
217
  clause = (@opts[:group] ? :having : :where)
205
218
  cond = cond.first if cond.size == 1
206
219
  if cond === true || cond === false
207
- raise SequelError, "Invalid filter specified. Did you mean to supply a block?"
220
+ raise Error::InvalidFilter, "Invalid filter specified. Did you mean to supply a block?"
208
221
  end
209
222
  parenthesize = !(cond.is_a?(Hash) || cond.is_a?(Array))
210
223
  filter = cond.is_a?(Hash) && cond
@@ -228,7 +241,7 @@ module Sequel
228
241
  r = expression_list(block || cond, parenthesize)
229
242
  clone_merge(clause => "#{l} OR #{r}")
230
243
  else
231
- raise SequelError, "No existing filter found."
244
+ raise Error::NoExistingFilter, "No existing filter found."
232
245
  end
233
246
  end
234
247
 
@@ -238,7 +251,7 @@ module Sequel
238
251
  def and(*cond, &block)
239
252
  clause = (@opts[:group] ? :having : :where)
240
253
  unless @opts[clause]
241
- raise SequelError, "No existing filter found."
254
+ raise Error::NoExistingFilter, "No existing filter found."
242
255
  end
243
256
  filter(*cond, &block)
244
257
  end
@@ -265,7 +278,7 @@ module Sequel
265
278
  # if the dataset has been grouped. See also #filter.
266
279
  def where(*cond, &block)
267
280
  if @opts[:group]
268
- raise SequelError, "Can't specify a WHERE clause once the dataset has been grouped"
281
+ raise Error, "Can't specify a WHERE clause once the dataset has been grouped"
269
282
  else
270
283
  filter(*cond, &block)
271
284
  end
@@ -275,7 +288,7 @@ module Sequel
275
288
  # if the dataset has not been grouped. See also #filter
276
289
  def having(*cond, &block)
277
290
  unless @opts[:group]
278
- raise SequelError, "Can only specify a HAVING clause on a grouped dataset"
291
+ raise Error, "Can only specify a HAVING clause on a grouped dataset"
279
292
  else
280
293
  filter(*cond, &block)
281
294
  end
@@ -310,7 +323,7 @@ module Sequel
310
323
  def join_expr(type, table, expr)
311
324
  join_type = JOIN_TYPES[type || :inner]
312
325
  unless join_type
313
- raise SequelError, "Invalid join type: #{type}"
326
+ raise Error::InvalidJoinType, "Invalid join type: #{type}"
314
327
  end
315
328
 
316
329
  join_conditions = {}
@@ -471,9 +484,9 @@ module Sequel
471
484
  opts = opts ? @opts.merge(opts) : @opts
472
485
 
473
486
  if opts[:group]
474
- raise SequelError, "Can't update a grouped dataset"
487
+ raise Error::InvalidOperation, "A grouped dataset cannot be updated"
475
488
  elsif (opts[:from].size > 1) or opts[:join]
476
- raise SequelError, "Can't update a joined dataset"
489
+ raise Error::InvalidOperation, "A joined dataset cannot be updated"
477
490
  end
478
491
 
479
492
  sql = "UPDATE #{@opts[:from]} SET "
@@ -507,9 +520,9 @@ module Sequel
507
520
  opts = opts ? @opts.merge(opts) : @opts
508
521
 
509
522
  if opts[:group]
510
- raise SequelError, "Can't delete from a grouped dataset"
523
+ raise Error::InvalidOperation, "Grouped datasets cannot be deleted from"
511
524
  elsif opts[:from].is_a?(Array) && opts[:from].size > 1
512
- raise SequelError, "Can't delete from a joined dataset"
525
+ raise Error::InvalidOperation, "Joined datasets cannot be deleted from"
513
526
  end
514
527
 
515
528
  sql = "DELETE FROM #{opts[:from]}"
@@ -0,0 +1,45 @@
1
+ module Sequel
2
+ # Represents an error raised in Sequel code.
3
+ class Error < StandardError
4
+
5
+ # Rollback is a special error used to rollback a transactions.
6
+ # A transaction block will catch this error and wont pass further up the stack.
7
+ class Rollback < Error ; end
8
+
9
+ class InvalidDatabaseScheme < Error; end
10
+
11
+ # Represents an invalid value stored in the database.
12
+ class InvalidValue < Error ; end
13
+
14
+ # Represents an Invalid transform.
15
+ class InvalidTransform < Error ; end
16
+
17
+ # Represents an Invalid filter.
18
+ class InvalidFilter < Error ; end
19
+
20
+ class InvalidExpression < Error; end
21
+
22
+ # Represents an attempt to performing filter operations when no filter has been specified yet.
23
+ class NoExistingFilter < Error ; end
24
+
25
+ # Represents an invalid join type.
26
+ class InvalidJoinType < Error ; end
27
+
28
+ class WorkerStop < RuntimeError ; end
29
+
30
+ end
31
+ end
32
+
33
+ # Object extensions
34
+ class Object
35
+ # Cancels the current transaction without an error:
36
+ #
37
+ # DB.tranaction do
38
+ # ...
39
+ # rollback! if failed_to_contact_client
40
+ # ...
41
+ # end
42
+ def rollback!
43
+ raise Sequel::Error::Rollback
44
+ end
45
+ end