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,46 +1,46 @@
1
- module ActiveRecord
2
- module Associations
3
- class Preloader
4
- class HasAndBelongsToMany
5
- def records_for(ids)
6
- # CPK
7
- # scope = super
8
- predicate = cpk_in_predicate(join_table, reflection.foreign_key, ids)
9
- scope = build_scope.where(predicate)
10
-
11
- klass.connection.select_all(scope.arel.to_sql, 'SQL', scope.bind_values)
12
- end
13
-
14
- def join
15
- # CPK
16
- #condition = table[reflection.association_primary_key].eq(
17
- # join_table[reflection.association_foreign_key])
18
- condition = cpk_join_predicate(table, reflection.association_primary_key,
19
- join_table, reflection.association_foreign_key)
20
-
21
- table.create_join(join_table, table.create_on(condition))
22
- end
23
-
24
- def association_key_alias(field)
25
- "ar_association_key_name_#{field.to_s}"
26
- end
27
-
28
- def join_select
29
- # CPK
30
- # association_key.as(Arel.sql(association_key_name))
31
- Array(reflection.foreign_key).map do |key|
32
- join_table[key].as(Arel.sql(association_key_alias(key)))
33
- end
34
- end
35
-
36
- def association_key_name
37
- # CPK
38
- # 'ar_association_key_name'
39
- Array(reflection.foreign_key).map do |key|
40
- association_key_alias(key)
41
- end
42
- end
43
- end
44
- end
45
- end
46
- end
1
+ module ActiveRecord
2
+ module Associations
3
+ class Preloader
4
+ class HasAndBelongsToMany
5
+ def records_for(ids)
6
+ # CPK
7
+ # scope = super
8
+ predicate = cpk_in_predicate(join_table, reflection.foreign_key, ids)
9
+ scope = build_scope.where(predicate)
10
+
11
+ klass.connection.select_all(scope.arel.to_sql, 'SQL', scope.bind_values)
12
+ end
13
+
14
+ def join
15
+ # CPK
16
+ #condition = table[reflection.association_primary_key].eq(
17
+ # join_table[reflection.association_foreign_key])
18
+ condition = cpk_join_predicate(table, reflection.association_primary_key,
19
+ join_table, reflection.association_foreign_key)
20
+
21
+ table.create_join(join_table, table.create_on(condition))
22
+ end
23
+
24
+ def association_key_alias(field)
25
+ "ar_association_key_name_#{field.to_s}"
26
+ end
27
+
28
+ def join_select
29
+ # CPK
30
+ # association_key.as(Arel.sql(association_key_name))
31
+ Array(reflection.foreign_key).map do |key|
32
+ join_table[key].as(Arel.sql(association_key_alias(key)))
33
+ end
34
+ end
35
+
36
+ def association_key_name
37
+ # CPK
38
+ # 'ar_association_key_name'
39
+ Array(reflection.foreign_key).map do |key|
40
+ association_key_alias(key)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,26 +1,26 @@
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
- # [attr_name, value].transpose.map {|name,val| write_attribute(name, val)}
10
- else
11
- attr = attr.to_s
12
-
13
- save_changed_attribute(attr, value)
14
- end
15
-
16
- # Carry on.
17
- super(attr, value)
18
- end
19
- end
20
- end
21
- end
22
-
23
- ActiveRecord::Base.class_eval do
24
- alias :[]= :write_attribute
25
- public :[]=
26
- 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
+ # [attr_name, value].transpose.map {|name,val| write_attribute(name, val)}
10
+ else
11
+ attr = attr.to_s
12
+
13
+ save_changed_attribute(attr, value)
14
+ end
15
+
16
+ # Carry on.
17
+ super(attr, value)
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ ActiveRecord::Base.class_eval do
24
+ alias :[]= :write_attribute
25
+ public :[]=
26
+ end
@@ -1,35 +1,35 @@
1
- module ActiveRecord
2
- module AttributeMethods
3
- module Read
4
- def read_attribute(attr_name)
5
- if attr_name.kind_of?(Array)
6
- attr_name.map {|name| read_attribute(name)}.to_composite_keys
7
- else
8
- # If it's cached, just return it
9
- # We use #[] first as a perf optimization for non-nil values. See https://gist.github.com/jonleighton/3552829.
10
- name = attr_name.to_s
11
- @attributes_cache[name] || @attributes_cache.fetch(name) {
12
- column = @column_types_override[name] if @column_types_override
13
- column ||= @column_types[name]
14
-
15
- return @attributes.fetch(name) {
16
- if name == 'id' && self.class.primary_key != name
17
- read_attribute(self.class.primary_key)
18
- end
19
- } unless column
20
-
21
- value = @attributes.fetch(name) {
22
- return block_given? ? yield(name) : nil
23
- }
24
-
25
- if self.class.cache_attribute?(name)
26
- @attributes_cache[name] = column.type_cast(value)
27
- else
28
- column.type_cast value
29
- end
30
- }
31
- end
32
- end
33
- end
34
- end
1
+ module ActiveRecord
2
+ module AttributeMethods
3
+ module Read
4
+ def read_attribute(attr_name)
5
+ if attr_name.kind_of?(Array)
6
+ attr_name.map {|name| read_attribute(name)}.to_composite_keys
7
+ else
8
+ # If it's cached, just return it
9
+ # We use #[] first as a perf optimization for non-nil values. See https://gist.github.com/jonleighton/3552829.
10
+ name = attr_name.to_s
11
+ @attributes_cache[name] || @attributes_cache.fetch(name) {
12
+ column = @column_types_override[name] if @column_types_override
13
+ column ||= @column_types[name]
14
+
15
+ return @attributes.fetch(name) {
16
+ if name == 'id' && self.class.primary_key != name
17
+ read_attribute(self.class.primary_key)
18
+ end
19
+ } unless column
20
+
21
+ value = @attributes.fetch(name) {
22
+ return block_given? ? yield(name) : nil
23
+ }
24
+
25
+ if self.class.cache_attribute?(name)
26
+ @attributes_cache[name] = column.type_cast(value)
27
+ else
28
+ column.type_cast value
29
+ end
30
+ }
31
+ end
32
+ end
33
+ end
34
+ end
35
35
  end
