composite_primary_keys 12.0.8 → 13.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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/History.rdoc +888 -874
  3. data/README.rdoc +181 -180
  4. data/lib/composite_primary_keys/active_model/attribute_assignment.rb +19 -19
  5. data/lib/composite_primary_keys/associations/association_scope.rb +66 -68
  6. data/lib/composite_primary_keys/associations/join_dependency.rb +137 -103
  7. data/lib/composite_primary_keys/attribute_methods/primary_key.rb +0 -2
  8. data/lib/composite_primary_keys/attribute_methods/read.rb +30 -30
  9. data/lib/composite_primary_keys/attribute_methods/write.rb +35 -35
  10. data/lib/composite_primary_keys/attribute_methods.rb +21 -9
  11. data/lib/composite_primary_keys/base.rb +141 -141
  12. data/lib/composite_primary_keys/composite_predicates.rb +2 -1
  13. data/lib/composite_primary_keys/connection_adapters/abstract/database_statements.rb +37 -22
  14. data/lib/composite_primary_keys/connection_adapters/sqlserver/database_statements.rb +44 -44
  15. data/lib/composite_primary_keys/core.rb +48 -48
  16. data/lib/composite_primary_keys/nested_attributes.rb +1 -1
  17. data/lib/composite_primary_keys/persistence.rb +82 -81
  18. data/lib/composite_primary_keys/reflection.rb +91 -29
  19. data/lib/composite_primary_keys/relation/batches.rb +15 -7
  20. data/lib/composite_primary_keys/relation/calculations.rb +104 -81
  21. data/lib/composite_primary_keys/relation/finder_methods.rb +235 -235
  22. data/lib/composite_primary_keys/relation/predicate_builder/association_query_value.rb +39 -20
  23. data/lib/composite_primary_keys/relation/query_methods.rb +42 -42
  24. data/lib/composite_primary_keys/relation/where_clause.rb +18 -23
  25. data/lib/composite_primary_keys/relation.rb +197 -193
  26. data/lib/composite_primary_keys/table_metadata.rb +11 -0
  27. data/lib/composite_primary_keys/version.rb +8 -8
  28. data/lib/composite_primary_keys.rb +119 -119
  29. data/test/abstract_unit.rb +114 -114
  30. data/test/connections/databases.ci.yml +22 -22
  31. data/test/fixtures/db_definitions/db2-create-tables.sql +112 -112
  32. data/test/fixtures/db_definitions/db2-drop-tables.sql +16 -16
  33. data/test/fixtures/db_definitions/mysql.sql +180 -180
  34. data/test/fixtures/db_definitions/oracle.drop.sql +41 -41
  35. data/test/fixtures/db_definitions/oracle.sql +199 -199
  36. data/test/fixtures/db_definitions/postgresql.sql +182 -182
  37. data/test/fixtures/db_definitions/sqlite.sql +169 -169
  38. data/test/fixtures/db_definitions/sqlserver.sql +176 -176
  39. data/test/fixtures/department.rb +16 -16
  40. data/test/fixtures/departments.yml +19 -15
  41. data/test/fixtures/employees.yml +33 -28
  42. data/test/fixtures/membership.rb +8 -6
  43. data/test/fixtures/restaurants_suburbs.yml +10 -10
  44. data/test/fixtures/streets.yml +16 -16
  45. data/test/fixtures/suburbs.yml +14 -14
  46. data/test/fixtures/user.rb +11 -11
  47. data/test/test_associations.rb +372 -358
  48. data/test/test_attributes.rb +75 -60
  49. data/test/test_calculations.rb +49 -42
  50. data/test/test_create.rb +218 -206
  51. data/test/test_delete.rb +188 -179
  52. data/test/test_exists.rb +39 -39
  53. data/test/test_find.rb +170 -164
  54. data/test/test_ids.rb +112 -112
  55. data/test/test_nested_attributes.rb +67 -67
  56. data/test/test_update.rb +102 -96
  57. metadata +6 -6
  58. data/lib/composite_primary_keys/connection_adapters/mysql/database_statements.rb +0 -24
