sequel_core 1.5.1 → 2.0.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 (68) hide show
  1. data/CHANGELOG +116 -0
  2. data/COPYING +19 -19
  3. data/README +83 -32
  4. data/Rakefile +9 -20
  5. data/bin/sequel +43 -112
  6. data/doc/cheat_sheet.rdoc +225 -0
  7. data/doc/dataset_filtering.rdoc +257 -0
  8. data/lib/sequel_core/adapters/adapter_skeleton.rb +4 -2
  9. data/lib/sequel_core/adapters/ado.rb +3 -1
  10. data/lib/sequel_core/adapters/db2.rb +4 -2
  11. data/lib/sequel_core/adapters/dbi.rb +127 -113
  12. data/lib/sequel_core/adapters/informix.rb +4 -2
  13. data/lib/sequel_core/adapters/jdbc.rb +5 -3
  14. data/lib/sequel_core/adapters/mysql.rb +112 -46
  15. data/lib/sequel_core/adapters/odbc.rb +5 -7
  16. data/lib/sequel_core/adapters/odbc_mssql.rb +12 -3
  17. data/lib/sequel_core/adapters/openbase.rb +3 -1
  18. data/lib/sequel_core/adapters/oracle.rb +11 -9
  19. data/lib/sequel_core/adapters/postgres.rb +261 -262
  20. data/lib/sequel_core/adapters/sqlite.rb +72 -22
  21. data/lib/sequel_core/connection_pool.rb +140 -73
  22. data/lib/sequel_core/core_ext.rb +201 -66
  23. data/lib/sequel_core/core_sql.rb +123 -153
  24. data/lib/sequel_core/database/schema.rb +156 -0
  25. data/lib/sequel_core/database.rb +321 -338
  26. data/lib/sequel_core/dataset/callback.rb +11 -12
  27. data/lib/sequel_core/dataset/convenience.rb +213 -240
  28. data/lib/sequel_core/dataset/pagination.rb +58 -43
  29. data/lib/sequel_core/dataset/parse_tree_sequelizer.rb +331 -0
  30. data/lib/sequel_core/dataset/query.rb +41 -0
  31. data/lib/sequel_core/dataset/schema.rb +15 -0
  32. data/lib/sequel_core/dataset/sequelizer.rb +41 -373
  33. data/lib/sequel_core/dataset/sql.rb +741 -632
  34. data/lib/sequel_core/dataset.rb +183 -168
  35. data/lib/sequel_core/deprecated.rb +1 -169
  36. data/lib/sequel_core/exceptions.rb +24 -19
  37. data/lib/sequel_core/migration.rb +44 -52
  38. data/lib/sequel_core/object_graph.rb +43 -42
  39. data/lib/sequel_core/pretty_table.rb +71 -76
  40. data/lib/sequel_core/schema/generator.rb +163 -105
  41. data/lib/sequel_core/schema/sql.rb +250 -93
  42. data/lib/sequel_core/schema.rb +2 -8
  43. data/lib/sequel_core/sql.rb +394 -0
  44. data/lib/sequel_core/worker.rb +37 -27
  45. data/lib/sequel_core.rb +99 -45
  46. data/spec/adapters/informix_spec.rb +0 -1
  47. data/spec/adapters/mysql_spec.rb +177 -124
  48. data/spec/adapters/oracle_spec.rb +0 -1
  49. data/spec/adapters/postgres_spec.rb +98 -58
  50. data/spec/adapters/sqlite_spec.rb +45 -4
  51. data/spec/blockless_filters_spec.rb +269 -0
  52. data/spec/connection_pool_spec.rb +21 -18
  53. data/spec/core_ext_spec.rb +169 -19
  54. data/spec/core_sql_spec.rb +56 -49
  55. data/spec/database_spec.rb +78 -17
  56. data/spec/dataset_spec.rb +300 -428
  57. data/spec/migration_spec.rb +1 -1
  58. data/spec/object_graph_spec.rb +5 -11
  59. data/spec/rcov.opts +1 -1
  60. data/spec/schema_generator_spec.rb +16 -4
  61. data/spec/schema_spec.rb +89 -10
  62. data/spec/sequelizer_spec.rb +56 -56
  63. data/spec/spec.opts +0 -5
  64. data/spec/spec_config.rb +7 -0
  65. data/spec/spec_config.rb.example +5 -5
  66. data/spec/spec_helper.rb +6 -0
  67. data/spec/worker_spec.rb +1 -1
  68. metadata +78 -63
