sequel_core 2.2.0 → 3.8.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 (66) hide show
  1. metadata +30 -101
  2. data/CHANGELOG +0 -1519
  3. data/COPYING +0 -19
  4. data/README +0 -313
  5. data/Rakefile +0 -158
  6. data/bin/sequel +0 -117
  7. data/doc/cheat_sheet.rdoc +0 -225
  8. data/doc/dataset_filtering.rdoc +0 -182
  9. data/lib/sequel_core.rb +0 -136
  10. data/lib/sequel_core/adapters/adapter_skeleton.rb +0 -68
  11. data/lib/sequel_core/adapters/ado.rb +0 -90
  12. data/lib/sequel_core/adapters/db2.rb +0 -160
  13. data/lib/sequel_core/adapters/dbi.rb +0 -127
  14. data/lib/sequel_core/adapters/informix.rb +0 -89
  15. data/lib/sequel_core/adapters/jdbc.rb +0 -110
  16. data/lib/sequel_core/adapters/mysql.rb +0 -486
  17. data/lib/sequel_core/adapters/odbc.rb +0 -167
  18. data/lib/sequel_core/adapters/odbc_mssql.rb +0 -106
  19. data/lib/sequel_core/adapters/openbase.rb +0 -76
  20. data/lib/sequel_core/adapters/oracle.rb +0 -182
  21. data/lib/sequel_core/adapters/postgres.rb +0 -560
  22. data/lib/sequel_core/adapters/sqlite.rb +0 -270
  23. data/lib/sequel_core/connection_pool.rb +0 -194
  24. data/lib/sequel_core/core_ext.rb +0 -197
  25. data/lib/sequel_core/core_sql.rb +0 -184
  26. data/lib/sequel_core/database.rb +0 -462
  27. data/lib/sequel_core/database/schema.rb +0 -156
  28. data/lib/sequel_core/dataset.rb +0 -457
  29. data/lib/sequel_core/dataset/callback.rb +0 -13
  30. data/lib/sequel_core/dataset/convenience.rb +0 -245
  31. data/lib/sequel_core/dataset/pagination.rb +0 -96
  32. data/lib/sequel_core/dataset/query.rb +0 -41
  33. data/lib/sequel_core/dataset/schema.rb +0 -15
  34. data/lib/sequel_core/dataset/sql.rb +0 -889
  35. data/lib/sequel_core/deprecated.rb +0 -26
  36. data/lib/sequel_core/exceptions.rb +0 -42
  37. data/lib/sequel_core/migration.rb +0 -187
  38. data/lib/sequel_core/object_graph.rb +0 -216
  39. data/lib/sequel_core/pretty_table.rb +0 -71
  40. data/lib/sequel_core/schema.rb +0 -2
  41. data/lib/sequel_core/schema/generator.rb +0 -239
  42. data/lib/sequel_core/schema/sql.rb +0 -326
  43. data/lib/sequel_core/sql.rb +0 -812
  44. data/lib/sequel_core/worker.rb +0 -68
  45. data/spec/adapters/informix_spec.rb +0 -96
  46. data/spec/adapters/mysql_spec.rb +0 -765
  47. data/spec/adapters/oracle_spec.rb +0 -222
  48. data/spec/adapters/postgres_spec.rb +0 -441
  49. data/spec/adapters/sqlite_spec.rb +0 -413
  50. data/spec/connection_pool_spec.rb +0 -363
  51. data/spec/core_ext_spec.rb +0 -156
  52. data/spec/core_sql_spec.rb +0 -427
  53. data/spec/database_spec.rb +0 -963
  54. data/spec/dataset_spec.rb +0 -2933
  55. data/spec/expression_filters_spec.rb +0 -316
  56. data/spec/migration_spec.rb +0 -261
  57. data/spec/object_graph_spec.rb +0 -230
  58. data/spec/pretty_table_spec.rb +0 -58
  59. data/spec/rcov.opts +0 -6
  60. data/spec/schema_generator_spec.rb +0 -122
  61. data/spec/schema_spec.rb +0 -422
  62. data/spec/spec.opts +0 -0
  63. data/spec/spec_config.rb +0 -7
  64. data/spec/spec_config.rb.example +0 -8
  65. data/spec/spec_helper.rb +0 -55
  66. data/spec/worker_spec.rb +0 -96
