sequel 3.41.0 → 3.42.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.
- data/CHANGELOG +28 -0
- data/README.rdoc +18 -6
- data/Rakefile +45 -40
- data/doc/release_notes/3.42.0.txt +74 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +55 -0
- data/lib/sequel/adapters/postgres.rb +4 -32
- data/lib/sequel/adapters/shared/mssql.rb +9 -3
- data/lib/sequel/adapters/shared/oracle.rb +5 -0
- data/lib/sequel/adapters/shared/postgres.rb +59 -2
- data/lib/sequel/adapters/shared/sqlite.rb +5 -0
- data/lib/sequel/database/misc.rb +21 -0
- data/lib/sequel/database/query.rb +10 -2
- data/lib/sequel/database/schema_generator.rb +9 -4
- data/lib/sequel/database/schema_methods.rb +18 -4
- data/lib/sequel/dataset/actions.rb +28 -12
- data/lib/sequel/dataset/query.rb +1 -1
- data/lib/sequel/dataset/sql.rb +1 -1
- data/lib/sequel/extensions/schema_dumper.rb +1 -0
- data/lib/sequel/model.rb +2 -3
- data/lib/sequel/model/base.rb +54 -33
- data/lib/sequel/model/dataset_module.rb +30 -0
- data/lib/sequel/plugins/force_encoding.rb +4 -1
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +84 -73
- data/spec/core/database_spec.rb +11 -3
- data/spec/core/dataset_spec.rb +22 -0
- data/spec/core/schema_spec.rb +41 -0
- data/spec/extensions/force_encoding_spec.rb +9 -0
- data/spec/integration/schema_test.rb +32 -7
- data/spec/model/base_spec.rb +16 -0
- metadata +5 -2
@@ -140,6 +140,11 @@ module Sequel
|
|
140
140
|
sqlite_version >= 30300
|
141
141
|
end
|
142
142
|
|
143
|
+
# SQLite 3.6.19+ supports deferrable foreign key constraints.
|
144
|
+
def supports_deferrable_foreign_key_constraints?
|
145
|
+
sqlite_version >= 30619
|
146
|
+
end
|
147
|
+
|
143
148
|
# SQLite 3.6.8+ supports savepoints.
|
144
149
|
def supports_savepoints?
|
145
150
|
sqlite_version >= 30608
|
data/lib/sequel/database/misc.rb
CHANGED
@@ -10,6 +10,10 @@ module Sequel
|
|
10
10
|
# in the extension).
|
11
11
|
EXTENSIONS = {}
|
12
12
|
|
13
|
+
# The general default size for string columns for all Sequel::Database
|
14
|
+
# instances.
|
15
|
+
DEFAULT_STRING_COLUMN_SIZE = 255
|
16
|
+
|
13
17
|
# Register an extension callback for Database objects. ext should be the
|
14
18
|
# extension name symbol, and mod should either be a Module that the
|
15
19
|
# database is extended with, or a callable object called with the database
|
@@ -44,11 +48,15 @@ module Sequel
|
|
44
48
|
# Set the timezone to use for this database, overridding <tt>Sequel.database_timezone</tt>.
|
45
49
|
attr_writer :timezone
|
46
50
|
|
51
|
+
# The specific default size of string columns for this Sequel::Database, usually 255 by default.
|
52
|
+
attr_accessor :default_string_column_size
|
53
|
+
|
47
54
|
# Constructs a new instance of a database connection with the specified
|
48
55
|
# options hash.
|
49
56
|
#
|
50
57
|
# Accepts the following options:
|
51
58
|
# :default_schema :: The default schema to use, see #default_schema.
|
59
|
+
# :default_string_column_size :: The default size of string columns, 255 by default.
|
52
60
|
# :identifier_input_method :: A string method symbol to call on identifiers going into the database
|
53
61
|
# :identifier_output_method :: A string method symbol to call on identifiers coming from the database
|
54
62
|
# :logger :: A specific logger to use
|
@@ -71,6 +79,7 @@ module Sequel
|
|
71
79
|
@opts[:single_threaded] = @single_threaded = typecast_value_boolean(@opts.fetch(:single_threaded, @@single_threaded))
|
72
80
|
@schemas = {}
|
73
81
|
@default_schema = @opts.fetch(:default_schema, default_schema_default)
|
82
|
+
@default_string_column_size = @opts[:default_string_column_size] || DEFAULT_STRING_COLUMN_SIZE
|
74
83
|
@prepared_statements = {}
|
75
84
|
@transactions = {}
|
76
85
|
@identifier_input_method = nil
|
@@ -205,6 +214,18 @@ module Sequel
|
|
205
214
|
false
|
206
215
|
end
|
207
216
|
|
217
|
+
# Whether the database supports deferrable constraints, false
|
218
|
+
# by default as few databases do.
|
219
|
+
def supports_deferrable_constraints?
|
220
|
+
false
|
221
|
+
end
|
222
|
+
|
223
|
+
# Whether the database supports deferrable foreign key constraints,
|
224
|
+
# false by default as few databases do.
|
225
|
+
def supports_deferrable_foreign_key_constraints?
|
226
|
+
supports_deferrable_constraints?
|
227
|
+
end
|
228
|
+
|
208
229
|
# Whether the database supports DROP TABLE IF EXISTS syntax,
|
209
230
|
# default is the same as #supports_create_table_if_not_exists?.
|
210
231
|
def supports_drop_table_if_exists?
|
@@ -232,7 +232,7 @@ module Sequel
|
|
232
232
|
|
233
233
|
# Starts a database transaction. When a database transaction is used,
|
234
234
|
# either all statements are successful or none of the statements are
|
235
|
-
# successful. Note that MySQL MyISAM
|
235
|
+
# successful. Note that MySQL MyISAM tables do not support transactions.
|
236
236
|
#
|
237
237
|
# The following general options are respected:
|
238
238
|
#
|
@@ -333,7 +333,15 @@ module Sequel
|
|
333
333
|
begin
|
334
334
|
committed = commit_or_rollback_transaction(e, conn, opts)
|
335
335
|
rescue Exception => e2
|
336
|
-
|
336
|
+
begin
|
337
|
+
raise_error(e2, :classes=>database_error_classes, :conn=>conn)
|
338
|
+
rescue Sequel::DatabaseError => e4
|
339
|
+
begin
|
340
|
+
rollback_transaction(conn, opts)
|
341
|
+
ensure
|
342
|
+
raise e4
|
343
|
+
end
|
344
|
+
end
|
337
345
|
ensure
|
338
346
|
remove_transaction(conn, committed)
|
339
347
|
end
|
@@ -79,10 +79,11 @@ module Sequel
|
|
79
79
|
# The following options are supported:
|
80
80
|
#
|
81
81
|
# :default :: The default value for the column.
|
82
|
-
# :deferrable ::
|
83
|
-
#
|
84
|
-
#
|
85
|
-
# DEFERRABLE INITIALLY DEFERRED on key creation.
|
82
|
+
# :deferrable :: For foreign key columns, this ensures referential integrity will work even if
|
83
|
+
# referencing table uses a foreign key value that does not
|
84
|
+
# yet exist on referenced table (but will exist before the transaction commits).
|
85
|
+
# Basically it adds DEFERRABLE INITIALLY DEFERRED on key creation.
|
86
|
+
# If you use :immediate as the value, uses DEFERRABLE INITIALLY IMMEDIATE.
|
86
87
|
# :index :: Create an index on this column. If given a hash, use the hash as the
|
87
88
|
# options for the index.
|
88
89
|
# :key :: For foreign key columns, the column in the associated table
|
@@ -239,6 +240,8 @@ module Sequel
|
|
239
240
|
# Add a unique constraint on the given columns to the DDL.
|
240
241
|
#
|
241
242
|
# unique(:name) # UNIQUE (name)
|
243
|
+
#
|
244
|
+
# Supports the same :deferrable option as #column.
|
242
245
|
def unique(columns, opts = {})
|
243
246
|
constraints << {:type => :unique, :columns => Array(columns)}.merge(opts)
|
244
247
|
end
|
@@ -304,6 +307,8 @@ module Sequel
|
|
304
307
|
#
|
305
308
|
# add_unique_constraint(:name) # ADD UNIQUE (name)
|
306
309
|
# add_unique_constraint(:name, :name=>:unique_name) # ADD CONSTRAINT unique_name UNIQUE (name)
|
310
|
+
#
|
311
|
+
# Supports the same :deferrable option as CreateTableGenerator#column.
|
307
312
|
def add_unique_constraint(columns, opts = {})
|
308
313
|
@operations << {:op => :add_constraint, :type => :unique, :columns => Array(columns)}.merge(opts)
|
309
314
|
end
|
@@ -493,7 +493,7 @@ module Sequel
|
|
493
493
|
sql << "(#{Array(column[:key]).map{|x| quote_identifier(x)}.join(COMMA_SEPARATOR)})" if column[:key]
|
494
494
|
sql << " ON DELETE #{on_delete_clause(column[:on_delete])}" if column[:on_delete]
|
495
495
|
sql << " ON UPDATE #{on_update_clause(column[:on_update])}" if column[:on_update]
|
496
|
-
sql
|
496
|
+
constraint_deferrable_sql_append(sql, column[:deferrable])
|
497
497
|
sql
|
498
498
|
end
|
499
499
|
|
@@ -524,9 +524,23 @@ module Sequel
|
|
524
524
|
else
|
525
525
|
raise Error, "Invalid constriant type #{constraint[:type]}, should be :check, :primary_key, :foreign_key, or :unique"
|
526
526
|
end
|
527
|
+
constraint_deferrable_sql_append(sql, constraint[:deferrable])
|
527
528
|
sql
|
528
529
|
end
|
529
530
|
|
531
|
+
# SQL DDL fragment specifying the deferrable constraint attributes.
|
532
|
+
def constraint_deferrable_sql_append(sql, defer)
|
533
|
+
case defer
|
534
|
+
when nil
|
535
|
+
when false
|
536
|
+
sql << ' NOT DEFERRABLE'
|
537
|
+
when :immediate
|
538
|
+
sql << ' DEFERRABLE INITIALLY IMMEDIATE'
|
539
|
+
else
|
540
|
+
sql << ' DEFERRABLE INITIALLY DEFERRED'
|
541
|
+
end
|
542
|
+
end
|
543
|
+
|
530
544
|
# Execute the create table statements using the generator.
|
531
545
|
def create_table_from_generator(name, generator, options)
|
532
546
|
execute_ddl(create_table_sql(name, generator, options))
|
@@ -788,9 +802,9 @@ module Sequel
|
|
788
802
|
if column[:text]
|
789
803
|
uses_clob_for_text? ? :clob : :text
|
790
804
|
elsif column[:fixed]
|
791
|
-
"char(#{column[:size]||
|
805
|
+
"char(#{column[:size]||default_string_column_size})"
|
792
806
|
else
|
793
|
-
"varchar(#{column[:size]||
|
807
|
+
"varchar(#{column[:size]||default_string_column_size})"
|
794
808
|
end
|
795
809
|
end
|
796
810
|
|
@@ -810,7 +824,7 @@ module Sequel
|
|
810
824
|
def type_literal_specific(column)
|
811
825
|
type = column[:type]
|
812
826
|
type = "double precision" if type.to_s == 'double'
|
813
|
-
column[:size] ||=
|
827
|
+
column[:size] ||= default_string_column_size if type.to_s == 'varchar'
|
814
828
|
elements = column[:size] || column[:elements]
|
815
829
|
"#{type}#{literal(Array(elements)) if elements}#{UNSIGNED if column[:unsigned]}"
|
816
830
|
end
|
@@ -58,11 +58,14 @@ module Sequel
|
|
58
58
|
a
|
59
59
|
end
|
60
60
|
|
61
|
-
# Returns the average value for the given column.
|
61
|
+
# Returns the average value for the given column/expression.
|
62
|
+
# Uses a virtual row block if no argument is given.
|
62
63
|
#
|
63
64
|
# DB[:table].avg(:number) # SELECT avg(number) FROM table LIMIT 1
|
64
65
|
# # => 3
|
65
|
-
|
66
|
+
# DB[:table].avg{function(column)} # SELECT avg(function(column)) FROM table LIMIT 1
|
67
|
+
# # => 1
|
68
|
+
def avg(column=Sequel.virtual_row(&Proc.new))
|
66
69
|
aggregate_dataset.get{avg(column)}
|
67
70
|
end
|
68
71
|
|
@@ -342,11 +345,13 @@ module Sequel
|
|
342
345
|
end
|
343
346
|
|
344
347
|
# Returns the interval between minimum and maximum values for the given
|
345
|
-
# column.
|
348
|
+
# column/expression. Uses a virtual row block if no argument is given.
|
346
349
|
#
|
347
350
|
# DB[:table].interval(:id) # SELECT (max(id) - min(id)) FROM table LIMIT 1
|
348
351
|
# # => 6
|
349
|
-
|
352
|
+
# DB[:table].interval{function(column)} # SELECT (max(function(column)) - min(function(column))) FROM table LIMIT 1
|
353
|
+
# # => 7
|
354
|
+
def interval(column=Sequel.virtual_row(&Proc.new))
|
350
355
|
aggregate_dataset.get{max(column) - min(column)}
|
351
356
|
end
|
352
357
|
|
@@ -393,19 +398,25 @@ module Sequel
|
|
393
398
|
end
|
394
399
|
end
|
395
400
|
|
396
|
-
# Returns the maximum value for the given column.
|
401
|
+
# Returns the maximum value for the given column/expression.
|
402
|
+
# Uses a virtual row block if no argument is given.
|
397
403
|
#
|
398
404
|
# DB[:table].max(:id) # SELECT max(id) FROM table LIMIT 1
|
399
405
|
# # => 10
|
400
|
-
|
406
|
+
# DB[:table].max{function(column)} # SELECT max(function(column)) FROM table LIMIT 1
|
407
|
+
# # => 7
|
408
|
+
def max(column=Sequel.virtual_row(&Proc.new))
|
401
409
|
aggregate_dataset.get{max(column)}
|
402
410
|
end
|
403
411
|
|
404
|
-
# Returns the minimum value for the given column.
|
412
|
+
# Returns the minimum value for the given column/expression.
|
413
|
+
# Uses a virtual row block if no argument is given.
|
405
414
|
#
|
406
415
|
# DB[:table].min(:id) # SELECT min(id) FROM table LIMIT 1
|
407
416
|
# # => 1
|
408
|
-
|
417
|
+
# DB[:table].min{function(column)} # SELECT min(function(column)) FROM table LIMIT 1
|
418
|
+
# # => 0
|
419
|
+
def min(column=Sequel.virtual_row(&Proc.new))
|
409
420
|
aggregate_dataset.get{min(column)}
|
410
421
|
end
|
411
422
|
|
@@ -428,11 +439,13 @@ module Sequel
|
|
428
439
|
end
|
429
440
|
|
430
441
|
# Returns a +Range+ instance made from the minimum and maximum values for the
|
431
|
-
# given column.
|
442
|
+
# given column/expression. Uses a virtual row block if no argument is given.
|
432
443
|
#
|
433
444
|
# DB[:table].range(:id) # SELECT max(id) AS v1, min(id) AS v2 FROM table LIMIT 1
|
434
445
|
# # => 1..10
|
435
|
-
|
446
|
+
# DB[:table].interval{function(column)} # SELECT max(function(column)) AS v1, min(function(column)) AS v2 FROM table LIMIT 1
|
447
|
+
# # => 0..7
|
448
|
+
def range(column=Sequel.virtual_row(&Proc.new))
|
436
449
|
if r = aggregate_dataset.select{[min(column).as(v1), max(column).as(v2)]}.first
|
437
450
|
(r[:v1]..r[:v2])
|
438
451
|
end
|
@@ -543,11 +556,14 @@ module Sequel
|
|
543
556
|
end
|
544
557
|
end
|
545
558
|
|
546
|
-
# Returns the sum for the given column.
|
559
|
+
# Returns the sum for the given column/expression.
|
560
|
+
# Uses a virtual row block if no column is given.
|
547
561
|
#
|
548
562
|
# DB[:table].sum(:id) # SELECT sum(id) FROM table LIMIT 1
|
549
563
|
# # => 55
|
550
|
-
|
564
|
+
# DB[:table].sum{function(column)} # SELECT sum(function(column)) FROM table LIMIT 1
|
565
|
+
# # => 10
|
566
|
+
def sum(column=Sequel.virtual_row(&Proc.new))
|
551
567
|
aggregate_dataset.get{sum(column)}
|
552
568
|
end
|
553
569
|
|
data/lib/sequel/dataset/query.rb
CHANGED
data/lib/sequel/dataset/sql.rb
CHANGED
@@ -206,7 +206,7 @@ module Sequel
|
|
206
206
|
COMMA_SEPARATOR = COMMA
|
207
207
|
CONDITION_FALSE = '(1 = 0)'.freeze
|
208
208
|
CONDITION_TRUE = '(1 = 1)'.freeze
|
209
|
-
COUNT_FROM_SELF_OPTS = [:distinct, :group, :sql, :limit, :compounds]
|
209
|
+
COUNT_FROM_SELF_OPTS = [:distinct, :group, :sql, :limit, :offset, :compounds]
|
210
210
|
COUNT_OF_ALL_AS_COUNT = SQL::Function.new(:count, WILDCARD).as(:count)
|
211
211
|
DATASET_ALIAS_BASE_NAME = 't'.freeze
|
212
212
|
DEFAULT = LiteralString.new('DEFAULT').freeze
|
data/lib/sequel/model.rb
CHANGED
@@ -106,7 +106,7 @@ module Sequel
|
|
106
106
|
# Class instance variables that are inherited in subclasses. If the value is <tt>:dup</tt>, dup is called
|
107
107
|
# on the superclass's instance variable when creating the instance variable in the subclass.
|
108
108
|
# If the value is +nil+, the superclass's instance variable is used directly in the subclass.
|
109
|
-
INHERITED_INSTANCE_VARIABLES = {:@allowed_columns=>:dup,
|
109
|
+
INHERITED_INSTANCE_VARIABLES = {:@allowed_columns=>:dup,
|
110
110
|
:@dataset_method_modules=>:dup, :@primary_key=>nil, :@use_transactions=>nil,
|
111
111
|
:@raise_on_save_failure=>nil, :@require_modification=>nil,
|
112
112
|
:@restricted_columns=>:dup, :@restrict_primary_key=>nil,
|
@@ -129,7 +129,6 @@ module Sequel
|
|
129
129
|
@db = nil
|
130
130
|
@db_schema = nil
|
131
131
|
@dataset_method_modules = []
|
132
|
-
@dataset_methods = {}
|
133
132
|
@overridable_methods_module = nil
|
134
133
|
@plugins = []
|
135
134
|
@primary_key = :id
|
@@ -147,7 +146,7 @@ module Sequel
|
|
147
146
|
@use_after_commit_rollback = true
|
148
147
|
@use_transactions = true
|
149
148
|
|
150
|
-
Sequel.require %w"default_inflections inflections plugins base exceptions errors", "model"
|
149
|
+
Sequel.require %w"default_inflections inflections plugins dataset_module base exceptions errors", "model"
|
151
150
|
if !defined?(::SEQUEL_NO_ASSOCIATIONS) && !ENV.has_key?('SEQUEL_NO_ASSOCIATIONS')
|
152
151
|
Sequel.require 'associations', 'model'
|
153
152
|
plugin Model::Associations
|
data/lib/sequel/model/base.rb
CHANGED
@@ -24,11 +24,6 @@ module Sequel
|
|
24
24
|
# with all of these modules.
|
25
25
|
attr_reader :dataset_method_modules
|
26
26
|
|
27
|
-
# Hash of dataset methods with method name keys and proc values that are
|
28
|
-
# stored so when the dataset changes, methods defined with def_dataset_method
|
29
|
-
# will be applied to the new dataset.
|
30
|
-
attr_reader :dataset_methods
|
31
|
-
|
32
27
|
# SQL string fragment used for faster DELETE statement creation when deleting/destroying
|
33
28
|
# model instances, or nil if the optimization should not be used. For internal use only.
|
34
29
|
attr_reader :fast_instance_delete_sql
|
@@ -179,13 +174,19 @@ module Sequel
|
|
179
174
|
end
|
180
175
|
|
181
176
|
# Extend the dataset with a module, similar to adding
|
182
|
-
# a plugin with the methods defined in DatasetMethods.
|
183
|
-
# is
|
184
|
-
#
|
185
|
-
# module
|
177
|
+
# a plugin with the methods defined in DatasetMethods.
|
178
|
+
# This is the recommended way to add methods to model datasets.
|
179
|
+
#
|
180
|
+
# If an argument, it should be a module, and is used to extend
|
181
|
+
# the underlying dataset. Otherwise an anonymous module is created, and
|
182
|
+
# if a block is given, it is module_evaled, allowing you do define
|
183
|
+
# dataset methods directly using the standard ruby def syntax.
|
184
|
+
# Returns the module given or the anonymous module created.
|
186
185
|
#
|
186
|
+
# # Usage with existing module
|
187
187
|
# Artist.dataset_module Sequel::ColumnsIntrospection
|
188
188
|
#
|
189
|
+
# # Usage with anonymous module
|
189
190
|
# Artist.dataset_module do
|
190
191
|
# def foo
|
191
192
|
# :bar
|
@@ -195,13 +196,24 @@ module Sequel
|
|
195
196
|
# # => :bar
|
196
197
|
# Artist.foo
|
197
198
|
# # => :bar
|
199
|
+
#
|
200
|
+
# Any anonymous modules created are actually instances of Sequel::Model::DatasetModule
|
201
|
+
# (a Module subclass), which allows you to call the subset method on them:
|
202
|
+
#
|
203
|
+
# Artist.dataset_module do
|
204
|
+
# subset :released, Sequel.identifier(release_date) > Sequel::CURRENT_DATE
|
205
|
+
# end
|
206
|
+
#
|
207
|
+
# Any public methods in the dataset module will have class methods created that
|
208
|
+
# call the method on the dataset, assuming that the class method is not already
|
209
|
+
# defined.
|
198
210
|
def dataset_module(mod = nil)
|
199
211
|
if mod
|
200
212
|
raise Error, "can't provide both argument and block to Model.dataset_module" if block_given?
|
201
213
|
dataset_extend(mod)
|
202
214
|
mod
|
203
215
|
else
|
204
|
-
@dataset_module ||=
|
216
|
+
@dataset_module ||= DatasetModule.new(self)
|
205
217
|
@dataset_module.module_eval(&Proc.new) if block_given?
|
206
218
|
dataset_extend(@dataset_module)
|
207
219
|
@dataset_module
|
@@ -270,6 +282,10 @@ module Sequel
|
|
270
282
|
# If a block is not given, just define a class method on the model for each argument
|
271
283
|
# that calls the dataset method of the same argument name.
|
272
284
|
#
|
285
|
+
# It is recommended that you define methods inside a block passed to #dataset_module
|
286
|
+
# instead of using this method, as #dataset_module allows you to use normal
|
287
|
+
# ruby def syntax.
|
288
|
+
#
|
273
289
|
# # Add new dataset method and class method that calls it
|
274
290
|
# Artist.def_dataset_method(:by_name){order(:name)}
|
275
291
|
# Artist.filter(:name.like('A%')).by_name
|
@@ -280,18 +296,12 @@ module Sequel
|
|
280
296
|
# Artist.server!(:server1)
|
281
297
|
def def_dataset_method(*args, &block)
|
282
298
|
raise(Error, "No arguments given") if args.empty?
|
299
|
+
|
283
300
|
if block
|
284
301
|
raise(Error, "Defining a dataset method using a block requires only one argument") if args.length > 1
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
end
|
289
|
-
args.each do |arg|
|
290
|
-
if arg.to_s =~ NORMAL_METHOD_NAME_REGEXP
|
291
|
-
instance_eval("def #{arg}(*args, &block); dataset.#{arg}(*args, &block) end", __FILE__, __LINE__) unless respond_to?(arg, true)
|
292
|
-
else
|
293
|
-
def_model_dataset_method_block(arg)
|
294
|
-
end
|
302
|
+
dataset_module{define_method(args.first, &block)}
|
303
|
+
else
|
304
|
+
args.each{|arg| def_model_dataset_method(arg)}
|
295
305
|
end
|
296
306
|
end
|
297
307
|
|
@@ -483,8 +493,7 @@ module Sequel
|
|
483
493
|
# Returns self.
|
484
494
|
#
|
485
495
|
# This changes the row_proc of the dataset to return
|
486
|
-
# model objects
|
487
|
-
# and defines methods on the dataset using the dataset_methods.
|
496
|
+
# model objects and extends the dataset with the dataset_method_modules.
|
488
497
|
# It also attempts to determine the database schema for the model,
|
489
498
|
# based on the given dataset.
|
490
499
|
#
|
@@ -514,11 +523,10 @@ module Sequel
|
|
514
523
|
@columns = @dataset.columns rescue nil
|
515
524
|
else
|
516
525
|
@dataset_method_modules.each{|m| @dataset.extend(m)} if @dataset_method_modules
|
517
|
-
@dataset_methods.each{|meth, block| @dataset.meta_def(meth, &block)} if @dataset_methods
|
518
526
|
end
|
519
527
|
@dataset.model = self if @dataset.respond_to?(:model=)
|
520
528
|
check_non_connection_error{@db_schema = (inherited ? superclass.db_schema : get_db_schema)}
|
521
|
-
|
529
|
+
reset_instance_dataset
|
522
530
|
self
|
523
531
|
end
|
524
532
|
|
@@ -577,8 +585,8 @@ module Sequel
|
|
577
585
|
end
|
578
586
|
end
|
579
587
|
|
580
|
-
#
|
581
|
-
#
|
588
|
+
# Sets up a dataset method that returns a filtered dataset.
|
589
|
+
# Sometimes thought of as a scope, and like most dataset methods,
|
582
590
|
# they can be chained.
|
583
591
|
# For example:
|
584
592
|
#
|
@@ -597,9 +605,10 @@ module Sequel
|
|
597
605
|
# Both the args given and the block are passed to <tt>Dataset#filter</tt>.
|
598
606
|
#
|
599
607
|
# This method creates dataset methods that do not accept arguments. To create
|
600
|
-
# dataset methods that accept arguments, you
|
608
|
+
# dataset methods that accept arguments, you should use define a
|
609
|
+
# method directly inside a #dataset_module block.
|
601
610
|
def subset(name, *args, &block)
|
602
|
-
|
611
|
+
dataset_module.subset(name, *args, &block)
|
603
612
|
end
|
604
613
|
|
605
614
|
# Returns name of primary table for the dataset. If the table for the dataset
|
@@ -640,10 +649,10 @@ module Sequel
|
|
640
649
|
# module if the model has a dataset. Add dataset methods to the class for all
|
641
650
|
# public dataset methods.
|
642
651
|
def dataset_extend(mod)
|
643
|
-
dataset.extend(mod) if @dataset
|
652
|
+
@dataset.extend(mod) if @dataset
|
653
|
+
reset_instance_dataset
|
644
654
|
dataset_method_modules << mod
|
645
|
-
|
646
|
-
def_dataset_method(*meths) unless meths.empty?
|
655
|
+
mod.public_instance_methods.each{|meth| def_model_dataset_method(meth)}
|
647
656
|
end
|
648
657
|
|
649
658
|
# Create a column accessor for a column with a method name that is hard to use in ruby code.
|
@@ -671,8 +680,14 @@ module Sequel
|
|
671
680
|
# Define a model method that calls the dataset method with the same name,
|
672
681
|
# only used for methods with names that can't be presented directly in
|
673
682
|
# ruby code.
|
674
|
-
def
|
675
|
-
|
683
|
+
def def_model_dataset_method(meth)
|
684
|
+
return if respond_to?(meth, true)
|
685
|
+
|
686
|
+
if meth.to_s =~ NORMAL_METHOD_NAME_REGEXP
|
687
|
+
instance_eval("def #{meth}(*args, &block); dataset.#{meth}(*args, &block) end", __FILE__, __LINE__)
|
688
|
+
else
|
689
|
+
meta_def(meth){|*args, &block| dataset.send(meth, *args, &block)}
|
690
|
+
end
|
676
691
|
end
|
677
692
|
|
678
693
|
# Get the schema from the database, fall back on checking the columns
|
@@ -799,6 +814,12 @@ module Sequel
|
|
799
814
|
"DELETE FROM #@simple_table WHERE #@simple_pk = ".freeze
|
800
815
|
end
|
801
816
|
end
|
817
|
+
|
818
|
+
# Reset the instance dataset to a modified copy of the current dataset,
|
819
|
+
# should be used whenever the model's dataset is modified.
|
820
|
+
def reset_instance_dataset
|
821
|
+
@instance_dataset = @dataset.limit(1).naked if @dataset
|
822
|
+
end
|
802
823
|
|
803
824
|
# Set the columns for this model and create accessor methods for each column.
|
804
825
|
def set_columns(new_columns)
|