sequel 2.10.0 → 2.11.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 (78) hide show
  1. data/CHANGELOG +51 -1
  2. data/README.rdoc +2 -2
  3. data/Rakefile +2 -2
  4. data/doc/advanced_associations.rdoc +6 -18
  5. data/doc/release_notes/1.0.txt +38 -0
  6. data/doc/release_notes/1.1.txt +143 -0
  7. data/doc/release_notes/1.3.txt +101 -0
  8. data/doc/release_notes/1.4.0.txt +53 -0
  9. data/doc/release_notes/1.5.0.txt +155 -0
  10. data/doc/release_notes/2.0.0.txt +298 -0
  11. data/doc/release_notes/2.1.0.txt +271 -0
  12. data/doc/release_notes/2.10.0.txt +328 -0
  13. data/doc/release_notes/2.11.0.txt +215 -0
  14. data/doc/release_notes/2.2.0.txt +253 -0
  15. data/doc/release_notes/2.3.0.txt +88 -0
  16. data/doc/release_notes/2.4.0.txt +106 -0
  17. data/doc/release_notes/2.5.0.txt +137 -0
  18. data/doc/release_notes/2.6.0.txt +157 -0
  19. data/doc/release_notes/2.7.0.txt +166 -0
  20. data/doc/release_notes/2.8.0.txt +171 -0
  21. data/doc/release_notes/2.9.0.txt +97 -0
  22. data/lib/sequel_core/adapters/ado.rb +3 -0
  23. data/lib/sequel_core/adapters/db2.rb +0 -11
  24. data/lib/sequel_core/adapters/dbi.rb +0 -11
  25. data/lib/sequel_core/adapters/do.rb +0 -12
  26. data/lib/sequel_core/adapters/firebird.rb +21 -16
  27. data/lib/sequel_core/adapters/informix.rb +1 -11
  28. data/lib/sequel_core/adapters/jdbc.rb +1 -13
  29. data/lib/sequel_core/adapters/jdbc/h2.rb +3 -11
  30. data/lib/sequel_core/adapters/jdbc/mysql.rb +0 -17
  31. data/lib/sequel_core/adapters/jdbc/postgresql.rb +3 -15
  32. data/lib/sequel_core/adapters/mysql.rb +31 -27
  33. data/lib/sequel_core/adapters/odbc.rb +34 -28
  34. data/lib/sequel_core/adapters/openbase.rb +0 -11
  35. data/lib/sequel_core/adapters/oracle.rb +11 -9
  36. data/lib/sequel_core/adapters/postgres.rb +14 -17
  37. data/lib/sequel_core/adapters/shared/mssql.rb +6 -15
  38. data/lib/sequel_core/adapters/shared/mysql.rb +29 -14
  39. data/lib/sequel_core/adapters/shared/oracle.rb +4 -0
  40. data/lib/sequel_core/adapters/shared/postgres.rb +30 -35
  41. data/lib/sequel_core/adapters/shared/progress.rb +4 -0
  42. data/lib/sequel_core/adapters/shared/sqlite.rb +73 -13
  43. data/lib/sequel_core/adapters/sqlite.rb +8 -18
  44. data/lib/sequel_core/adapters/utils/date_format.rb +21 -0
  45. data/lib/sequel_core/{dataset → adapters/utils}/stored_procedures.rb +0 -0
  46. data/lib/sequel_core/{dataset → adapters/utils}/unsupported.rb +0 -0
  47. data/lib/sequel_core/core_ext.rb +1 -1
  48. data/lib/sequel_core/core_sql.rb +9 -4
  49. data/lib/sequel_core/database.rb +63 -62
  50. data/lib/sequel_core/dataset.rb +9 -4
  51. data/lib/sequel_core/dataset/convenience.rb +10 -9
  52. data/lib/sequel_core/dataset/prepared_statements.rb +1 -1
  53. data/lib/sequel_core/dataset/sql.rb +130 -36
  54. data/lib/sequel_core/schema/sql.rb +2 -2
  55. data/lib/sequel_core/sql.rb +44 -51
  56. data/lib/sequel_core/version.rb +1 -1
  57. data/lib/sequel_model/associations.rb +25 -17
  58. data/lib/sequel_model/base.rb +35 -7
  59. data/lib/sequel_model/caching.rb +1 -6
  60. data/lib/sequel_model/record.rb +23 -5
  61. data/lib/sequel_model/validations.rb +20 -5
  62. data/spec/adapters/firebird_spec.rb +6 -1
  63. data/spec/adapters/mysql_spec.rb +12 -0
  64. data/spec/adapters/postgres_spec.rb +2 -2
  65. data/spec/adapters/sqlite_spec.rb +81 -2
  66. data/spec/integration/dataset_test.rb +2 -2
  67. data/spec/integration/type_test.rb +12 -2
  68. data/spec/sequel_core/core_sql_spec.rb +46 -12
  69. data/spec/sequel_core/database_spec.rb +24 -12
  70. data/spec/sequel_core/dataset_spec.rb +82 -32
  71. data/spec/sequel_core/schema_spec.rb +16 -0
  72. data/spec/sequel_model/associations_spec.rb +89 -0
  73. data/spec/sequel_model/base_spec.rb +66 -0
  74. data/spec/sequel_model/eager_loading_spec.rb +32 -0
  75. data/spec/sequel_model/record_spec.rb +9 -9
  76. data/spec/sequel_model/spec_helper.rb +3 -0
  77. data/spec/sequel_model/validations_spec.rb +63 -3
  78. metadata +41 -4
