composite_primary_keys 3.0.9 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +6 -0
- data/Rakefile +10 -1
- data/lib/composite_primary_keys.rb +75 -75
- data/lib/composite_primary_keys/base.rb +190 -194
- data/lib/composite_primary_keys/composite_arrays.rb +23 -23
- data/lib/composite_primary_keys/finder_methods.rb +0 -11
- data/lib/composite_primary_keys/reflection.rb +38 -38
- data/lib/composite_primary_keys/version.rb +2 -2
- data/test/abstract_unit.rb +3 -2
- data/test/connections/connection_spec.rb +1 -2
- data/test/connections/databases.example.yml +14 -12
- data/test/connections/databases.yml +14 -14
- data/test/connections/native_ibm_db/connection.rb +0 -3
- data/test/connections/native_mysql/connection.rb +3 -9
- data/test/connections/native_oracle/connection.rb +4 -10
- data/test/connections/native_oracle_enhanced/connection.rb +4 -11
- data/test/connections/native_postgresql/connection.rb +1 -3
- data/test/connections/native_sqlite/connection.rb +2 -4
- data/test/debug.log +589 -589
- data/test/fixtures/article.rb +5 -5
- data/test/fixtures/articles.yml +5 -5
- data/test/fixtures/capitol.rb +3 -0
- data/test/fixtures/capitols.yml +16 -0
- data/test/fixtures/db_definitions/mysql.sql +5 -0
- data/test/fixtures/db_definitions/postgresql.sql +5 -0
- data/test/fixtures/product.rb +7 -7
- data/test/fixtures/product_tariff.rb +5 -5
- data/test/fixtures/product_tariffs.yml +12 -12
- data/test/fixtures/products.yml +5 -5
- data/test/fixtures/reading.rb +4 -4
- data/test/fixtures/readings.yml +9 -9
- data/test/fixtures/reference_code.rb +7 -7
- data/test/fixtures/reference_codes.yml +29 -29
- data/test/fixtures/reference_type.rb +7 -7
- data/test/fixtures/reference_types.yml +9 -9
- data/test/fixtures/suburb.rb +5 -5
- data/test/fixtures/suburbs.yml +8 -8
- data/test/fixtures/tariff.rb +6 -6
- data/test/fixtures/tariffs.yml +12 -12
- data/test/fixtures/user.rb +10 -10
- data/test/fixtures/users.yml +5 -5
- data/test/hash_tricks.rb +34 -34
- data/test/test_associations.rb +180 -180
- data/test/test_attribute_methods.rb +0 -2
- data/test/test_attributes.rb +0 -5
- data/test/test_clone.rb +31 -33
- data/test/test_composite_arrays.rb +0 -2
- data/test/test_create.rb +0 -4
- data/test/test_delete.rb +92 -96
- data/test/test_equal.rb +21 -0
- data/test/test_exists.rb +0 -2
- data/test/test_find.rb +79 -76
- data/test/test_ids.rb +81 -83
- data/test/test_miscellaneous.rb +36 -38
- data/test/test_pagination.rb +35 -37
- data/test/test_polymorphic.rb +0 -6
- data/test/test_santiago.rb +23 -27
- data/test/test_suite.rb +1 -0
- data/test/test_tutorial_example.rb +0 -4
- data/test/test_update.rb +37 -39
- data/test/test_validations.rb +0 -1
- metadata +8 -4
data/History.txt
CHANGED
data/Rakefile
CHANGED
@@ -19,4 +19,13 @@ Rake::GemPackageTask.new(spec).define
|
|
19
19
|
# Now load in other task files
|
20
20
|
Dir.glob('tasks/**/*.rake').each do |rake_file|
|
21
21
|
load File.join(File.dirname(__FILE__), rake_file)
|
22
|
-
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Set up test tasks
|
25
|
+
for adapter in %w( mysql sqlite oracle oracle_enhanced postgresql ibm_db )
|
26
|
+
Rake::TestTask.new("test_#{adapter}") do |t|
|
27
|
+
t.libs << "test" << "test/connections/native_#{adapter}"
|
28
|
+
t.pattern = "test/test_*.rb"
|
29
|
+
t.verbose = true
|
30
|
+
end
|
31
|
+
end
|
@@ -1,75 +1,75 @@
|
|
1
|
-
#--
|
2
|
-
# Copyright (c) 2006 Nic Williams
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
-
# a copy of this software and associated documentation files (the
|
6
|
-
# "Software"), to deal in the Software without restriction, including
|
7
|
-
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
-
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
-
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
-
# the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be
|
13
|
-
# included in all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
-
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
-
#++
|
23
|
-
|
24
|
-
$:.unshift(File.dirname(__FILE__)) unless
|
25
|
-
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
26
|
-
|
27
|
-
unless defined?(ActiveRecord)
|
28
|
-
begin
|
29
|
-
require 'active_record'
|
30
|
-
rescue LoadError
|
31
|
-
require 'rubygems'
|
32
|
-
gem 'active_record'
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
require 'active_record/associations.rb'
|
37
|
-
require 'active_record/associations/association_proxy.rb'
|
38
|
-
require 'active_record/associations/association_collection'
|
39
|
-
require 'active_record/associations/association_proxy'
|
40
|
-
require 'active_record/associations/belongs_to_association'
|
41
|
-
require 'active_record/associations/belongs_to_polymorphic_association'
|
42
|
-
require 'active_record/associations/has_and_belongs_to_many_association'
|
43
|
-
require 'active_record/associations/has_many_association'
|
44
|
-
require 'active_record/associations/has_one_association'
|
45
|
-
require 'active_record/associations/has_one_through_association'
|
46
|
-
require 'active_record/associations/through_association_scope'
|
47
|
-
require 'active_record/relation/query_methods'
|
48
|
-
require 'active_record/attribute_methods/primary_key'
|
49
|
-
require 'active_record/fixtures'
|
50
|
-
|
51
|
-
require 'composite_primary_keys/composite_arrays'
|
52
|
-
require 'composite_primary_keys/associations'
|
53
|
-
require 'composite_primary_keys/associations/association_proxy'
|
54
|
-
require 'composite_primary_keys/associations/has_one_association'
|
55
|
-
require 'composite_primary_keys/associations/has_many_association'
|
56
|
-
require 'composite_primary_keys/associations/has_and_belongs_to_many_association'
|
57
|
-
require 'composite_primary_keys/associations/through_association_scope'
|
58
|
-
require 'composite_primary_keys/association_preload'
|
59
|
-
require 'composite_primary_keys/reflection'
|
60
|
-
require 'composite_primary_keys/relation'
|
61
|
-
require 'composite_primary_keys/read'
|
62
|
-
require 'composite_primary_keys/finder_methods'
|
63
|
-
require 'composite_primary_keys/base'
|
64
|
-
require 'composite_primary_keys/calculations'
|
65
|
-
require 'composite_primary_keys/validations/uniqueness'
|
66
|
-
require 'composite_primary_keys/query_methods'
|
67
|
-
require 'composite_primary_keys/primary_key'
|
68
|
-
require 'composite_primary_keys/fixtures'
|
69
|
-
|
70
|
-
Dir[File.dirname(__FILE__) + '/composite_primary_keys/connection_adapters/*.rb'].each do |adapter|
|
71
|
-
begin
|
72
|
-
require adapter.gsub('.rb','')
|
73
|
-
rescue MissingSourceFile
|
74
|
-
end
|
75
|
-
end
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2006 Nic Williams
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
25
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
26
|
+
|
27
|
+
unless defined?(ActiveRecord)
|
28
|
+
begin
|
29
|
+
require 'active_record'
|
30
|
+
rescue LoadError
|
31
|
+
require 'rubygems'
|
32
|
+
gem 'active_record'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
require 'active_record/associations.rb'
|
37
|
+
require 'active_record/associations/association_proxy.rb'
|
38
|
+
require 'active_record/associations/association_collection'
|
39
|
+
require 'active_record/associations/association_proxy'
|
40
|
+
require 'active_record/associations/belongs_to_association'
|
41
|
+
require 'active_record/associations/belongs_to_polymorphic_association'
|
42
|
+
require 'active_record/associations/has_and_belongs_to_many_association'
|
43
|
+
require 'active_record/associations/has_many_association'
|
44
|
+
require 'active_record/associations/has_one_association'
|
45
|
+
require 'active_record/associations/has_one_through_association'
|
46
|
+
require 'active_record/associations/through_association_scope'
|
47
|
+
require 'active_record/relation/query_methods'
|
48
|
+
require 'active_record/attribute_methods/primary_key'
|
49
|
+
require 'active_record/fixtures'
|
50
|
+
|
51
|
+
require 'composite_primary_keys/composite_arrays'
|
52
|
+
require 'composite_primary_keys/associations'
|
53
|
+
require 'composite_primary_keys/associations/association_proxy'
|
54
|
+
require 'composite_primary_keys/associations/has_one_association'
|
55
|
+
require 'composite_primary_keys/associations/has_many_association'
|
56
|
+
require 'composite_primary_keys/associations/has_and_belongs_to_many_association'
|
57
|
+
require 'composite_primary_keys/associations/through_association_scope'
|
58
|
+
require 'composite_primary_keys/association_preload'
|
59
|
+
require 'composite_primary_keys/reflection'
|
60
|
+
require 'composite_primary_keys/relation'
|
61
|
+
require 'composite_primary_keys/read'
|
62
|
+
require 'composite_primary_keys/finder_methods'
|
63
|
+
require 'composite_primary_keys/base'
|
64
|
+
require 'composite_primary_keys/calculations'
|
65
|
+
require 'composite_primary_keys/validations/uniqueness'
|
66
|
+
require 'composite_primary_keys/query_methods'
|
67
|
+
require 'composite_primary_keys/primary_key'
|
68
|
+
require 'composite_primary_keys/fixtures'
|
69
|
+
|
70
|
+
Dir[File.dirname(__FILE__) + '/composite_primary_keys/connection_adapters/*.rb'].each do |adapter|
|
71
|
+
begin
|
72
|
+
require adapter.gsub('.rb','')
|
73
|
+
rescue MissingSourceFile
|
74
|
+
end
|
75
|
+
end
|
@@ -1,195 +1,191 @@
|
|
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 set_primary_keys(*keys)
|
11
|
-
keys = keys.first if keys.first.is_a?(Array)
|
12
|
-
|
13
|
-
if keys.length == 1
|
14
|
-
set_primary_key(keys.first)
|
15
|
-
return
|
16
|
-
end
|
17
|
-
|
18
|
-
cattr_accessor :primary_keys
|
19
|
-
self.primary_keys = keys.map { |k| k.to_sym }
|
20
|
-
|
21
|
-
class_eval <<-EOV
|
22
|
-
extend CompositeClassMethods
|
23
|
-
include CompositeInstanceMethods
|
24
|
-
include CompositePrimaryKeys::ActiveRecord::AssociationPreload
|
25
|
-
EOV
|
26
|
-
end
|
27
|
-
|
28
|
-
def composite?
|
29
|
-
false
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def composite?
|
34
|
-
self.class.composite?
|
35
|
-
end
|
36
|
-
|
37
|
-
def [](attr_name)
|
38
|
-
# CPK
|
39
|
-
if attr_name.is_a?(String) and attr_name != attr_name.split(CompositePrimaryKeys::ID_SEP).first
|
40
|
-
attr_name = attr_name.split(CompositePrimaryKeys::ID_SEP)
|
41
|
-
end
|
42
|
-
|
43
|
-
# CPK
|
44
|
-
if attr_name.is_a?(Array)
|
45
|
-
values = attr_name.map {|name| read_attribute(name)}
|
46
|
-
CompositePrimaryKeys::CompositeKeys.new(values)
|
47
|
-
else
|
48
|
-
read_attribute(attr_name)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def []=(attr_name, value)
|
53
|
-
# CPK
|
54
|
-
if attr_name.is_a?(String) and attr_name != attr_name.split(CompositePrimaryKeys::ID_SEP).first
|
55
|
-
attr_name = attr_name.split(CompositePrimaryKeys::ID_SEP)
|
56
|
-
end
|
57
|
-
|
58
|
-
if attr_name.is_a? Array
|
59
|
-
unless value.length == attr_name.length
|
60
|
-
raise "Number of attr_names and values do not match"
|
61
|
-
end
|
62
|
-
[attr_name, value].transpose.map {|name,val| write_attribute(name, val)}
|
63
|
-
value
|
64
|
-
else
|
65
|
-
write_attribute(attr_name, value)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
module CompositeClassMethods
|
70
|
-
def primary_key
|
71
|
-
primary_keys
|
72
|
-
end
|
73
|
-
|
74
|
-
def primary_key=(keys)
|
75
|
-
primary_keys = keys
|
76
|
-
end
|
77
|
-
|
78
|
-
def composite?
|
79
|
-
true
|
80
|
-
end
|
81
|
-
|
82
|
-
#ids_to_s([[1,2],[7,3]]) -> "(1,2),(7,3)"
|
83
|
-
#ids_to_s([[1,2],[7,3]], ',', ';') -> "1,2;7,3"
|
84
|
-
def ids_to_s(many_ids, id_sep = CompositePrimaryKeys::ID_SEP, list_sep = ',', left_bracket = '(', right_bracket = ')')
|
85
|
-
many_ids.map {|ids| "#{left_bracket}#{CompositePrimaryKeys::CompositeKeys.new(ids)}#{right_bracket}"}.join(list_sep)
|
86
|
-
end
|
87
|
-
|
88
|
-
def relation #:nodoc:
|
89
|
-
@relation ||= begin
|
90
|
-
result = Relation.new(self, arel_table)
|
91
|
-
# CPK
|
92
|
-
class << result
|
93
|
-
include CompositePrimaryKeys::ActiveRecord::FinderMethods::InstanceMethods
|
94
|
-
include CompositePrimaryKeys::ActiveRecord::Relation::InstanceMethods
|
95
|
-
end
|
96
|
-
result
|
97
|
-
end
|
98
|
-
|
99
|
-
finder_needs_type_condition? ? @relation.where(type_condition) : @relation
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
module CompositeInstanceMethods
|
104
|
-
# A model instance's primary keys is always available as model.ids
|
105
|
-
# whether you name it the default 'id' or set it to something else.
|
106
|
-
def id
|
107
|
-
attr_names = self.class.primary_keys
|
108
|
-
::CompositePrimaryKeys::CompositeKeys.new(attr_names.map { |attr_name| read_attribute(attr_name) })
|
109
|
-
end
|
110
|
-
alias_method :ids, :id
|
111
|
-
|
112
|
-
def ids_hash
|
113
|
-
self.class.primary_key.zip(ids).inject(Hash.new) do |hash, (key, value)|
|
114
|
-
hash[key] = value
|
115
|
-
hash
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def
|
120
|
-
|
121
|
-
end
|
122
|
-
|
123
|
-
def
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
ids.
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
#
|
150
|
-
#
|
151
|
-
#
|
152
|
-
#
|
153
|
-
|
154
|
-
|
155
|
-
#
|
156
|
-
#
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
self.class.unscoped.where(ids_hash).arel.update(attributes_with_values)
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
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 set_primary_keys(*keys)
|
11
|
+
keys = keys.first if keys.first.is_a?(Array)
|
12
|
+
|
13
|
+
if keys.length == 1
|
14
|
+
set_primary_key(keys.first)
|
15
|
+
return
|
16
|
+
end
|
17
|
+
|
18
|
+
cattr_accessor :primary_keys
|
19
|
+
self.primary_keys = keys.map { |k| k.to_sym }
|
20
|
+
|
21
|
+
class_eval <<-EOV
|
22
|
+
extend CompositeClassMethods
|
23
|
+
include CompositeInstanceMethods
|
24
|
+
include CompositePrimaryKeys::ActiveRecord::AssociationPreload
|
25
|
+
EOV
|
26
|
+
end
|
27
|
+
|
28
|
+
def composite?
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def composite?
|
34
|
+
self.class.composite?
|
35
|
+
end
|
36
|
+
|
37
|
+
def [](attr_name)
|
38
|
+
# CPK
|
39
|
+
if attr_name.is_a?(String) and attr_name != attr_name.split(CompositePrimaryKeys::ID_SEP).first
|
40
|
+
attr_name = attr_name.split(CompositePrimaryKeys::ID_SEP)
|
41
|
+
end
|
42
|
+
|
43
|
+
# CPK
|
44
|
+
if attr_name.is_a?(Array)
|
45
|
+
values = attr_name.map {|name| read_attribute(name)}
|
46
|
+
CompositePrimaryKeys::CompositeKeys.new(values)
|
47
|
+
else
|
48
|
+
read_attribute(attr_name)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def []=(attr_name, value)
|
53
|
+
# CPK
|
54
|
+
if attr_name.is_a?(String) and attr_name != attr_name.split(CompositePrimaryKeys::ID_SEP).first
|
55
|
+
attr_name = attr_name.split(CompositePrimaryKeys::ID_SEP)
|
56
|
+
end
|
57
|
+
|
58
|
+
if attr_name.is_a? Array
|
59
|
+
unless value.length == attr_name.length
|
60
|
+
raise "Number of attr_names and values do not match"
|
61
|
+
end
|
62
|
+
[attr_name, value].transpose.map {|name,val| write_attribute(name, val)}
|
63
|
+
value
|
64
|
+
else
|
65
|
+
write_attribute(attr_name, value)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
module CompositeClassMethods
|
70
|
+
def primary_key
|
71
|
+
primary_keys
|
72
|
+
end
|
73
|
+
|
74
|
+
def primary_key=(keys)
|
75
|
+
primary_keys = keys
|
76
|
+
end
|
77
|
+
|
78
|
+
def composite?
|
79
|
+
true
|
80
|
+
end
|
81
|
+
|
82
|
+
#ids_to_s([[1,2],[7,3]]) -> "(1,2),(7,3)"
|
83
|
+
#ids_to_s([[1,2],[7,3]], ',', ';') -> "1,2;7,3"
|
84
|
+
def ids_to_s(many_ids, id_sep = CompositePrimaryKeys::ID_SEP, list_sep = ',', left_bracket = '(', right_bracket = ')')
|
85
|
+
many_ids.map {|ids| "#{left_bracket}#{CompositePrimaryKeys::CompositeKeys.new(ids)}#{right_bracket}"}.join(list_sep)
|
86
|
+
end
|
87
|
+
|
88
|
+
def relation #:nodoc:
|
89
|
+
@relation ||= begin
|
90
|
+
result = Relation.new(self, arel_table)
|
91
|
+
# CPK
|
92
|
+
class << result
|
93
|
+
include CompositePrimaryKeys::ActiveRecord::FinderMethods::InstanceMethods
|
94
|
+
include CompositePrimaryKeys::ActiveRecord::Relation::InstanceMethods
|
95
|
+
end
|
96
|
+
result
|
97
|
+
end
|
98
|
+
|
99
|
+
finder_needs_type_condition? ? @relation.where(type_condition) : @relation
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
module CompositeInstanceMethods
|
104
|
+
# A model instance's primary keys is always available as model.ids
|
105
|
+
# whether you name it the default 'id' or set it to something else.
|
106
|
+
def id
|
107
|
+
attr_names = self.class.primary_keys
|
108
|
+
::CompositePrimaryKeys::CompositeKeys.new(attr_names.map { |attr_name| read_attribute(attr_name) })
|
109
|
+
end
|
110
|
+
alias_method :ids, :id
|
111
|
+
|
112
|
+
def ids_hash
|
113
|
+
self.class.primary_key.zip(ids).inject(Hash.new) do |hash, (key, value)|
|
114
|
+
hash[key] = value
|
115
|
+
hash
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def id_before_type_cast #:nodoc:
|
120
|
+
raise CompositeKeyError, CompositePrimaryKeys::ActiveRecord::Base::NOT_IMPLEMENTED_YET
|
121
|
+
end
|
122
|
+
|
123
|
+
def quoted_id #:nodoc:
|
124
|
+
[self.class.primary_keys, ids].
|
125
|
+
transpose.
|
126
|
+
map {|attr_name,id| quote_value(id, column_for_attribute(attr_name))}.
|
127
|
+
to_composite_ids
|
128
|
+
end
|
129
|
+
|
130
|
+
# Sets the primary ID.
|
131
|
+
def id=(ids)
|
132
|
+
ids = ids.split(CompositePrimaryKeys::ID_SEP) if ids.is_a?(String)
|
133
|
+
ids.flatten!
|
134
|
+
unless ids.is_a?(Array) and ids.length == self.class.primary_keys.length
|
135
|
+
raise "#{self.class}.id= requires #{self.class.primary_keys.length} ids"
|
136
|
+
end
|
137
|
+
[primary_keys, ids].transpose.each {|key, an_id| write_attribute(key , an_id)}
|
138
|
+
id
|
139
|
+
end
|
140
|
+
|
141
|
+
# Cloned objects have no id assigned and are treated as new records. Note that this is a "shallow" clone
|
142
|
+
# as it copies the object's attributes only, not its associations. The extent of a "deep" clone is
|
143
|
+
# application specific and is therefore left to the application to implement according to its need.
|
144
|
+
def initialize_copy(other)
|
145
|
+
# Think the assertion which fails if the after_initialize callback goes at the end of the method is wrong. The
|
146
|
+
# deleted clone method called new which therefore called the after_initialize callback. It then went on to copy
|
147
|
+
# over the attributes. But if it's copying the attributes afterwards then it hasn't finished initializing right?
|
148
|
+
# For example in the test suite the topic model's after_initialize method sets the author_email_address to
|
149
|
+
# test@test.com. I would have thought this would mean that all cloned models would have an author email address
|
150
|
+
# of test@test.com. However the test_clone test method seems to test that this is not the case. As a result the
|
151
|
+
# after_initialize callback has to be run *before* the copying of the atrributes rather than afterwards in order
|
152
|
+
# for all tests to pass. This makes no sense to me.
|
153
|
+
callback(:after_initialize) if respond_to_without_attributes?(:after_initialize)
|
154
|
+
cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
|
155
|
+
# CPK
|
156
|
+
#cloned_attributes.delete(self.class.primary_key)
|
157
|
+
self.class.primary_key.each {|key| cloned_attributes.delete(key.to_s)}
|
158
|
+
|
159
|
+
@attributes = cloned_attributes
|
160
|
+
clear_aggregation_cache
|
161
|
+
@attributes_cache = {}
|
162
|
+
@new_record = true
|
163
|
+
ensure_proper_type
|
164
|
+
|
165
|
+
if scope = self.class.send(:current_scoped_methods)
|
166
|
+
create_with = scope.scope_for_create
|
167
|
+
create_with.each { |att,value| self.send("#{att}=", value) } if create_with
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def destroy
|
172
|
+
if persisted?
|
173
|
+
# CPK
|
174
|
+
# self.class.unscoped.where(self.class.arel_table[self.class.primary_key].eq(id)).delete_all
|
175
|
+
self.class.unscoped.where(ids_hash).delete_all
|
176
|
+
end
|
177
|
+
|
178
|
+
@destroyed = true
|
179
|
+
freeze
|
180
|
+
end
|
181
|
+
|
182
|
+
def update(attribute_names = @attributes.keys)
|
183
|
+
attributes_with_values = arel_attributes_values(false, false, attribute_names)
|
184
|
+
return 0 if attributes_with_values.empty?
|
185
|
+
# CPK
|
186
|
+
# self.class.unscoped.where(self.class.arel_table[self.class.primary_key].eq(id)).arel.update(attributes_with_values)
|
187
|
+
self.class.unscoped.where(ids_hash).arel.update(attributes_with_values)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
195
191
|
end
|