composite_primary_keys 8.1.0 → 8.1.1

Sign up to get free protection for your applications and to get access to all the features.
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