composite_primary_keys 7.0.16 → 8.0.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.
- checksums.yaml +4 -4
- data/History.rdoc +600 -623
- data/lib/composite_primary_keys.rb +113 -115
- data/lib/composite_primary_keys/associations/association.rb +23 -23
- data/lib/composite_primary_keys/associations/association_scope.rb +73 -77
- data/lib/composite_primary_keys/associations/collection_association.rb +15 -0
- data/lib/composite_primary_keys/associations/has_many_association.rb +69 -56
- data/lib/composite_primary_keys/associations/has_many_through_association.rb +30 -28
- data/lib/composite_primary_keys/associations/join_dependency.rb +87 -89
- data/lib/composite_primary_keys/associations/join_dependency/join_association.rb +22 -22
- data/lib/composite_primary_keys/associations/preloader/association.rb +90 -78
- data/lib/composite_primary_keys/associations/preloader/belongs_to.rb +19 -19
- data/lib/composite_primary_keys/associations/singular_association.rb +15 -0
- data/lib/composite_primary_keys/attribute_methods.rb +9 -0
- data/lib/composite_primary_keys/attribute_methods/dirty.rb +29 -26
- data/lib/composite_primary_keys/attribute_methods/read.rb +19 -34
- data/lib/composite_primary_keys/attribute_methods/write.rb +30 -36
- data/lib/composite_primary_keys/attribute_set/builder.rb +20 -0
- data/lib/composite_primary_keys/base.rb +135 -129
- data/lib/composite_primary_keys/composite_arrays.rb +30 -30
- data/lib/composite_primary_keys/composite_predicates.rb +50 -50
- data/lib/composite_primary_keys/composite_relation.rb +48 -48
- data/lib/composite_primary_keys/connection_adapters/abstract/connection_specification_changes.rb +2 -4
- data/lib/composite_primary_keys/connection_adapters/postgresql_adapter.rb +46 -60
- data/lib/composite_primary_keys/core.rb +69 -47
- data/lib/composite_primary_keys/fixtures.rb +22 -22
- data/lib/composite_primary_keys/persistence.rb +56 -60
- data/lib/composite_primary_keys/relation.rb +68 -56
- data/lib/composite_primary_keys/relation/calculations.rb +79 -75
- data/lib/composite_primary_keys/relation/finder_methods.rb +175 -196
- data/lib/composite_primary_keys/relation/query_methods.rb +40 -40
- data/lib/composite_primary_keys/sanitization.rb +52 -52
- data/lib/composite_primary_keys/validations/uniqueness.rb +36 -37
- data/lib/composite_primary_keys/version.rb +8 -8
- data/tasks/databases/oracle.rake +25 -25
- data/tasks/databases/sqlserver.rake +27 -40
- data/test/abstract_unit.rb +113 -113
- data/test/connections/databases.ci.yml +15 -15
- data/test/connections/databases.example.yml +18 -18
- data/test/connections/native_oracle/connection.rb +11 -11
- data/test/connections/native_oracle_enhanced/connection.rb +16 -16
- data/test/connections/native_sqlserver/connection.rb +11 -14
- data/test/fixtures/comment.rb +7 -7
- data/test/fixtures/db_definitions/db2-create-tables.sql +125 -126
- data/test/fixtures/db_definitions/db2-drop-tables.sql +18 -18
- data/test/fixtures/db_definitions/mysql.sql +207 -208
- data/test/fixtures/db_definitions/oracle.drop.sql +45 -45
- data/test/fixtures/db_definitions/oracle.sql +222 -223
- data/test/fixtures/db_definitions/postgresql.sql +209 -210
- data/test/fixtures/db_definitions/sqlite.sql +196 -197
- data/test/fixtures/db_definitions/sqlserver.drop.sql +91 -94
- data/test/fixtures/db_definitions/sqlserver.sql +225 -232
- data/test/fixtures/dorm.rb +2 -2
- data/test/fixtures/employee.rb +5 -5
- data/test/fixtures/membership.rb +6 -6
- data/test/fixtures/membership_statuses.yml +16 -16
- data/test/fixtures/memberships.yml +10 -10
- data/test/fixtures/product_tariffs.yml +14 -14
- data/test/fixtures/reference_code.rb +7 -7
- data/test/fixtures/restaurants_suburb.rb +2 -2
- data/test/fixtures/suburb.rb +5 -5
- data/test/fixtures/topic.rb +5 -5
- data/test/fixtures/topic_source.rb +6 -6
- data/test/fixtures/topic_sources.yml +3 -3
- data/test/fixtures/topics.yml +8 -8
- data/test/fixtures/users.yml +10 -10
- data/test/test_associations.rb +295 -275
- data/test/test_attribute_methods.rb +63 -63
- data/test/test_attributes.rb +60 -60
- data/test/test_calculations.rb +37 -42
- data/test/test_callbacks.rb +99 -99
- data/test/test_create.rb +112 -112
- data/test/test_delete.rb +148 -152
- data/test/test_delete_all.rb +28 -26
- data/test/test_dumpable.rb +15 -15
- data/test/test_enum.rb +21 -20
- data/test/test_equal.rb +26 -26
- data/test/test_find.rb +118 -118
- data/test/test_habtm.rb +113 -113
- data/test/test_nested_attributes.rb +124 -124
- data/test/test_polymorphic.rb +26 -26
- data/test/test_predicates.rb +40 -40
- data/test/test_santiago.rb +23 -23
- data/test/test_suite.rb +33 -34
- data/test/test_touch.rb +23 -23
- data/test/test_tutorial_example.rb +21 -21
- data/test/test_update.rb +71 -71
- metadata +9 -13
- data/lib/composite_primary_keys/arel/visitors/to_sql.rb +0 -20
- data/lib/composite_primary_keys/associations/has_and_belongs_to_many_association.rb +0 -59
- data/lib/composite_primary_keys/associations/join_dependency/join_part.rb +0 -39
- data/lib/composite_primary_keys/associations/preloader/has_and_belongs_to_many.rb +0 -46
- data/lib/composite_primary_keys/connection_adapters/sqlserver_adapter.rb +0 -17
- data/lib/composite_primary_keys/locking/optimistic.rb +0 -55
- data/test/test_optimistic.rb +0 -18
@@ -1,19 +1,19 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module Associations
|
3
|
-
class Preloader
|
4
|
-
class BelongsTo
|
5
|
-
def query_scope(ids)
|
6
|
-
# CPK
|
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
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
1
|
+
module ActiveRecord
|
2
|
+
module Associations
|
3
|
+
class Preloader
|
4
|
+
class BelongsTo
|
5
|
+
def query_scope(ids)
|
6
|
+
# CPK
|
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
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module CompositePrimaryKeys
|
2
|
+
module SingularAssociation
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
included do
|
5
|
+
def get_records_with_cpk_support
|
6
|
+
cpk_applies = (target && target.composite?) || (owner && owner.composite?)
|
7
|
+
return scope.limit(1).to_a if cpk_applies
|
8
|
+
get_records_without_cpk_support
|
9
|
+
end
|
10
|
+
alias_method_chain :get_records, :cpk_support
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
ActiveRecord::Associations::SingularAssociation.send(:include, CompositePrimaryKeys::SingularAssociation)
|
@@ -1,26 +1,29 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module AttributeMethods
|
3
|
-
module Dirty
|
4
|
-
def write_attribute(attr, value)
|
5
|
-
# CPK
|
6
|
-
if attr.kind_of?(Array)
|
7
|
-
# A *composite* attribute can't be marked as changed! So do nothing now.
|
8
|
-
# We will come back in here with an *individual* attribute when Write#write_attribute looks through the individual attributes comprising this composite key:
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
1
|
+
module ActiveRecord
|
2
|
+
module AttributeMethods
|
3
|
+
module Dirty
|
4
|
+
def write_attribute(attr, value)
|
5
|
+
# CPK
|
6
|
+
if attr.kind_of?(Array)
|
7
|
+
# A *composite* attribute can't be marked as changed! So do nothing now.
|
8
|
+
# We will come back in here with an *individual* attribute when Write#write_attribute looks through the individual attributes comprising this composite key:
|
9
|
+
value = [nil] * attr.length if value.nil?
|
10
|
+
[attr, value].transpose.map {|name,val| write_attribute(name, val)}
|
11
|
+
else
|
12
|
+
attr = attr.to_s
|
13
|
+
|
14
|
+
old_value = old_attribute_value(attr)
|
15
|
+
|
16
|
+
result = super
|
17
|
+
store_original_raw_attribute(attr)
|
18
|
+
save_changed_attribute(attr, old_value)
|
19
|
+
result
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
ActiveRecord::Base.class_eval do
|
27
|
+
alias :[]= :write_attribute
|
28
|
+
public :[]=
|
29
|
+
end
|
@@ -1,35 +1,20 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module AttributeMethods
|
3
|
-
module Read
|
4
|
-
def read_attribute(attr_name)
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
value = @attributes.fetch(name) {
|
22
|
-
return block_given? ? yield(name) : nil
|
23
|
-
}
|
24
|
-
|
25
|
-
if self.class.cache_attribute?(name)
|
26
|
-
@attributes_cache[name] = column.type_cast(value)
|
27
|
-
else
|
28
|
-
column.type_cast value
|
29
|
-
end
|
30
|
-
}
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
1
|
+
module ActiveRecord
|
2
|
+
module AttributeMethods
|
3
|
+
module Read
|
4
|
+
def read_attribute(attr_name, &block)
|
5
|
+
# CPK
|
6
|
+
# name = attr_name.to_s
|
7
|
+
# name = self.class.primary_key if name == 'id'
|
8
|
+
# @attributes.fetch_value(name, &block)
|
9
|
+
|
10
|
+
if attr_name.kind_of?(Array)
|
11
|
+
attr_name.map {|name| read_attribute(name)}.to_composite_keys
|
12
|
+
else
|
13
|
+
name = attr_name.to_s
|
14
|
+
name = self.class.primary_key if name == 'id' && !composite?
|
15
|
+
@attributes.fetch_value(name, &block)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
35
20
|
end
|
@@ -1,36 +1,30 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module AttributeMethods
|
3
|
-
module Write
|
4
|
-
def write_attribute_with_type_cast(attr_name, value,
|
5
|
-
# CPK
|
6
|
-
if attr_name.kind_of?(Array)
|
7
|
-
value = [nil]*attr_name.length if value.nil?
|
8
|
-
unless value.length == attr_name.length
|
9
|
-
raise "Number of attr_names #{attr_name.inspect} and values #{value.inspect} do not match"
|
10
|
-
end
|
11
|
-
[attr_name, value].transpose.map {|name,val| write_attribute(name, val)}
|
12
|
-
value
|
13
|
-
else
|
14
|
-
attr_name = attr_name.to_s
|
15
|
-
# CPK
|
16
|
-
# attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key
|
17
|
-
attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key && !self.composite?
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
1
|
+
module ActiveRecord
|
2
|
+
module AttributeMethods
|
3
|
+
module Write
|
4
|
+
def write_attribute_with_type_cast(attr_name, value, should_type_cast)
|
5
|
+
# CPK
|
6
|
+
if attr_name.kind_of?(Array)
|
7
|
+
value = [nil]*attr_name.length if value.nil?
|
8
|
+
unless value.length == attr_name.length
|
9
|
+
raise "Number of attr_names #{attr_name.inspect} and values #{value.inspect} do not match"
|
10
|
+
end
|
11
|
+
[attr_name, value].transpose.map {|name,val| write_attribute(name, val)}
|
12
|
+
value
|
13
|
+
else
|
14
|
+
attr_name = attr_name.to_s
|
15
|
+
# CPK
|
16
|
+
# attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key
|
17
|
+
attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key && !self.composite?
|
18
|
+
|
19
|
+
if should_type_cast
|
20
|
+
@attributes.write_from_user(attr_name, value)
|
21
|
+
else
|
22
|
+
@attributes.write_from_database(attr_name, value)
|
23
|
+
end
|
24
|
+
|
25
|
+
value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class AttributeSet # :nodoc:
|
3
|
+
class Builder # :nodoc:
|
4
|
+
def build_from_database(values = {}, additional_types = {})
|
5
|
+
# CPK
|
6
|
+
# if always_initialized && !values.key?(always_initialized)
|
7
|
+
# values[always_initialized] = nil
|
8
|
+
# end
|
9
|
+
Array(always_initialized).each do |always_initialized_attribute|
|
10
|
+
if always_initialized_attribute && !values.key?(always_initialized_attribute)
|
11
|
+
values[always_initialized_attribute] = nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
attributes = LazyAttributeHash.new(types, values, additional_types)
|
16
|
+
AttributeSet.new(attributes)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,129 +1,135 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
class CompositeKeyError < StandardError #:nodoc:
|
3
|
-
end
|
4
|
-
|
5
|
-
class Base
|
6
|
-
INVALID_FOR_COMPOSITE_KEYS = 'Not appropriate for composite primary keys'
|
7
|
-
NOT_IMPLEMENTED_YET = 'Not implemented for composite primary keys yet'
|
8
|
-
|
9
|
-
class << self
|
10
|
-
def primary_keys
|
11
|
-
unless defined?(@primary_keys)
|
12
|
-
reset_primary_keys
|
13
|
-
end
|
14
|
-
@primary_keys
|
15
|
-
end
|
16
|
-
|
17
|
-
# Don't like this method name, but its modeled after how AR does it
|
18
|
-
def reset_primary_keys
|
19
|
-
if self != base_class
|
20
|
-
self.primary_keys = base_class.primary_keys
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def primary_key_with_composite_key_support=(keys)
|
25
|
-
unless keys.kind_of?(Array)
|
26
|
-
self.primary_key_without_composite_key_support = keys
|
27
|
-
return
|
28
|
-
end
|
29
|
-
|
30
|
-
@primary_keys = keys.map { |k| k.to_s }.to_composite_keys
|
31
|
-
|
32
|
-
class_eval <<-EOV
|
33
|
-
extend CompositeClassMethods
|
34
|
-
include CompositeInstanceMethods
|
35
|
-
EOV
|
36
|
-
end
|
37
|
-
alias_method_chain :primary_key=, :composite_key_support
|
38
|
-
alias_method :primary_keys=, :primary_key=
|
39
|
-
|
40
|
-
def set_primary_keys(*keys)
|
41
|
-
ActiveSupport::Deprecation.warn(
|
42
|
-
"Calling set_primary_keys is deprecated. Please use `self.primary_keys = keys` instead."
|
43
|
-
)
|
44
|
-
|
45
|
-
keys = keys.first if keys.first.is_a?(Array)
|
46
|
-
if keys.length == 1
|
47
|
-
self.primary_key = keys.first
|
48
|
-
else
|
49
|
-
self.primary_keys = keys
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def composite?
|
54
|
-
false
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def composite?
|
59
|
-
self.class.composite?
|
60
|
-
end
|
61
|
-
|
62
|
-
module CompositeClassMethods
|
63
|
-
def primary_key
|
64
|
-
primary_keys
|
65
|
-
end
|
66
|
-
|
67
|
-
def primary_key=(keys)
|
68
|
-
primary_keys = keys
|
69
|
-
end
|
70
|
-
|
71
|
-
def composite?
|
72
|
-
true
|
73
|
-
end
|
74
|
-
|
75
|
-
#ids_to_s([[1,2],[7,3]]) -> "(1,2),(7,3)"
|
76
|
-
#ids_to_s([[1,2],[7,3]], ',', ';') -> "1,2;7,3"
|
77
|
-
def ids_to_s(many_ids, id_sep = CompositePrimaryKeys::ID_SEP, list_sep = ',', left_bracket = '(', right_bracket = ')')
|
78
|
-
many_ids.map {|ids| "#{left_bracket}#{CompositePrimaryKeys::CompositeKeys.new(ids)}#{right_bracket}"}.join(list_sep)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
module CompositeInstanceMethods
|
83
|
-
# A model instance's primary keys is always available as model.ids
|
84
|
-
# whether you name it the default 'id' or set it to something else.
|
85
|
-
def id
|
86
|
-
attr_names = self.class.primary_keys
|
87
|
-
::CompositePrimaryKeys::CompositeKeys.new(attr_names.map { |attr_name| read_attribute(attr_name) })
|
88
|
-
end
|
89
|
-
alias_method :ids, :id
|
90
|
-
|
91
|
-
def ids_hash
|
92
|
-
self.class.primary_key.zip(ids).inject(Hash.new) do |hash, (key, value)|
|
93
|
-
hash[key] = value
|
94
|
-
hash
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def id_before_type_cast
|
99
|
-
self.class.primary_keys.map do |key|
|
100
|
-
self.send("#{key.to_s}_before_type_cast")
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
# Sets the primary ID.
|
105
|
-
def id=(ids)
|
106
|
-
ids = CompositePrimaryKeys::CompositeKeys.parse(ids)
|
107
|
-
unless ids.length == self.class.primary_keys.length
|
108
|
-
raise "#{self.class}.id= requires #{self.class.primary_keys.length} ids"
|
109
|
-
end
|
110
|
-
[self.class.primary_keys, ids].transpose.each {|key, an_id| write_attribute(key , an_id)}
|
111
|
-
id
|
112
|
-
end
|
113
|
-
|
114
|
-
def
|
115
|
-
false
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
def
|
121
|
-
|
122
|
-
end
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
1
|
+
module ActiveRecord
|
2
|
+
class CompositeKeyError < StandardError #:nodoc:
|
3
|
+
end
|
4
|
+
|
5
|
+
class Base
|
6
|
+
INVALID_FOR_COMPOSITE_KEYS = 'Not appropriate for composite primary keys'
|
7
|
+
NOT_IMPLEMENTED_YET = 'Not implemented for composite primary keys yet'
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def primary_keys
|
11
|
+
unless defined?(@primary_keys)
|
12
|
+
reset_primary_keys
|
13
|
+
end
|
14
|
+
@primary_keys
|
15
|
+
end
|
16
|
+
|
17
|
+
# Don't like this method name, but its modeled after how AR does it
|
18
|
+
def reset_primary_keys
|
19
|
+
if self != base_class
|
20
|
+
self.primary_keys = base_class.primary_keys
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def primary_key_with_composite_key_support=(keys)
|
25
|
+
unless keys.kind_of?(Array)
|
26
|
+
self.primary_key_without_composite_key_support = keys
|
27
|
+
return
|
28
|
+
end
|
29
|
+
|
30
|
+
@primary_keys = keys.map { |k| k.to_s }.to_composite_keys
|
31
|
+
|
32
|
+
class_eval <<-EOV
|
33
|
+
extend CompositeClassMethods
|
34
|
+
include CompositeInstanceMethods
|
35
|
+
EOV
|
36
|
+
end
|
37
|
+
alias_method_chain :primary_key=, :composite_key_support
|
38
|
+
alias_method :primary_keys=, :primary_key=
|
39
|
+
|
40
|
+
def set_primary_keys(*keys)
|
41
|
+
ActiveSupport::Deprecation.warn(
|
42
|
+
"Calling set_primary_keys is deprecated. Please use `self.primary_keys = keys` instead."
|
43
|
+
)
|
44
|
+
|
45
|
+
keys = keys.first if keys.first.is_a?(Array)
|
46
|
+
if keys.length == 1
|
47
|
+
self.primary_key = keys.first
|
48
|
+
else
|
49
|
+
self.primary_keys = keys
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def composite?
|
54
|
+
false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def composite?
|
59
|
+
self.class.composite?
|
60
|
+
end
|
61
|
+
|
62
|
+
module CompositeClassMethods
|
63
|
+
def primary_key
|
64
|
+
primary_keys
|
65
|
+
end
|
66
|
+
|
67
|
+
def primary_key=(keys)
|
68
|
+
primary_keys = keys
|
69
|
+
end
|
70
|
+
|
71
|
+
def composite?
|
72
|
+
true
|
73
|
+
end
|
74
|
+
|
75
|
+
#ids_to_s([[1,2],[7,3]]) -> "(1,2),(7,3)"
|
76
|
+
#ids_to_s([[1,2],[7,3]], ',', ';') -> "1,2;7,3"
|
77
|
+
def ids_to_s(many_ids, id_sep = CompositePrimaryKeys::ID_SEP, list_sep = ',', left_bracket = '(', right_bracket = ')')
|
78
|
+
many_ids.map {|ids| "#{left_bracket}#{CompositePrimaryKeys::CompositeKeys.new(ids)}#{right_bracket}"}.join(list_sep)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
module CompositeInstanceMethods
|
83
|
+
# A model instance's primary keys is always available as model.ids
|
84
|
+
# whether you name it the default 'id' or set it to something else.
|
85
|
+
def id
|
86
|
+
attr_names = self.class.primary_keys
|
87
|
+
::CompositePrimaryKeys::CompositeKeys.new(attr_names.map { |attr_name| read_attribute(attr_name) })
|
88
|
+
end
|
89
|
+
alias_method :ids, :id
|
90
|
+
|
91
|
+
def ids_hash
|
92
|
+
self.class.primary_key.zip(ids).inject(Hash.new) do |hash, (key, value)|
|
93
|
+
hash[key] = value
|
94
|
+
hash
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def id_before_type_cast
|
99
|
+
self.class.primary_keys.map do |key|
|
100
|
+
self.send("#{key.to_s}_before_type_cast")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Sets the primary ID.
|
105
|
+
def id=(ids)
|
106
|
+
ids = CompositePrimaryKeys::CompositeKeys.parse(ids)
|
107
|
+
unless ids.length == self.class.primary_keys.length
|
108
|
+
raise "#{self.class}.id= requires #{self.class.primary_keys.length} ids"
|
109
|
+
end
|
110
|
+
[self.class.primary_keys, ids].transpose.each {|key, an_id| write_attribute(key , an_id)}
|
111
|
+
id
|
112
|
+
end
|
113
|
+
|
114
|
+
def ==(comparison_object)
|
115
|
+
return false if !persisted? && comparison_object.object_id != object_id
|
116
|
+
return true if equal? comparison_object
|
117
|
+
ids.is_a?(Array) ? super(comparison_object) && ids.all? {|id| !id.nil?} : super(comparison_object)
|
118
|
+
end
|
119
|
+
|
120
|
+
def can_change_primary_key_values?
|
121
|
+
false
|
122
|
+
end
|
123
|
+
|
124
|
+
# Returns this record's primary keys values in an Array
|
125
|
+
# if any value is available
|
126
|
+
def to_key
|
127
|
+
ids.to_a if !ids.compact.empty? # XXX Maybe use primary_keys with send instead of ids
|
128
|
+
end
|
129
|
+
|
130
|
+
def to_param
|
131
|
+
persisted? ? to_key.join(CompositePrimaryKeys::ID_SEP) : nil
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|