@@ -1,156 +0,0 @@
1
- module Sequel
2
- class Database
3
- # Adds a column to the specified table. This method expects a column name,
4
- # a datatype and optionally a hash with additional constraints and options:
5
- #
6
- # DB.add_column :items, :name, :text, :unique => true, :null => false
7
- # DB.add_column :items, :category, :text, :default => 'ruby'
8
- #
9
- # See alter_table.
10
- def add_column(table, *args)
11
- alter_table(table) {add_column(*args)}
12
- end
13
-
14
- # Adds an index to a table for the given columns:
15
- #
16
- # DB.add_index :posts, :title
17
- # DB.add_index :posts, [:author, :title], :unique => true
18
- #
19
- # See alter_table.
20
- def add_index(table, *args)
21
- alter_table(table) {add_index(*args)}
22
- end
23
-
24
- # Alters the given table with the specified block. Here are the currently
25
- # available operations:
26
- #
27
- # DB.alter_table :items do
28
- # add_column :category, :text, :default => 'ruby'
29
- # drop_column :category
30
- # rename_column :cntr, :counter
31
- # set_column_type :value, :float
32
- # set_column_default :value, :float
33
- # add_index [:group, :category]
34
- # drop_index [:group, :category]
35
- # end
36
- #
37
- # Note that #add_column accepts all the options available for column
38
- # definitions using create_table, and #add_index accepts all the options
39
- # available for index definition.
40
- #
41
- # See Schema::AlterTableGenerator.
42
- def alter_table(name, &block)
43
- g = Schema::AlterTableGenerator.new(self, &block)
44
- alter_table_sql_list(name, g.operations).each {|sql| execute(sql)}
45
- end
46
-
47
- # Creates a table with the columns given in the provided block:
48
- #
49
- # DB.create_table :posts do
50
- # primary_key :id, :serial
51
- # column :title, :text
52
- # column :content, :text
53
- # index :title
54
- # end
55
- #
56
- # See Schema::Generator.
57
- def create_table(name, &block)
58
- g = Schema::Generator.new(self, &block)
59
- create_table_sql_list(name, *g.create_info).each {|sql| execute(sql)}
60
- end
61
-
62
- # Forcibly creates a table. If the table already exists it is dropped.
63
- def create_table!(name, &block)
64
- drop_table(name) rescue nil
65
- create_table(name, &block)
66
- end
67
-
68
- # Creates a view, replacing it if it already exists:
69
- #
70
- # DB.create_or_replace_view(:cheap_items, "SELECT * FROM items WHERE price < 100")
71
- # DB.create_or_replace_view(:ruby_items, DB[:items].filter(:category => 'ruby'))
72
- def create_or_replace_view(name, source)
73
- source = source.sql if source.is_a?(Dataset)
74
- execute("CREATE OR REPLACE VIEW #{name} AS #{source}")
75
- end
76
-
77
- # Creates a view based on a dataset or an SQL string:
78
- #
79
- # DB.create_view(:cheap_items, "SELECT * FROM items WHERE price < 100")
80
- # DB.create_view(:ruby_items, DB[:items].filter(:category => 'ruby'))
81
- def create_view(name, source)
82
- source = source.sql if source.is_a?(Dataset)
83
- execute("CREATE VIEW #{name} AS #{source}")
84
- end
85
-
86
- # Removes a column from the specified table:
87
- #
88
- # DB.drop_column :items, :category
89
- #
90
- # See alter_table.
91
- def drop_column(table, *args)
92
- alter_table(table) {drop_column(*args)}
93
- end
94
-
95
- # Removes an index for the given table and column/s:
96
- #
97
- # DB.drop_index :posts, :title
98
- # DB.drop_index :posts, [:author, :title]
99
- #
100
- # See alter_table.
101
- def drop_index(table, columns)
102
- alter_table(table) {drop_index(columns)}
103
- end
104
-
105
- # Drops one or more tables corresponding to the given table names:
106
- #
107
- # DB.drop_table(:posts, :comments)
108
- def drop_table(*names)
109
- names.each {|n| execute(drop_table_sql(n))}
110
- end
111
-
112
- # Drops a view:
113
- #
114
- # DB.drop_view(:cheap_items)
115
- def drop_view(name)
116
- execute("DROP VIEW #{name}")
117
- end
118
-
119
- # Renames a table:
120
- #
121
- # DB.tables #=> [:items]
122
- # DB.rename_table :items, :old_items
123
- # DB.tables #=> [:old_items]
124
- def rename_table(*args)
125
- execute(rename_table_sql(*args))
126
- end
127
-
128
- # Renames a column in the specified table. This method expects the current
129
- # column name and the new column name:
130
- #
131
- # DB.rename_column :items, :cntr, :counter
132
- #
133
- # See alter_table.
134
- def rename_column(table, *args)
135
- alter_table(table) {rename_column(*args)}
136
- end
137
-
138
- # Sets the default value for the given column in the given table:
139
- #
140
- # DB.set_column_default :items, :category, 'perl!'
141
- #
142
- # See alter_table.
143
- def set_column_default(table, *args)
144
- alter_table(table) {set_column_default(*args)}
145
- end
146
-
147
- # Set the data type for the given column in the given table:
148
- #
149
- # DB.set_column_type :items, :price, :float
150
- #
151
- # See alter_table.
152
- def set_column_type(table, *args)
153
- alter_table(table) {set_column_type(*args)}
154
- end
155
- end
156
- end
@@ -1,457 +0,0 @@
1
- %w'callback convenience pagination query schema sql'.each do |f|
2
- require "sequel_core/dataset/#{f}"
3
- end
4
-
5
- module Sequel
6
- # A Dataset represents a view of a the data in a database, constrained by
7
- # specific parameters such as filtering conditions, order, etc. Datasets
8
- # can be used to create, retrieve, update and delete records.
9
- #
10
- # Query results are always retrieved on demand, so a dataset can be kept
11
- # around and reused indefinitely:
12
- #
13
- # my_posts = DB[:posts].filter(:author => 'david') # no records are retrieved
14
- # p my_posts.all # records are now retrieved
15
- # ...
16
- # p my_posts.all # records are retrieved again
17
- #
18
- # In order to provide this functionality, dataset methods such as where,
19
- # select, order, etc. return modified copies of the dataset, so you can
20
- # use different datasets to access data:
21
- #
22
- # posts = DB[:posts]
23
- # davids_posts = posts.filter(:author => 'david')
24
- # old_posts = posts.filter('stamp < ?', Date.today - 7)
25
- #
26
- # Datasets are Enumerable objects, so they can be manipulated using any
27
- # of the Enumerable methods, such as map, inject, etc.
28
- #
29
- # === The Dataset Adapter Interface
30
- #
31
- # Each adapter should define its own dataset class as a descendant of
32
- # Sequel::Dataset. The following methods should be overridden by the adapter
33
- # Dataset class (each method with the stock implementation):
34
- #
35
- # # Iterate over the results of the SQL query and call the supplied
36
- # # block with each record (as a hash).
37
- # def fetch_rows(sql, &block)
38
- # @db.synchronize do
39
- # r = @db.execute(sql)
40
- # r.each(&block)
41
- # end
42
- # end
43
- #
44
- # # Insert records.
45
- # def insert(*values)
46
- # @db.synchronize do
47
- # @db.execute(insert_sql(*values)).last_insert_id
48
- # end
49
- # end
50
- #
51
- # # Update records.
52
- # def update(*args, &block)
53
- # @db.synchronize do
54
- # @db.execute(update_sql(*args, &block)).affected_rows
55
- # end
56
- # end
57
- #
58
- # # Delete records.
59
- # def delete(opts = nil)
60
- # @db.synchronize do
61
- # @db.execute(delete_sql(opts)).affected_rows
62
- # end
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.
75
- class Dataset
76
- include Enumerable
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
-
106
- # The database that corresponds to this dataset
107
- attr_accessor :db
108
-
109
- # The hash of options for this dataset, keys are symbols.
110
- attr_accessor :opts
111
-
112
- # The row_proc for this database, should be a Proc that takes
113
- # a single hash argument and returns the object you want to
114
- # fetch_rows to return.
115
- attr_accessor :row_proc
116
-
117
- # Whether to quote identifiers for this dataset
118
- attr_writer :quote_identifiers
119
-
120
- # Constructs a new instance of a dataset with an associated database and
121
- # options. Datasets are usually constructed by invoking Database methods:
122
- #
123
- # DB[:posts]
124
- #
125
- # Or:
126
- #
127
- # DB.dataset # the returned dataset is blank
128
- #
129
- # Sequel::Dataset is an abstract class that is not useful by itself. Each
130
- # database adaptor should provide a descendant class of Sequel::Dataset.
131
- def initialize(db, opts = nil)
132
- @db = db
133
- @quote_identifiers = db.quote_identifiers? if db.respond_to?(:quote_identifiers?)
134
- @opts = opts || {}
135
- @row_proc = nil
136
- @transform = nil
137
- end
138
-
139
- ### Class Methods ###
140
-
141
- # The array of dataset subclasses.
142
- def self.dataset_classes
143
- DATASET_CLASSES
144
- end
145
-
146
- # Setup mutation (e.g. filter!) methods. These operate the same as the
147
- # non-! methods, but replace the options of the current dataset with the
148
- # options of the resulting dataset.
149
- def self.def_mutation_method(*meths)
150
- meths.each do |meth|
151
- class_eval("def #{meth}!(*args, &block); mutation_method(:#{meth}, *args, &block) end")
152
- end
153
- end
154
-
155
- # Add the subclass to the array of subclasses.
156
- def self.inherited(c)
157
- DATASET_CLASSES << c
158
- end
159
-
160
- ### Instance Methods ###
161
-
162
- # Alias for insert, but not aliased directly so subclasses
163
- # don't have to override both methods.
164
- def <<(*args)
165
- insert(*args)
166
- end
167
-
168
- # Return the dataset as a column with the given alias, so it can be used in the
169
- # SELECT clause. This dataset should result in a single row and a single column.
170
- def as(aliaz)
171
- ::Sequel::SQL::AliasedExpression.new(self, aliaz)
172
- end
173
-
174
- # Returns an array with all records in the dataset. If a block is given,
175
- # the array is iterated over after all items have been loaded.
176
- def all(opts = nil, &block)
177
- a = []
178
- each(opts) {|r| a << r}
179
- post_load(a)
180
- a.each(&block) if block
181
- a
182
- end
183
-
184
- # Returns a new clone of the dataset with with the given options merged.
185
- # If the options changed include options in COLUMN_CHANGE_OPTS, the cached
186
- # columns are deleted.
187
- def clone(opts = {})
188
- c = super()
189
- c.opts = @opts.merge(opts)
190
- c.instance_variable_set(:@columns, nil) if opts.keys.any?{|o| COLUMN_CHANGE_OPTS.include?(o)}
191
- c
192
- end
193
-
194
- # Returns the columns in the result set in their true order.
195
- # If the columns are currently cached, returns the cached value. Otherwise,
196
- # a SELECT query is performed to get a single row. Adapters are expected
197
- # to fill the columns cache with the column information when a query is performed.
198
- # If the dataset does not have any rows, this will be an empty array.
199
- # If you are looking for all columns for a single table, see Schema::SQL#schema.
200
- def columns
201
- return @columns if @columns
202
- ds = unfiltered.unordered.clone(:distinct => nil)
203
- ds.single_record
204
- @columns = ds.instance_variable_get(:@columns)
205
- @columns || []
206
- end
207
-
208
- # Remove the cached list of columns and do a SELECT query to find
209
- # the columns.
210
- def columns!
211
- @columns = nil
212
- columns
213
- end
214
-
215
- # Add a mutation method to this dataset instance.
216
- def def_mutation_method(*meths)
217
- meths.each do |meth|
218
- instance_eval("def #{meth}!(*args, &block); mutation_method(:#{meth}, *args, &block) end")
219
- end
220
- end
221
-
222
- # Deletes the records in the dataset. Adapters should override this method.
223
- def delete(opts = nil)
224
- raise NotImplementedError, NOTIMPL_MSG
225
- end
226
-
227
- # Iterates over the records in the dataset.
228
- def each(opts = nil, &block)
229
- if graph = @opts[:graph]
230
- graph_each(opts, &block)
231
- else
232
- row_proc = @row_proc unless opts && opts[:naked]
233
- transform = @transform
234
- fetch_rows(select_sql(opts)) do |r|
235
- r = transform_load(r) if transform
236
- r = row_proc[r] if row_proc
237
- yield r
238
- end
239
- end
240
- self
241
- end
242
-
243
- # Executes a select query and fetches records, passing each record to the
244
- # supplied block. Adapters should override this method.
245
- def fetch_rows(sql, &block)
246
- raise NotImplementedError, NOTIMPL_MSG
247
- end
248
-
249
- # Inserts values into the associated table. Adapters should override this
250
- # method.
251
- def insert(*values)
252
- raise NotImplementedError, NOTIMPL_MSG
253
- end
254
-
255
- # Returns a string representation of the dataset including the class name
256
- # and the corresponding SQL select statement.
257
- def inspect
258
- "#<#{self.class}: #{sql.inspect}>"
259
- end
260
-
261
- # Returns the the model classes associated with the dataset as a hash.
262
- # If the dataset is associated with a single model class, a key of nil
263
- # is used. For datasets with polymorphic models, the keys are
264
- # values of the polymorphic column and the values are the corresponding
265
- # model classes to which they map.
266
- def model_classes
267
- @opts[:models]
268
- end
269
-
270
- # Returns a naked dataset clone - i.e. a dataset that returns records as
271
- # hashes rather than model objects.
272
- def naked
273
- clone.set_model(nil)
274
- end
275
-
276
- # Returns the column name for the polymorphic key.
277
- def polymorphic_key
278
- @opts[:polymorphic_key]
279
- end
280
-
281
- # Whether this dataset quotes identifiers.
282
- def quote_identifiers?
283
- @quote_identifiers
284
- end
285
-
286
- # Alias for set, but not aliased directly so subclasses
287
- # don't have to override both methods.
288
- def set(*args, &block)
289
- update(*args, &block)
290
- end
291
-
292
- # Associates or disassociates the dataset with a model(s). If
293
- # nil is specified, the dataset is turned into a naked dataset and returns
294
- # records as hashes. If a model class specified, the dataset is modified
295
- # to return records as instances of the model class, e.g:
296
- #
297
- # class MyModel
298
- # def initialize(values)
299
- # @values = values
300
- # ...
301
- # end
302
- # end
303
- #
304
- # dataset.set_model(MyModel)
305
- #
306
- # You can also provide additional arguments to be passed to the model's
307
- # initialize method:
308
- #
309
- # class MyModel
310
- # def initialize(values, options)
311
- # @values = values
312
- # ...
313
- # end
314
- # end
315
- #
316
- # dataset.set_model(MyModel, :allow_delete => false)
317
- #
318
- # The dataset can be made polymorphic by specifying a column name as the
319
- # polymorphic key and a hash mapping column values to model classes.
320
- #
321
- # dataset.set_model(:kind, {1 => Person, 2 => Business})
322
- #
323
- # You can also set a default model class to fall back on by specifying a
324
- # class corresponding to nil:
325
- #
326
- # dataset.set_model(:kind, {nil => DefaultClass, 1 => Person, 2 => Business})
327
- #
328
- # To make sure that there is always a default model class, the hash provided
329
- # should have a default value. To make the dataset map string values to
330
- # model classes, and keep a good default, try:
331
- #
332
- # dataset.set_model(:kind, Hash.new{|h,k| h[k] = (k.constantize rescue DefaultClass)})
333
- def set_model(key, *args)
334
- # This code is more verbose then necessary for performance reasons
335
- case key
336
- when nil # set_model(nil) => no argument provided, so the dataset is denuded
337
- @opts.merge!(:naked => true, :models => nil, :polymorphic_key => nil)
338
- self.row_proc = nil
339
- when Class
340
- # isomorphic model
341
- @opts.merge!(:naked => nil, :models => {nil => key}, :polymorphic_key => nil)
342
- if key.respond_to?(:load)
343
- # the class has a values setter method, so we use it
344
- self.row_proc = proc{|h| key.load(h, *args)}
345
- else
346
- # otherwise we just pass the hash to the constructor
347
- self.row_proc = proc{|h| key.new(h, *args)}
348
- end
349
- when Symbol
350
- # polymorphic model
351
- hash = args.shift || raise(ArgumentError, "No class hash supplied for polymorphic model")
352
- @opts.merge!(:naked => true, :models => hash, :polymorphic_key => key)
353
- if (hash.empty? ? (hash[nil] rescue nil) : hash.values.first).respond_to?(:load)
354
- # the class has a values setter method, so we use it
355
- self.row_proc = proc do |h|
356
- c = hash[h[key]] || hash[nil] || \
357
- raise(Error, "No matching model class for record (#{polymorphic_key} => #{h[polymorphic_key].inspect})")
358
- c.load(h, *args)
359
- end
360
- else
361
- # otherwise we just pass the hash to the constructor
362
- self.row_proc = proc do |h|
363
- c = hash[h[key]] || hash[nil] || \
364
- raise(Error, "No matching model class for record (#{polymorphic_key} => #{h[polymorphic_key].inspect})")
365
- c.new(h, *args)
366
- end
367
- end
368
- else
369
- raise ArgumentError, "Invalid model specified"
370
- end
371
- self
372
- end
373
-
374
- # Sets a value transform which is used to convert values loaded and saved
375
- # to/from the database. The transform should be supplied as a hash. Each
376
- # value in the hash should be an array containing two proc objects - one
377
- # for transforming loaded values, and one for transforming saved values.
378
- # The following example demonstrates how to store Ruby objects in a dataset
379
- # using Marshal serialization:
380
- #
381
- # dataset.transform(:obj => [
382
- # proc {|v| Marshal.load(v)},
383
- # proc {|v| Marshal.dump(v)}
384
- # ])
385
- #
386
- # dataset.insert_sql(:obj => 1234) #=>
387
- # "INSERT INTO items (obj) VALUES ('\004\bi\002\322\004')"
388
- #
389
- # Another form of using transform is by specifying stock transforms:
390
- #
391
- # dataset.transform(:obj => :marshal)
392
- #
393
- # The currently supported stock transforms are :marshal and :yaml.
394
- def transform(t)
395
- @transform = t
396
- t.each do |k, v|
397
- case v
398
- when Array
399
- if (v.size != 2) || !v.first.is_a?(Proc) && !v.last.is_a?(Proc)
400
- raise Error::InvalidTransform, "Invalid transform specified"
401
- end
402
- else
403
- unless v = STOCK_TRANSFORMS[v]
404
- raise Error::InvalidTransform, "Invalid transform specified"
405
- else
406
- t[k] = v
407
- end
408
- end
409
- end
410
- self
411
- end
412
-
413
- # Applies the value transform for data loaded from the database.
414
- def transform_load(r)
415
- r.inject({}) do |m, kv|
416
- k, v = *kv
417
- m[k] = (tt = @transform[k]) ? tt[0][v] : v
418
- m
419
- end
420
- end
421
-
422
- # Applies the value transform for data saved to the database.
423
- def transform_save(r)
424
- r.inject({}) do |m, kv|
425
- k, v = *kv
426
- m[k] = (tt = @transform[k]) ? tt[1][v] : v
427
- m
428
- end
429
- end
430
-
431
- # Updates values for the dataset. Adapters should override this method.
432
- def update(values, opts = nil)
433
- raise NotImplementedError, NOTIMPL_MSG
434
- end
435
-
436
- # Add the mutation methods via metaprogramming
437
- def_mutation_method(*MUTATION_METHODS)
438
-
439
- protected
440
-
441
- # Return true if the dataset has a non-nil value for any key in opts.
442
- def options_overlap(opts)
443
- !(@opts.collect{|k,v| k unless v.nil?}.compact & opts).empty?
444
- end
445
-
446
- private
447
-
448
- # Modify the receiver with the results of sending the meth, args, and block
449
- # to the receiver and merging the options of the resulting dataset into
450
- # the receiver's options.
451
- def mutation_method(meth, *args, &block)
452
- copy = send(meth, *args, &block)
453
- @opts.merge!(copy.opts)
454
- self
455
- end
456
- end
457
- end