composite_primary_keys 8.1.0 → 8.1.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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/History.rdoc +642 -625
  3. data/README.rdoc +5 -2
  4. data/lib/composite_primary_keys.rb +115 -115
  5. data/lib/composite_primary_keys/associations/association.rb +23 -23
  6. data/lib/composite_primary_keys/associations/association_scope.rb +73 -73
  7. data/lib/composite_primary_keys/associations/collection_association.rb +14 -14
  8. data/lib/composite_primary_keys/associations/has_many_association.rb +69 -69
  9. data/lib/composite_primary_keys/associations/join_dependency.rb +87 -87
  10. data/lib/composite_primary_keys/associations/preloader/association.rb +90 -90
  11. data/lib/composite_primary_keys/associations/singular_association.rb +18 -18
  12. data/lib/composite_primary_keys/attribute_methods.rb +9 -9
  13. data/lib/composite_primary_keys/attribute_methods/dirty.rb +29 -29
  14. data/lib/composite_primary_keys/attribute_methods/read.rb +24 -24
  15. data/lib/composite_primary_keys/attribute_methods/write.rb +30 -30
  16. data/lib/composite_primary_keys/attribute_set/builder.rb +19 -19
  17. data/lib/composite_primary_keys/base.rb +129 -135
  18. data/lib/composite_primary_keys/composite_arrays.rb +43 -43
  19. data/lib/composite_primary_keys/connection_adapters/abstract/connection_specification_changes.rb +2 -3
  20. data/lib/composite_primary_keys/core.rb +60 -60
  21. data/lib/composite_primary_keys/persistence.rb +56 -56
  22. data/lib/composite_primary_keys/relation.rb +68 -68
  23. data/lib/composite_primary_keys/relation/calculations.rb +78 -78
  24. data/lib/composite_primary_keys/relation/finder_methods.rb +179 -179
  25. data/lib/composite_primary_keys/sanitization.rb +52 -52
  26. data/lib/composite_primary_keys/validations/uniqueness.rb +36 -36
  27. data/lib/composite_primary_keys/version.rb +8 -8
  28. data/tasks/databases/sqlserver.rake +27 -27
  29. data/test/abstract_unit.rb +114 -113
  30. data/test/connections/databases.example.yml +25 -25
  31. data/test/connections/native_sqlserver/connection.rb +11 -11
  32. data/test/fixtures/db_definitions/mysql.sql +218 -218
  33. data/test/fixtures/db_definitions/postgresql.sql +220 -220
  34. data/test/fixtures/db_definitions/sqlite.sql +206 -206
  35. data/test/fixtures/db_definitions/sqlserver.drop.sql +91 -91
  36. data/test/fixtures/db_definitions/sqlserver.sql +226 -226
  37. data/test/fixtures/employee.rb +11 -11
  38. data/test/fixtures/salary.rb +5 -5
  39. data/test/test_associations.rb +341 -340
  40. data/test/test_attributes.rb +60 -60
  41. data/test/test_create.rb +157 -157
  42. data/test/test_delete.rb +158 -158
  43. data/test/test_delete_all.rb +33 -28
  44. data/test/test_enum.rb +21 -21
  45. data/test/test_equal.rb +26 -26
  46. data/test/test_find.rb +119 -118
  47. data/test/test_habtm.rb +117 -113
  48. data/test/test_polymorphic.rb +27 -26
  49. data/test/test_tutorial_example.rb +25 -25
  50. metadata +44 -2
