composite_primary_keys 13.0.2 → 13.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eeb7ac69a866392d1d19aec7ae67f99af052e72e5585375c2cb73990f442cc28
4
- data.tar.gz: 6552f1e74d6ab9a40aadd66ea78e8d6c489e6d793a47cc52ab2582f60dfbced7
3
+ metadata.gz: e585b24e33313e3e28cb2930a551379cdd08acee51021a3291f2a31ba63000e6
4
+ data.tar.gz: f6cd7efcbce731128f39a732cf90623c3b06ce5669c71b79cede3b7cb3f2ec8a
5
5
  SHA512:
6
- metadata.gz: 1b0bd53df9177d3569e4646124ff2aaf6bacf4d83a78f287a9e954ed388a37ed4872f4024204e34f7402b7989b401586c53636a551d745e5aaf4871927bb66fb
7
- data.tar.gz: 8c2eacaaff041c6c4255aed0402f63038d6e0d781665208cbb9b3bdbcc86666087f69822400384f9dfc44215c23be46ddc1c3c69b7ee0008db636d8ff1e0a29c
6
+ metadata.gz: ceea9d28fa8d5f910158f1c8ac69ca1d56bca8ab095cab681db4f749f0cae1dc0d9a3ff24009b4a0ffd7afb3f1cb452487e24bacddf48144a280a7e61d459028
7
+ data.tar.gz: b5ccaaad9807d0a6f82a03be277fea073cc6cfe5dbeb235fbef42ecfd6ca0f321b08367f78e8c8a493614071119399df84c207e3a3cda434f75a9a190980cb5b
data/History.rdoc CHANGED
@@ -1,3 +1,8 @@
1
+ == 13.0.3 (2022-01-09)
2
+ * Remove override on ActiveRecord::Base#to_param. That method has moved to Integration
3
+ so no longer works. #541. (Charlie Savage)
4
+ * Check if an assocation is polymorhpic. Fixes #558.
5
+
1
6
  == 13.0.2 (2022-01-09)
2
7
  * Fix scoped associations take #2 (Charlie Savage)
3
8
 