@@ -1,13 +1,6 @@
1
- require 'time'
2
- require 'date'
3
- require 'yaml'
4
- require 'base64'
5
-
6
- require File.join(File.dirname(__FILE__), 'dataset/sql')
7
- require File.join(File.dirname(__FILE__), 'dataset/sequelizer')
8
- require File.join(File.dirname(__FILE__), 'dataset/convenience')
9
- require File.join(File.dirname(__FILE__), 'dataset/callback')
10
- require File.join(File.dirname(__FILE__), 'dataset/pagination')
1
+ %w'callback convenience pagination query schema sequelizer sql'.each do |f|
2
+ require "sequel_core/dataset/#{f}"
3
+ end
11
4
 
12
5
  module Sequel
13
6
  # A Dataset represents a view of a the data in a database, constrained by
@@ -16,6 +9,7 @@ module Sequel
16
9
  #
17
10
  # Query results are always retrieved on demand, so a dataset can be kept
18
11
  # around and reused indefinitely:
12
+ #
19
13
  # my_posts = DB[:posts].filter(:author => 'david') # no records are retrieved
20
14
  # p my_posts.all # records are now retrieved
21
15
  # ...
@@ -24,6 +18,7 @@ module Sequel
24
18
  # In order to provide this functionality, dataset methods such as where,
25
19
  # select, order, etc. return modified copies of the dataset, so you can
26
20
  # use different datasets to access data:
21
+ #
27
22
  # posts = DB[:posts]
28
23
  # davids_posts = posts.filter(:author => 'david')
29
24
  # old_posts = posts.filter('stamp < ?', Date.today - 7)
@@ -34,7 +29,7 @@ module Sequel
34
29
  # === The Dataset Adapter Interface
35
30
  #
36
31
  # Each adapter should define its own dataset class as a descendant of
37
- # Sequel::Dataset. The following methods should be overriden by the adapter
32
+ # Sequel::Dataset. The following methods should be overridden by the adapter
38
33
  # Dataset class (each method with the stock implementation):
39
34
  #
40
35
  # # Iterate over the results of the SQL query and call the supplied
@@ -66,113 +61,158 @@ module Sequel
66
61
  # @db.execute(delete_sql(opts)).affected_rows
67
62
  # end
68
63
  # end
64
+ #
65
+ # === Methods added via metaprogramming
66
+ #
67
+ # Some methods are added via metaprogramming:
68
+ #
69
+ # * ! methods - These methods are the same as their non-! counterparts,
70
+ # but they modify the receiver instead of returning a modified copy
71
+ # of the dataset.
72
+ # * inner_join, full_outer_join, right_outer_join, left_outer_join -
73
+ # This methods are shortcuts to join_table with the join type
74
+ # already specified.
69
75
  class Dataset
70
76
  include Enumerable
71
- include Sequelizer
72
- include SQL
73
- include Convenience
74
- include Callback
75
77
 
78
+ # The dataset options that require the removal of cached columns
79
+ # if changed.
80
+ COLUMN_CHANGE_OPTS = [:select, :sql, :from, :join].freeze
81
+
82
+ # Array of all subclasses of Dataset
83
+ DATASET_CLASSES = []
84
+
85
+ # All methods that should have a ! method added that modifies
86
+ # the receiver.
87
+ MUTATION_METHODS = %w'and distinct exclude exists filter from from_self full_outer_join graph
88
+ group group_and_count group_by having inner_join intersect invert join
89
+ left_outer_join limit naked or order order_by order_more paginate query reject
90
+ reverse reverse_order right_outer_join select select_all select_more
91
+ set_graph_aliases set_model sort sort_by unfiltered union unordered where'.collect{|x| x.to_sym}
92
+
93
+ NOTIMPL_MSG = "This method must be overridden in Sequel adapters".freeze
94
+ STOCK_TRANSFORMS = {
95
+ :marshal => [
96
+ # for backwards-compatibility we support also non-base64-encoded values.
97
+ proc {|v| Marshal.load(v.unpack('m')[0]) rescue Marshal.load(v)},
98
+ proc {|v| [Marshal.dump(v)].pack('m')}
99
+ ],
100
+ :yaml => [
101
+ proc {|v| YAML.load v if v},
102
+ proc {|v| v.to_yaml}
103
+ ]
104
+ }
105
+
76
106
  attr_accessor :db, :opts, :row_proc