@@ -1,69 +1,69 @@
1
- module ActiveRecord
2
- module Associations
3
- class HasManyAssociation
4
- def delete_count(method, scope)
5
- if method == :delete_all
6
- scope.delete_all
7
- else
8
- # CPK
9
- # scope.update_all(reflection.foreign_key => nil)
10
- conds = Array(reflection.foreign_key).inject(Hash.new) do |mem, key|
11
- mem[key] = nil
12
- mem
13
- end
14
- scope.update_all(conds)
15
- end
16
- end
17
-
18
- def delete_records(records, method)
19
- if method == :destroy
20
- records.each(&:destroy!)
21
- update_counter(-records.length) unless inverse_updates_counter_cache?
22
- else
23
- if records == :all || !reflection.klass.primary_key
24
- scope = self.scope
25
- else
26
- # CPK
27
- # scope = self.scope.where(reflection.klass.primary_key => records)
28
- table = Arel::Table.new(reflection.table_name)
29
- and_conditions = records.map do |record|
30
- eq_conditions = Array(reflection.association_primary_key).map do |name|
31
- table[name].eq(record[name])
32
- end
33
- Arel::Nodes::And.new(eq_conditions)
34
- end
35
-
36
- condition = and_conditions.shift
37
- and_conditions.each do |and_condition|
38
- condition = condition.or(and_condition)
39
- end
40
-
41
- scope = self.scope.where(condition)
42
- end
43
-
44
- if method == :delete_all
45
- update_counter(-scope.delete_all)
46
- else
47
- # CPK
48
- # update_counter(-scope.update_all(reflection.foreign_key => nil))
49
- update_hash = Array(reflection.foreign_key).inject(Hash.new) do |hash, key|
50
- hash[key] = nil
51
- hash
52
- end
53
- update_counter(-scope.update_all(update_hash))
54
- end
55
- end
56
- end
57
-
58
- def foreign_key_present?
59
- if reflection.klass.primary_key
60
- # CPK
61
- # owner.attribute_present?(reflection.association_primary_key)
62
- Array(reflection.klass.primary_key).all? {|key| owner.attribute_present?(key)}
63
- else
64
- false
65
- end
66
- end
67
- end
68
- end
69
- end
1
+ module ActiveRecord
2
+ module Associations
3
+ class HasManyAssociation
4
+ def delete_count(method, scope)
5
+ if method == :delete_all
6
+ scope.delete_all
7
+ else
8
+ # CPK
9
+ # scope.update_all(reflection.foreign_key => nil)
10
+ conds = Array(reflection.foreign_key).inject(Hash.new) do |mem, key|
11
+ mem[key] = nil
12
+ mem
13
+ end
14
+ scope.update_all(conds)
15
+ end
16
+ end
17
+
18
+ def delete_records(records, method)
19
+ if method == :destroy
20
+ records.each(&:destroy!)
21
+ update_counter(-records.length) unless inverse_updates_counter_cache?
22
+ else
23
+ if records == :all || !reflection.klass.primary_key
24
+ scope = self.scope
25
+ else
26
+ # CPK
27
+ # scope = self.scope.where(reflection.klass.primary_key => records)
28
+ table = Arel::Table.new(reflection.table_name)
29
+ and_conditions = records.map do |record|
30
+ eq_conditions = Array(reflection.association_primary_key).map do |name|
31
+ table[name].eq(record[name])
32
+ end
33
+ Arel::Nodes::And.new(eq_conditions)
34
+ end
35
+
36
+ condition = and_conditions.shift
37
+ and_conditions.each do |and_condition|
38
+ condition = condition.or(and_condition)
39
+ end
40
+
41
+ scope = self.scope.where(condition)
42
+ end
43
+
44
+ if method == :delete_all
45
+ update_counter(-scope.delete_all)
46
+ else
47
+ # CPK
48
+ # update_counter(-scope.update_all(reflection.foreign_key => nil))
49
+ update_hash = Array(reflection.foreign_key).inject(Hash.new) do |hash, key|
50
+ hash[key] = nil
51
+ hash
52
+ end
53
+ update_counter(-scope.update_all(update_hash))
54
+ end
55
+ end
56
+ end
57
+
58
+ def foreign_key_present?
59
+ if reflection.klass.primary_key
60
+ # CPK
61
+ # owner.attribute_present?(reflection.association_primary_key)
62
+ Array(reflection.klass.primary_key).all? {|key| owner.attribute_present?(key)}
63
+ else
64
+ false
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -1,87 +1,87 @@
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, aliases)
19
- primary_key = aliases.column_alias(join_root, join_root.primary_key)
20
-
21
- seen = Hash.new { |h,parent_klass|
22
- h[parent_klass] = Hash.new { |i,parent_id|
23
- i[parent_id] = Hash.new { |j,child_klass| j[child_klass] = {} }
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
- result_set.each { |row_hash|
32
- # CPK
33
- primary_id = if primary_key.kind_of?(Array)
34
- primary_key.map {|key| row_hash[key]}
35
- else
36
- row_hash[primary_key]
37
- end
38
- parent = parents[primary_id] ||= join_root.instantiate(row_hash, column_aliases)
39
- construct(parent, join_root, row_hash, result_set, seen, model_cache, aliases)
40
- }
41
-
42
- parents.values
43
- end
44
-
45
- def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
46
- primary_id = ar_parent.id
47
-
48
- parent.children.each do |node|
49
- if node.reflection.collection?
50
- other = ar_parent.association(node.reflection.name)
51
- other.loaded!
52
- else
53
- if ar_parent.association_cache.key?(node.reflection.name)
54
- model = ar_parent.association(node.reflection.name).target
55
- construct(model, node, row, rs, seen, model_cache, aliases)
56
- next
57
- end
58
- end
59
-
60
- key = aliases.column_alias(node, node.primary_key)
61
-
62
- # CPK
63
- if key.is_a?(Array)
64
- id = Array(key).map do |column_alias|
65
- value = row[column_alias]
66
- end
67
- # At least the first value in the key has to be set. Should we require all values to be set?
68
- next if id.first.nil?
69
- else
70
- id = row[key]
71
- next if id.nil?
72
- end
73
-
74
- model = seen[parent.base_klass][primary_id][node.base_klass][id]
75
-
76
- if model
77
- construct(model, node, row, rs, seen, model_cache, aliases)
78
- else
79
- model = construct_model(ar_parent, node, row, model_cache, id, aliases)
80
- seen[parent.base_klass][primary_id][node.base_klass][id] = model
81
- construct(model, node, row, rs, seen, model_cache, aliases)
82
- end
83
- end
84
- end
85
- end
86
- end
87
- end
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, aliases)
19
+ primary_key = aliases.column_alias(join_root, join_root.primary_key)
20
+
21
+ seen = Hash.new { |h,parent_klass|
22
+ h[parent_klass] = Hash.new { |i,parent_id|
23
+ i[parent_id] = Hash.new { |j,child_klass| j[child_klass] = {} }
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
+ result_set.each { |row_hash|
32
+ # CPK
33
+ primary_id = if primary_key.kind_of?(Array)
34
+ primary_key.map {|key| row_hash[key]}
35
+ else
36
+ row_hash[primary_key]
37
+ end
38
+ parent = parents[primary_id] ||= join_root.instantiate(row_hash, column_aliases)
39
+ construct(parent, join_root, row_hash, result_set, seen, model_cache, aliases)
40
+ }
41
+
42
+ parents.values
43
+ end
44
+
45
+ def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
46
+ primary_id = ar_parent.id
47
+
48
+ parent.children.each do |node|
49
+ if node.reflection.collection?
50
+ other = ar_parent.association(node.reflection.name)
51
+ other.loaded!
52
+ else
53
+ if ar_parent.association_cache.key?(node.reflection.name)
54
+ model = ar_parent.association(node.reflection.name).target
55
+ construct(model, node, row, rs, seen, model_cache, aliases)
56
+ next
57
+ end
58
+ end
59
+
60
+ key = aliases.column_alias(node, node.primary_key)
61
+
62
+ # CPK
63
+ if key.is_a?(Array)
64
+ id = Array(key).map do |column_alias|
65
+ value = row[column_alias]
66
+ end
67
+ # At least the first value in the key has to be set. Should we require all values to be set?
68
+ next if id.first.nil?
69
+ else
70
+ id = row[key]
71
+ next if id.nil?
72
+ end
73
+
74
+ model = seen[parent.base_klass][primary_id][node.base_klass][id]
75
+
76
+ if model
77
+ construct(model, node, row, rs, seen, model_cache, aliases)
78
+ else
79
+ model = construct_model(ar_parent, node, row, model_cache, id, aliases)
80
+ seen[parent.base_klass][primary_id][node.base_klass][id] = model
81
+ construct(model, node, row, rs, seen, model_cache, aliases)
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -1,90 +1,90 @@
1
- module ActiveRecord
2
- module Associations
3
- class Preloader
4
- class Association
5
- def query_scope(ids)
6
- # CPK
7
- # scope.where(association_key.in(ids))
8
-
9
- if reflection.foreign_key.is_a?(Array)
10
- predicate = cpk_in_predicate(table, reflection.foreign_key, ids)
11
- scope.where(predicate)
12
- else
13
- scope.where(association_key.in(ids))
14
- end
15
- end
16
-
17
- def associated_records_by_owner(preloader)
18
- owners_map = owners_by_key
19
- # CPK
20
- # owner_keys = owners_map.keys.compact
21
- owner_keys = if reflection.foreign_key.is_a?(Array)
22
- owners.map do |owner|
23
- Array(owner_key_name).map do |owner_key|
24
- owner[owner_key]
25
- end
26
- end.compact.uniq
27
- else
28
- owners_map.keys.compact
29
- end
30
-
31
- # Each record may have multiple owners, and vice-versa
32
- records_by_owner = owners.each_with_object({}) do |owner,h|
33
- h[owner] = []
34
- end
35
-
36
- if owner_keys.any?
37
- # Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
38
- # Make several smaller queries if necessary or make one query if the adapter supports it
39
- sliced = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size)
40
-
41
- records = load_slices sliced
42
- records.each do |record, owner_key|
43
- owners_map[owner_key].each do |owner|
44
- records_by_owner[owner] << record
45
- end
46
- end
47
- end
48
-
49
- records_by_owner
50
- end
51
-
52
- def load_slices(slices)
53
- @preloaded_records = slices.flat_map { |slice|
54
- records_for(slice)
55
- }
56
-
57
- @preloaded_records.map { |record|
58
- # CPK
59
- #[record, record[association_key_name]]
60
- owner_key = Array(association_key_name).map do |key_name|
61
- record[key_name]
62
- end.join(CompositePrimaryKeys::ID_SEP)
63
- [record, owner_key]
64
- }
65
- end
66
-
67
- def owners_by_key
68
- @owners_by_key ||= if key_conversion_required?
69
- owners.group_by do |owner|
70
- # CPK
71
- # owner[owner_key_name].to_s
72
- key = Array(owner_key_name).map do |key_name|
73
- owner[key_name]
74
- end.join(CompositePrimaryKeys::ID_SEP)
75
- end
76
- else
77
- owners.group_by do |owner|
78
- # CPK
79
- # owner[owner_key_name]
80
- key = Array(owner_key_name).map do |key_name|
81
- owner[key_name]
82
- end.join(CompositePrimaryKeys::ID_SEP)
83
- end
84
- end
85
-
86
- end
87
- end
88
- end
89
- end
90
- end
1
+ module ActiveRecord
2
+ module Associations
3
+ class Preloader
4
+ class Association
5
+ def query_scope(ids)
6
+ # CPK
7
+ # scope.where(association_key.in(ids))
8
+
9
+ if reflection.foreign_key.is_a?(Array)
10
+ predicate = cpk_in_predicate(table, reflection.foreign_key, ids)
11
+ scope.where(predicate)
12
+ else
13
+ scope.where(association_key.in(ids))
14
+ end
15
+ end
16
+
17
+ def associated_records_by_owner(preloader)
18
+ owners_map = owners_by_key
19
+ # CPK
20
+ # owner_keys = owners_map.keys.compact
21
+ owner_keys = if reflection.foreign_key.is_a?(Array)
22
+ owners.map do |owner|
23
+ Array(owner_key_name).map do |owner_key|
24
+ owner[owner_key]
25
+ end
26
+ end.compact.uniq
27
+ else
28
+ owners_map.keys.compact
29
+ end
30
+
31
+ # Each record may have multiple owners, and vice-versa
32
+ records_by_owner = owners.each_with_object({}) do |owner,h|
33
+ h[owner] = []
34
+ end
35
+
36
+ if owner_keys.any?
37
+ # Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
38
+ # Make several smaller queries if necessary or make one query if the adapter supports it
39
+ sliced = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size)
40
+
41
+ records = load_slices sliced
42
+ records.each do |record, owner_key|
43
+ owners_map[owner_key].each do |owner|
44
+ records_by_owner[owner] << record
45
+ end
46
+ end
47
+ end
48
+
49
+ records_by_owner
50
+ end
51
+
52
+ def load_slices(slices)
53
+ @preloaded_records = slices.flat_map { |slice|
54
+ records_for(slice)
55
+ }
56
+
57
+ @preloaded_records.map { |record|
58
+ # CPK
59
+ #[record, record[association_key_name]]
60
+ owner_key = Array(association_key_name).map do |key_name|
61
+ record[key_name]
62
+ end.join(CompositePrimaryKeys::ID_SEP)
63
+ [record, owner_key]
64
+ }
65
+ end
66
+
67
+ def owners_by_key
68
+ @owners_by_key ||= if key_conversion_required?
69
+ owners.group_by do |owner|
70
+ # CPK
71
+ # owner[owner_key_name].to_s
72
+ key = Array(owner_key_name).map do |key_name|
73
+ owner[key_name]
74
+ end.join(CompositePrimaryKeys::ID_SEP)
75
+ end
76
+ else
77
+ owners.group_by do |owner|
78
+ # CPK
79
+ # owner[owner_key_name]
80
+ key = Array(owner_key_name).map do |key_name|
81
+ owner[key_name]
82
+ end.join(CompositePrimaryKeys::ID_SEP)
83
+ end
84
+ end
85
+
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end