@@ -1,36 +1,36 @@
1
- module ActiveRecord
2
- module AttributeMethods
3
- module Write
4
- def write_attribute_with_type_cast(attr_name, value, type_cast_method)
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
- @attributes_cache.delete(attr_name)
19
- column = column_for_attribute(attr_name)
20
-
21
- # If we're dealing with a binary column, write the data to the cache
22
- # so we don't attempt to typecast multiple times.
23
- if column && column.binary?
24
- @attributes_cache[attr_name] = value
25
- end
26
-
27
- if column || @attributes.has_key?(attr_name)
28
- @attributes[attr_name] = send(type_cast_method, column, value)
29
- else
30
- raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{attr_name}'"
31
- end
32
- end
33
- end
34
- end
35
- end
36
- end
1
+ module ActiveRecord
2
+ module AttributeMethods
3
+ module Write
4
+ def write_attribute_with_type_cast(attr_name, value, type_cast_method)
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
+ @attributes_cache.delete(attr_name)
19
+ column = column_for_attribute(attr_name)
20
+
21
+ # If we're dealing with a binary column, write the data to the cache
22
+ # so we don't attempt to typecast multiple times.
23
+ if column && column.binary?
24
+ @attributes_cache[attr_name] = value
25
+ end
26
+
27
+ if column || @attributes.has_key?(attr_name)
28
+ @attributes[attr_name] = send(type_cast_method, column, value)
29
+ else
30
+ raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{attr_name}'"
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -111,12 +111,6 @@ module ActiveRecord
111
111
  id
112
112
  end
113
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
114
  def can_change_primary_key_values?
121
115
  false
122
116
  end
@@ -1,30 +1,30 @@
1
- module CompositePrimaryKeys
2
- ID_SEP = ','
3
- ID_SET_SEP = ';'
4
-
5
- module ArrayExtension
6
- def to_composite_keys
7
- CompositeKeys.new(self)
8
- end
9
- end
10
-
11
- class CompositeKeys < Array
12
- def self.parse(value)
13
- case value
14
- when Array
15
- value.to_composite_keys
16
- when String
17
- self.new(value.split(ID_SEP))
18
- else
19
- raise(ArgumentError, "Unsupported type: #{value}")
20
- end
21
- end
22
-
23
- def to_s
24
- # Doing this makes it easier to parse Base#[](attr_name)
25
- join(ID_SEP)
26
- end
27
- end
28
- end
29
-
30
- Array.send(:include, CompositePrimaryKeys::ArrayExtension)
1
+ module CompositePrimaryKeys
2
+ ID_SEP = ','
3
+ ID_SET_SEP = ';'
4
+
5
+ module ArrayExtension
6
+ def to_composite_keys
7
+ CompositeKeys.new(self)
8
+ end
9
+ end
10
+
11
+ class CompositeKeys < Array
12
+ def self.parse(value)
13
+ case value
14
+ when Array
15
+ value.to_composite_keys
16
+ when String
17
+ self.new(value.split(ID_SEP))
18
+ else
19
+ raise(ArgumentError, "Unsupported type: #{value}")
20
+ end
21
+ end
22
+
23
+ def to_s
24
+ # Doing this makes it easier to parse Base#[](attr_name)
25
+ join(ID_SEP)
26
+ end
27
+ end
28
+ end
29
+
30
+ Array.send(:include, CompositePrimaryKeys::ArrayExtension)
@@ -4,6 +4,9 @@ module ActiveRecord
4
4
  if (adapter.to_s =~ /postgresql/) or (adapter.to_s =~ /postgis/)
