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,18 +1,18 @@
1
- module CompositePrimaryKeys
2
- module SingularAssociation
3
- extend ActiveSupport::Concern
4
- included do
5
- def get_records_with_cpk_support
6
- cpk_applies = (target && target.composite?) ||
7
- (owner && owner.composite?) ||
8
- (options[:primary_key] && options[:primary_key].kind_of?(Array)) ||
9
- (options[:foreign_key] && options[:foreign_key].kind_of?(Array))
10
- return scope.limit(1).to_a if cpk_applies
11
- get_records_without_cpk_support
12
- end
13
- alias_method_chain :get_records, :cpk_support
14
- end
15
- end
16
- end
17
-
18
- ActiveRecord::Associations::SingularAssociation.send(:include, CompositePrimaryKeys::SingularAssociation)
1
+ module CompositePrimaryKeys
2
+ module SingularAssociation
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ def get_records_with_cpk_support
6
+ cpk_applies = (target && target.composite?) ||
7
+ (owner && owner.composite?) ||
8
+ (options[:primary_key] && options[:primary_key].kind_of?(Array)) ||
9
+ (options[:foreign_key] && options[:foreign_key].kind_of?(Array))
10
+ return scope.limit(1).to_a if cpk_applies
11
+ get_records_without_cpk_support
12
+ end
13
+ alias_method_chain :get_records, :cpk_support
14
+ end
15
+ end
16
+ end
17
+
18
+ ActiveRecord::Associations::SingularAssociation.send(:include, CompositePrimaryKeys::SingularAssociation)
@@ -1,9 +1,9 @@
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
+ # @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,29 +1,29 @@
1
- module ActiveRecord
2
- module AttributeMethods
3
- module Dirty
4
- def write_attribute(attr, value)
5
- # CPK
6
- if attr.kind_of?(Array)
7
- # A *composite* attribute can't be marked as changed! So do nothing now.
8
- # We will come back in here with an *individual* attribute when Write#write_attribute looks through the individual attributes comprising this composite key:
9
- value = [nil] * attr.length if value.nil?
10
- [attr, value].transpose.map {|name,val| write_attribute(name, val)}
11
- else
12
- attr = attr.to_s
13
-
14
- old_value = old_attribute_value(attr)
15
-
16
- result = super
17
- store_original_raw_attribute(attr)
18
- save_changed_attribute(attr, old_value)
19
- result
20
- end
21
- end
22
- end
23
- end
24
- end
25
-
26
- ActiveRecord::Base.class_eval do
27
- alias :[]= :write_attribute
28
- public :[]=
29
- end
1
+ module ActiveRecord
2
+ module AttributeMethods
3
+ module Dirty
4
+ def write_attribute(attr, value)
5
+ # CPK
6
+ if attr.kind_of?(Array)
7
+ # A *composite* attribute can't be marked as changed! So do nothing now.
8
+ # We will come back in here with an *individual* attribute when Write#write_attribute looks through the individual attributes comprising this composite key:
9
+ value = [nil] * attr.length if value.nil?
10
+ [attr, value].transpose.map {|name,val| write_attribute(name, val)}
11
+ else
12
+ attr = attr.to_s
13
+
14
+ old_value = old_attribute_value(attr)
15
+
16
+ result = super
17
+ store_original_raw_attribute(attr)
18
+ save_changed_attribute(attr, old_value)
19
+ result
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ ActiveRecord::Base.class_eval do
27
+ alias :[]= :write_attribute
28
+ public :[]=
29
+ end
@@ -1,25 +1,25 @@
1
- module ActiveRecord
2
- module AttributeMethods
3
- module Read
4
- def read_attribute(attr_name, &block)
5
- # CPK
6
- if attr_name.kind_of?(Array)
7
- _read_attribute(attr_name, &block)
8
- else
9
- name = attr_name.to_s
10
- name = self.class.primary_key if name == 'id'
11
- _read_attribute(name, &block)
12
- end
13
- end
14
-
15
- def _read_attribute(attr_name)
16
- # CPK
17
- if attr_name.kind_of?(Array)
18
- attr_name.map {|name| @attributes.fetch_value(name.to_s)}
19
- else
20
- @attributes.fetch_value(attr_name.to_s) { |n| yield n if block_given? }
21
- end
22
- end
23
- end
24
- end
1
+ module ActiveRecord
2
+ module AttributeMethods
3
+ module Read
4
+ def read_attribute(attr_name, &block)
5
+ # CPK
6
+ if attr_name.kind_of?(Array)
7
+ _read_attribute(attr_name, &block)
8
+ else
9
+ name = attr_name.to_s
10
+ name = self.class.primary_key if name == 'id'
11
+ _read_attribute(name, &block)
12
+ end
13
+ end
14
+
15
+ def _read_attribute(attr_name)
16
+ # CPK
17
+ if attr_name.kind_of?(Array)
18
+ attr_name.map {|name| @attributes.fetch_value(name.to_s)}
19
+ else
20
+ @attributes.fetch_value(attr_name.to_s) { |n| yield n if block_given? }
21
+ end
22
+ end
23
+ end
24
+ end
25
25
  end