@@ -1,103 +1,137 @@
1
- module ActiveRecord
2
- module Associations
3
- class JoinDependency
4
- class Aliases # :nodoc:
5
- def column_alias(node, column)
6
- # CPK
7
- #@alias_cache[node][column]
8
- if column.kind_of?(Array)
9
- column.map do |a_column|
10
- @alias_cache[node][a_column]
11
- end
12
- else
13
- @alias_cache[node][column]
14
- end
15
- end
16
- end
17
-
18
- def instantiate(result_set, &block)
19
- primary_key = aliases.column_alias(join_root, join_root.primary_key)
20
-
21
- seen = Hash.new { |i, object_id|
22
- i[object_id] = Hash.new { |j, child_class|
23
- j[child_class] = {}
24
- }
25
- }
26
-
27
- model_cache = Hash.new { |h, klass| h[klass] = {} }
28
- parents = model_cache[join_root]
29
- column_aliases = aliases.column_aliases join_root
30
-
31
- message_bus = ActiveSupport::Notifications.instrumenter
32
-
33
- payload = {
34
- record_count: result_set.length,
35
- class_name: join_root.base_klass.name
36
- }
37
-
38
- message_bus.instrument("instantiation.active_record", payload) do
39
- result_set.each { |row_hash|
40
- # CPK
41
- # parent_key = primary_key ? row_hash[primary_key] : row_hash
42
- # CPK
43
- parent_key = if primary_key.kind_of?(Array)
44
- primary_key.map {|key| row_hash[key]}
45
- else
46
- primary_key ? row_hash[primary_key] : row_hash
47
- end
48
-
49
- parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases, &block)
50
- construct(parent, join_root, row_hash, seen, model_cache)
51
- }
52
- end
53
-
54
- parents.values
55
- end
56
-
57
- def construct(ar_parent, parent, row, seen, model_cache)
58
- return if ar_parent.nil?
59
-
60
- parent.children.each do |node|
61
- if node.reflection.collection?
62
- other = ar_parent.association(node.reflection.name)
63
- other.loaded!
64
- elsif ar_parent.association_cached?(node.reflection.name)
65
- model = ar_parent.association(node.reflection.name).target
66
- construct(model, node, row, seen, model_cache)
67
- next
68
- end
69
-
70
- key = aliases.column_alias(node, node.primary_key)
71
-
72
- # CPK
73
- if key.is_a?(Array)
74
- id = Array(key).map do |column_alias|
75
- row[column_alias]
76
- end
77
- # At least the first value in the key has to be set. Should we require all values to be set?
78
- id = nil if id.first.nil?
79
- else # original
80
- id = row[key]
81
- end
82
-
83
- if id.nil? # duplicating this so it is clear what remained unchanged from the original
84
- nil_association = ar_parent.association(node.reflection.name)
85
- nil_association.loaded!
86
- next
87
- end
88
-
89
- model = seen[ar_parent.object_id][node][id]
90
-
91
- if model
92
- construct(model, node, row, seen, model_cache)
93
- else
94
- model = construct_model(ar_parent, node, row, model_cache, id)
95
-
96
- seen[ar_parent.object_id][node][id] = model
97
- construct(model, node, row, seen, model_cache)
98
- end
99
- end
100
- end
101
- end
102
- end
103
- 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.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
@@ -16,7 +16,6 @@ module ActiveRecord
16
16
 
17
17
  # Returns the primary key previous value.
18
18
  def id_was
19
- sync_with_transaction_state
20
19
  # CPK
21
20
  # attribute_was(self.class.primary_key)
22
21
  if self.composite?
@@ -29,7 +28,6 @@ module ActiveRecord
29
28
  end
30
29
 
31
30
  def id_in_database
32
- sync_with_transaction_state
33
31
  # CPK
34
32
  # attribute_in_database(self.class.primary_key)
35
33
  if self.composite?
