composite_primary_keys 13.0.2 → 13.0.3

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 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