107
+
108
+ # Whether to quote identifiers for this dataset
109
+ attr_writer :quote_identifiers
77
110
 
78
- alias_method :size, :count
79
-
80
- # Returns an array with all records in the dataset. If a block is given,
81
- # the array is iterated over.
82
- def all(opts = nil, &block)
83
- a = []
84
- each(opts) {|r| a << r}
85
- post_load(a)
86
- a.each(&block) if block
87
- a
88
- end
89
-
90
- # Constructs a new instance of a dataset with a database instance, initial
91
- # options and an optional record class. Datasets are usually constructed by
92
- # invoking Database methods:
111
+ # Constructs a new instance of a dataset with an associated database and
112
+ # options. Datasets are usually constructed by invoking Database methods:
113
+ #
93
114
  # DB[:posts]
115
+ #
94
116
  # Or:
117
+ #
95
118
  # DB.dataset # the returned dataset is blank
96
119
  #
97
120
  # Sequel::Dataset is an abstract class that is not useful by itself. Each
98
121
  # database adaptor should provide a descendant class of Sequel::Dataset.
99
122
  def initialize(db, opts = nil)
100
123
  @db = db
124
+ @quote_identifiers = db.quote_identifiers? if db.respond_to?(:quote_identifiers?)
101
125
  @opts = opts || {}
102
126
  @row_proc = nil
103
127
  @transform = nil
104
128
  end
105
129
 
106
- # Returns a new clone of the dataset with with the given options merged.
107
- def clone(opts = {})
108
- c = super()
109
- c.opts = @opts.merge(opts)
110
- c.instance_variable_set(:@columns, nil)
111
- c
130
+ ### Class Methods ###
131
+
132
+ # The array of dataset subclasses.
133
+ def self.dataset_classes
134
+ DATASET_CLASSES
135
+ end
136
+
137
+ # Setup mutation (e.g. filter!) methods. These operate the same as the
138
+ # non-! methods, but replace the options of the current dataset with the
139
+ # options of the resulting dataset.
140
+ def self.def_mutation_method(*meths)
141
+ meths.each do |meth|
142
+ class_eval("def #{meth}!(*args, &block); mutation_method(:#{meth}, *args, &block) end")
143
+ end
144
+ end
145
+
146
+ # Add the subclass to the array of subclasses.
147
+ def self.inherited(c)
148
+ DATASET_CLASSES << c
112
149
  end
113
150
 
114
- NOTIMPL_MSG = "This method must be overriden in Sequel adapters".freeze
115
-
116
- # Executes a select query and fetches records, passing each record to the
117
- # supplied block. Adapters should override this method.
118
- def fetch_rows(sql, &block)
119
- # @db.synchronize do
120
- # r = @db.execute(sql)
121
- # r.each(&block)
122
- # end
123
- raise NotImplementedError, NOTIMPL_MSG
151
+ ### Instance Methods ###
152
+
153
+ # Alias for insert, but not aliased directly so subclasses
154
+ # don't have to override both methods.
155
+ def <<(*args)
156
+ insert(*args)
124
157
  end
125
-
126
- # Inserts values into the associated table. Adapters should override this
127
- # method.
128
- def insert(*values)
129
- # @db.synchronize do
130
- # @db.execute(insert_sql(*values)).last_insert_id
131
- # end
132
- raise NotImplementedError, NOTIMPL_MSG
158
+
159
+ # Return the dataset as a column with the given alias, so it can be used in the
160
+ # SELECT clause. This dataset should result in a single row and a single column.
161
+ def as(a)
162
+ ::Sequel::SQL::ColumnExpr.new(self, 'AS', a)
133
163
  end
