sequel 4.18.0 → 4.19.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +18 -0
  3. data/MIT-LICENSE +1 -1
  4. data/doc/advanced_associations.rdoc +1 -1
  5. data/doc/association_basics.rdoc +55 -34
  6. data/doc/model_hooks.rdoc +7 -5
  7. data/doc/release_notes/4.19.0.txt +45 -0
  8. data/doc/validations.rdoc +4 -0
  9. data/lib/sequel/adapters/shared/mysql.rb +5 -3
  10. data/lib/sequel/adapters/shared/sqlanywhere.rb +3 -2
  11. data/lib/sequel/dataset/sql.rb +1 -1
  12. data/lib/sequel/extensions/migration.rb +12 -8
  13. data/lib/sequel/model/associations.rb +24 -24
  14. data/lib/sequel/model/base.rb +39 -8
  15. data/lib/sequel/plugins/accessed_columns.rb +61 -0
  16. data/lib/sequel/plugins/association_pks.rb +4 -4
  17. data/lib/sequel/plugins/boolean_readers.rb +1 -1
  18. data/lib/sequel/plugins/class_table_inheritance.rb +1 -1
  19. data/lib/sequel/plugins/column_conflicts.rb +93 -0
  20. data/lib/sequel/plugins/composition.rb +3 -3
  21. data/lib/sequel/plugins/dirty.rb +6 -6
  22. data/lib/sequel/plugins/json_serializer.rb +1 -1
  23. data/lib/sequel/plugins/list.rb +4 -4
  24. data/lib/sequel/plugins/mssql_optimistic_locking.rb +1 -1
  25. data/lib/sequel/plugins/nested_attributes.rb +2 -2
  26. data/lib/sequel/plugins/optimistic_locking.rb +3 -3
  27. data/lib/sequel/plugins/pg_array_associations.rb +23 -23
  28. data/lib/sequel/plugins/prepared_statements_associations.rb +1 -1
  29. data/lib/sequel/plugins/rcte_tree.rb +2 -2
  30. data/lib/sequel/plugins/serialization.rb +1 -1
  31. data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
  32. data/lib/sequel/plugins/timestamps.rb +2 -2
  33. data/lib/sequel/plugins/typecast_on_load.rb +1 -1
  34. data/lib/sequel/plugins/validation_class_methods.rb +4 -4
  35. data/lib/sequel/plugins/validation_helpers.rb +2 -2
  36. data/lib/sequel/version.rb +1 -1
  37. data/spec/core/dataset_spec.rb +7 -0
  38. data/spec/extensions/accessed_columns_spec.rb +51 -0
  39. data/spec/extensions/column_conflicts_spec.rb +55 -0
  40. data/spec/extensions/hook_class_methods_spec.rb +18 -5
  41. data/spec/extensions/migration_spec.rb +4 -1
  42. data/spec/extensions/static_cache_spec.rb +3 -3
  43. data/spec/model/hooks_spec.rb +76 -9
  44. data/spec/model/record_spec.rb +43 -2
  45. metadata +8 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0fc29f94c84321473e3ed262bd8ac957a265e295
4
- data.tar.gz: f25fc9635d509858d7275081fe1e5c67cf6db8ce
3
+ metadata.gz: ce1762f276f7bfdac15fe395f0eef9696c185397
4
+ data.tar.gz: f1164599a6a4bccd41e20d7ff36f443e6a46551f
5
5
  SHA512:
6
- metadata.gz: 306ffd681a632fe5aee226016f51f62beb296e7b080d69b3c791690825e370c3e85ebea3002007ee9bc0f371f0d05026a215229364af10c9dcad0cc906f1e2bd
7
- data.tar.gz: f0c9cf0fe10ce041abd556111a0f845840f2415ad6832a8ddcc2b37b0a4fcff0b538f0da3fbc95f21d7a5995df9bfb61a95bfa48a202686ba4abb4533105658d
6
+ metadata.gz: 31ecc2aef0b4d68eb9424f60cd2b1b7256b8916ca57d5fe6b74c5d3681e0b72a73014fa7225c4a87c87ee23656699ea85d027d919ac30613aa99269007676f22
7
+ data.tar.gz: fe8a6d58fab4a544a5cc5168b6721dc7d72c93567b8d17d04a940efd0ac4fb5dcf5bbe6968ed8fe9e6d52c30dbde418d571567b7f49103ec20f9f86cf9a82a7c
data/CHANGELOG CHANGED
@@ -1,3 +1,21 @@
1
+ === 4.19.0 (2015-02-01)
2
+
3
+ * Make jdbc/sqlanywhere correctly set :auto_increment entry in schema hashes (jeremyevans)
4
+
5
+ * Add Model#cancel_action for canceling actions in before hooks, instead of having the hooks return false (jeremyevans)
6
+
7
+ * Support not setting @@wait_timeout on MySQL via :timeout=>nil Database option (jeremyevans)
8
+
9
+ * Add accessed_columns plugin, recording which columns have been accessed for a model instance (jeremyevans)
10
+
11
+ * Use correct migration version when using IntegerMigrator with :allow_missing_migration_files (blerins) (#938)
12
+
13
+ * Make Dataset#union, #intersect, and #except automatically handle datasets with raw SQL (jeremyevans) (#934)
14
+
15
+ * Add column_conflicts plugin to automatically handle columns that conflict with method names (jeremyevans) (#929)
16
+
17
+ * Add Model#get_column_value and #set_column_value to get/set column values (jeremyevans) (#929)
18
+
1
19
  === 4.18.0 (2015-01-02)
2
20
 
3
21
  * Make Dataset#empty? work when the dataset is ordered by a non-column expression (pete) (#923)
data/MIT-LICENSE CHANGED
@@ -1,5 +1,5 @@
1
1
  Copyright (c) 2007-2008 Sharon Rosner
2
- Copyright (c) 2008-2014 Jeremy Evans
2
+ Copyright (c) 2008-2015 Jeremy Evans
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  of this software and associated documentation files (the "Software"), to
@@ -457,7 +457,7 @@ array of symbols and procs. For <tt>:after_load</tt> with a *_to_many associati
457
457
  the associated object argument is an array of associated objects.
458
458
 
459
459
  If any of the before callbacks return +false+, the adding/removing
460
- does not happen and it either raises a <tt>Sequel::BeforeHookFailed</tt> (the default), or
460
+ does not happen and it either raises a <tt>Sequel::HookFailed</tt> (the default), or
461
461
  returns false (if +raise_on_save_failure+ is false).
462
462
 
463
463
  === Association extensions
@@ -304,6 +304,11 @@ Examples:
304
304
 
305
305
  one_through_one associations do not have any modification methods added.
306
306
 
307
+ Note that the remove_all_* method does not call remove hooks defined on
308
+ the association, it just issues a single query to the database. If you
309
+ want to remove all associated objects and call remove hooks, iterate
310
+ over the array of associated objects and call remove_* for each.
311
+
307
312
  == Caching
308
313
 
309
314
  Associations are cached after being retrieved:
@@ -1165,16 +1170,18 @@ Called after adding an object to the association:
1165
1170
 
1166
1171
  ==== :before_remove [+one_to_many+, +many_to_many+]
1167
1172
 
1168
- Called before removing an object from the association:
1173
+ Called before removing an object from the association using <tt>remove_<i>association</i></tt>:
1169
1174
 
1170
1175
  class Artist
1171
1176
  # Don't allow removing a self-titled album
1172
1177
  one_to_many :albums, :before_remove=>proc{|ar, al| false if al.name == ar.name}
1173
1178
  end
1174
1179
 
1180
+ This is not called when using <tt>remove_all_<i>association</i></tt>.
1181
+
1175
1182
  ==== :after_remove [+one_to_many+, +many_to_many+]
1176
1183
 
1177
- Called after removing an object from the association:
1184
+ Called after removing an object from the association using <tt>remove_<i>association</i></tt>:
1178
1185
 
1179
1186
  class Artist
1180
1187
  # Log all disassociations of albums to an audit logging table
@@ -1187,6 +1194,8 @@ Called after removing an object from the association:
1187
1194
  end
1188
1195
  end
1189
1196
 
1197
+ This is not called when using <tt>remove_all_<i>association</i></tt>.
1198
+
1190
1199
  ==== :before_set [+many_to_one+, +one_to_one+]
1191
1200
 
1192
1201
  Called before the _<i>association</i>= method is called to modify the objects:
@@ -1490,72 +1499,84 @@ by the foreign/primary keys. This option causes the
1490
1499
  you want to replace the default foreign/primary key conditions that Sequel
1491
1500
  would use when eagerly graphing.
1492
1501
 
1493
- === Column Naming Conflict Options
1502
+ === Associations Based on SQL Expressions Options
1494
1503
 
1495
- Sequel's association support historically called methods on model objects
1496
- to get primary key or foreign key values instead of accessing the column
1497
- values directly, in order to allow advanced features such as associations
1498
- based on virtual column keys. Unfortunately, that causes issues if columns
1499
- are used with names that clash with existing method names, which can happen
1500
- if you want to name the association the same name as an existing column, or
1501
- if the column has the same name as an already defined method such as
1502
- <tt>object_id</tt>.
1504
+ Sequel's associations can work not just with columns, but also with
1505
+ arbitrary SQL expressions. For example, on PostgreSQL, you can store
1506
+ foreign keys to other tables in hstore, json, or jsonb columns, and Sequel
1507
+ can automatically work with such constructs, including full support for
1508
+ eager loading.
1503
1509
 
1504
- Sequel has added the following options that allow you to work around the
1505
- issue by either specifying the column name symbol or the method name symbol
1506
- to use. In most cases, these methods are designed to be used with column
1507
- aliases defined with <tt>Model.def_column_alias</tt>:
1510
+ There's actually two parts to supporting associations based on SQL
1511
+ expressions. First is you must have an instance method in the model
1512
+ that returns the value that the SQL expression would return. Second
1513
+ is you must have an SQL expression object. If Sequel has access to
1514
+ a model instance and needs to get the value of the expression, it
1515
+ calls the method to get the value. If Sequel does not have access
1516
+ to a model instance, but needs to use the SQL expression in a query,
1517
+ it will use the SQL expression object.
1518
+
1519
+ Below is an example storing foreign keys to other tables in a
1520
+ PostgreSQL hstore column, using the +pg_hstore+ and +pg_hstore_ops+
1521
+ extensions.
1508
1522
 
1509
1523
  # Example schema:
1510
- # albums artists
1511
- # :id /--> :id
1512
- # :artist --/ :name
1524
+ # albums artists
1525
+ # :id /---> :id
1526
+ # :meta ---/ :name
1513
1527
  # :name
1514
1528
  class Album < Sequel::Model
1515
- def_column_alias(:artist_id, :artist)
1516
- many_to_one :artist, :key=>:artist_id, :key_column=>:artist
1529
+ many_to_one :artist, :key_column=>Sequel.cast(Sequel.hstore(:meta)['artist_id'], Integer)
1530
+
1531
+ def artist_id
1532
+ meta['artist_id'].to_i
1533
+ end
1534
+ end
1535
+ class Artist < Sequel::Model
1536
+ one_to_many :albums, :key=>Sequel.cast(Sequel.hstore(:meta)['artist_id'], Integer), :key_method=>:artist_id
1517
1537
  end
1518
1538
 
1519
1539
  # Example schema:
1520
- # things objs
1521
- # :id /--> :id
1522
- # :object_id --/ :name
1523
- # :name
1524
- class Thing < Sequel::Model
1525
- def_column_alias(:obj_id, :object_id)
1540
+ # albums albums_artists artists
1541
+ # :id <----- :meta -------> :id
1542
+ # :name :name
1543
+ class Album < Sequel::Model
1544
+ many_to_many :artists, :left_key=>Sequel.cast(Sequel.hstore(:meta)['album_id'], Integer),
1545
+ :right_key=>Sequel.cast(Sequel.hstore(:meta)['artist_id'], Integer)
1526
1546
  end
1527
- class Obj < Sequel::Model
1528
- one_to_many :things, :key=>:object_id, :key_method=>:obj_id
1547
+ class Artist < Sequel::Model
1548
+ many_to_many :albums, :left_key=>Sequel.cast(Sequel.hstore(:meta)['artist_id'], Integer),
1549
+ :right_key=>Sequel.cast(Sequel.hstore(:meta)['album_id'], Integer)
1529
1550
  end
1530
1551
 
1531
1552
  ==== :key_column [+many_to_one+]
1532
1553
 
1533
1554
  Like the :key option, but :key references the method name, while
1534
- :key_column references the underlying column.
1555
+ :key_column references the underlying column/expression.
1535
1556
 
1536
1557
  ==== :primary_key_method [+many_to_one+]
1537
1558
 
1538
- Like the :primary_key option, but :primary_key references the column
1559
+ Like the :primary_key option, but :primary_key references the column/expression
1539
1560
  name, while :primary_key_method references the method name.
1540
1561
 
1541
1562
  ==== :primary_key_column [+one_to_many+, +one_to_one+]
1542
1563
 
1543
1564
  Like the :primary_key option, but :primary_key references the method name, while
1544
- :primary_key_column references the underlying column.
1565
+ :primary_key_column references the underlying column/expression.
1545
1566
 
1546
1567
  ==== :key_method [+one_to_many+, +one_to_one+]
1547
1568
 
1548
- Like the :key option, but :key references the column
1569
+ Like the :key option, but :key references the column/expression
1549
1570
  name, while :key_method references the method name.
1550
1571
 
1551
1572
  ==== :left_primary_key_column [+many_to_many+, +one_through_one+]
1552
1573
 
1553
1574
  Like the :left_primary_key option, but :left_primary_key references the method name, while
1554
- :left_primary_key_column references the underlying column.
1575
+ :left_primary_key_column references the underlying column/expression.
1555
1576
 
1556
1577
  ==== :right_primary_key_method [+many_to_many+, +one_through_one+]
1557
1578
 
1558
- Like the :right_primary_key option, but :right_primary_key references the column
1579
+ Like the :right_primary_key option, but :right_primary_key references the column/expression
1559
1580
  name, while :right_primary_key_method references the method name.
1560
1581
 
1561
1582
  === Private Method Overriding Options
data/doc/model_hooks.rdoc CHANGED
@@ -127,20 +127,22 @@ If you want to insert a row into the model's table without running the creation
127
127
 
128
128
  Album.insert(:name=>'RF') # does not run hooks
129
129
 
130
- == Halting Hook Processing
130
+ == Canceling Actions in Hooks
131
131
 
132
- Sequel uses a convention that if any <tt>before_*</tt> hook method returns false (but not nil), that the action will be canceled and a <tt>Sequel::HookFailed</tt> raised (or +nil+ to be returned by +save+ if +raise_on_save_failure+ is +false+). You can use this to implement validation-like behavior, that will run even if validations are skipped. For example:
132
+ Sometimes want to cancel an action in a before hook, so the action is not performed. For example, you may want to not allow destroying or saving a record in certain cases. In those cases, you can call +cancel_action+ inside the <tt>before_*</tt> hook, which will stop processing the hook and will either raise a <tt>Sequel::HookFailed</tt> exception (the default), or return +nil+ if +raise_on_save_failure+ is +false+). You can use this to implement validation-like behavior, that will run even if validations are skipped:
133
133
 
134
134
  class Album < Sequel::Model
135
135
  def before_save
136
- return false if name == ''
136
+ cancel_action if name == ''
137
137
  super
138
138
  end
139
139
  end
140
140
 
141
- While returning false is not really recommended, you should be aware of this behavior so that you do not inadvertently return false. For around hooks, neglecting to call +super+ halts hook processing in the same way as returning +false+ in a before hook. You can't halt hook processing in after hooks, since by then the main processing has already taken place.
141
+ For backwards compatibility, Sequel also treats the <tt>before_*</tt> hook methods returning +false+ as an indication that the action should be canceled. This usage is discouraged in new code, but you should be aware of this behavior so that you do not inadvertently return false.
142
142
 
143
- By default, Sequel runs hooks other than validation hooks inside a transaction, so if you abort the hook by returning false in a before hook or by raising an exception in any hook, Sequel will rollback the transaction. However, note that the implicit use of transactions when saving and destroying model objects is conditional (it depends on the model instance's +use_transactions+ setting and the <tt>:transaction</tt> option passed to save).
143
+ For around hooks, neglecting to call +super+ halts hook processing in the same way as calling +cancel_action+ in a before hook. It's probably a bad idea to use +cancel_action+ hook processing in after hooks, or after yielding in around hooks, since by then the main processing has already taken place.
144
+
145
+ By default, Sequel runs hooks other than validation hooks inside a transaction, so if you cancel the action by calling +cancel_action+ in any hook, Sequel will rollback the transaction. However, note that the implicit use of transactions when saving and destroying model objects is conditional (it depends on the model instance's +use_transactions+ setting and the <tt>:transaction</tt> option passed to save).
144
146
 
145
147
  == Conditional Hooks
146
148
 
@@ -0,0 +1,45 @@
1
+ = New Features
2
+
3
+ * Model#get_column_value and #set_column_value have been added for
4
+ getting/setting column values. Historically, to get column
5
+ values, you would just send the column name, and to set column
6
+ values you would send the column name suffixed by =. However,
7
+ this doesn't work when such methods are already defined by
8
+ ruby or Sequel itself (e.g. class, model, object_id).
9
+
10
+ Both #get_column_value and #set_column_value are just aliases to
11
+ #send, but you can safely override the methods to handle column
12
+ names that conflict with existing method names. Both the core
13
+ model code and all of the plugins that ship with Sequel have
14
+ been updated to use these new methods. External plugins are
15
+ strongly encouraged to switch to these new methods.
16
+
17
+ * A column_conflicts plugin has been added to automatically handle
18
+ columns that conflict with existing method names. So if you
19
+ have a column named "model" in your table, you can just load the
20
+ column_conflicts plugin and Sequel will handle things correctly.
21
+
22
+ * A accessed_columns plugin has been added, which records which
23
+ columns have been accessed for a model instance. This is useful
24
+ in development when you are planning on restricted the columns
25
+ selected by the dataset that retrieved the instance. SELECTing
26
+ only the columns you need can result in significant performance
27
+ increases, and the accessed_columns plugin makes that easier.
28
+
29
+ * Model#cancel_action has been added for canceling actions in
30
+ before hooks, instead of having the before hook methods return
31
+ false (which is still supported). In addition to being easier to
32
+ use, this also makes it possible to use custom exception messages
33
+ for hook failures, if you are using the default behavior of raising
34
+ exceptions on save failures.
35
+
36
+ = Other Improvements
37
+
38
+ * Dataset#union, #intersect, and #except now automatically handle
39
+ datasets with raw SQL, by wrapping such datasets in subqueries.
40
+
41
+ * The integer migrator now stores the correct migration number
42
+ when migrating with allow_missing_migration_files set.
43
+
44
+ * A :timeout=>nil Database option on MySQL no longer sets a
45
+ wait_timeout.
data/doc/validations.rdoc CHANGED
@@ -353,6 +353,10 @@ The <tt>:allow_blank</tt> is similar to the <tt>:allow_nil</tt> option, but inst
353
353
  a.website = ''
354
354
  a.valid? # true
355
355
 
356
+ If you are going to use <tt>:allow_blank</tt> you should make sure that all objects respond to the blank? method. Sequel ships with an extension that will do this for you:
357
+
358
+ Sequel.extension :blank
359
+
356
360
  === <tt>:allow_missing</tt>
357
361
 
358
362
  The <tt>:allow_missing</tt> option is different from the <tt>:allow_nil</tt> option, in that instead of checking if the attribute value is nil, it checks if the attribute is present in the model instance's values hash. <tt>:allow_nil</tt> will skip the validation when the attribute is in the values hash and has a nil value and when the attribute is not in the values hash. <tt>:allow_missing</tt> will only skip the validation when the attribute is not in the values hash. If the attribute is in the values hash but has a nil value, <tt>:allow_missing</tt> will not skip it.
@@ -274,9 +274,11 @@ module Sequel
274
274
  def mysql_connection_setting_sqls
275
275
  sqls = []
276
276
 
277
- # Increase timeout so mysql server doesn't disconnect us
278
- # Value used by default is maximum allowed value on Windows.
279
- sqls << "SET @@wait_timeout = #{opts[:timeout] || 2147483}"
277
+ if wait_timeout = opts.fetch(:timeout, 2147483)
278
+ # Increase timeout so mysql server doesn't disconnect us
279
+ # Value used by default is maximum allowed value on Windows.
280
+ sqls << "SET @@wait_timeout = #{wait_timeout}"
281
+ end
280
282
 
281
283
  # By default, MySQL 'where id is null' selects the last inserted id
282
284
  sqls << "SET SQL_AUTO_IS_NULL=0" unless opts[:auto_is_null]
@@ -56,8 +56,9 @@ module Sequel
56
56
  from{sa_describe_query("select * from #{im.call(table)}").as(:a)}.
57
57
  join(:syscolumn___b, :table_id=>:base_table_id, :column_id=>:base_column_id).
58
58
  order(:a__column_number).
59
- map do |row|
60
- row[:auto_increment] = row.delete(:is_autoincrement) == 1
59
+ map do |row|
60
+ auto_increment = row.delete(:is_autoincrement)
61
+ row[:auto_increment] = auto_increment == 1 || auto_increment == true
61
62
  row[:primary_key] = row.delete(:pkey) == 'Y'
62
63
  row[:allow_null] = row[:nulls_allowed].is_a?(Fixnum) ? row.delete(:nulls_allowed) == 1 : row.delete(:nulls_allowed)
63
64
  row[:db_type] = row.delete(:domain_name)
@@ -827,7 +827,7 @@ module Sequel
827
827
  # Return a from_self dataset if an order or limit is specified, so it works as expected
828
828
  # with UNION, EXCEPT, and INTERSECT clauses.
829
829
  def compound_from_self
830
- (@opts[:limit] || @opts[:order]) ? from_self : self
830
+ (@opts[:sql] || @opts[:limit] || @opts[:order]) ? from_self : self
831
831
  end
832
832
 
833
833
  private
@@ -523,13 +523,12 @@ module Sequel
523
523
  def run
524
524
  migrations.zip(version_numbers).each do |m, v|
525
525
  t = Time.now
526
- lv = up? ? v : v + 1
527
- db.log_info("Begin applying migration version #{lv}, direction: #{direction}")
526
+ db.log_info("Begin applying migration version #{v}, direction: #{direction}")
528
527
  checked_transaction(m) do
529
528
  m.apply(db, direction)
530
- set_migration_version(v)
529
+ set_migration_version(up? ? v : v-1)
531
530
  end
532
- db.log_info("Finished applying migration version #{lv}, direction: #{direction}, took #{sprintf('%0.6f', Time.now - t)} seconds")
531
+ db.log_info("Finished applying migration version #{v}, direction: #{direction}, took #{sprintf('%0.6f', Time.now - t)} seconds")
533
532
  end
534
533
 
535
534
  target
@@ -565,11 +564,10 @@ module Sequel
565
564
  remove_migration_classes
566
565
 
567
566
  # load migration files
568
- files[up? ? (current + 1)..target : (target + 1)..current].compact.each{|f| load(f)}
567
+ version_numbers.each{|n| load(files[n])}
569
568
 
570
569
  # get migration classes
571
- classes = Migration.descendants
572
- up? ? classes : classes.reverse
570
+ Migration.descendants
573
571
  end
574
572
 
575
573
  # Returns the latest version available in the specified directory.
@@ -606,7 +604,13 @@ module Sequel
606
604
  # so that each number in the array is the migration version
607
605
  # that will be in affect after the migration is run.
608
606
  def version_numbers
609
- up? ? ((current+1)..target).to_a : (target..(current - 1)).to_a.reverse
607
+ versions = files.
608
+ compact.
609
+ map{|f| migration_version_from_file(File.basename(f))}.
610
+ select{|v| up? ? (v > current && v <= target) : (v <= current && v > target)}.
611
+ sort
612
+ versions.reverse! unless up?
613
+ versions
610
614
  end
611
615
  end
612
616
 
@@ -355,7 +355,7 @@ module Sequel
355
355
 
356
356
  # The values that predicate_keys should match for objects to be associated.
357
357
  def predicate_key_values(object)
358
- predicate_key_methods.map{|k| object.send(k)}
358
+ predicate_key_methods.map{|k| object.get_column_value(k)}
359
359
  end
360
360
 
361
361
  # Qualify +col+ with the given table name. If +col+ is an array of columns,
@@ -732,7 +732,7 @@ module Sequel
732
732
  # many_to_one associations can only have associated objects if none of
733
733
  # the :keys options have a nil value.
734
734
  def can_have_associated_objects?(obj)
735
- !self[:keys].any?{|k| obj.send(k).nil?}
735
+ !self[:keys].any?{|k| obj.get_column_value(k).nil?}
736
736
  end
737
737
 
738
738
  # Whether the dataset needs a primary key to function, false for many_to_one associations.
@@ -897,7 +897,7 @@ module Sequel
897
897
  # one_to_many associations can only have associated objects if none of
898
898
  # the :keys options have a nil value.
899
899
  def can_have_associated_objects?(obj)
900
- !self[:primary_keys].any?{|k| obj.send(k).nil?}
900
+ !self[:primary_keys].any?{|k| obj.get_column_value(k).nil?}
901
901
  end
902
902
 
903
903
  # one_to_many and one_to_one associations can be clones
@@ -1120,7 +1120,7 @@ module Sequel
1120
1120
  # many_to_many associations can only have associated objects if none of
1121
1121
  # the :left_primary_keys options have a nil value.
1122
1122
  def can_have_associated_objects?(obj)
1123
- !self[:left_primary_keys].any?{|k| obj.send(k).nil?}
1123
+ !self[:left_primary_keys].any?{|k| obj.get_column_value(k).nil?}
1124
1124
  end
1125
1125
 
1126
1126
  # one_through_one and many_to_many associations can be clones
@@ -1851,17 +1851,17 @@ module Sequel
1851
1851
 
1852
1852
  opts[:adder] ||= proc do |o|
1853
1853
  h = {}
1854
- lcks.zip(lcpks).each{|k, pk| h[k] = send(pk)}
1855
- rcks.zip(opts.right_primary_key_methods).each{|k, pk| h[k] = o.send(pk)}
1854
+ lcks.zip(lcpks).each{|k, pk| h[k] = get_column_value(pk)}
1855
+ rcks.zip(opts.right_primary_key_methods).each{|k, pk| h[k] = o.get_column_value(pk)}
1856
1856
  _join_table_dataset(opts).insert(h)
1857
1857
  end
1858
1858
 
1859
1859
  opts[:remover] ||= proc do |o|
1860
- _join_table_dataset(opts).where(lcks.zip(lcpks.map{|k| send(k)}) + rcks.zip(opts.right_primary_key_methods.map{|k| o.send(k)})).delete
1860
+ _join_table_dataset(opts).where(lcks.zip(lcpks.map{|k| get_column_value(k)}) + rcks.zip(opts.right_primary_key_methods.map{|k| o.get_column_value(k)})).delete
1861
1861
  end
1862
1862
 
1863
1863
  opts[:clearer] ||= proc do
1864
- _join_table_dataset(opts).where(lcks.zip(lcpks.map{|k| send(k)})).delete
1864
+ _join_table_dataset(opts).where(lcks.zip(lcpks.map{|k| get_column_value(k)})).delete
1865
1865
  end
1866
1866
  end
1867
1867
 
@@ -1898,7 +1898,7 @@ module Sequel
1898
1898
  pk_meths = opts.primary_key_methods
1899
1899
 
1900
1900
  eager_load_results(opts, eo) do |assoc_record|
1901
- hash_key = uses_cks ? pk_meths.map{|k| assoc_record.send(k)} : assoc_record.send(opts.primary_key_method)
1901
+ hash_key = uses_cks ? pk_meths.map{|k| assoc_record.get_column_value(k)} : assoc_record.get_column_value(opts.primary_key_method)
1902
1902
  if objects = h[hash_key]
1903
1903
  objects.each{|object| object.associations[name] = assoc_record}
1904
1904
  end
@@ -1919,7 +1919,7 @@ module Sequel
1919
1919
 
1920
1920
  return if opts[:read_only]
1921
1921
 
1922
- opts[:setter] ||= proc{|o| cks.zip(opts.primary_key_methods).each{|k, pk| send(:"#{k}=", (o.send(pk) if o))}}
1922
+ opts[:setter] ||= proc{|o| cks.zip(opts.primary_key_methods).each{|k, pk| set_column_value(:"#{k}=", (o.get_column_value(pk) if o))}}
1923
1923
  opts[:_setter] = proc{|o| set_associated_object(opts, o)}
1924
1924
  end
1925
1925
 
@@ -1947,7 +1947,7 @@ module Sequel
1947
1947
 
1948
1948
  eager_load_results(opts, eo) do |assoc_record|
1949
1949
  assoc_record.values.delete(delete_rn) if delete_rn
1950
- hash_key = uses_cks ? km.map{|k| assoc_record.send(k)} : assoc_record.send(km)
1950
+ hash_key = uses_cks ? km.map{|k| assoc_record.get_column_value(k)} : assoc_record.get_column_value(km)
1951
1951
  next unless objects = h[hash_key]
1952
1952
  if assign_singular
1953
1953
  objects.each do |object|
@@ -1988,10 +1988,10 @@ module Sequel
1988
1988
 
1989
1989
  if one_to_one
1990
1990
  opts[:setter] ||= proc do |o|
1991
- up_ds = _apply_association_options(opts, opts.associated_dataset.where(cks.zip(cpks.map{|k| send(k)})))
1991
+ up_ds = _apply_association_options(opts, opts.associated_dataset.where(cks.zip(cpks.map{|k| get_column_value(k)})))
1992
1992
  if o
1993
1993
  up_ds = up_ds.exclude(o.pk_hash) unless o.new?
1994
- cks.zip(cpks).each{|k, pk| o.send(:"#{k}=", send(pk))}
1994
+ cks.zip(cpks).each{|k, pk| o.set_column_value(:"#{k}=", get_column_value(pk))}
1995
1995
  end
1996
1996
  checked_transaction do
1997
1997
  up_ds.update(ck_nil_hash)
@@ -2003,17 +2003,17 @@ module Sequel
2003
2003
  save_opts[:raise_on_failure] = opts[:raise_on_save_failure] != false
2004
2004
 
2005
2005
  opts[:adder] ||= proc do |o|
2006
- cks.zip(cpks).each{|k, pk| o.send(:"#{k}=", send(pk))}
2006
+ cks.zip(cpks).each{|k, pk| o.set_column_value(:"#{k}=", get_column_value(pk))}
2007
2007
  o.save(save_opts)
2008
2008
  end
2009
2009
 
2010
2010
  opts[:remover] ||= proc do |o|
2011
- cks.each{|k| o.send(:"#{k}=", nil)}
2011
+ cks.each{|k| o.set_column_value(:"#{k}=", nil)}
2012
2012
  o.save(save_opts)
2013
2013
  end
2014
2014
 
2015
2015
  opts[:clearer] ||= proc do
2016
- _apply_association_options(opts, opts.associated_dataset.where(cks.zip(cpks.map{|k| send(k)}))).update(ck_nil_hash)
2016
+ _apply_association_options(opts, opts.associated_dataset.where(cks.zip(cpks.map{|k| get_column_value(k)}))).update(ck_nil_hash)
2017
2017
  end
2018
2018
  end
2019
2019
  end
@@ -2115,7 +2115,7 @@ module Sequel
2115
2115
 
2116
2116
  # Return the associated single object using a primary key lookup on the associated class.
2117
2117
  def _load_associated_object_via_primary_key(opts)
2118
- opts.associated_class.send(:primary_key_lookup, ((fk = opts[:key]).is_a?(Array) ? fk.map{|c| send(c)} : send(fk)))
2118
+ opts.associated_class.send(:primary_key_lookup, ((fk = opts[:key]).is_a?(Array) ? fk.map{|c| get_column_value(c)} : get_column_value(fk)))
2119
2119
  end
2120
2120
 
2121
2121
  # Load the associated objects for the given association reflection and dynamic options
@@ -2315,7 +2315,7 @@ module Sequel
2315
2315
  raise Error, "callbacks should either be Procs or Symbols"
2316
2316
  end
2317
2317
  if res == false and stop_on_false
2318
- raise(BeforeHookFailed, "Unable to modify association for #{inspect}: one of the #{callback_type} hooks returned false") if raise_error
2318
+ raise(HookFailed, "Unable to modify association for #{inspect}: one of the #{callback_type} hooks returned false") if raise_error
2319
2319
  return false
2320
2320
  end
2321
2321
  end
@@ -2729,17 +2729,17 @@ END
2729
2729
  vals = if obj.is_a?(Sequel::Dataset)
2730
2730
  {(keys.length == 1 ? keys.first : keys)=>obj.select(*meths).exclude(Sequel::SQL::BooleanExpression.from_value_pairs(meths.zip([]), :OR))}
2731
2731
  else
2732
- vals = Array(obj).reject{|o| !meths.all?{|m| o.send(m)}}
2732
+ vals = Array(obj).reject{|o| !meths.all?{|m| o.get_column_value(m)}}
2733
2733
  return SQL::Constants::FALSE if vals.empty?
2734
2734
  if obj.is_a?(Array)
2735
2735
  if keys.length == 1
2736
2736
  meth = meths.first
2737
- {keys.first=>vals.map{|o| o.send(meth)}}
2737
+ {keys.first=>vals.map{|o| o.get_column_value(meth)}}
2738
2738
  else
2739
- {keys=>vals.map{|o| meths.map{|m| o.send(m)}}}
2739
+ {keys=>vals.map{|o| meths.map{|m| o.get_column_value(m)}}}
2740
2740
  end
2741
2741
  else
2742
- keys.zip(meths.map{|k| obj.send(k)})
2742
+ keys.zip(meths.map{|k| obj.get_column_value(k)})
2743
2743
  end
2744
2744
  end
2745
2745
  SQL::BooleanExpression.from_value_pairs(vals)
@@ -2786,11 +2786,11 @@ END
2786
2786
  a.each do |rec|
2787
2787
  case key
2788
2788
  when Array
2789
- if (k = key.map{|k2| rec.send(k2)}) && k.all?
2789
+ if (k = key.map{|k2| rec.get_column_value(k2)}) && k.all?
2790
2790
  id_map[k] << rec
2791
2791
  end
2792
2792
  when Symbol
2793
- if k = rec.send(key)
2793
+ if k = rec.get_column_value(key)
2794
2794
  id_map[k] << rec
2795
2795
  end
2796
2796
  else