@@ -1,30 +1,30 @@
1
- module ActiveRecord
2
- module AttributeMethods
3
- module Read
4
- def read_attribute(attr_name, &block)
5
- # CPK
6
- # name = attr_name.to_s
7
- name = attr_name
8
- if self.class.attribute_alias?(name)
9
- name = self.class.attribute_alias(name)
10
- end
11
-
12
- primary_key = self.class.primary_key
13
- # CPK
14
- # name = primary_key if name == "id" && primary_key
15
- name = primary_key if name == "id" && primary_key && !composite?
16
- sync_with_transaction_state if name == primary_key
17
- _read_attribute(name, &block)
18
- end
19
-
20
- def _read_attribute(attr_name, &block) # :nodoc
21
- # CPK
22
- if attr_name.kind_of?(Array)
23
- attr_name.map {|name| @attributes.fetch_value(name.to_s, &block)}
24
- else
25
- @attributes.fetch_value(attr_name.to_s, &block)
26
- end
27
- end
28
- end
29
- end
30
- end
1
+ module ActiveRecord
2
+ module AttributeMethods
3
+ module Read
4
+ def read_attribute(attr_name, &block)
5
+ # CPK
6
+ # name = attr_name.to_s
7
+ name = attr_name
8
+ if self.class.attribute_alias?(name)
9
+ name = self.class.attribute_alias(name)
10
+ end
11
+
12
+ primary_key = self.class.primary_key
13
+ # CPK
14
+ # name = primary_key if name == "id" && primary_key
15
+ name = primary_key if name == "id" && primary_key && !composite?
16
+
17
+ _read_attribute(name, &block)
18
+ end
19
+
20
+ def _read_attribute(attr_name, &block) # :nodoc
21
+ # CPK
22
+ if attr_name.kind_of?(Array)
23
+ attr_name.map {|name| @attributes.fetch_value(name.to_s, &block)}
24
+ else
25
+ @attributes.fetch_value(attr_name.to_s, &block)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,35 +1,35 @@
1
- module ActiveRecord
2
- module AttributeMethods
3
- module Write
4
- def write_attribute(attr_name, value)
5
- # CPK
6
- #name = attr_name.to_s
7
- name = attr_name
8
- if self.class.attribute_alias?(name)
9
- name = self.class.attribute_alias(name)
10
- end
11
-
12
- primary_key = self.class.primary_key
13
- # CPK
14
- # name = primary_key if name == "id" && primary_key
15
- name = primary_key if name == "id" && primary_key && !composite?
16
- sync_with_transaction_state if name == primary_key
17
- _write_attribute(name, value)
18
- end
19
-
20
- def _write_attribute(attr_name, value) # :nodoc:
21
- # CPK
22
- if attr_name.kind_of?(Array)
23
- attr_name.each_with_index do |attr_child_name, i|
24
- child_value = value ? value[i] : value
25
- @attributes.write_from_user(attr_child_name.to_s, child_value)
26
- end
27
- else
28
- @attributes.write_from_user(attr_name.to_s, value)
29
- end
30
-
31
- value
32
- end
33
- end
34
- end
35
- end
1
+ module ActiveRecord
2
+ module AttributeMethods
3
+ module Write
4
+ def write_attribute(attr_name, value)
5
+ # CPK
6
+ #name = attr_name.to_s
7
+ name = attr_name
8
+ if self.class.attribute_alias?(name)
9
+ name = self.class.attribute_alias(name)
10
+ end
11
+
12
+ primary_key = self.class.primary_key
13
+ # CPK
14
+ # name = primary_key if name == "id" && primary_key
15
+ name = primary_key if name == "id" && primary_key && !composite?
16
+
17
+ _write_attribute(name, value)
18
+ end
19
+
20
+ def _write_attribute(attr_name, value) # :nodoc:
21
+ # CPK
22
+ if attr_name.kind_of?(Array)
23
+ attr_name.each_with_index do |attr_child_name, i|
24
+ child_value = value ? value[i] : value
25
+ @attributes.write_from_user(attr_child_name.to_s, child_value)
26
+ end
27
+ else
28
+ @attributes.write_from_user(attr_name.to_s, value)
29
+ end
30
+
31
+ value
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,9 +1,21 @@
1
- module ActiveRecord
2
- module AttributeMethods
3
- def has_attribute?(attr_name)
4
- # CPK
5
- # @attributes.key?(attr_name.to_s)
6
- Array(attr_name).all? {|single_attr| @attributes.key?(single_attr.to_s) }
7
- end
8
- end
9
- end
1
+ module ActiveRecord
2
+ module AttributeMethods
3
+ def has_attribute?(attr_name)
4
+ # CPK
5
+ # attr_name = attr_name.to_s
6
+ # attr_name = self.class.attribute_aliases[attr_name] || attr_name
7
+ # @attributes.key?(attr_name)
8
+ Array(attr_name).all? do |attr|
9
+ attr = attr.to_s
10
+ attr = self.class.attribute_aliases[attr] || attr
11
+ @attributes.key?(attr)
12
+ end
13
+ end
14
+
15
+ def _has_attribute?(attr_name)
16
+ # CPK
17
+ # @attributes.key?(attr_name)
18
+ Array(attr_name).all? { |attr| @attributes.key?(attr) }
19
+ end
20
+ end
21
+ end