134
-
135
- # Updates values for the dataset. Adapters should override this method.
136
- def update(values, opts = nil)
137
- # @db.synchronize do
138
- # @db.execute(update_sql(values, opts)).affected_rows
139
- # end
140
- raise NotImplementedError, NOTIMPL_MSG
164
+
165
+ # Returns an array with all records in the dataset. If a block is given,
166
+ # the array is iterated over after all items have been loaded.
167
+ def all(opts = nil, &block)
168
+ a = []
169
+ each(opts) {|r| a << r}
170
+ post_load(a)
171
+ a.each(&block) if block
172
+ a
141
173
  end
142
174
 
143
- # Deletes the records in the dataset. Adapters should override this method.
144
- def delete(opts = nil)
145
- # @db.synchronize do
146
- # @db.execute(delete_sql(opts)).affected_rows
147
- # end
148
- raise NotImplementedError, NOTIMPL_MSG
175
+ # Returns a new clone of the dataset with with the given options merged.
176
+ # If the options changed include options in COLUMN_CHANGE_OPTS, the cached
177
+ # columns are deleted.
178
+ def clone(opts = {})
179
+ c = super()
180
+ c.opts = @opts.merge(opts)
181
+ c.instance_variable_set(:@columns, nil) unless (opts.keys & COLUMN_CHANGE_OPTS).empty?
182
+ c
149
183
  end
150
184
 
151
- # Returns the columns in the result set in their true order. The stock
152
- # implementation returns the content of @columns. If @columns is nil,
153
- # a query is performed. Adapters are expected to fill @columns with the
154
- # column information when a query is performed.
185
+ # Returns the columns in the result set in their true order.
186
+ # If the columns are currently cached, returns the cached value. Otherwise,
187
+ # a SELECT query is performed to get a single row. Adapters are expected
188
+ # to fill the columns cache with the column information when a query is performed.
189
+ # If the dataset does not have any rows, this will be an empty array.
190
+ # If you are looking for all columns for a single table, see Schema::SQL#schema.
155
191
  def columns
156
- first unless @columns
192
+ single_record unless @columns
157
193
  @columns || []
158
194
  end
159
195
 
196
+ # Remove the cached list of columns and do a SELECT query to find
197
+ # the columns.
160
198
  def columns!
161
- first
162
- @columns || []
199
+ @columns = nil
200
+ columns
163
201
  end
164
202
 
165
- # Inserts the supplied values into the associated table.
166
- def <<(*args)
167
- insert(*args)
203
+ # Add a mutation method to this dataset instance.
204
+ def def_mutation_method(*meths)
205
+ meths.each do |meth|
206
+ instance_eval("def #{meth}!(*args, &block); mutation_method(:#{meth}, *args, &block) end")
207
+ end
168
208
  end
169
-
170
- # Updates the dataset with the given values.
171
- def set(*args, &block)
172
- update(*args, &block)
209
+
210
+ # Deletes the records in the dataset. Adapters should override this method.
211
+ def delete(opts = nil)
212
+ raise NotImplementedError, NOTIMPL_MSG
173
213
  end
174
214
 
175
- # Iterates over the records in the dataset
215
+ # Iterates over the records in the dataset.
176
216
  def each(opts = nil, &block)
177
217
  if graph = @opts[:graph]
178
218
  graph_each(opts, &block)
@@ -188,25 +228,56 @@ module Sequel
188
228
  self
189
229
  end
190
230
 
231
+ # Executes a select query and fetches records, passing each record to the
232
+ # supplied block. Adapters should override this method.
233
+ def fetch_rows(sql, &block)
234
+ raise NotImplementedError, NOTIMPL_MSG
235
+ end
236
+
237
+ # Inserts values into the associated table. Adapters should override this
238
+ # method.
239
+ def insert(*values)
240
+ raise NotImplementedError, NOTIMPL_MSG
241
+ end
242
+
243
+ # Returns a string representation of the dataset including the class name
244
+ # and the corresponding SQL select statement.
245
+ def inspect
246
+ "#<#{self.class}: #{sql.inspect}>"
247
+ end
248
+
191
249
  # Returns the the model classes associated with the dataset as a hash.
250
+ # If the dataset is associated with a single model class, a key of nil
251
+ # is used. For datasets with polymorphic models, the keys are
252
+ # values of the polymorphic column and the values are the corresponding
253
+ # model classes to which they map.
192
254
  def model_classes
