composite_primary_keys 7.0.13 → 7.0.14

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