5
5
  require "composite_primary_keys/connection_adapters/postgresql_adapter.rb"
6
6
  end
7
+ if (adapter.to_s =~ /sqlserver/)
8
+ require "composite_primary_keys/connection_adapters/sqlserver_adapter.rb"
9
+ end
7
10
  end
8
11
 
9
12
  def self.establish_connection(spec = ENV["DATABASE_URL"])
@@ -61,8 +64,7 @@ module ActiveRecord
61
64
  connection_handler.clear_active_connections!
62
65
  end
63
66
 
64
- delegate :clear_reloadable_connections!,
65
- :clear_all_connections!,:verify_active_connections!, :to => :connection_handler
67
+ delegate :clear_reloadable_connections!, :clear_all_connections!, :to => :connection_handler
66
68
  end
67
69
  end
68
70
  end
@@ -0,0 +1,17 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ class SQLServerAdapter
4
+ def sql_for_insert(sql, pk, id_value, sequence_name, binds)
5
+ sql =
6
+ if pk
7
+ # support composite primary keys consisting of more than one column name
8
+ inserted_pks = [pk].flatten.map {|pk| "inserted.#{pk}"}
9
+ sql.insert(sql.index(/ (DEFAULT )?VALUES/), " OUTPUT #{inserted_pks.join(", ")}")
10
+ else
11
+ "#{sql}; SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident"
12
+ end
13
+ [sql, binds]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,47 +1,47 @@
1
- module ActiveRecord
2
- module Core
3
- def init_internals
4
- pk = self.class.primary_key
5
-
6
- # CPK
7
- #@attributes[pk] = nil unless @attributes.key?(pk)
8
- unless self.composite?
9
- @attributes[pk] = nil unless @attributes.key?(pk)
10
- end
11
-
12
- @aggregation_cache = {}
13
- @association_cache = {}
14
- @attributes_cache = {}
15
- @readonly = false
16
- @destroyed = false
17
- @marked_for_destruction = false
18
- @destroyed_by_association = nil
19
- @new_record = true
20
- @txn = nil
21
- @_start_transaction_state = {}
22
- @transaction_state = nil
23
- @reflects_state = [false]
24
- end
25
-
26
- def initialize_dup(other) # :nodoc:
27
- cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
28
- self.class.initialize_attributes(cloned_attributes, :serialized => false)
29
-
30
- @attributes = cloned_attributes
31
-
32
- # CPK
33
- #@attributes[self.class.primary_key] = nil
34
- Array(self.class.primary_key).each {|key| @attributes[key] = nil}
35
-
36
- run_callbacks(:initialize) unless _initialize_callbacks.empty?
37
-
38
- @aggregation_cache = {}
39
- @association_cache = {}
40
- @attributes_cache = {}
41
-
42
- @new_record = true
43
-
44
- super
45
- end
46
- end
47
- end
1
+ module ActiveRecord
2
+ module Core
3
+ def init_internals
4
+ pk = self.class.primary_key
5
+
6
+ # CPK
7
+ #@attributes[pk] = nil unless @attributes.key?(pk)
8
+ unless self.composite?
9
+ @attributes[pk] = nil unless @attributes.key?(pk)
10
+ end
11
+
12
+ @aggregation_cache = {}
13
+ @association_cache = {}
14
+ @attributes_cache = {}
15
+ @readonly = false
16
+ @destroyed = false
17
+ @marked_for_destruction = false
18
+ @destroyed_by_association = nil
19
+ @new_record = true
20
+ @txn = nil
21
+ @_start_transaction_state = {}
22
+ @transaction_state = nil
23
+ @reflects_state = [false]
24
+ end
25
+
26
+ def initialize_dup(other) # :nodoc:
27
+ cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
28
+ self.class.initialize_attributes(cloned_attributes, :serialized => false)
29
+
30
+ @attributes = cloned_attributes
31
+
32
+ # CPK
33
+ #@attributes[self.class.primary_key] = nil
34
+ Array(self.class.primary_key).each {|key| @attributes[key] = nil}
35
+
36
+ run_callbacks(:initialize) unless _initialize_callbacks.empty?
37
+
38
+ @aggregation_cache = {}
39
+ @association_cache = {}
40
+ @attributes_cache = {}
41
+
42
+ @new_record = true
43
+
44
+ super
45
+ end
46
+ end
47
+ end