193
255
  @opts[:models]
194
256
  end
195
257
 
258
+ # Returns a naked dataset clone - i.e. a dataset that returns records as
259
+ # hashes rather than model objects.
260
+ def naked
261
+ clone.set_model(nil)
262
+ end
263
+
196
264
  # Returns the column name for the polymorphic key.
197
265
  def polymorphic_key
198
266
  @opts[:polymorphic_key]
199
267
  end
200
268
 
201
- # Returns a naked dataset clone - i.e. a dataset that returns records as
202
- # hashes rather than model objects.
203
- def naked
204
- d = clone(:naked => true, :models => nil, :polymorphic_key => nil)
205
- d.set_model(nil)
206
- d
269
+ # Whether this dataset quotes identifiers.
270
+ def quote_identifiers?
271
+ @quote_identifiers
207
272
  end
208
-
209
- # Associates or disassociates the dataset with a model. If no argument or
273
+
274
+ # Alias for set, but not aliased directly so subclasses
275
+ # don't have to override both methods.
276
+ def set(*args, &block)
277
+ update(*args, &block)
278
+ end
279
+
280
+ # Associates or disassociates the dataset with a model(s). If
210
281
  # nil is specified, the dataset is turned into a naked dataset and returns
211
282
  # records as hashes. If a model class specified, the dataset is modified
212
283
  # to return records as instances of the model class, e.g:
@@ -241,20 +312,18 @@ module Sequel
241
312
  # class corresponding to nil:
242
313
  #
243
314
  # dataset.set_model(:kind, {nil => DefaultClass, 1 => Person, 2 => Business})
244
- #
245
- # To disassociate a model from the dataset, you can call the #set_model
246
- # and specify nil as the class:
247
- #
248
- # dataset.set_model(nil)
249
315
  #
316
+ # To make sure that there is always a default model class, the hash provided
317
+ # should have a default value. To make the dataset map string values to
318
+ # model classes, and keep a good default, try:
319
+ #
320
+ # dataset.set_model(:kind, Hash.new{|h,k| h[k] = (k.constantize rescue DefaultClass)})
250
321
  def set_model(key, *args)
251
- # pattern matching
322
+ # This code is more verbose then necessary for performance reasons
252
323
  case key
253
- when nil # set_model(nil) => no
254
- # no argument provided, so the dataset is denuded
324
+ when nil # set_model(nil) => no argument provided, so the dataset is denuded
255
325
  @opts.merge!(:naked => true, :models => nil, :polymorphic_key => nil)
256
326
  self.row_proc = nil
257
- # extend_with_stock_each
258
327
  when Class
259
328
  # isomorphic model
260
329
  @opts.merge!(:naked => nil, :models => {nil => key}, :polymorphic_key => nil)
@@ -265,12 +334,11 @@ module Sequel
265
334
  # otherwise we just pass the hash to the constructor
266
335
  self.row_proc = proc{|h| key.new(h, *args)}
267
336
  end
268
- extend_with_destroy
269
337
  when Symbol
270
338
  # polymorphic model
271
339
  hash = args.shift || raise(ArgumentError, "No class hash supplied for polymorphic model")
272
340
  @opts.merge!(:naked => true, :models => hash, :polymorphic_key => key)
273
- if hash.values.first.respond_to?(:load)
341
+ if (hash.empty? ? (hash[nil] rescue nil) : hash.values.first).respond_to?(:load)
274
342
  # the class has a values setter method, so we use it
275
343
  self.row_proc = proc do |h|
276
344
  c = hash[h[key]] || hash[nil] || \
@@ -285,25 +353,12 @@ module Sequel
285
353
  c.new(h, *args)
286
354
  end
287
355
  end
288
- extend_with_destroy
289
356
  else
290
357
  raise ArgumentError, "Invalid model specified"
291
358
  end
292
359
  self
293
360
  end
294
361
 
295
- STOCK_TRANSFORMS = {
296
- :marshal => [
297
- # for backwards-compatibility we support also non-base64-encoded values.
298
- proc {|v| Marshal.load(Base64.decode64(v)) rescue Marshal.load(v)},
299
- proc {|v| Base64.encode64(Marshal.dump(v))}
300
- ],
301
- :yaml => [
302
- proc {|v| YAML.load v if v},
303
- proc {|v| v.to_yaml}
304
- ]
305
- }
306
-
307
362
  # Sets a value transform which is used to convert values loaded and saved
