composite_primary_keys 14.0.7 → 14.0.8

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,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
@@ -1,110 +1,110 @@
1
- module CompositePrimaryKeys
2
- module ActiveRecord
3
- module Calculations
4
- def aggregate_column(column_name)
5
- # CPK
6
- if column_name.kind_of?(Array)
7
- # Note: Test don't seem to run this code?
8
- column_name.map do |column|
9
- @klass.arel_table[column]
10
- end
11
- elsif @klass.has_attribute?(column_name) || @klass.attribute_alias?(column_name)
12
- @klass.arel_table[column_name]
13
- else
14
- Arel.sql(column_name == :all ? "*" : column_name.to_s)
15
- end
16
- end
17
-
18
- def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
19
- column_alias = column_name
20
-
21
- # CPK
22
- # if operation == "count" && (column_name == :all && distinct || has_limit_or_offset?)
23
- # # Shortcut when limit is zero.
24
- # return 0 if limit_value == 0
25
- #
26
- # query_builder = build_count_subquery(spawn, column_name, distinct)
27
- if operation == "count"
28
- relation = unscope(:order)
29
- query_builder = build_count_subquery(spawn, column_name, distinct)
30
- else
31
- # PostgreSQL doesn't like ORDER BY when there are no GROUP BY
32
- relation = unscope(:order).distinct!(false)
33
-
34
- column = aggregate_column(column_name)
35
- select_value = operation_over_aggregate_column(column, operation, distinct)
36
- select_value.distinct = true if operation == "sum" && distinct
37
-
38
- relation.select_values = [select_value]
39
-
40
- query_builder = relation.arel
41
- end
42
-
43
- result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder) }
44
-
45
- if operation != "count"
46
- type = column.try(:type_caster) ||
47
- lookup_cast_type_from_join_dependencies(column_name.to_s) || ::ActiveRecord::Type.default_value
48
- type = type.subtype if ::ActiveRecord::Enum::EnumType === type
49
- end
50
-
51
- type_cast_calculated_value(result.cast_values.first, operation, type) do |value|
52
- type = column.try(:type_caster) ||
53
- # CPK
54
- # lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
55
- lookup_cast_type_from_join_dependencies(column_name.to_s) || ::ActiveRecord::Type.default_value
56
- type.deserialize(value)
57
- end
58
- end
59
-
60
- def build_count_subquery(relation, column_name, distinct)
61
- if column_name == :all
62
- column_alias = Arel.star
63
- # CPK
64
- # relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
65
- relation.select_values = [ Arel.sql(::ActiveRecord::FinderMethods::ONE_AS_ONE) ] unless distinct
66
- elsif column_name.is_a?(Array)
67
- column_alias = Arel.star
68
- relation.select_values = column_name.map do |column|
69
- Arel::Attribute.new(@klass.unscoped.table, column)
70
- end
71
- else
72
- column_alias = Arel.sql("count_column")
73
- relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
74
- end
75
-
76
- subquery_alias = Arel.sql("subquery_for_count")
77
- select_value = operation_over_aggregate_column(column_alias, "count", false)
78
-
79
- relation.build_subquery(subquery_alias, select_value)
80
- end
81
-
82
- def calculate(operation, column_name)
83
- if has_include?(column_name)
84
- relation = apply_join_dependency
85
-
86
- if operation.to_s.downcase == "count"
87
- unless distinct_value || distinct_select?(column_name || select_for_count)
88
- relation.distinct!
89
- # CPK
90
- # relation.select_values = [ klass.primary_key || table[Arel.star] ]
91
- if klass.primary_key.present? && klass.primary_key.is_a?(Array)
92
- relation.select_values = klass.primary_key.map do |k|
93
- "#{connection.quote_table_name(klass.table_name)}.#{connection.quote_column_name(k)}"
94
- end
95
- else
96
- relation.select_values = [ klass.primary_key || table[Arel.star] ]
97
- end
98
- end
99
- # PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
100
- relation.order_values = [] if group_values.empty?
101
- end
102
-
103
- relation.calculate(operation, column_name)
104
- else
105
- perform_calculation(operation, column_name)
106
- end
107
- end
108
- end
109
- end
110
- end
1
+ module CompositePrimaryKeys
2
+ module ActiveRecord
3
+ module Calculations
4
+ def aggregate_column(column_name)
5
+ # CPK
6
+ if column_name.kind_of?(Array)
7
+ # Note: Test don't seem to run this code?
8
+ column_name.map do |column|
9
+ @klass.arel_table[column]
10
+ end
11
+ elsif @klass.has_attribute?(column_name) || @klass.attribute_alias?(column_name)
12
+ @klass.arel_table[column_name]
13
+ else
14
+ Arel.sql(column_name == :all ? "*" : column_name.to_s)
15
+ end
16
+ end
17
+
18
+ def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
19
+ column_alias = column_name
20
+
21
+ # CPK
22
+ # if operation == "count" && (column_name == :all && distinct || has_limit_or_offset?)
23
+ # # Shortcut when limit is zero.
24
+ # return 0 if limit_value == 0
25
+ #
26
+ # query_builder = build_count_subquery(spawn, column_name, distinct)
27
+ if operation == "count"
28
+ relation = unscope(:order)
29
+ query_builder = build_count_subquery(spawn, column_name, distinct)
30
+ else
31
+ # PostgreSQL doesn't like ORDER BY when there are no GROUP BY
32
+ relation = unscope(:order).distinct!(false)
33
+
34
+ column = aggregate_column(column_name)
35
+ select_value = operation_over_aggregate_column(column, operation, distinct)
36
+ select_value.distinct = true if operation == "sum" && distinct
37
+
38
+ relation.select_values = [select_value]
39
+
40
+ query_builder = relation.arel
41
+ end
42
+
43
+ result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder) }
44
+
45
+ if operation != "count"
46
+ type = column.try(:type_caster) ||
47
+ lookup_cast_type_from_join_dependencies(column_name.to_s) || ::ActiveRecord::Type.default_value
48
+ type = type.subtype if ::ActiveRecord::Enum::EnumType === type
49
+ end
50
+
51
+ type_cast_calculated_value(result.cast_values.first, operation, type) do |value|
52
+ type = column.try(:type_caster) ||
53
+ # CPK
54
+ # lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
55
+ lookup_cast_type_from_join_dependencies(column_name.to_s) || ::ActiveRecord::Type.default_value
56
+ type.deserialize(value)
57
+ end
58
+ end
59
+
60
+ def build_count_subquery(relation, column_name, distinct)
61
+ if column_name == :all
62
+ column_alias = Arel.star
63
+ # CPK
64
+ # relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
65
+ relation.select_values = [ Arel.sql(::ActiveRecord::FinderMethods::ONE_AS_ONE) ] unless distinct
66
+ elsif column_name.is_a?(Array)
67
+ column_alias = Arel.star
68
+ relation.select_values = column_name.map do |column|
69
+ Arel::Attribute.new(@klass.unscoped.table, column)
70
+ end
71
+ else
72
+ column_alias = Arel.sql("count_column")
73
+ relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
74
+ end
75
+
76
+ subquery_alias = Arel.sql("subquery_for_count")
77
+ select_value = operation_over_aggregate_column(column_alias, "count", false)
78
+
79
+ relation.build_subquery(subquery_alias, select_value)
80
+ end
81
+
82
+ def calculate(operation, column_name)
83
+ if has_include?(column_name)
84
+ relation = apply_join_dependency
85
+
86
+ if operation.to_s.downcase == "count"
87
+ unless distinct_value || distinct_select?(column_name || select_for_count)
88
+ relation.distinct!
89
+ # CPK
90
+ # relation.select_values = [ klass.primary_key || table[Arel.star] ]
91
+ if klass.primary_key.present? && klass.primary_key.is_a?(Array)
92
+ relation.select_values = klass.primary_key.map do |k|
93
+ "#{connection.quote_table_name(klass.table_name)}.#{connection.quote_column_name(k)}"
94
+ end
95
+ else
96
+ relation.select_values = [ klass.primary_key || table[Arel.star] ]
97
+ end
98
+ end
99
+ # PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
100
+ relation.order_values = [] if group_values.empty?
101
+ end
102
+
103
+ relation.calculate(operation, column_name)
104
+ else
105
+ perform_calculation(operation, column_name)
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -1,40 +1,40 @@
1
- module ActiveRecord
2
- module Validations
3
- class UniquenessValidator
4
- def validate_each(record, attribute, value)
5
- finder_class = find_finder_class_for(record)
6
- value = map_enum_attribute(finder_class, attribute, value)
7
-
8
- relation = build_relation(finder_class, attribute, value)
9
- if record.persisted?
10
- # CPK
11
- if finder_class.primary_key.is_a?(Array)
12
- predicate = finder_class.cpk_id_predicate(finder_class.arel_table, finder_class.primary_key, record.id_in_database || record.id)
13
- relation = relation.where.not(predicate)
14
- elsif finder_class.primary_key
15
- relation = relation.where.not(finder_class.primary_key => record.id_in_database)
16
- else
17
- raise UnknownPrimaryKey.new(finder_class, "Can not validate uniqueness for persisted record without primary key.")
18
- end
19
- end
20
- relation = scope_relation(record, relation)
21
- if options[:conditions]
22
- conditions = options[:conditions]
23
-
24
- relation = if conditions.arity.zero?
25
- relation.instance_exec(&conditions)
26
- else
27
- relation.instance_exec(record, &conditions)
28
- end
29
- end
30
-
31
- if relation.exists?
32
- error_options = options.except(:case_sensitive, :scope, :conditions)
33
- error_options[:value] = value
34
-
35
- record.errors.add(attribute, :taken, **error_options)
36
- end
37
- end
38
- end
39
- end
40
- end
1
+ module ActiveRecord
2
+ module Validations
3
+ class UniquenessValidator
4
+ def validate_each(record, attribute, value)
5
+ finder_class = find_finder_class_for(record)
6
+ value = map_enum_attribute(finder_class, attribute, value)
7
+
8
+ relation = build_relation(finder_class, attribute, value)
9
+ if record.persisted?
10
+ # CPK
11
+ if finder_class.primary_key.is_a?(Array)
12
+ predicate = finder_class.cpk_id_predicate(finder_class.arel_table, finder_class.primary_key, record.id_in_database || record.id)
13
+ relation = relation.where.not(predicate)
14
+ elsif finder_class.primary_key
15
+ relation = relation.where.not(finder_class.primary_key => record.id_in_database)
16
+ else
17
+ raise UnknownPrimaryKey.new(finder_class, "Can not validate uniqueness for persisted record without primary key.")
18
+ end
19
+ end
20
+ relation = scope_relation(record, relation)
21
+ if options[:conditions]
22
+ conditions = options[:conditions]
23
+
24
+ relation = if conditions.arity.zero?
25
+ relation.instance_exec(&conditions)
26
+ else
27
+ relation.instance_exec(record, &conditions)
28
+ end
29
+ end
30
+
31
+ if relation.exists?
32
+ error_options = options.except(:case_sensitive, :scope, :conditions)
33
+ error_options[:value] = value
34
+
35
+ record.errors.add(attribute, :taken, **error_options)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -2,7 +2,7 @@ module CompositePrimaryKeys
2
2
  module VERSION