@@ -1,30 +1,30 @@
1
- module ActiveRecord
2
- module AttributeMethods
3
- module Write
4
- def write_attribute_with_type_cast(attr_name, value, should_type_cast)
5
- # CPK
6
- if attr_name.kind_of?(Array)
7
- value = [nil]*attr_name.length if value.nil?
8
- unless value.length == attr_name.length
9
- raise "Number of attr_names #{attr_name.inspect} and values #{value.inspect} do not match"
10
- end
11
- [attr_name, value].transpose.map {|name,val| write_attribute(name, val)}
12
- value
13
- else
14
- attr_name = attr_name.to_s
15
- # CPK
16
- # attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key
17
- attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key && !self.composite?
18
-
19
- if should_type_cast
20
- @attributes.write_from_user(attr_name, value)
21
- else
22
- @attributes.write_from_database(attr_name, value)
23
- end
24
-
25
- value
26
- end
27
- end
28
- end
29
- end
30
- end
1
+ module ActiveRecord
2
+ module AttributeMethods
3
+ module Write
4
+ def write_attribute_with_type_cast(attr_name, value, should_type_cast)
5
+ # CPK
6
+ if attr_name.kind_of?(Array)
7
+ value = [nil]*attr_name.length if value.nil?
8
+ unless value.length == attr_name.length
9
+ raise "Number of attr_names #{attr_name.inspect} and values #{value.inspect} do not match"
10
+ end
11
+ [attr_name, value].transpose.map {|name,val| write_attribute(name, val)}
12
+ value
13
+ else
14
+ attr_name = attr_name.to_s
15
+ # CPK
16
+ # attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key
17
+ attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key && !self.composite?
18
+
19
+ if should_type_cast
20
+ @attributes.write_from_user(attr_name, value)
21
+ else
22
+ @attributes.write_from_database(attr_name, value)
23
+ end
24
+
25
+ value
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,20 +1,20 @@
1
- module ActiveRecord
2
- class AttributeSet # :nodoc:
3
- class Builder # :nodoc:
4
- def build_from_database(values = {}, additional_types = {})
5
- # CPK
6
- # if always_initialized && !values.key?(always_initialized)
7
- # values[always_initialized] = nil
8
- # end
9
- Array(always_initialized).each do |always_initialized_attribute|
10
- if always_initialized_attribute && !values.key?(always_initialized_attribute)
11
- values[always_initialized_attribute] = nil
12
- end
13
- end
14
-
15
- attributes = LazyAttributeHash.new(types, values, additional_types)
16
- AttributeSet.new(attributes)
17
- end
18
- end
19
- end
1
+ module ActiveRecord
2
+ class AttributeSet # :nodoc:
3
+ class Builder # :nodoc:
4
+ def build_from_database(values = {}, additional_types = {})
5
+ # CPK
6
+ # if always_initialized && !values.key?(always_initialized)
7
+ # values[always_initialized] = nil
8
+ # end
9
+ Array(always_initialized).each do |always_initialized_attribute|
10
+ if always_initialized_attribute && !values.key?(always_initialized_attribute)
11
+ values[always_initialized_attribute] = nil
12
+ end
13
+ end
14
+
15
+ attributes = LazyAttributeHash.new(types, values, additional_types)
16
+ AttributeSet.new(attributes)
17
+ end
18
+ end
19
+ end
20
20
  end