308
363
  # to/from the database. The transform should be supplied as a hash. Each
309
364
  # value in the hash should be an array containing two proc objects - one
@@ -361,63 +416,23 @@ module Sequel
361
416
  end
362
417
  end
363
418
 
364
- # Extends the dataset with a destroy method, that calls destroy for each
365
- # record in the dataset.
366
- def extend_with_destroy
367
- unless respond_to?(:destroy)
368
- meta_def(:destroy) do
369
- unless @opts[:models]
370
- raise Error, "No model associated with this dataset"
371
- end
372
- count = 0
373
- @db.transaction {each {|r| count += 1; r.destroy}}
374
- count
375
- end
376
- end
377
- end
378
-
379
- @@dataset_classes = []
380
-
381
- def self.dataset_classes #:nodoc:
382
- @@dataset_classes
383
- end
384
-
385
- def self.inherited(c) #:nodoc:
386
- @@dataset_classes << c
387
- end
388
-
389
- # Returns a string representation of the dataset including the class name
390
- # and the corresponding SQL select statement.
391
- def inspect
392
- '#<%s: %s>' % [self.class.to_s, sql.inspect]
393
- end
394
-
395
- # Setup mutation (e.g. filter!) methods
396
- def self.def_mutation_method(*meths)
397
- meths.each do |meth|
398
- class_eval("def #{meth}!(*args, &block); mutation_method(:#{meth}, *args, &block) end")
399
- end
400
- end
401
- def def_mutation_method(*meths)
402
- meths.each do |meth|
403
- instance_eval("def #{meth}!(*args, &block); mutation_method(:#{meth}, *args, &block) end")
404
- end
419
+ # Updates values for the dataset. Adapters should override this method.
420
+ def update(values, opts = nil)
421
+ raise NotImplementedError, NOTIMPL_MSG
405
422
  end
406
-
407
- MUTATION_METHODS = %w'and distinct exclude exists filter from from_self full_outer_join graph
408
- group group_and_count group_by having inner_join intersect invert_order join
409
- left_outer_join limit naked or order order_by order_more paginate query reject
410
- reverse reverse_order right_outer_join select select_all select_more
411
- set_graph_aliases set_model sort sort_by union unordered where'.collect{|x| x.to_sym}
412
-
423
+
424
+ # Add the mutation methods via metaprogramming
413
425
  def_mutation_method(*MUTATION_METHODS)
414
426
 
415
427
  private
416
- def mutation_method(meth, *args, &block)
417
- copy = send(meth, *args, &block)
418
- @opts.merge!(copy.opts)
419
- self
420
- end
428
+
429
+ # Modify the receiver with the results of sending the meth, args, and block
430
+ # to the receiver and merging the options of the resulting dataset into
431
+ # the receiver's options.
432
+ def mutation_method(meth, *args, &block)
433
+ copy = send(meth, *args, &block)
434
+ @opts.merge!(copy.opts)
435
+ self
436
+ end
421
437
  end
422
438
  end
423
-
@@ -1,6 +1,6 @@
1
1
  module Sequel
2
2
  # This module makes it easy to add deprecation functionality to other classes.
3
- module Deprecation
3
+ module Deprecation # :nodoc:
4
4
  # This sets the output stream for the deprecation messages. Set it to an IO
5
5
  # (or any object that responds to puts) and it will call puts on that
6
6
  # object with the deprecation message. Set to nil to ignore deprecation messages.