3
3
  MAJOR = 14
4
4
  MINOR = 0
5
- TINY = 7
5
+ TINY = 8
6
6
  STRING = [MAJOR, MINOR, TINY].join('.')
7
7
  end
8
8
  end
@@ -1,20 +1,20 @@
1
- class Department < ActiveRecord::Base
2
- self.primary_keys = :id, :location_id
3
-
4
- has_many :employees,
5
- # We intentionally redefine primary key for test purposes. #455
6
- :primary_key => [:id, :location_id],
7
- :foreign_key => [:department_id, :location_id]
8
-
9
- has_many :comments, :through => :employees
10
-
11
- has_one :head, :class_name => 'Employee', :autosave => true, :dependent => :delete,
12
- # We intentionally redefine primary key for test purposes. #455
13
- :primary_key => [:id, :location_id],
14
- :foreign_key => [:department_id, :location_id]
15
-
16
- has_one :head_without_autosave, :class_name => 'Employee',
17
- # We intentionally redefine primary key for test purposes. #455
18
- :primary_key => [:id, :location_id],
19
- :foreign_key => [:department_id, :location_id]
20
- end
1
+ class Department < ActiveRecord::Base
2
+ self.primary_keys = :id, :location_id
3
+
4
+ has_many :employees,
5
+ # We intentionally redefine primary key for test purposes. #455
6
+ :primary_key => [:id, :location_id],
7
+ :foreign_key => [:department_id, :location_id]
8
+
9
+ has_many :comments, :through => :employees
10
+
11
+ has_one :head, :class_name => 'Employee', :autosave => true, :dependent => :delete,
12
+ # We intentionally redefine primary key for test purposes. #455
13
+ :primary_key => [:id, :location_id],
14
+ :foreign_key => [:department_id, :location_id]
15
+
16
+ has_one :head_without_autosave, :class_name => 'Employee',
17
+ # We intentionally redefine primary key for test purposes. #455
18
+ :primary_key => [:id, :location_id],
19
+ :foreign_key => [:department_id, :location_id]
20
+ end
@@ -1,18 +1,18 @@
1
- class RoomAssignment < ActiveRecord::Base
2
- self.primary_keys = :student_id, :dorm_id, :room_id
3
- belongs_to :student
4
- belongs_to :room, :foreign_key => [:dorm_id, :room_id], :primary_key => [:dorm_id, :room_id]
5
- validates :student_id, uniqueness: {
6
- conditions: ->(record) {
7
- where(student_id: record.student_id) # enough just to exercise this code path
8
- }
9
- }
10
-
11
- before_destroy do |record|
12
- puts record
13
- end
14
-
15
- after_destroy do |record|
16
- puts record
17
- end
18
- end
1
+ class RoomAssignment < ActiveRecord::Base
2
+ self.primary_keys = :student_id, :dorm_id, :room_id
3
+ belongs_to :student
4
+ belongs_to :room, :foreign_key => [:dorm_id, :room_id], :primary_key => [:dorm_id, :room_id]
5
+ validates :student_id, uniqueness: {
6
+ conditions: ->(record) {
7
+ where(student_id: record.student_id) # enough just to exercise this code path
8
+ }
9
+ }
10
+
11
+ before_destroy do |record|
12
+ puts record
13
+ end
14
+
15
+ after_destroy do |record|
16
+ puts record
17
+ end
18
+ end