composite_primary_keys 13.0.7 → 14.0.1

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,83 +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 = _substitute_values(constraints).map { |attr, bind| attr.eq(bind) }
34
-
35
- um = arel_table.where(
36
- constraints.reduce(&:and)
37
- ).compile_update(_substitute_values(values), primary_key)
38
-
39
- connection.update(um, "#{self} Update")
40
- end
41
-
42
- def _delete_record(constraints) # :nodoc:
43
- # CPK
44
- if self.composite? && constraints[primary_key]
45
- primary_key_values = constraints.delete(primary_key)
46
- primary_key.each_with_index do |key, i|
47
- constraints[key] = primary_key_values[i]
48
- end
49
- end
50
-
51
- constraints = _substitute_values(constraints).map { |attr, bind| attr.eq(bind) }
52
-
53
- dm = Arel::DeleteManager.new
54
- dm.from(arel_table)
55
- dm.wheres = constraints
56
-
57
- connection.delete(dm, "#{self} Destroy")
58
- end
59
- end
60
-
61
- def _create_record(attribute_names = self.attribute_names)
62
- attribute_names = attributes_for_create(attribute_names)
63
-
64
- new_id = self.class._insert_record(
65
- attributes_with_values(attribute_names)
66
- )
67
-
68
- # CPK
69
- if self.composite?
70
- self.id = self.id.zip(Array(new_id)).map {|id1, id2| id2.nil? ? id1 : id2}
71
- else
72
- self.id ||= new_id if self.class.primary_key
73
- end
74
-
75
- @new_record = false
76
- @previously_new_record = true
77
-
78
- yield(self) if block_given?
79
-
80
- id
81
- end
82
- end
83
- 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,104 +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
- type_cast_calculated_value(result.cast_values.first, operation) do |value|
46
- type = column.try(:type_caster) ||
47
- # CPK
48
- # lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
49
- lookup_cast_type_from_join_dependencies(column_name.to_s) || ::ActiveRecord::Type.default_value
50
- type.deserialize(value)
51
- end
52
- end
53
-
54
- def build_count_subquery(relation, column_name, distinct)
55
- if column_name == :all
56
- column_alias = Arel.star
57
- # CPK
58
- # relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
59
- relation.select_values = [ Arel.sql(::ActiveRecord::FinderMethods::ONE_AS_ONE) ] unless distinct
60
- elsif column_name.is_a?(Array)
61
- column_alias = Arel.star
62
- relation.select_values = column_name.map do |column|
63
- Arel::Attribute.new(@klass.unscoped.table, column)
64
- end
65
- else
66
- column_alias = Arel.sql("count_column")
67
- relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
68
- end
69
-
70
- subquery_alias = Arel.sql("subquery_for_count")
71
- select_value = operation_over_aggregate_column(column_alias, "count", false)
72
-
73
- relation.build_subquery(subquery_alias, select_value)
74
- end
75
-
76
- def calculate(operation, column_name)
77
- if has_include?(column_name)
78
- relation = apply_join_dependency
79
-
80
- if operation.to_s.downcase == "count"
81
- unless distinct_value || distinct_select?(column_name || select_for_count)
82
- relation.distinct!
83
- # CPK
84
- # relation.select_values = [ klass.primary_key || table[Arel.star] ]
85
- if klass.primary_key.present? && klass.primary_key.is_a?(Array)
86
- relation.select_values = klass.primary_key.map do |k|
87
- "#{connection.quote_table_name(klass.table_name)}.#{connection.quote_column_name(k)}"
88
- end
89
- else
90
- relation.select_values = [ klass.primary_key || table[Arel.star] ]
91
- end
92
- end
93
- # PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
94
- relation.order_values = [] if group_values.empty?
95
- end
96
-
97
- relation.calculate(operation, column_name)
98
- else
99
- perform_calculation(operation, column_name)
100
- end
101
- end
102
- end
103
- end
104
- 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
@@ -29,7 +29,7 @@ module ActiveRecord
29
29
  stmt.key = table[primary_key]
30
30
 
31
31
  # CPK
32
- if @klass.composite?
32
+ if @klass.composite? && @klass.connection.visitor.compile(stmt.ast) =~ /['"]#{primary_key.to_s}['"]/
33
33
  stmt = Arel::UpdateManager.new
34
34
  stmt.table(arel_table)
35
35
  cpk_subquery(stmt)
@@ -74,7 +74,7 @@ module ActiveRecord
74
74
  stmt.key = table[primary_key]
75
75
 
76
76
  # CPK
77
- if @klass.composite?
77
+ if @klass.composite? && @klass.connection.visitor.compile(stmt.ast) =~ /['"]#{primary_key.to_s}['"]/
78
78
  stmt = Arel::DeleteManager.new
79
79
  stmt.from(arel_table)
80
80
  cpk_subquery(stmt)
@@ -1,32 +1,32 @@
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
- relation = relation.merge(options[:conditions]) if options[:conditions]
22
-
23
- if relation.exists?
24
- error_options = options.except(:case_sensitive, :scope, :conditions)
25
- error_options[:value] = value
26
-
27
- record.errors.add(attribute, :taken, **error_options)
28
- end
29
- end
30
- end
31
- 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
+ relation = relation.merge(options[:conditions]) if options[:conditions]
22
+
23
+ if relation.exists?
24
+ error_options = options.except(:case_sensitive, :scope, :conditions)
25
+ error_options[:value] = value
26
+
27
+ record.errors.add(attribute, :taken, **error_options)
28
+ end
29
+ end
30
+ end
31
+ end
32
32
  end
@@ -1,8 +1,8 @@
1
- module CompositePrimaryKeys
2
- module VERSION
3
- MAJOR = 13
4
- MINOR = 0
5
- TINY = 7
6
- STRING = [MAJOR, MINOR, TINY].join('.')
7
- end
8
- end
1
+ module CompositePrimaryKeys
2
+ module VERSION
3
+ MAJOR = 14
4
+ MINOR = 0
5
+ TINY = 1
6
+ STRING = [MAJOR, MINOR, TINY].join('.')
7
+ end
8
+ end