composite_primary_keys 7.0.13 → 7.0.14

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