@@ -12,7 +12,7 @@ module Sequel
12
12
  SET_DEFAULT = 'SET DEFAULT'.freeze
13
13
  SET_NULL = 'SET NULL'.freeze
14
14
  TYPES = Hash.new {|h, k| k}
15
- TYPES.merge!(:double=>'double precision', String=>'varchar',
15
+ TYPES.merge!(:double=>'double precision', String=>'varchar(255)',
16
16
  Integer=>'integer', Fixnum=>'integer', Bignum=>'bigint',
17
17
  Float=>'double precision', BigDecimal=>'numeric', Numeric=>'numeric',
18
18
  Date=>'date', DateTime=>'timestamp', Time=>'timestamp', File=>'blob',
@@ -124,7 +124,7 @@ module Sequel
124
124
  # for certain databases.
125
125
  def default_index_name(table_name, columns)
126
126
  schema, table = schema_and_table(table_name)
127
- "#{"#{schema}_" if schema and schema != default_schema}#{table}_#{columns.join(UNDERSCORE)}_index"
127
+ "#{"#{schema}_" if schema and schema != default_schema}#{table}_#{columns.map{|c| c.is_one_of?(String, Symbol) ? c : literal(c).gsub(/\W/, '_')}.join(UNDERSCORE)}_index"
128
128
  end
129
129
 
130
130
  # The SQL to drop an index for the table.
@@ -181,21 +181,21 @@ module Sequel
181
181
  module CastMethods
182
182
  # Cast the reciever to the given SQL type
183
183
  def cast(sql_type)
184
- IrregularFunction.new(:cast, self, :AS, sql_type.to_s.lit)
184
+ Cast.new(self, sql_type)
185
185
  end
186
186
  alias_method :cast_as, :cast
187
187
 
188
188
  # Cast the reciever to the given SQL type (or integer if none given),
189
189
  # and return the result as a NumericExpression.
190
190
  def cast_numeric(sql_type = nil)
191
- cast(sql_type || :integer).sql_number
191
+ cast(sql_type || Integer).sql_number
192
192
  end
193
193
 
194
194
  # Cast the reciever to the given SQL type (or text if none given),
195
195
  # and return the result as a StringExpression, so you can use +
196
196
  # directly on the result for SQL string concatenation.
197
197
  def cast_string(sql_type = nil)
198
- cast(sql_type || :text).sql_string
198
+ cast(sql_type || String).sql_string
199
199
  end
200
200
  end
201
201
 
@@ -336,12 +336,12 @@ module Sequel
336
336
  module ComplexExpressionMethods
337
337
  # Extract a datetime_part (e.g. year, month) from self:
338
338
  #
339
- # :date.extract(:year) # SQL: extract(year FROM date)
339
+ # :date.extract(:year) # SQL: extract(year FROM "date")
340
340
  #
341
341
  # Also has the benefit of returning the result as a
342
342
  # NumericExpression instead of a generic ComplexExpression.
343
343
  def extract(datetime_part)
344
- IrregularFunction.new(:extract, datetime_part.to_s.lit, :FROM, self).sql_number
344
+ Function.new(:extract, PlaceholderLiteralString.new("#{datetime_part} FROM ?", [self])).sql_number
345
345
  end
346
346
 
347
347
  # Return a BooleanExpression representation of self.
@@ -400,22 +400,6 @@ module Sequel
400
400
  end
401
401
  end
402
402
 
403
- # Represents an SQL array. Added so it is possible to deal with a
404
- # ruby array of all two pairs as an SQL array instead of an ordered
405
- # hash-like conditions specifier.
406
- class SQLArray < Expression
407
- # Create an object with the given array.
408
- def initialize(array)
409
- @array = array
410
- end
411
-
412
- # Delegate the creation of the resulting SQL to the given dataset,
413
- # since it may be database dependent.
414
- def to_s(ds)
415
- ds.array_sql(@array)
416
- end
417
- end
418
-
419
403
  # Blob is used to represent binary data in the Ruby environment that is
420
404
  # stored as a blob type in the database. In PostgreSQL, the blob type is
421
405
  # called bytea. Sequel represents binary data as a Blob object because
@@ -423,9 +407,10 @@ module Sequel
423
407
  # escaped.
424
408
  class Blob < ::String
425
409
  # return self.
426
- def to_blob
410
+ def to_sequel_blob
427
411
  self
428
412
  end
413
+ alias to_blob to_sequel_blob
429
414
  end
430
415
 
431
416
  # Subclass of ComplexExpression where the expression results
@@ -516,6 +501,27 @@ module Sequel
516
501
  end
517
502
  end
518
503
 
504
+ # Represents a cast of an SQL expression to a specific type.
505
+ class Cast < GenericExpression
506
+ # The expression to cast
507
+ attr_reader :expr
508
+
509
+ # The type to which to cast the expression
510
+ attr_reader :type
511
+
512
+ # Set the attributes to the given arguments
513
+ def initialize(expr, type)
514
+ @expr = expr
515
+ @type = type
516
+ end
517
+
518
+ # Delegate the creation of the resulting SQL to the given dataset,
519
+ # since it may be database dependent.
520
+ def to_s(ds)
521
+ ds.cast_sql(expr, type)
522
+ end
523
+ end
524
+
519
525
  # Represents all columns in a given table, table.* in SQL
520
526
  class ColumnAll < SpecificExpression
521
527
  # The table containing the columns being selected
@@ -586,35 +592,6 @@ module Sequel
586
592
  end
587
593
  end
588
594
 
589
- # IrregularFunction is used for the SQL EXTRACT and CAST functions,
590
- # which don't use regular function calling syntax. The IrregularFunction
591
- # replaces the commas the regular function uses with a custom
592
- # join string.
593
- #
594
- # This shouldn't be used directly, see CastMethods#cast and
595
- # ComplexExpressionMethods#extract.
596
- class IrregularFunction < Function
597
- # The arguments to pass to the function (may be blank)
598
- attr_reader :arg1, :arg2
599
-
600
- # The SQL function to call
601
- attr_reader :f
602
-
603
- # The literal string to use in place of a comma to join arguments
604
- attr_reader :joiner
605
-
606
- # Set the attributes to the given arguments
607
- def initialize(f, arg1, joiner, arg2)
608
- @f, @arg1, @joiner, @arg2 = f, arg1, joiner, arg2
609
- end
610
-
611
- # Delegate the creation of the resulting SQL to the given dataset,
612
- # since it may be database dependent.
613
- def to_s(ds)
614
- ds.irregular_function_sql(self)
615
- end
616
- end
617
-
618
595
  # Represents an SQL JOIN clause, used for joining tables.
619
596
  class JoinClause < SpecificExpression
620
597
  # The type of join to do
@@ -785,6 +762,22 @@ module Sequel
785
762
  end
786
763
  end
787
764
 
765
+ # Represents an SQL array. Added so it is possible to deal with a
766
+ # ruby array of all two pairs as an SQL array instead of an ordered
767
+ # hash-like conditions specifier.
768
+ class SQLArray < Expression
769
+ # Create an object with the given array.
770
+ def initialize(array)
771
+ @array = array
772
+ end
773
+
774
+ # Delegate the creation of the resulting SQL to the given dataset,
775
+ # since it may be database dependent.
776
+ def to_s(ds)
777
+ ds.array_sql(@array)
778
+ end
779
+ end
780
+
788
781
  # Represents an SQL array access, with multiple possible arguments.
789
782
  class Subscript < GenericExpression
790
783
  # The SQL array column
@@ -1,6 +1,6 @@
1
1
  module Sequel
2
2
  MAJOR = 2
3
- MINOR = 10
3
+ MINOR = 11
4
4
  TINY = 0
5
5
 
6
6
  VERSION = [MAJOR, MINOR, TINY].join('.')
@@ -51,6 +51,15 @@
51
51
  # one_to_many :attributes
52
52
  # has_many :attributes
53
53
  module Sequel::Model::Associations
54
+ # This module contains methods added to all association datasets
55
+ module DatasetMethods
56
+ # The model object that created the association dataset
57
+ attr_accessor :model_object
58
+
59
+ # The association reflection related to the association dataset
60
+ attr_accessor :association_reflection
61
+ end
62
+
54
63
  # Array of all association reflections for this model class
55
64
  def all_association_reflections
56
65
  association_reflections.values
@@ -100,6 +109,10 @@ module Sequel::Model::Associations
100
109
  # - :class - The associated class or its name. If not
101
110
  # given, uses the association's name, which is camelized (and
102
111
  # singularized unless the type is :many_to_one)
112
+ # - :clone - Merge the current options and block into the options and block used in defining
113
+ # the given association. Can be used to DRY up a bunch of similar associations that
114
+ # all share the same options such as :class and :key, while changing the order and block used.
115
+ # - :conditions - The conditions to use to filter the association, can be any argument passed to filter.
103
116
  # - :dataset - A proc that is instance_evaled to get the base dataset
104
117
  # to use for the _dataset method (before the other options are applied).
105
118
  # - :eager - The associations to eagerly load via EagerLoading#eager when loading the associated object(s).
@@ -126,7 +139,8 @@ module Sequel::Model::Associations
126
139
  # - :graph_block - The block to pass to join_table when eagerly loading
127
140
  # the association via eager_graph.
128
141
  # - :graph_conditions - The additional conditions to use on the SQL join when eagerly loading
129
- # the association via eager_graph. Should be a hash or an array of all two pairs.
142
+ # the association via eager_graph. Should be a hash or an array of all two pairs. If not
143
+ # specified, the :conditions option is used if it is a hash or array of all two pairs.
130
144
  # - :graph_join_type - The type of SQL join to use when eagerly loading the association via
131
145
  # eager_graph. Defaults to :left_outer.
132
146
  # - :graph_only_conditions - The conditions to use on the SQL join when eagerly loading
@@ -203,11 +217,16 @@ module Sequel::Model::Associations
203
217
  raise(Error, 'Model.associate name argument must be a symbol') unless Symbol === name
204
218
 
205
219
  # merge early so we don't modify opts
206
- opts = opts.merge(:type => type, :name => name, :block => block, :cache => true, :model => self)
220
+ orig_opts = opts.dup
221
+ orig_opts = association_reflection(opts[:clone])[:orig_opts].merge(orig_opts) if opts[:clone]
222
+ opts = orig_opts.merge(:type => type, :name => name, :cache => true, :model => self)
223
+ opts[:block] = block if block
207
224
  opts = assoc_class.new.merge!(opts)
208
225
  opts[:eager_block] = block unless opts.include?(:eager_block)
209
226
  opts[:graph_join_type] ||= :left_outer
210
227
  opts[:order_eager_graph] = true unless opts.include?(:order_eager_graph)
228
+ conds = opts[:conditions]
229
+ opts[:graph_conditions] = conds if !opts.include?(:graph_conditions) and (conds.is_a?(Hash) or (conds.is_a?(Array) and conds.all_two_pairs?))
211
230
  opts[:graph_conditions] = opts[:graph_conditions] ? opts[:graph_conditions].to_a : []
212
231
  opts[:graph_select] = Array(opts[:graph_select]) if opts[:graph_select]
213
232
  [:before_add, :before_remove, :after_add, :after_remove, :after_load, :extend].each do |cb_type|
@@ -225,6 +244,9 @@ module Sequel::Model::Associations
225
244
 
226
245
  send(:"def_#{type}", opts)
227
246
 
247
+ orig_opts.delete(:clone)
248
+ orig_opts.merge!(:class_name=>opts[:class_name], :class=>opts[:class], :block=>block)
249
+ opts[:orig_opts] = orig_opts
228
250
  # don't add to association_reflections until we are sure there are no errors
229
251
  association_reflections[name] = opts
230
252
  end
@@ -386,21 +408,7 @@ module Sequel::Model::Associations
386
408
  return if opts[:read_only]
387
409
 
388
410
  association_module_private_def(opts._setter_method){|o| send(:"#{key}=", (o.send(opts.primary_key) if o))}
389
-
390
- association_module_def(opts.setter_method) do |o|
391
- raise(Sequel::Error, "model object #{model} does not have a primary key") if o && !o.pk
392
- old_val = send(opts.association_method)
393
- return o if old_val == o
394
- return if old_val and run_association_callbacks(opts, :before_remove, old_val) == false
395
- return if o and run_association_callbacks(opts, :before_add, o) == false
396
- send(opts._setter_method, o)
397
- associations[name] = o
398
- remove_reciprocal_object(opts, old_val) if old_val
399
- add_reciprocal_object(opts, o) if o
400
- run_association_callbacks(opts, :after_add, o) if o
401
- run_association_callbacks(opts, :after_remove, old_val) if old_val
402
- o
403
- end
411
+ association_module_def(opts.setter_method){|o| set_associated_object(opts, o)}
404
412
  end
405
413
 
406
414
  # Adds one_to_many association instance methods
@@ -2,16 +2,25 @@ module Sequel
2
2
  class Model
3
3
  @allowed_columns = nil
4
4
  @association_reflections = {}
5
+ @cache_store = nil
6
+ @cache_ttl = nil
7
+ @db = nil
8
+ @db_schema = nil
5
9
  @dataset_methods = {}
6
10
  @hooks = {}
11
+ @overridable_methods_module = nil
7
12
  @primary_key = :id
8
13
  @raise_on_save_failure = true
9
14
  @raise_on_typecast_failure = true
10
15
  @restrict_primary_key = true
11
16
  @restricted_columns = nil
17
+ @simple_pk = nil
18
+ @simple_table = nil
19
+ @skip_superclass_validations = nil
12
20
  @sti_dataset = nil
13
21
  @sti_key = nil
14
22
  @strict_param_setting = true
23
+ @transform = nil
15
24
  @typecast_empty_string_to_nil = true
16
25
  @typecast_on_assignment = true
17
26
 
@@ -41,6 +50,14 @@ module Sequel
41
50
  # (default: no columns).
42
51
  metaattr_reader :restricted_columns
43
52
 
53
+ # Should be the literal primary key column name if this Model's table has a simple primary key, or
54
+ # nil if the model has a compound primary key or no primary key.
55
+ metaattr_reader :simple_pk
56
+
57
+ # Should be the literal table name if this Model's dataset is a simple table (no select, order, join, etc.),
58
+ # or nil otherwise.
59
+ metaattr_reader :simple_table
60
+
44
61
  # The base dataset for STI, to which filters are added to get
45
62
  # only the models for the specific STI subclass.
46
63
  metaattr_reader :sti_dataset
@@ -68,15 +85,19 @@ module Sequel
68
85
  left_outer_join limit map multi_insert naked order order_by order_more
69
86
  paginate print query range reverse_order right_outer_join select
70
87
  select_all select_more server set set_graph_aliases single_value size to_csv to_hash
71
- transform union uniq unfiltered unordered update where'.map{|x| x.to_sym}
88
+ transform union uniq unfiltered unordered update where with_sql'.map{|x| x.to_sym}
72
89
 
73
90
  # Instance variables that are inherited in subclasses
74
91
  INHERITED_INSTANCE_VARIABLES = {:@allowed_columns=>:dup, :@cache_store=>nil,
75
92
  :@cache_ttl=>nil, :@dataset_methods=>:dup, :@primary_key=>nil,
76
93
  :@raise_on_save_failure=>nil, :@restricted_columns=>:dup, :@restrict_primary_key=>nil,
94
+ :@simple_pk=>nil, :@simple_table=>nil,
77
95
  :@sti_dataset=>nil, :@sti_key=>nil, :@strict_param_setting=>nil,
78
96
  :@typecast_empty_string_to_nil=>nil, :@typecast_on_assignment=>nil,
79
97
  :@raise_on_typecast_failure=>nil, :@association_reflections=>:dup}
98
+
99
+ # Empty instance variables, for -w compliance
100
+ EMPTY_INSTANCE_VARIABLES = [:@overridable_methods_module, :@transform, :@db, :@skip_superclass_validations]
80
101
 
81
102
  # Returns the first record from the database matching the conditions.
82
103
  # If a hash is given, it is used as the conditions. If another
@@ -85,11 +106,12 @@ module Sequel
85
106
  # first before a dataset lookup is attempted unless a hash is supplied.
86
107
  def self.[](*args)
87
108
  args = args.first if (args.size == 1)
88
-
89
- if Hash === args
90
- dataset[args]
109
+ return dataset[args] if args.is_a?(Hash)
110
+ return cache_lookup(args) if @cache_store
111
+ if t = simple_table and p = simple_pk
112
+ with_sql("SELECT * FROM #{t} WHERE #{p} = #{dataset.literal(args)} LIMIT 1").first
91
113
  else
92
- @cache_store ? cache_lookup(args) : dataset[primary_key_hash(args)]
114
+ dataset[primary_key_hash(args)]
93
115
  end
94
116
  end
95
117
 
@@ -174,6 +196,7 @@ module Sequel
174
196
  # Modify and return eager loading dataset based on association options
175
197
  def self.eager_loading_dataset(opts, ds, select, associations)
176
198
  ds = ds.select(*select) if select
199
+ ds = ds.filter(opts[:conditions]) if opts[:conditions]
177
200
  ds = ds.order(*opts[:order]) if opts[:order]
178
201
  ds = ds.eager(opts[:eager]) if opts[:eager]
179
202
  ds = ds.eager_graph(opts[:eager_graph]) if opts[:eager_graph]
@@ -201,6 +224,7 @@ module Sequel
201
224
  def self.inherited(subclass)
202
225
  sup_class = subclass.superclass
203
226
  ivs = subclass.instance_variables.collect{|x| x.to_s}
227
+ EMPTY_INSTANCE_VARIABLES.each{|iv| subclass.instance_variable_set(iv, nil) unless ivs.include?(iv.to_s)}
204
228
  INHERITED_INSTANCE_VARIABLES.each do |iv, dup|
205
229
  next if ivs.include?(iv.to_s)
206
230
  sup_class_value = sup_class.instance_variable_get(iv)
@@ -211,7 +235,7 @@ module Sequel
211
235
  db
212
236
  begin
213
237
  if sup_class == Model
214
- subclass.set_dataset(Model.db[subclass.implicit_table_name]) unless subclass.name.blank?
238
+ subclass.set_dataset(subclass.implicit_table_name) unless subclass.name.blank?
215
239
  elsif ds = sup_class.instance_variable_get(:@dataset)
216
240
  subclass.set_dataset(sup_class.sti_key ? sup_class.sti_dataset.filter(sup_class.sti_key=>subclass.name.to_s) : ds.clone, :inherited=>true)
217
241
  end
@@ -239,7 +263,7 @@ module Sequel
239
263
  # Mark the model as not having a primary key. Not having a primary key
240
264
  # can cause issues, among which is that you won't be able to update records.
241
265
  def self.no_primary_key
242
- @primary_key = nil
266
+ @simple_pk = @primary_key = nil
243
267
  end
244
268
 
245
269
  # Returns primary key attribute hash. If using a composite primary key
@@ -317,8 +341,10 @@ module Sequel
317
341
  inherited = opts[:inherited]
318
342
  @dataset = case ds
319
343
  when Symbol
344
+ @simple_table = db.literal(ds)
320
345
  db[ds]
321
346
  when Dataset
347
+ @simple_table = nil
322
348
  @db = ds.db
323
349
  ds
324
350
  else
@@ -327,6 +353,7 @@ module Sequel
327
353
  @dataset.set_model(self)
328
354
  @dataset.transform(@transform) if @transform
329
355
  if inherited
356
+ @simple_table = sti_key ? nil : superclass.simple_table
330
357
  @columns = @dataset.columns rescue nil
331
358
  else
332
359
  @dataset.extend(DatasetMethods)
@@ -354,6 +381,7 @@ module Sequel
354
381
  # You can set it to nil to not have a primary key, but that
355
382
  # cause certain things not to work, see #no_primary_key.
356
383
  def self.set_primary_key(*key)
384
+ @simple_pk = key.length == 1 ? db.literal(key.first) : nil
357
385
  @primary_key = (key.length == 1) ? key[0] : key.flatten
358
386
  end
359
387
 
@@ -17,7 +17,7 @@ module Sequel
17
17
  def self.set_cache(store, opts = {})
18
18
  @cache_store = store
19
19
  @cache_ttl = opts[:ttl] || 3600
20
- before_save :cache_delete_unless_new
20
+ before_update :cache_delete
21
21
  before_update_values :cache_delete
22
22
  before_delete :cache_delete
23
23
  end
@@ -78,10 +78,5 @@ module Sequel
78
78
  def cache_delete
79
79
  model.send(:cache_delete, cache_key)
80
80
  end
81
-
82
- # Delete this object from the cache unless it is a new record
83
- def cache_delete_unless_new
84
- cache_delete unless new?
85
- end
86
81
  end
87
82
  end
@@ -345,8 +345,12 @@ module Sequel
345
345
  def _dataset(opts)
346
346
  raise(Sequel::Error, "model object #{model} does not have a primary key") if opts.dataset_need_primary_key? && !pk
347
347
  ds = send(opts._dataset_method)
348
+ ds.extend(Associations::DatasetMethods)
349
+ ds.model_object = self
350
+ ds.association_reflection = opts
348
351
  opts[:extend].each{|m| ds.extend(m)}
349
352
  ds = ds.select(*opts.select) if opts.select
353
+ ds = ds.filter(opts[:conditions]) if opts[:conditions]
350
354
  ds = ds.order(*opts[:order]) if opts[:order]
351
355
  ds = ds.limit(*opts[:limit]) if opts[:limit]
352
356
  ds = ds.eager(*opts[:eager]) if opts[:eager]
@@ -470,6 +474,24 @@ module Sequel
470
474
  end
471
475
  end
472
476
 
477
+ # Set the given object as the associated object for the given association
478
+ def set_associated_object(opts, o)
479
+ raise(Sequel::Error, "model object #{model} does not have a primary key") if o && !o.pk
480
+ old_val = send(opts.association_method)
481
+ return o if old_val == o
482
+ return if old_val and run_association_callbacks(opts, :before_remove, old_val) == false
483
+ return if o and run_association_callbacks(opts, :before_add, o) == false
484
+ send(opts._setter_method, o)
485
+ associations[opts[:name]] = o
486
+ remove_reciprocal_object(opts, old_val) if old_val
487
+ if o
488
+ add_reciprocal_object(opts, o)
489
+ run_association_callbacks(opts, :after_add, o)
490
+ end
491
+ run_association_callbacks(opts, :after_remove, old_val) if old_val
492
+ o
493
+ end
494
+
473
495
  # Set the columns, filtered by the only and except arrays.
474
496
  def set_restricted(hash, only, except)
475
497
  columns_not_set = model.instance_variable_get(:@columns).blank?
@@ -527,11 +549,7 @@ module Sequel
527
549
  begin
528
550
  model.db.typecast_value(col_schema[:type], value)
529
551
  rescue Error::InvalidValue
530
- if raise_on_typecast_failure
531
- raise
532
- else
533
- value
534
- end
552
+ raise_on_typecast_failure ? raise : value
535
553
  end
536
554
  end
537
555