@@ -1,135 +1,129 @@
1
- module ActiveRecord
2
- class CompositeKeyError < StandardError #:nodoc:
3
- end
4
-
5
- class Base
6
- INVALID_FOR_COMPOSITE_KEYS = 'Not appropriate for composite primary keys'
7
- NOT_IMPLEMENTED_YET = 'Not implemented for composite primary keys yet'
8
-
9
- class << self
10
- def primary_keys
11
- unless defined?(@primary_keys)
12
- reset_primary_keys
13
- end
14
- @primary_keys
15
- end
16
-
17
- # Don't like this method name, but its modeled after how AR does it
18
- def reset_primary_keys
19
- if self != base_class
20
- self.primary_keys = base_class.primary_keys
21
- end
22
- end
23
-
24
- def primary_key_with_composite_key_support=(keys)
25
- unless keys.kind_of?(Array)
26
- self.primary_key_without_composite_key_support = keys
27
- return
28
- end
29
-
30
- @primary_keys = keys.map { |k| k.to_s }.to_composite_keys
31
-
32
- class_eval <<-EOV
33
- extend CompositeClassMethods
34
- include CompositeInstanceMethods
35
- EOV
36
- end
37
- alias_method_chain :primary_key=, :composite_key_support
38
- alias_method :primary_keys=, :primary_key=
39
-
40
- def set_primary_keys(*keys)
41
- ActiveSupport::Deprecation.warn(
42
- "Calling set_primary_keys is deprecated. Please use `self.primary_keys = keys` instead."
43
- )
44
-
45
- keys = keys.first if keys.first.is_a?(Array)
46
- if keys.length == 1
47
- self.primary_key = keys.first
48
- else
49
- self.primary_keys = keys
50
- end
51
- end
52
-
53
- def composite?
54
- false
55
- end
56
- end
57
-
58
- def composite?
59
- self.class.composite?
60
- end
61
-
62
- module CompositeClassMethods
63
- def primary_key
64
- primary_keys
65
- end
66
-
67
- def primary_key=(keys)
68
- primary_keys = keys
69
- end
70
-
71
- def composite?
72
- true
73
- end
74
-
75
- #ids_to_s([[1,2],[7,3]]) -> "(1,2),(7,3)"
76
- #ids_to_s([[1,2],[7,3]], ',', ';') -> "1,2;7,3"
77
- def ids_to_s(many_ids, id_sep = CompositePrimaryKeys::ID_SEP, list_sep = ',', left_bracket = '(', right_bracket = ')')
78
- many_ids.map {|ids| "#{left_bracket}#{CompositePrimaryKeys::CompositeKeys.new(ids)}#{right_bracket}"}.join(list_sep)
79
- end
80
- end
81
-
82
- module CompositeInstanceMethods
83
- # A model instance's primary keys is always available as model.ids
84
- # whether you name it the default 'id' or set it to something else.
85
- def id
86
- attr_names = self.class.primary_keys
87
- ::CompositePrimaryKeys::CompositeKeys.new(attr_names.map { |attr_name| read_attribute(attr_name) })
88
- end
89
- alias_method :ids, :id
90
-
91
- def ids_hash
92
- self.class.primary_key.zip(ids).inject(Hash.new) do |hash, (key, value)|
93
- hash[key] = value
94
- hash
95
- end
96
- end
97
-
98
- def id_before_type_cast
99
- self.class.primary_keys.map do |key|
100
- self.send("#{key.to_s}_before_type_cast")
101
- end
102
- end
103
-
104
- # Sets the primary ID.
105
- def id=(ids)
106
- ids = CompositePrimaryKeys::CompositeKeys.parse(ids)
107
- unless ids.length == self.class.primary_keys.length
108
- raise "#{self.class}.id= requires #{self.class.primary_keys.length} ids"
109
- end
110
- [self.class.primary_keys, ids].transpose.each {|key, an_id| write_attribute(key , an_id)}
111
- id
112
- end
113
-
114
- def ==(comparison_object)
115
- return false if !persisted? && comparison_object.object_id != object_id
116
- return true if equal? comparison_object
117
- ids.is_a?(Array) ? super(comparison_object) && ids.all? {|id| !id.nil?} : super(comparison_object)
118
- end
119
-
120
- def can_change_primary_key_values?
121
- false
122
- end
123
-
124
- # Returns this record's primary keys values in an Array
125
- # if any value is available
126
- def to_key
127
- ids.to_a if !ids.compact.empty? # XXX Maybe use primary_keys with send instead of ids
128
- end
129
-
130
- def to_param
131
- persisted? ? to_key.join(CompositePrimaryKeys::ID_SEP) : nil
132
- end
133
- end
134
- end
135
- end
1
+ module ActiveRecord
2
+ class CompositeKeyError < StandardError #:nodoc:
3
+ end
4
+
5
+ class Base
6
+ INVALID_FOR_COMPOSITE_KEYS = 'Not appropriate for composite primary keys'
7
+ NOT_IMPLEMENTED_YET = 'Not implemented for composite primary keys yet'
8
+
9
+ class << self
10
+ def primary_keys
11
+ unless defined?(@primary_keys)
12
+ reset_primary_keys
13
+ end
14
+ @primary_keys
15
+ end
16
+
17
+ # Don't like this method name, but its modeled after how AR does it
18
+ def reset_primary_keys
19
+ if self != base_class
20
+ self.primary_keys = base_class.primary_keys
21
+ end
22
+ end
23
+
24
+ def primary_key_with_composite_key_support=(keys)
25
+ unless keys.kind_of?(Array)
26
+ self.primary_key_without_composite_key_support = keys
27
+ return
28
+ end
29
+
30
+ @primary_keys = keys.map { |k| k.to_s }.to_composite_keys
31
+
32
+ class_eval <<-EOV
33
+ extend CompositeClassMethods
34
+ include CompositeInstanceMethods
35
+ EOV
36
+ end
37
+ alias_method_chain :primary_key=, :composite_key_support
38
+ alias_method :primary_keys=, :primary_key=
39
+
40
+ def set_primary_keys(*keys)
41
+ ActiveSupport::Deprecation.warn(
42
+ "Calling set_primary_keys is deprecated. Please use `self.primary_keys = keys` instead."
43
+ )
44
+
45
+ keys = keys.first if keys.first.is_a?(Array)
46
+ if keys.length == 1
47
+ self.primary_key = keys.first
48
+ else
49
+ self.primary_keys = keys
50
+ end
51
+ end
52
+
53
+ def composite?
54
+ false
55
+ end
56
+ end
57
+
58
+ def composite?
59
+ self.class.composite?
60
+ end
61
+
62
+ module CompositeClassMethods
63
+ def primary_key
64
+ primary_keys
65
+ end
66
+
67
+ def primary_key=(keys)
68
+ primary_keys = keys
69
+ end
70
+
71
+ def composite?
72
+ true
73
+ end
74
+
75
+ #ids_to_s([[1,2],[7,3]]) -> "(1,2),(7,3)"
76
+ #ids_to_s([[1,2],[7,3]], ',', ';') -> "1,2;7,3"
77
+ def ids_to_s(many_ids, id_sep = CompositePrimaryKeys::ID_SEP, list_sep = ',', left_bracket = '(', right_bracket = ')')
78
+ many_ids.map {|ids| "#{left_bracket}#{CompositePrimaryKeys::CompositeKeys.new(ids)}#{right_bracket}"}.join(list_sep)
79
+ end
80
+ end
81
+
82
+ module CompositeInstanceMethods
83
+ # A model instance's primary keys is always available as model.ids
84
+ # whether you name it the default 'id' or set it to something else.
85
+ def id
86
+ attr_names = self.class.primary_keys
87
+ ::CompositePrimaryKeys::CompositeKeys.new(attr_names.map { |attr_name| read_attribute(attr_name) })
88
+ end
89
+ alias_method :ids, :id
90
+
91
+ def ids_hash
92
+ self.class.primary_key.zip(ids).inject(Hash.new) do |hash, (key, value)|
93
+ hash[key] = value
94
+ hash
95
+ end
96
+ end
97
+
98
+ def id_before_type_cast
99
+ self.class.primary_keys.map do |key|
100
+ self.send("#{key.to_s}_before_type_cast")
101
+ end
102
+ end
103
+
104
+ # Sets the primary ID.
105
+ def id=(ids)
106
+ ids = CompositePrimaryKeys::CompositeKeys.parse(ids)
107
+ unless ids.length == self.class.primary_keys.length
108
+ raise "#{self.class}.id= requires #{self.class.primary_keys.length} ids"
109
+ end
110
+ [self.class.primary_keys, ids].transpose.each {|key, an_id| write_attribute(key , an_id)}
111
+ id
112
+ end
113
+
114
+ def can_change_primary_key_values?
115
+ false
116
+ end
117
+
118
+ # Returns this record's primary keys values in an Array
119
+ # if any value is available
120
+ def to_key
121
+ ids.to_a if !ids.compact.empty? # XXX Maybe use primary_keys with send instead of ids
122
+ end
123
+
124
+ def to_param
125
+ persisted? ? to_key.join(CompositePrimaryKeys::ID_SEP) : nil
126
+ end
127
+ end
128
+ end
129
+ end