@@ -29,172 +29,4 @@ module Sequel
29
29
  ::Sequel::Deprecation.deprecate("#{meth} is deprecated, and will be removed in Sequel 2.0.#{" #{message}." if message}")
30
30
  end
31
31
  end
32
-
33
- class << self
34
- include Sequel::Deprecation
35
- def method_missing(m, *args) #:nodoc:
36
- deprecate("Sequel.method_missing", "You should define Sequel.#{m} for the adapter.")
37
- c = Database.adapter_class(m)
38
- begin
39
- # three ways to invoke this:
40
- # 0 arguments: Sequel.dbi
41
- # 1 argument: Sequel.dbi(db_name)
42
- # more args: Sequel.dbi(db_name, opts)
43
- case args.size
44
- when 0
45
- opts = {}
46
- when 1
47
- opts = args[0].is_a?(Hash) ? args[0] : {:database => args[0]}
48
- else
49
- opts = args[1].merge(:database => args[0])
50
- end
51
- rescue
52
- raise Error::AdapterNotFound, "Unknown adapter (#{m})"
53
- end
54
- c.new(opts)
55
- end
56
- end
57
-
58
- class Dataset
59
- include Deprecation
60
-
61
- MUTATION_RE = /^(.+)!$/.freeze
62
-
63
- def clone_merge(opts = {}) #:nodoc:
64
- deprecate("Sequel::Dataset#clone", "Use clone")
65
- clone(opts)
66
- end
67
-
68
- def set_options(opts) #:nodoc:
69
- deprecate("Sequel::Dataset#set_options")
70
- @opts = opts
71
- @columns = nil
72
- end
73
-
74
- def set_row_proc(&filter) #:nodoc:
75
- deprecate("Sequel::Dataset#set_row_proc", "Use row_proc=")
76
- @row_proc = filter
77
- end
78
-
79
- def remove_row_proc #:nodoc:
80
- deprecate("Sequel::Dataset#remove_row_proc", "Use row_proc=nil")
81
- @row_proc = nil
82
- end
83
-
84
- # Provides support for mutation methods (filter!, order!, etc.) and magic
85
- # methods.
86
- def method_missing(m, *args, &block) #:nodoc:
87
- if m.to_s =~ MUTATION_RE
88
- meth = $1.to_sym
89
- super unless respond_to?(meth)
90
- copy = send(meth, *args, &block)
91
- super if copy.class != self.class
92
- deprecate("Sequel::Dataset#method_missing", "Define Sequel::Dataset##{m}, or use Sequel::Dataset.def_mutation_method(:#{meth})")
93
- @opts.merge!(copy.opts)
94
- self
95
- elsif magic_method_missing(m)
96
- send(m, *args)
97
- else
98
- super
99
- end
100
- end
101
-
102
- MAGIC_METHODS = {
103
- /^order_by_(.+)$/ => proc {|c| proc {deprecate("Sequel::Dataset#method_missing", "Use order(#{c.inspect}) or define order_by_#{c}"); order(c)}},
104
- /^first_by_(.+)$/ => proc {|c| proc {deprecate("Sequel::Dataset#method_missing", "Use order(#{c.inspect}).first or define first_by_#{c}"); order(c).first}},
105
- /^last_by_(.+)$/ => proc {|c| proc {deprecate("Sequel::Dataset#method_missing", "Use order(#{c.inspect}).last or define last_by_#{c}"); order(c).last}},
106
- /^filter_by_(.+)$/ => proc {|c| proc {|v| deprecate("Sequel::Dataset#method_missing", "Use filter(#{c.inspect}=>#{v.inspect}) or define filter_by_#{c}"); filter(c => v)}},
107
- /^all_by_(.+)$/ => proc {|c| proc {|v| deprecate("Sequel::Dataset#method_missing", "Use filter(#{c.inspect}=>#{v.inspect}).all or define all_by_#{c}"); filter(c => v).all}},
108
- /^find_by_(.+)$/ => proc {|c| proc {|v| deprecate("Sequel::Dataset#method_missing", "Use filter(#{c.inspect}=>#{v.inspect}).first or define find_by_#{c}"); filter(c => v).first}},
109
- /^group_by_(.+)$/ => proc {|c| proc {deprecate("Sequel::Dataset#method_missing", "Use group(#{c.inspect}) or define group_by_#{c}"); group(c)}},
110
- /^count_by_(.+)$/ => proc {|c| proc {deprecate("Sequel::Dataset#method_missing", "Use group_and_count(#{c.inspect}) or define count_by_#{c})"); group_and_count(c)}}
111
- }
112
-
113
- # Checks if the given method name represents a magic method and
114
- # defines it. Otherwise, nil is returned.
115
- def magic_method_missing(m) #:nodoc:
116
- method_name = m.to_s
117
- MAGIC_METHODS.each_pair do |r, p|
118
- if method_name =~ r
119
- impl = p[$1.to_sym]
120
- return Dataset.class_def(m, &impl)
121
- end
122
- end
123
- nil
124
- end
125
- end
126
-
127
- module SQL
128
- module DeprecatedColumnMethods #:nodoc:
129
- AS = 'AS'.freeze
130
- DESC = 'DESC'.freeze
131
- ASC = 'ASC'.freeze
132
-
133
- def as(a) #:nodoc:
134
- Sequel::Deprecation.deprecate("Object#as is deprecated and will be removed in Sequel 2.0. Use Symbol#as or String#as.")
135
- ColumnExpr.new(self, AS, a)
136
- end
137
- def AS(a) #:nodoc:
138
- Sequel::Deprecation.deprecate("Object#AS is deprecated and will be removed in Sequel 2.0. Use Symbol#as or String#as.")
139
- ColumnExpr.new(self, AS, a)
140
- end
141
- def desc #:nodoc:
142
- Sequel::Deprecation.deprecate("Object#desc is deprecated and will be removed in Sequel 2.0. Use Symbol#desc or String#desc.")
143
- ColumnExpr.new(self, DESC)
144
- end
145
- def DESC #:nodoc:
146
- Sequel::Deprecation.deprecate("Object#DESC is deprecated and will be removed in Sequel 2.0. Use Symbol#desc or String#desc.")
147
- ColumnExpr.new(self, DESC)
148
- end
149
- def asc #:nodoc:
150
- Sequel::Deprecation.deprecate("Object#asc is deprecated and will be removed in Sequel 2.0. Use Symbol#asc or String#asc.")
151
- ColumnExpr.new(self, ASC)
152
- end
153
- def ASC #:nodoc:
154
- Sequel::Deprecation.deprecate("Object#ASC is deprecated and will be removed in Sequel 2.0. Use Symbol#asc or String#asc.")
155
- ColumnExpr.new(self, ASC)
156
- end
157
- def all #:nodoc:
158
- Sequel::Deprecation.deprecate("Object#all is deprecated and will be removed in Sequel 2.0. Use :#{self}.* or '#{self}.*'.lit.")
159
- Sequel::SQL::ColumnAll.new(self)
160
- end
161
- def ALL #:nodoc:
162
- Sequel::Deprecation.deprecate("Object#ALL is deprecated and will be removed in Sequel 2.0. Use :#{self}.* or '#{self}.*'.lit.")
163
- Sequel::SQL::ColumnAll.new(self)
164
- end
165
-
166
- def cast_as(t) #:nodoc:
167
- Sequel::Deprecation.deprecate("Object#cast_as is deprecated and will be removed in Sequel 2.0. Use Symbol#cast_as or String#cast_as.")
168
- if t.is_a?(Symbol)
169
- t = t.to_s.lit
170
- end
171
- Sequel::SQL::Function.new(:cast, self.as(t))
172
- end
173
- end
174
- end
175
- end
176
-
177
- class Object
178
- include Sequel::SQL::DeprecatedColumnMethods
179
- def Sequel(*args) #:nodoc:
180
- Sequel::Deprecation.deprecate("Object#Sequel is deprecated and will be removed in Sequel 2.0. Use Sequel.connect.")
181
- Sequel.connect(*args)
182
- end
183
- def rollback! #:nodoc:
184
- Sequel::Deprecation.deprecate("Object#rollback! is deprecated and will be removed in Sequel 2.0. Use raise Sequel::Error::Rollback.")
185
- raise Sequel::Error::Rollback
186
- end
187
- end
188
-
189
- class Symbol
190
- # Converts missing method calls into functions on columns, if the
191
- # method name is made of all upper case letters.
192
- def method_missing(sym, *args) #:nodoc:
193
- if ((s = sym.to_s) =~ /^([A-Z]+)$/)
194
- Sequel::Deprecation.deprecate("Symbol#method_missing is deprecated and will be removed in Sequel 2.0. Use :#{sym}[:#{self}].")
195
- Sequel::SQL::Function.new(s.downcase, self)
196
- else
197
- super
198
- end
199
- end
200
32
  end