@@ -1,137 +1,137 @@
1
- module ActiveRecord
2
- module Associations
3
- class JoinDependency
4
-
5
- class JoinAssociation < JoinPart # :nodoc:
6
- private
7
- def append_constraints(join, constraints)
8
- if join.is_a?(Arel::Nodes::StringJoin)
9
- join_string = Arel::Nodes::And.new(constraints.unshift join.left)
10
- join.left = Arel.sql(base_klass.connection.visitor.compile(join_string))
11
- else
12
- right = join.right
13
- # CPK
14
- if right.expr.is_a?(Arel::Nodes::And) && right.expr.children.empty?
15
- right.expr = Arel::Nodes::And.new(constraints)
16
- else
17
- right.expr = Arel::Nodes::And.new(constraints.unshift right.expr)
18
- end
19
- end
20
- end
21
- end
22
-
23
- class Aliases # :nodoc:
24
- def column_alias(node, column)
25
- # CPK
26
- #@alias_cache[node][column]
27
- if column.kind_of?(Array)
28
- column.map do |a_column|
29
- @alias_cache[node][a_column]
30
- end
31
- else
32
- @alias_cache[node][column]
33
- end
34
- end
35
- end
36
-
37
- def instantiate(result_set, strict_loading_value, &block)
38
- primary_key = aliases.column_alias(join_root, join_root.primary_key)
39
-
40
- seen = Hash.new { |i, parent|
41
- i[parent] = Hash.new { |j, child_class|
42
- j[child_class] = {}
43
- }
44
- }.compare_by_identity
45
-
46
- model_cache = Hash.new { |h, klass| h[klass] = {} }
47
- parents = model_cache[join_root]
48
-
49
- column_aliases = aliases.column_aliases(join_root)
50
- column_names = []
51
-
52
- result_set.columns.each do |name|
53
- column_names << name unless /\At\d+_r\d+\z/.match?(name)
54
- end
55
-
56
- if column_names.empty?
57
- column_types = {}
58
- else
59
- column_types = result_set.column_types
60
- unless column_types.empty?
61
- attribute_types = join_root.attribute_types
62
- column_types = column_types.slice(*column_names).delete_if { |k, _| attribute_types.key?(k) }
63
- end
64
- column_aliases += column_names.map! { |name| Aliases::Column.new(name, name) }
65
- end
66
-
67
- message_bus = ActiveSupport::Notifications.instrumenter
68
-
69
- payload = {
70
- record_count: result_set.length,
71
- class_name: join_root.base_klass.name
72
- }
73
-
74
- message_bus.instrument("instantiation.active_record", payload) do
75
- result_set.each { |row_hash|
76
- # CPK
77
- # parent_key = primary_key ? row_hash[primary_key] : row_hash
78
- parent_key = if primary_key.kind_of?(Array)
79
- primary_key.map {|key| row_hash[key]}
80
- else
81
- primary_key ? row_hash[primary_key] : row_hash
82
- end
83
-
84
- parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases, column_types, &block)
85
- construct(parent, join_root, row_hash, seen, model_cache, strict_loading_value)
86
- }
87
- end
88
-
89
- parents.values
90
- end
91
-
92
- def construct(ar_parent, parent, row, seen, model_cache, strict_loading_value)
93
- return if ar_parent.nil?
94
-
95
- parent.children.each do |node|
96
- if node.reflection.collection?
97
- other = ar_parent.association(node.reflection.name)
98
- other.loaded!
99
- elsif ar_parent.association_cached?(node.reflection.name)
100
- model = ar_parent.association(node.reflection.name).target
101
- construct(model, node, row, seen, model_cache, strict_loading_value)
102
- next
103
- end
104
-
105
- key = aliases.column_alias(node, node.primary_key)
106
- # CPK
107
- if key.is_a?(Array)
108
- id = Array(key).map do |column_alias|
109
- row[column_alias]
110
- end
111
- # At least the first value in the key has to be set. Should we require all values to be set?
112
- id = nil if id.first.nil?
113
- else # original
114
- id = row[key]
115
- end
116
-
117
- if id.nil?
118
- nil_association = ar_parent.association(node.reflection.name)
119
- nil_association.loaded!
120
- next
121
- end
122
-
123
- model = seen[ar_parent][node][id]
124
-
125
- if model
126
- construct(model, node, row, seen, model_cache, strict_loading_value)
127
- else
128
- model = construct_model(ar_parent, node, row, model_cache, id, strict_loading_value)
129
-
130
- seen[ar_parent][node][id] = model
131
- construct(model, node, row, seen, model_cache, strict_loading_value)
132
- end
133
- end
134
- end
135
- end
136
- end
137
- end
1
+ module ActiveRecord
2
+ module Associations
3
+ class JoinDependency
4
+
5
+ class JoinAssociation < JoinPart # :nodoc:
6
+ private
7
+ def append_constraints(join, constraints)
8
+ if join.is_a?(Arel::Nodes::StringJoin)
9
+ join_string = Arel::Nodes::And.new(constraints.unshift join.left)
10
+ join.left = Arel.sql(base_klass.connection.visitor.compile(join_string))
11
+ else
12
+ right = join.right
13
+ # CPK
14
+ if right.expr.is_a?(Arel::Nodes::And) && right.expr.children.empty?
15
+ right.expr = Arel::Nodes::And.new(constraints)
16
+ else
17
+ right.expr = Arel::Nodes::And.new(constraints.unshift right.expr)
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ class Aliases # :nodoc:
24
+ def column_alias(node, column)
25
+ # CPK
26
+ #@alias_cache[node][column]
27
+ if column.kind_of?(Array)
28
+ column.map do |a_column|
29
+ @alias_cache[node][a_column]
30
+ end
31
+ else
32
+ @alias_cache[node][column]
33
+ end
34
+ end
35
+ end
36
+
37
+ def instantiate(result_set, strict_loading_value, &block)
38
+ primary_key = aliases.column_alias(join_root, join_root.primary_key)
39
+
40
+ seen = Hash.new { |i, parent|
41
+ i[parent] = Hash.new { |j, child_class|
42
+ j[child_class] = {}
43
+ }
44
+ }.compare_by_identity
45
+
46
+ model_cache = Hash.new { |h, klass| h[klass] = {} }
47
+ parents = model_cache[join_root]
48
+
49
+ column_aliases = aliases.column_aliases(join_root)
50
+ column_names = []
51
+
52
+ result_set.columns.each do |name|
53
+ column_names << name unless /\At\d+_r\d+\z/.match?(name)
54
+ end
55
+
56
+ if column_names.empty?
57
+ column_types = {}
58
+ else
59
+ column_types = result_set.column_types
60
+ unless column_types.empty?
61
+ attribute_types = join_root.attribute_types
62
+ column_types = column_types.slice(*column_names).delete_if { |k, _| attribute_types.key?(k) }
63
+ end
64
+ column_aliases += column_names.map! { |name| Aliases::Column.new(name, name) }
65
+ end
66
+
67
+ message_bus = ActiveSupport::Notifications.instrumenter
68
+
69
+ payload = {
70
+ record_count: result_set.length,
71
+ class_name: join_root.base_klass.name
72
+ }
73
+
74
+ message_bus.instrument("instantiation.active_record", payload) do
75
+ result_set.each { |row_hash|
76
+ # CPK
77
+ # parent_key = primary_key ? row_hash[primary_key] : row_hash
78
+ parent_key = if primary_key.kind_of?(Array)
79
+ primary_key.map {|key| row_hash[key]}
80
+ else
81
+ primary_key ? row_hash[primary_key] : row_hash
82
+ end
83
+
84
+ parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases, column_types, &block)
85
+ construct(parent, join_root, row_hash, seen, model_cache, strict_loading_value)
86
+ }
87
+ end
88
+
89
+ parents.values
90
+ end
91
+
92
+ def construct(ar_parent, parent, row, seen, model_cache, strict_loading_value)
93
+ return if ar_parent.nil?
94
+
95
+ parent.children.each do |node|
96
+ if node.reflection.collection?
97
+ other = ar_parent.association(node.reflection.name)
98
+ other.loaded!
99
+ elsif ar_parent.association_cached?(node.reflection.name)
100
+ model = ar_parent.association(node.reflection.name).target
101
+ construct(model, node, row, seen, model_cache, strict_loading_value)
102
+ next
103
+ end
104
+
105
+ key = aliases.column_alias(node, node.primary_key)
106
+ # CPK
107
+ if key.is_a?(Array)
108
+ id = Array(key).map do |column_alias|
109
+ row[column_alias]
110
+ end
111
+ # At least the first value in the key has to be set. Should we require all values to be set?
112
+ id = nil if id.first.nil?
113
+ else # original
114
+ id = row[key]
115
+ end
116
+
117
+ if id.nil?
118
+ nil_association = ar_parent.association(node.reflection.name)
119
+ nil_association.loaded!
120
+ next
121
+ end
122
+
123
+ model = seen[ar_parent][node][id]
124
+
125
+ if model
126
+ construct(model, node, row, seen, model_cache, strict_loading_value)
127
+ else
128
+ model = construct_model(ar_parent, node, row, model_cache, id, strict_loading_value)
129
+
130
+ seen[ar_parent][node][id] = model
131
+ construct(model, node, row, seen, model_cache, strict_loading_value)
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -1,25 +1,24 @@
1
- module ActiveRecord
2
- module Associations
3
- module ThroughAssociation
4
- alias :original_construct_join_attributes :construct_join_attributes
5
-
6
- def construct_join_attributes(*records)
7
- # CPK
8
- is_composite = self.source_reflection.polymorphic? ? source_reflection.active_record.composite? : source_reflection.klass.composite?
9
- if is_composite
10
- ensure_mutable
11
-
12
- ids = records.map do |record|
13
- source_reflection.association_primary_key(reflection.klass).map do |key|
14
- record.send(key)
15
- end
16
- end
17
-
18
- cpk_in_predicate(through_association.scope.klass.arel_table, source_reflection.foreign_key, ids)
19
- else
20
- original_construct_join_attributes(*records)
21
- end
22
- end
23
- end
24
- end
25
- end
1
+ module ActiveRecord
2
+ module Associations
3
+ module ThroughAssociation
4
+ alias :original_construct_join_attributes :construct_join_attributes
5
+
6
+ def construct_join_attributes(*records)
7
+ # CPK
8
+ if !self.source_reflection.polymorphic? && source_reflection.klass.composite?
9
+ ensure_mutable
10
+
11
+ ids = records.map do |record|
12
+ source_reflection.association_primary_key(reflection.klass).map do |key|
13
+ record.send(key)
14
+ end
15
+ end
16
+
17
+ cpk_in_predicate(through_association.scope.klass.arel_table, source_reflection.foreign_key, ids)
18
+ else
19
+ original_construct_join_attributes(*records)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,141 +1,137 @@
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
- alias_method :primary_key_without_composite_key_support=, :primary_key=
11
- def primary_key=(keys)
12
- unless keys.kind_of?(Array)
13
- self.primary_key_without_composite_key_support = keys
14
- return
15
- end
16
-
17
- @primary_keys = keys.map { |k| k.to_s }.to_composite_keys
18
-
19
- class_eval <<-EOV
20
- extend CompositeClassMethods
21
- include CompositeInstanceMethods
22
- EOV
23
- end
24
- alias_method :primary_keys=, :primary_key=
25
-
26
- def set_primary_keys(*keys)
27
- ActiveSupport::Deprecation.warn(
28
- "Calling set_primary_keys is deprecated. Please use `self.primary_keys = keys` instead."
29
- )
30
-
31
- keys = keys.first if keys.first.is_a?(Array)
32
- if keys.length == 1
33
- self.primary_key = keys.first
34
- else
35
- self.primary_keys = keys
36
- end
37
- end
38
-
39
- def composite?
40
- false
41
- end
42
- end
43
-
44
- def composite?
45
- self.class.composite?
46
- end
47
-
48
- module CompositeClassMethods
49
- def primary_keys
50
- @primary_keys = reset_primary_keys unless defined? @primary_keys
51
- @primary_keys
52
- end
53
-
54
- # Don't like this method name, but its modeled after how AR does it
55
- def reset_primary_keys #:nodoc:
56
- if self == base_class
57
- # CPK
58
- self.primary_keys = get_primary_key(base_class.name)
59
- else
60
- self.primary_keys = base_class.primary_keys
61
- end
62
- end
63
-
64
- def primary_key
65
- primary_keys
66
- end
67
-
68
- def primary_key=(keys)
69
- self.primary_keys = keys
70
- end
71
-
72
- def composite?
73
- true
74
- end
75
-
76
- #ids_to_s([[1,2],[7,3]]) -> "(1,2),(7,3)"
77
- #ids_to_s([[1,2],[7,3]], ',', ';') -> "1,2;7,3"
78
- def ids_to_s(many_ids, id_sep = CompositePrimaryKeys::ID_SEP, list_sep = ',', left_bracket = '(', right_bracket = ')')
79
- many_ids.map {|ids| "#{left_bracket}#{CompositePrimaryKeys::CompositeKeys.new(ids)}#{right_bracket}"}.join(list_sep)
80
- end
81
- end
82
-
83
- module CompositeInstanceMethods
84
- # A model instance's primary keys is always available as model.ids
85
- # whether you name it the default 'id' or set it to something else.
86
- def id
87
- attr_names = self.class.primary_keys
88
- ::CompositePrimaryKeys::CompositeKeys.new(attr_names.map { |attr_name| read_attribute(attr_name) })
89
- end
90
- alias_method :ids, :id
91
-
92
- # This is overridden purely for json serialization support. If the model is composite
93
- # and one of the keys is id, then we don't want to call the id method, instead we want
94
- # to get the id attribute value
95
- def read_attribute_for_serialization(attribute)
96
- if self.composite? && attribute == 'id'
97
- read_attribute(attribute)
98
- else
99
- send(attribute)
100
- end
101
- end
102
-
103
- def ids_hash
104
- self.class.primary_key.zip(ids).inject(Hash.new) do |hash, (key, value)|
105
- hash[key] = value
106
- hash
107
- end
108
- end
109
-
110
- def id_before_type_cast
111
- self.class.primary_keys.map do |key|
112
- self.read_attribute_before_type_cast(key)
113
- end
114
- end
115
-
116
- # Sets the primary ID.
117
- def id=(ids)
118
- ids = CompositePrimaryKeys::CompositeKeys.parse(ids)
119
- unless ids.length == self.class.primary_keys.length
120
- raise "#{self.class}.id= requires #{self.class.primary_keys.length} ids"
121
- end
122
- [self.class.primary_keys, ids].transpose.each {|key, an_id| write_attribute(key , an_id)}
123
- id
124
- end
125
-
126
- def can_change_primary_key_values?
127
- false
128
- end
129
-
130
- # Returns this record's primary keys values in an Array
131
- # if any value is available
132
- def to_key
133
- ids.to_a if !ids.compact.empty? # XXX Maybe use primary_keys with send instead of ids
134
- end
135
-
136
- def to_param
137
- persisted? ? to_key.to_composite_keys.to_s : nil
138
- end
139
- end
140
- end
141
- 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
+ alias_method :primary_key_without_composite_key_support=, :primary_key=
11
+ def primary_key=(keys)
12
+ unless keys.kind_of?(Array)
13
+ self.primary_key_without_composite_key_support = keys
14
+ return
15
+ end
16
+
17
+ @primary_keys = keys.map { |k| k.to_s }.to_composite_keys
18
+
19
+ class_eval <<-EOV
20
+ extend CompositeClassMethods
21
+ include CompositeInstanceMethods
22
+ EOV
23
+ end
24
+ alias_method :primary_keys=, :primary_key=
25
+
26
+ def set_primary_keys(*keys)
27
+ ActiveSupport::Deprecation.warn(
28
+ "Calling set_primary_keys is deprecated. Please use `self.primary_keys = keys` instead."
29
+ )
30
+
31
+ keys = keys.first if keys.first.is_a?(Array)
32
+ if keys.length == 1
33
+ self.primary_key = keys.first
34
+ else
35
+ self.primary_keys = keys
36
+ end
37
+ end
38
+
39
+ def composite?
40
+ false
41
+ end
42
+ end
43
+
44
+ def composite?
45
+ self.class.composite?
46
+ end
47
+
48
+ module CompositeClassMethods
49
+ def primary_keys
50
+ @primary_keys = reset_primary_keys unless defined? @primary_keys
51
+ @primary_keys
52
+ end
53
+
54
+ # Don't like this method name, but its modeled after how AR does it
55
+ def reset_primary_keys #:nodoc:
56
+ if self == base_class
57
+ # CPK
58
+ self.primary_keys = get_primary_key(base_class.name)
59
+ else
60
+ self.primary_keys = base_class.primary_keys
61
+ end
62
+ end
63
+
64
+ def primary_key
65
+ primary_keys
66
+ end
67
+
68
+ def primary_key=(keys)
69
+ self.primary_keys = keys
70
+ end
71
+
72
+ def composite?
73
+ true
74
+ end
75
+
76
+ #ids_to_s([[1,2],[7,3]]) -> "(1,2),(7,3)"
77
+ #ids_to_s([[1,2],[7,3]], ',', ';') -> "1,2;7,3"
78
+ def ids_to_s(many_ids, id_sep = CompositePrimaryKeys::ID_SEP, list_sep = ',', left_bracket = '(', right_bracket = ')')
79
+ many_ids.map {|ids| "#{left_bracket}#{CompositePrimaryKeys::CompositeKeys.new(ids)}#{right_bracket}"}.join(list_sep)
80
+ end
81
+ end
82
+
83
+ module CompositeInstanceMethods
84
+ # A model instance's primary keys is always available as model.ids
85
+ # whether you name it the default 'id' or set it to something else.
86
+ def id
87
+ attr_names = self.class.primary_keys
88
+ ::CompositePrimaryKeys::CompositeKeys.new(attr_names.map { |attr_name| read_attribute(attr_name) })
89
+ end
90
+ alias_method :ids, :id
91
+
92
+ # This is overridden purely for json serialization support. If the model is composite
93
+ # and one of the keys is id, then we don't want to call the id method, instead we want
94
+ # to get the id attribute value
95
+ def read_attribute_for_serialization(attribute)
96
+ if self.composite? && attribute == 'id'
97
+ read_attribute(attribute)
98
+ else
99
+ send(attribute)
100
+ end
101
+ end
102
+
103
+ def ids_hash
104
+ self.class.primary_key.zip(ids).inject(Hash.new) do |hash, (key, value)|
105
+ hash[key] = value
106
+ hash
107
+ end
108
+ end
109
+
110
+ def id_before_type_cast
111
+ self.class.primary_keys.map do |key|
112
+ self.read_attribute_before_type_cast(key)
113
+ end
114
+ end
115
+
116
+ # Sets the primary ID.
117
+ def id=(ids)
118
+ ids = CompositePrimaryKeys::CompositeKeys.parse(ids)
119
+ unless ids.length == self.class.primary_keys.length
120
+ raise "#{self.class}.id= requires #{self.class.primary_keys.length} ids"
121
+ end
122
+ [self.class.primary_keys, ids].transpose.each {|key, an_id| write_attribute(key , an_id)}
123
+ id
124
+ end
125
+
126
+ def can_change_primary_key_values?
127
+ false
128
+ end
129
+
130
+ # Returns this record's primary keys values in an Array
131
+ # if any value is available
132
+ def to_key
133
+ ids.to_a if !ids.compact.empty? # XXX Maybe use primary_keys with send instead of ids
134
+ end
135
+ end
136
+ end
137
+ end
@@ -2,7 +2,7 @@ module CompositePrimaryKeys
2
2
  module VERSION
3
3
  MAJOR = 13
4
4
  MINOR = 0
5
- TINY = 2
5
+ TINY = 3
6
6
  STRING = [MAJOR, MINOR, TINY].join('.')
7
7
  end
8
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: composite_primary_keys
3
3
  version: !ruby/object:Gem::Version
4
- version: 13.0.2
4
+ version: 13.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Charlie Savage