composite_primary_keys 14.0.1 → 14.0.2

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.
@@ -1,68 +1,68 @@
1
- module ActiveRecord
2
- module Associations
3
- class Preloader
4
- class Association
5
-
6
- class LoaderQuery
7
- def load_records_for_keys(keys, &block)
8
- # CPK
9
- if association_key_name.is_a?(Array)
10
- predicate = cpk_in_predicate(scope.klass.arel_table, association_key_name, keys)
11
- scope.where(predicate).load(&block)
12
- else
13
- scope.where(association_key_name => keys).load(&block)
14
- end
15
- end
16
- end
17
-
18
- # TODO: is records_for needed anymore? Rails' implementation has changed significantly
19
- def records_for(ids)
20
- records = if association_key_name.is_a?(Array)
21
- predicate = cpk_in_predicate(klass.arel_table, association_key_name, ids)
22
- scope.where(predicate)
23
- else
24
- scope.where(association_key_name => ids)
25
- end
26
- records.load do |record|
27
- # Processing only the first owner
28
- # because the record is modified but not an owner
29
- owner = owners_by_key[convert_key(record[association_key_name])].first
30
- association = owner.association(reflection.name)
31
- association.set_inverse_instance(record)
32
- end
33
- end
34
-
35
- def owners_by_key
36
- @owners_by_key ||= owners.each_with_object({}) do |owner, result|
37
- # CPK
38
- # key = convert_key(owner[owner_key_name])
39
- key = if owner_key_name.is_a?(Array)
40
- Array(owner_key_name).map do |key_name|
41
- convert_key(owner[key_name])
42
- end
43
- else
44
- convert_key(owner[owner_key_name])
45
- end
46
- (result[key] ||= []) << owner if key
47
- end
48
- end
49
-
50
- # TODO: is records_by_owner needed anymore? Rails' implementation has changed significantly
51
- def records_by_owner
52
- @records_by_owner ||= preloaded_records.each_with_object({}) do |record, result|
53
- key = if association_key_name.is_a?(Array)
54
- Array(record[association_key_name]).map do |key|
55
- convert_key(key)
56
- end
57
- else
58
- convert_key(record[association_key_name])
59
- end
60
- owners_by_key[key].each do |owner|
61
- (result[owner] ||= []) << record
62
- end
63
- end
64
- end
65
- end
66
- end
67
- end
68
- end
1
+ module ActiveRecord
2
+ module Associations
3
+ class Preloader
4
+ class Association
5
+
6
+ class LoaderQuery
7
+ def load_records_for_keys(keys, &block)
8
+ # CPK
9
+ if association_key_name.is_a?(Array)
10
+ predicate = cpk_in_predicate(scope.klass.arel_table, association_key_name, keys)
11
+ scope.where(predicate).load(&block)
12
+ else
13
+ scope.where(association_key_name => keys).load(&block)
14
+ end
15
+ end
16
+ end
17
+
18
+ # TODO: is records_for needed anymore? Rails' implementation has changed significantly
19
+ def records_for(ids)
20
+ records = if association_key_name.is_a?(Array)
21
+ predicate = cpk_in_predicate(klass.arel_table, association_key_name, ids)
22
+ scope.where(predicate)
23
+ else
24
+ scope.where(association_key_name => ids)
25
+ end
26
+ records.load do |record|
27
+ # Processing only the first owner
28
+ # because the record is modified but not an owner
29
+ owner = owners_by_key[convert_key(record[association_key_name])].first
30
+ association = owner.association(reflection.name)
31
+ association.set_inverse_instance(record)
32
+ end
33
+ end
34
+
35
+ def owners_by_key
36
+ @owners_by_key ||= owners.each_with_object({}) do |owner, result|
37
+ # CPK
38
+ # key = convert_key(owner[owner_key_name])
39
+ key = if owner_key_name.is_a?(Array)
40
+ Array(owner_key_name).map do |key_name|
41
+ convert_key(owner[key_name])
42
+ end
43
+ else
44
+ convert_key(owner[owner_key_name])
45
+ end
46
+ (result[key] ||= []) << owner if key
47
+ end
48
+ end
49
+
50
+ # TODO: is records_by_owner needed anymore? Rails' implementation has changed significantly
51
+ def records_by_owner
52
+ @records_by_owner ||= preloaded_records.each_with_object({}) do |record, result|
53
+ key = if association_key_name.is_a?(Array)
54
+ Array(record[association_key_name]).map do |key|
55
+ convert_key(key)
56
+ end
57
+ else
58
+ convert_key(record[association_key_name])
59
+ end
60
+ owners_by_key[key].each do |owner|
61
+ (result[owner] ||= []) << record
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -1,71 +1,71 @@
1
- module CompositePrimaryKeys
2
- module Predicates
3
- # Similar to module_function, but does not make instance methods private.
4
- # https://idiosyncratic-ruby.com/8-self-improvement.html
5
- extend self
6
-
7
- def cpk_and_predicate(predicates)
8
- if predicates.length == 1
9
- predicates.first
10
- else
11
- Arel::Nodes::And.new(predicates)
12
- end
13
- end
14
-
15
- def cpk_or_predicate(predicates, group = true)
16
- if predicates.length <= 1
17
- predicates.first
18
- else
19
- split_point = predicates.length / 2
20
- predicates_first_half = predicates[0...split_point]
21
- predicates_second_half = predicates[split_point..-1]
22
-
23
- or_predicate = ::Arel::Nodes::Or.new(cpk_or_predicate(predicates_first_half, false),
24
- cpk_or_predicate(predicates_second_half, false))
25
-
26
- if group
27
- ::Arel::Nodes::Grouping.new(or_predicate)
28
- else
29
- or_predicate
30
- end
31
- end
32
- end
33
-
34
- def cpk_id_predicate(table, keys, values)
35
- # We zip on values then keys in case values are not provided for each key field
36
- eq_predicates = values.zip(keys).map do |value, key|
37
- table[key].eq(value)
38
- end
39
- cpk_and_predicate(eq_predicates)
40
- end
41
-
42
- def cpk_join_predicate(table1, key1, table2, key2)
43
- key1_fields = Array(key1).map {|key| table1[key]}
44
- key2_fields = Array(key2).map {|key| table2[key]}
45
-
46
- eq_predicates = key1_fields.zip(key2_fields).map do |key_field1, key_field2|
47
- key_field2 = Arel::Nodes::Quoted.new(key_field2) unless Arel::Attributes::Attribute === key_field2
48
- key_field1.eq(key_field2)
49
- end
50
- cpk_and_predicate(eq_predicates)
51
- end
52
-
53
- def cpk_in_predicate(table, primary_keys, ids)
54
- and_predicates = ids.map do |id|
55
- cpk_id_predicate(table, primary_keys, id)
56
- end
57
- cpk_or_predicate(and_predicates)
58
- end
59
- end
60
- end
61
-
62
- ActiveRecord::Associations::AssociationScope.send(:include, CompositePrimaryKeys::Predicates)
63
- ActiveRecord::Associations::JoinDependency::JoinAssociation.send(:include, CompositePrimaryKeys::Predicates)
64
- ActiveRecord::Associations::Preloader::Association.send(:include, CompositePrimaryKeys::Predicates)
65
- ActiveRecord::Associations::Preloader::Association::LoaderQuery.send(:include, CompositePrimaryKeys::Predicates)
66
- ActiveRecord::Associations::HasManyAssociation.send(:include, CompositePrimaryKeys::Predicates)
67
- ActiveRecord::Associations::HasManyThroughAssociation.send(:include, CompositePrimaryKeys::Predicates)
68
- ActiveRecord::Base.send(:extend, CompositePrimaryKeys::Predicates)
69
- ActiveRecord::Reflection::AbstractReflection.send(:include, CompositePrimaryKeys::Predicates)
70
- ActiveRecord::Relation.send(:include, CompositePrimaryKeys::Predicates)
71
- ActiveRecord::PredicateBuilder.send(:extend, CompositePrimaryKeys::Predicates)
1
+ module CompositePrimaryKeys
2
+ module Predicates
3
+ # Similar to module_function, but does not make instance methods private.
4
+ # https://idiosyncratic-ruby.com/8-self-improvement.html
5
+ extend self
6
+
7
+ def cpk_and_predicate(predicates)
8
+ if predicates.length == 1
9
+ predicates.first
10
+ else
11
+ Arel::Nodes::And.new(predicates)
12
+ end
13
+ end
14
+
15
+ def cpk_or_predicate(predicates, group = true)
16
+ if predicates.length <= 1
17
+ predicates.first
18
+ else
19
+ split_point = predicates.length / 2
20
+ predicates_first_half = predicates[0...split_point]
21
+ predicates_second_half = predicates[split_point..-1]
22
+
23
+ or_predicate = ::Arel::Nodes::Or.new(cpk_or_predicate(predicates_first_half, false),
24
+ cpk_or_predicate(predicates_second_half, false))
25
+
26
+ if group
27
+ ::Arel::Nodes::Grouping.new(or_predicate)
28
+ else
29
+ or_predicate
30
+ end
31
+ end
32
+ end
33
+
34
+ def cpk_id_predicate(table, keys, values)
35
+ # We zip on values then keys in case values are not provided for each key field
36
+ eq_predicates = values.zip(keys).map do |value, key|
37
+ table[key].eq(value)
38
+ end
39
+ cpk_and_predicate(eq_predicates)
40
+ end
41
+
42
+ def cpk_join_predicate(table1, key1, table2, key2)
43
+ key1_fields = Array(key1).map {|key| table1[key]}
44
+ key2_fields = Array(key2).map {|key| table2[key]}
45
+
46
+ eq_predicates = key1_fields.zip(key2_fields).map do |key_field1, key_field2|
47
+ key_field2 = Arel::Nodes::Quoted.new(key_field2) unless Arel::Attributes::Attribute === key_field2
48
+ key_field1.eq(key_field2)
49
+ end
50
+ cpk_and_predicate(eq_predicates)
51
+ end
52
+
53
+ def cpk_in_predicate(table, primary_keys, ids)
54
+ and_predicates = ids.map do |id|
55
+ cpk_id_predicate(table, primary_keys, id)
56
+ end
57
+ cpk_or_predicate(and_predicates)
58
+ end
59
+ end
60
+ end
61
+
62
+ ActiveRecord::Associations::AssociationScope.send(:include, CompositePrimaryKeys::Predicates)
63
+ ActiveRecord::Associations::JoinDependency::JoinAssociation.send(:include, CompositePrimaryKeys::Predicates)
64
+ ActiveRecord::Associations::Preloader::Association.send(:include, CompositePrimaryKeys::Predicates)
65
+ ActiveRecord::Associations::Preloader::Association::LoaderQuery.send(:include, CompositePrimaryKeys::Predicates)
66
+ ActiveRecord::Associations::HasManyAssociation.send(:include, CompositePrimaryKeys::Predicates)
67
+ ActiveRecord::Associations::HasManyThroughAssociation.send(:include, CompositePrimaryKeys::Predicates)
68
+ ActiveRecord::Base.send(:extend, CompositePrimaryKeys::Predicates)
69
+ ActiveRecord::Reflection::AbstractReflection.send(:include, CompositePrimaryKeys::Predicates)
70
+ ActiveRecord::Relation.send(:include, CompositePrimaryKeys::Predicates)
71
+ ActiveRecord::PredicateBuilder.send(:extend, CompositePrimaryKeys::Predicates)
@@ -1,96 +1,96 @@
1
- module ActiveRecord
2
- module Persistence
3
- module ClassMethods
4
- def delete(id_or_array)
5
- # CPK
6
- if self.composite?
7
- id_or_array = if id_or_array.is_a?(CompositePrimaryKeys::CompositeKeys)
8
- [id_or_array]
9
- else
10
- Array(id_or_array)
11
- end
12
-
13
- # Delete should return the number of deleted records
14
- id_or_array.map do |id|
15
- # Is the passed in id actually a record?
16
- id = id.kind_of?(::ActiveRecord::Base) ? id.id : id
17
- delete_by(cpk_id_predicate(self.arel_table, self.primary_key, id))
18
- end.sum
19
- else
20
- delete_by(primary_key => id_or_array)
21
- end
22
- end
23
-
24
- def _update_record(values, constraints) # :nodoc:
25
- # CPK
26
- if self.composite? && constraints[primary_key]
27
- primary_key_values = constraints.delete(primary_key)
28
- primary_key.each_with_index do |key, i|
29
- constraints[key] = primary_key_values[i]
30
- end
31
- end
32
-
33
- constraints = constraints.map { |name, value| predicate_builder[name, value] }
34
-
35
- default_constraint = build_default_constraint
36
- constraints << default_constraint if default_constraint
37
-
38
- if current_scope = self.global_current_scope
39
- constraints << current_scope.where_clause.ast
40
- end
41
-
42
- um = Arel::UpdateManager.new(arel_table)
43
- um.set(values.transform_keys { |name| arel_table[name] })
44
- um.wheres = constraints
45
-
46
- connection.update(um, "#{self} Update")
47
- end
48
-
49
- def _delete_record(constraints) # :nodoc:
50
- # CPK
51
- if self.composite? && constraints[primary_key]
52
- primary_key_values = constraints.delete(primary_key)
53
- primary_key.each_with_index do |key, i|
54
- constraints[key] = primary_key_values[i]
55
- end
56
- end
57
-
58
- constraints = constraints.map { |name, value| predicate_builder[name, value] }
59
-
60
- default_constraint = build_default_constraint
61
- constraints << default_constraint if default_constraint
62
-
63
- if current_scope = self.global_current_scope
64
- constraints << current_scope.where_clause.ast
65
- end
66
-
67
- dm = Arel::DeleteManager.new(arel_table)
68
- dm.wheres = constraints
69
-
70
- connection.delete(dm, "#{self} Destroy")
71
- end
72
- end
73
-
74
- def _create_record(attribute_names = self.attribute_names)
75
- attribute_names = attributes_for_create(attribute_names)
76
-
77
- new_id = self.class._insert_record(
78
- attributes_with_values(attribute_names)
79
- )
80
-
81
- # CPK
82
- if self.composite?
83
- self.id = self.id.zip(Array(new_id)).map {|id1, id2| id2.nil? ? id1 : id2}
84
- else
85
- self.id ||= new_id if self.class.primary_key
86
- end
87
-
88
- @new_record = false
89
- @previously_new_record = true
90
-
91
- yield(self) if block_given?
92
-
93
- id
94
- end
95
- end
96
- end
1
+ module ActiveRecord
2
+ module Persistence
3
+ module ClassMethods
4
+ def delete(id_or_array)
5
+ # CPK
6
+ if self.composite?
7
+ id_or_array = if id_or_array.is_a?(CompositePrimaryKeys::CompositeKeys)
8
+ [id_or_array]
9
+ else
10
+ Array(id_or_array)
11
+ end
12
+
13
+ # Delete should return the number of deleted records
14
+ id_or_array.map do |id|
15
+ # Is the passed in id actually a record?
16
+ id = id.kind_of?(::ActiveRecord::Base) ? id.id : id
17
+ delete_by(cpk_id_predicate(self.arel_table, self.primary_key, id))
18
+ end.sum
19
+ else
20
+ delete_by(primary_key => id_or_array)
21
+ end
22
+ end
23
+
24
+ def _update_record(values, constraints) # :nodoc:
25
+ # CPK
26
+ if self.composite? && constraints[primary_key]
27
+ primary_key_values = constraints.delete(primary_key)
28
+ primary_key.each_with_index do |key, i|
29
+ constraints[key] = primary_key_values[i]
30
+ end
31
+ end
32
+
33
+ constraints = constraints.map { |name, value| predicate_builder[name, value] }
34
+
35
+ default_constraint = build_default_constraint
36
+ constraints << default_constraint if default_constraint
37
+
38
+ if current_scope = self.global_current_scope
39
+ constraints << current_scope.where_clause.ast
40
+ end
41
+
42
+ um = Arel::UpdateManager.new(arel_table)
43
+ um.set(values.transform_keys { |name| arel_table[name] })
44
+ um.wheres = constraints
45
+
46
+ connection.update(um, "#{self} Update")
47
+ end
48
+
49
+ def _delete_record(constraints) # :nodoc:
50
+ # CPK
51
+ if self.composite? && constraints[primary_key]
52
+ primary_key_values = constraints.delete(primary_key)
53
+ primary_key.each_with_index do |key, i|
54
+ constraints[key] = primary_key_values[i]
55
+ end
56
+ end
57
+
58
+ constraints = constraints.map { |name, value| predicate_builder[name, value] }
59
+
60
+ default_constraint = build_default_constraint
61
+ constraints << default_constraint if default_constraint
62
+
63
+ if current_scope = self.global_current_scope
64
+ constraints << current_scope.where_clause.ast
65
+ end
66
+
67
+ dm = Arel::DeleteManager.new(arel_table)
68
+ dm.wheres = constraints
69
+
70
+ connection.delete(dm, "#{self} Destroy")
71
+ end
72
+ end
73
+
74
+ def _create_record(attribute_names = self.attribute_names)
75
+ attribute_names = attributes_for_create(attribute_names)
76
+
77
+ new_id = self.class._insert_record(
78
+ attributes_with_values(attribute_names)
79
+ )
80
+
81
+ # CPK
82
+ if self.composite?
83
+ self.id = self.id.zip(Array(new_id)).map {|id1, id2| id2.nil? ? id1 : id2}
84
+ else
85
+ self.id ||= new_id if self.class.primary_key
86
+ end
87
+
88
+ @new_record = false
89
+ @previously_new_record = true
90
+
91
+ yield(self) if block_given?
92
+
93
+ id
94
+ end
95
+ end
96
+ end