composite_primary_keys 6.0.8 → 7.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.rdoc +2 -8
- data/lib/composite_primary_keys.rb +9 -11
- data/lib/composite_primary_keys/active_model/dirty.rb +14 -0
- data/lib/composite_primary_keys/associations/association_scope.rb +30 -32
- data/lib/composite_primary_keys/associations/has_and_belongs_to_many_association.rb +1 -2
- data/lib/composite_primary_keys/associations/has_many_association.rb +13 -14
- data/lib/composite_primary_keys/associations/has_many_through_association.rb +88 -0
- data/lib/composite_primary_keys/associations/join_dependency.rb +23 -15
- data/lib/composite_primary_keys/associations/join_dependency/join_association.rb +3 -3
- data/lib/composite_primary_keys/associations/preloader/association.rb +37 -21
- data/lib/composite_primary_keys/associations/preloader/belongs_to.rb +9 -3
- data/lib/composite_primary_keys/base.rb +0 -1
- data/lib/composite_primary_keys/composite_predicates.rb +11 -34
- data/lib/composite_primary_keys/connection_adapters/abstract/connection_specification_changes.rb +6 -5
- data/lib/composite_primary_keys/core.rb +28 -16
- data/lib/composite_primary_keys/model_schema.rb +15 -0
- data/lib/composite_primary_keys/nested_attributes.rb +8 -10
- data/lib/composite_primary_keys/persistence.rb +28 -29
- data/lib/composite_primary_keys/relation.rb +86 -16
- data/lib/composite_primary_keys/relation/finder_methods.rb +113 -59
- data/lib/composite_primary_keys/version.rb +2 -2
- data/test/abstract_unit.rb +7 -8
- data/test/fixtures/db_definitions/db2-create-tables.sql +13 -20
- data/test/fixtures/db_definitions/db2-drop-tables.sql +13 -14
- data/test/fixtures/db_definitions/mysql.sql +0 -7
- data/test/fixtures/db_definitions/oracle.drop.sql +0 -1
- data/test/fixtures/db_definitions/oracle.sql +0 -6
- data/test/fixtures/db_definitions/postgresql.sql +0 -7
- data/test/fixtures/db_definitions/sqlite.sql +24 -30
- data/test/fixtures/db_definitions/sqlserver.drop.sql +1 -4
- data/test/fixtures/db_definitions/sqlserver.sql +7 -16
- data/test/fixtures/dorm.rb +2 -2
- data/test/fixtures/suburb.rb +2 -2
- data/test/test_associations.rb +1 -2
- data/test/test_attribute_methods.rb +3 -3
- data/test/test_delete.rb +3 -5
- data/test/test_equal.rb +5 -5
- data/test/test_find.rb +2 -14
- data/test/test_predicates.rb +2 -2
- data/test/test_santiago.rb +1 -1
- data/test/test_serialize.rb +1 -1
- data/test/test_suite.rb +0 -1
- data/test/test_tutorial_example.rb +3 -3
- metadata +9 -32
- data/lib/composite_primary_keys/attribute_methods/primary_key.rb +0 -17
- data/lib/composite_primary_keys/composite_relation.rb +0 -44
- data/lib/composite_primary_keys/locking/optimistic.rb +0 -51
- data/test/fixtures/model_with_callback.rb +0 -39
- data/test/fixtures/model_with_callbacks.yml +0 -3
- data/test/test_callbacks.rb +0 -36
- data/test/test_dumpable.rb +0 -15
- data/test/test_optimistic.rb +0 -18
@@ -2,14 +2,19 @@ module ActiveRecord
|
|
2
2
|
module Associations
|
3
3
|
class Preloader
|
4
4
|
class Association
|
5
|
-
def
|
5
|
+
def query_scope(ids)
|
6
6
|
# CPK
|
7
7
|
# scope.where(association_key.in(ids))
|
8
|
-
|
9
|
-
|
8
|
+
|
9
|
+
if reflection.foreign_key.is_a?(Array)
|
10
|
+
predicate = cpk_in_predicate(table, reflection.foreign_key, ids)
|
11
|
+
scope.where(predicate)
|
12
|
+
else
|
13
|
+
scope.where(association_key.in(ids))
|
14
|
+
end
|
10
15
|
end
|
11
|
-
|
12
|
-
def associated_records_by_owner
|
16
|
+
|
17
|
+
def associated_records_by_owner(preloader)
|
13
18
|
# CPK
|
14
19
|
owners_map = owners_by_key
|
15
20
|
#owner_keys = owners_map.keys.compact
|
@@ -19,29 +24,40 @@ module ActiveRecord
|
|
19
24
|
end
|
20
25
|
end.compact.uniq
|
21
26
|
|
22
|
-
|
23
|
-
|
24
|
-
|
27
|
+
# Each record may have multiple owners, and vice-versa
|
28
|
+
records_by_owner = owners.each_with_object({}) do |owner,h|
|
29
|
+
h[owner] = []
|
30
|
+
end
|
31
|
+
|
32
|
+
if owner_keys.any?
|
25
33
|
# Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
|
26
34
|
# Make several smaller queries if necessary or make one query if the adapter supports it
|
27
|
-
sliced = owner_keys.each_slice(
|
28
|
-
|
35
|
+
sliced = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size)
|
36
|
+
|
37
|
+
records = load_slices sliced
|
38
|
+
records.each do |record, owner_key|
|
39
|
+
owners_map[owner_key].each do |owner|
|
40
|
+
records_by_owner[owner] << record
|
41
|
+
end
|
42
|
+
end
|
29
43
|
end
|
30
44
|
|
31
|
-
|
32
|
-
|
33
|
-
|
45
|
+
records_by_owner
|
46
|
+
end
|
47
|
+
|
48
|
+
def load_slices(slices)
|
49
|
+
@preloaded_records = slices.flat_map { |slice|
|
50
|
+
records_for(slice)
|
51
|
+
}
|
52
|
+
|
53
|
+
@preloaded_records.map { |record|
|
34
54
|
# CPK
|
35
|
-
#
|
55
|
+
#[record, record[association_key_name]]
|
36
56
|
owner_key = Array(association_key_name).map do |key_name|
|
37
57
|
record[key_name]
|
38
58
|
end.join(CompositePrimaryKeys::ID_SEP)
|
39
|
-
|
40
|
-
|
41
|
-
records_by_owner[owner] << record
|
42
|
-
end
|
43
|
-
end
|
44
|
-
records_by_owner
|
59
|
+
[record, owner_key]
|
60
|
+
}
|
45
61
|
end
|
46
62
|
|
47
63
|
def owners_by_key
|
@@ -59,4 +75,4 @@ module ActiveRecord
|
|
59
75
|
end
|
60
76
|
end
|
61
77
|
end
|
62
|
-
end
|
78
|
+
end
|
@@ -2,10 +2,16 @@ module ActiveRecord
|
|
2
2
|
module Associations
|
3
3
|
class Preloader
|
4
4
|
class BelongsTo
|
5
|
-
def
|
5
|
+
def query_scope(ids)
|
6
6
|
# CPK
|
7
|
-
|
8
|
-
|
7
|
+
# scope.where(association_key.in(ids))
|
8
|
+
|
9
|
+
if association_key_name.is_a?(Array)
|
10
|
+
predicate = cpk_in_predicate(table, association_key_name, ids)
|
11
|
+
scope.where(predicate)
|
12
|
+
else
|
13
|
+
scope.where(association_key.in(ids))
|
14
|
+
end
|
9
15
|
end
|
10
16
|
end
|
11
17
|
end
|
@@ -4,7 +4,6 @@ module ActiveRecord
|
|
4
4
|
|
5
5
|
class Base
|
6
6
|
include CompositePrimaryKeys::ActiveRecord::Persistence
|
7
|
-
include CompositePrimaryKeys::ActiveRecord::Locking::Optimistic
|
8
7
|
|
9
8
|
INVALID_FOR_COMPOSITE_KEYS = 'Not appropriate for composite primary keys'
|
10
9
|
NOT_IMPLEMENTED_YET = 'Not implemented for composite primary keys yet'
|
@@ -8,27 +8,10 @@ module CompositePrimaryKeys
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
when Arel::Table
|
16
|
-
table.engine
|
17
|
-
when ::ActiveRecord::Base
|
18
|
-
table
|
19
|
-
else
|
20
|
-
nil
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def cpk_or_predicate(predicates, table = nil)
|
25
|
-
engine = figure_engine(table)
|
26
|
-
predicates = predicates.map do |predicate|
|
27
|
-
predicate_sql = engine ? predicate.to_sql(engine) : predicate.to_sql
|
28
|
-
"(#{predicate_sql})"
|
29
|
-
end
|
30
|
-
predicates = "(#{predicates.join(" OR ")})"
|
31
|
-
Arel::Nodes::SqlLiteral.new(predicates)
|
11
|
+
def cpk_or_predicate(predicates)
|
12
|
+
::Arel::Nodes::Grouping.new(predicates.inject { |memo,node|
|
13
|
+
::Arel::Nodes::Or.new(memo, node)
|
14
|
+
})
|
32
15
|
end
|
33
16
|
|
34
17
|
def cpk_id_predicate(table, keys, values)
|
@@ -49,25 +32,19 @@ module CompositePrimaryKeys
|
|
49
32
|
end
|
50
33
|
|
51
34
|
def cpk_in_predicate(table, primary_keys, ids)
|
52
|
-
|
53
|
-
|
54
|
-
and_predicates = ids.map do |id_set|
|
55
|
-
eq_predicates = Array(primary_keys).zip(Array(id_set)).map do |primary_key, value|
|
56
|
-
table[primary_key].eq(value)
|
57
|
-
end
|
58
|
-
cpk_and_predicate(eq_predicates)
|
59
|
-
end
|
60
|
-
|
61
|
-
cpk_or_predicate(and_predicates, table)
|
62
|
-
else
|
63
|
-
table[primary_keys.first].in(ids.flatten)
|
35
|
+
and_predicates = ids.map do |id|
|
36
|
+
cpk_id_predicate(table, primary_keys, id)
|
64
37
|
end
|
38
|
+
cpk_or_predicate(and_predicates)
|
65
39
|
end
|
66
40
|
end
|
67
41
|
end
|
68
42
|
|
69
43
|
ActiveRecord::Associations::AssociationScope.send(:include, CompositePrimaryKeys::Predicates)
|
70
|
-
ActiveRecord::Associations::HasAndBelongsToManyAssociation.send(:include, CompositePrimaryKeys::Predicates)
|
71
44
|
ActiveRecord::Associations::JoinDependency::JoinAssociation.send(:include, CompositePrimaryKeys::Predicates)
|
72
45
|
ActiveRecord::Associations::Preloader::Association.send(:include, CompositePrimaryKeys::Predicates)
|
46
|
+
ActiveRecord::Associations::HasManyThroughAssociation.send(:include, CompositePrimaryKeys::Predicates)
|
73
47
|
ActiveRecord::Relation.send(:include, CompositePrimaryKeys::Predicates)
|
48
|
+
|
49
|
+
|
50
|
+
|
data/lib/composite_primary_keys/connection_adapters/abstract/connection_specification_changes.rb
CHANGED
@@ -5,14 +5,15 @@ module ActiveRecord
|
|
5
5
|
require "composite_primary_keys/connection_adapters/postgresql_adapter.rb"
|
6
6
|
end
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
def self.establish_connection(spec = ENV["DATABASE_URL"])
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
spec ||= ActiveRecord::ConnectionHandling::DEFAULT_ENV.call.to_sym
|
11
|
+
resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new configurations
|
12
|
+
spec = resolver.spec(spec)
|
13
|
+
|
13
14
|
# CPK
|
14
15
|
load_cpk_adapter(spec.config[:adapter])
|
15
|
-
|
16
|
+
|
16
17
|
unless respond_to?(spec.adapter_method)
|
17
18
|
raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter"
|
18
19
|
end
|
@@ -1,26 +1,39 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module Core
|
3
|
-
def
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
def init_internals
|
4
|
+
pk = self.class.primary_key
|
5
|
+
|
6
|
+
# CPK
|
7
|
+
#@attributes[pk] = nil unless @attributes.key?(pk)
|
8
|
+
unless self.composite?
|
9
|
+
@attributes[pk] = nil unless @attributes.key?(pk)
|
10
|
+
end
|
11
|
+
|
12
|
+
@aggregation_cache = {}
|
13
|
+
@association_cache = {}
|
14
|
+
@attributes_cache = {}
|
15
|
+
@readonly = false
|
16
|
+
@destroyed = false
|
17
|
+
@marked_for_destruction = false
|
18
|
+
@destroyed_by_association = nil
|
19
|
+
@new_record = true
|
20
|
+
@txn = nil
|
21
|
+
@_start_transaction_state = {}
|
22
|
+
@transaction_state = nil
|
23
|
+
@reflects_state = [false]
|
7
24
|
end
|
8
|
-
alias_method_chain :init_internals, :cpk
|
9
25
|
|
10
|
-
def initialize_dup(other)
|
26
|
+
def initialize_dup(other) # :nodoc:
|
11
27
|
cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
|
12
28
|
self.class.initialize_attributes(cloned_attributes, :serialized => false)
|
13
|
-
|
14
|
-
# cloned_attributes.delete(self.class.primary_key)
|
15
|
-
Array(self.class.primary_key).each {|key| cloned_attributes.delete(key.to_s)}
|
29
|
+
|
16
30
|
@attributes = cloned_attributes
|
17
|
-
|
18
|
-
run_callbacks(:initialize) unless _initialize_callbacks.empty?
|
19
31
|
|
20
|
-
|
21
|
-
self.class.
|
22
|
-
|
23
|
-
|
32
|
+
# CPK
|
33
|
+
#@attributes[self.class.primary_key] = nil
|
34
|
+
Array(self.class.primary_key).each {|key| @attributes[key] = nil}
|
35
|
+
|
36
|
+
run_callbacks(:initialize) unless _initialize_callbacks.empty?
|
24
37
|
|
25
38
|
@aggregation_cache = {}
|
26
39
|
@association_cache = {}
|
@@ -28,7 +41,6 @@ module ActiveRecord
|
|
28
41
|
|
29
42
|
@new_record = true
|
30
43
|
|
31
|
-
ensure_proper_type
|
32
44
|
super
|
33
45
|
end
|
34
46
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ModelSchema
|
3
|
+
module ClassMethods
|
4
|
+
def columns
|
5
|
+
@columns ||= connection.schema_cache.columns(table_name).map do |col|
|
6
|
+
col = col.dup
|
7
|
+
# CPK
|
8
|
+
#col.primary = (col.name == primary_key)
|
9
|
+
col.primary = Array(primary_key).include?(col.name)
|
10
|
+
col
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -12,10 +12,10 @@ module ActiveRecord
|
|
12
12
|
if attributes_collection.is_a? Hash
|
13
13
|
keys = attributes_collection.keys
|
14
14
|
attributes_collection = if keys.include?('id') || keys.include?(:id)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
[attributes_collection]
|
16
|
+
else
|
17
|
+
attributes_collection.values
|
18
|
+
end
|
19
19
|
end
|
20
20
|
|
21
21
|
association = association(association_name)
|
@@ -50,18 +50,16 @@ module ActiveRecord
|
|
50
50
|
end
|
51
51
|
elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes['id'].to_s }
|
52
52
|
unless call_reject_if(association_name, attributes)
|
53
|
-
# Make sure we are
|
53
|
+
# Make sure we are operating on the actual object which is in the association's
|
54
54
|
# proxy_target array (either by finding it, or adding it if not found)
|
55
|
-
|
56
|
-
|
55
|
+
# Take into account that the proxy_target may have changed due to callbacks
|
56
|
+
target_record = association.target.detect { |record| record.id.to_s == attributes['id'].to_s }
|
57
57
|
if target_record
|
58
58
|
existing_record = target_record
|
59
59
|
else
|
60
|
-
association.add_to_target(existing_record)
|
60
|
+
association.add_to_target(existing_record, :skip_callbacks)
|
61
61
|
end
|
62
|
-
end
|
63
62
|
|
64
|
-
if !call_reject_if(association_name, attributes)
|
65
63
|
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
|
66
64
|
end
|
67
65
|
else
|
@@ -2,24 +2,29 @@ module CompositePrimaryKeys
|
|
2
2
|
module ActiveRecord
|
3
3
|
module Persistence
|
4
4
|
def relation_for_destroy
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
# CPK
|
6
|
+
#pk = self.class.primary_key
|
7
|
+
#column = self.class.columns_hash[pk]
|
8
|
+
#substitute = self.class.connection.substitute_at(column, 0)
|
9
|
+
#relation = self.class.unscoped.where(
|
10
|
+
# self.class.arel_table[pk].eq(substitute))
|
11
|
+
#relation.bind_values = [[column, id]]
|
9
12
|
|
10
|
-
|
11
|
-
raise ActiveRecord::CompositeKeyError, "No primary key(s) defined for #{self.class.name}"
|
12
|
-
end
|
13
|
+
relation = self.class.unscoped
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
Array(self.class.primary_key).each_with_index do |key, index|
|
16
|
+
column = self.class.columns_hash[key]
|
17
|
+
substitute = self.class.connection.substitute_at(column, index)
|
18
|
+
relation = relation.where(self.class.arel_table[key].eq(substitute))
|
19
|
+
relation.bind_values += [[column, self[key]]]
|
16
20
|
end
|
17
21
|
|
18
|
-
relation
|
22
|
+
relation
|
19
23
|
end
|
20
|
-
|
21
24
|
|
22
25
|
def touch(name = nil)
|
26
|
+
raise ActiveRecordError, "cannot touch on a new record object" unless persisted?
|
27
|
+
|
23
28
|
attributes = timestamp_attributes_for_update_in_model
|
24
29
|
attributes << name if name
|
25
30
|
|
@@ -34,35 +39,29 @@ module CompositePrimaryKeys
|
|
34
39
|
|
35
40
|
changes[self.class.locking_column] = increment_lock if locking_enabled?
|
36
41
|
|
37
|
-
|
42
|
+
changed_attributes.except!(*changes.keys)
|
38
43
|
|
39
44
|
relation = self.class.send(:relation)
|
40
45
|
arel_table = self.class.arel_table
|
41
46
|
primary_key = self.class.primary_key
|
42
47
|
|
48
|
+
# CPK
|
49
|
+
#self.class.unscoped.where(primary_key => self[primary_key]).update_all(changes) == 1
|
43
50
|
primary_key_predicate = relation.cpk_id_predicate(arel_table, Array(primary_key), Array(id))
|
44
|
-
|
45
51
|
self.class.unscoped.where(primary_key_predicate).update_all(changes) == 1
|
52
|
+
else
|
53
|
+
true
|
46
54
|
end
|
47
55
|
end
|
48
56
|
|
49
|
-
def
|
50
|
-
|
51
|
-
|
52
|
-
klass = self.class
|
53
|
-
|
54
|
-
attributes_with_values = arel_attributes_with_values_for_update(attribute_names)
|
55
|
-
return 0 if attributes_with_values.empty?
|
57
|
+
def create_record(attribute_names = @attributes.keys)
|
58
|
+
attributes_values = arel_attributes_with_values_for_create(attribute_names)
|
56
59
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
stmt = klass.unscoped.where(ids_hash).arel.compile_update(attributes_with_values)
|
63
|
-
end
|
64
|
-
|
65
|
-
klass.connection.update stmt.to_sql
|
60
|
+
new_id = self.class.unscoped.insert attributes_values
|
61
|
+
self.id ||= new_id if self.class.primary_key
|
62
|
+
|
63
|
+
@new_record = false
|
64
|
+
id
|
66
65
|
end
|
67
66
|
end
|
68
67
|
end
|
@@ -1,25 +1,10 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
class Relation
|
3
|
-
def add_cpk_support
|
4
|
-
extend CompositePrimaryKeys::CompositeRelation
|
5
|
-
end
|
6
|
-
|
7
|
-
alias :where_values_hash_without_cpk :where_values_hash
|
8
|
-
def where_values_hash(relation_table_name = table_name)
|
9
|
-
# CPK adds this so that it finds the Equality nodes beneath the And node:
|
10
|
-
nodes_from_and = with_default_scope.where_values.grep(Arel::Nodes::And).map {|and_node| and_node.children.grep(Arel::Nodes::Equality) }.flatten
|
11
|
-
|
12
|
-
equalities = (nodes_from_and + with_default_scope.where_values.grep(Arel::Nodes::Equality)).find_all { |node|
|
13
|
-
node.left.relation.name == relation_table_name
|
14
|
-
}
|
15
|
-
|
16
|
-
Hash[equalities.map { |where| [where.left.name, where.right] }]
|
17
|
-
end
|
18
|
-
|
19
3
|
alias :initialize_without_cpk :initialize
|
20
4
|
def initialize(klass, table, values = {})
|
21
5
|
initialize_without_cpk(klass, table, values)
|
22
6
|
add_cpk_support if klass && klass.composite?
|
7
|
+
add_cpk_where_values_hash
|
23
8
|
end
|
24
9
|
|
25
10
|
alias :initialize_copy_without_cpk :initialize_copy
|
@@ -27,5 +12,90 @@ module ActiveRecord
|
|
27
12
|
initialize_copy_without_cpk(other)
|
28
13
|
add_cpk_support if klass.composite?
|
29
14
|
end
|
15
|
+
|
16
|
+
def add_cpk_support
|
17
|
+
class << self
|
18
|
+
include CompositePrimaryKeys::ActiveRecord::Batches
|
19
|
+
include CompositePrimaryKeys::ActiveRecord::Calculations
|
20
|
+
include CompositePrimaryKeys::ActiveRecord::FinderMethods
|
21
|
+
include CompositePrimaryKeys::ActiveRecord::QueryMethods
|
22
|
+
|
23
|
+
def delete(id_or_array)
|
24
|
+
# Without CPK:
|
25
|
+
# where(primary_key => id_or_array).delete_all
|
26
|
+
|
27
|
+
id_or_array = if id_or_array.kind_of?(CompositePrimaryKeys::CompositeKeys)
|
28
|
+
[id_or_array]
|
29
|
+
else
|
30
|
+
Array(id_or_array)
|
31
|
+
end
|
32
|
+
|
33
|
+
id_or_array.each do |id|
|
34
|
+
where(cpk_id_predicate(table, self.primary_key, id)).delete_all
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def destroy(id_or_array)
|
39
|
+
# Without CPK:
|
40
|
+
#if id.is_a?(Array)
|
41
|
+
# id.map { |one_id| destroy(one_id) }
|
42
|
+
#else
|
43
|
+
# find(id).destroy
|
44
|
+
#end
|
45
|
+
|
46
|
+
id_or_array = if id_or_array.kind_of?(CompositePrimaryKeys::CompositeKeys)
|
47
|
+
[id_or_array]
|
48
|
+
else
|
49
|
+
Array(id_or_array)
|
50
|
+
end
|
51
|
+
|
52
|
+
id_or_array.each do |id|
|
53
|
+
where(cpk_id_predicate(table, self.primary_key, id)).each do |record|
|
54
|
+
record.destroy
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def add_cpk_where_values_hash
|
62
|
+
class << self
|
63
|
+
def where_values_hash
|
64
|
+
# CPK adds this so that it finds the Equality nodes beneath the And node:
|
65
|
+
#equalities = where_values.grep(Arel::Nodes::Equality).find_all { |node|
|
66
|
+
# node.left.relation.name == table_name
|
67
|
+
# }
|
68
|
+
nodes_from_and = where_values.grep(Arel::Nodes::And).map {|and_node| and_node.children.grep(Arel::Nodes::Equality) }.flatten
|
69
|
+
|
70
|
+
equalities = (nodes_from_and + where_values.grep(Arel::Nodes::Equality)).find_all { |node|
|
71
|
+
node.left.relation.name == table_name
|
72
|
+
}
|
73
|
+
|
74
|
+
binds = Hash[bind_values.find_all(&:first).map { |column, v| [column.name, v] }]
|
75
|
+
|
76
|
+
Hash[equalities.map { |where|
|
77
|
+
name = where.left.name
|
78
|
+
[name, binds.fetch(name.to_s) { where.right }]
|
79
|
+
}]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def update_record(values, id, id_was) # :nodoc:
|
85
|
+
substitutes, binds = substitute_values values
|
86
|
+
|
87
|
+
# CPK
|
88
|
+
um = if self.composite?
|
89
|
+
relation = @klass.unscoped.where(cpk_id_predicate(@klass.arel_table, @klass.primary_key, id_was || id))
|
90
|
+
relation.arel.compile_update(substitutes, @klass.primary_key)
|
91
|
+
else
|
92
|
+
@klass.unscoped.where(@klass.arel_table[@klass.primary_key].eq(id_was || id)).arel.compile_update(substitutes, @klass.primary_key)
|
93
|
+
end
|
94
|
+
|
95
|
+
@klass.connection.update(
|
96
|
+
um,
|
97
|
+
'SQL',
|
98
|
+
binds)
|
99
|
+
end
|
30
100
|
end
|
31
101
|
end
|