composite_primary_keys 3.1.8 → 3.1.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/History.txt +16 -12
  2. data/Rakefile +2 -4
  3. data/lib/composite_primary_keys/version.rb +1 -1
  4. data/test/connections/native_mysql/connection.rb +1 -1
  5. data/test/connections/native_oracle/connection.rb +1 -1
  6. data/test/connections/native_oracle_enhanced/connection.rb +1 -1
  7. data/test/connections/native_postgresql/connection.rb +1 -1
  8. data/test/connections/native_sqlite/connection.rb +1 -1
  9. data/test/fixtures/article.rb +1 -1
  10. data/test/fixtures/comment.rb +0 -1
  11. data/test/fixtures/db_definitions/db2-create-tables.sql +4 -13
  12. data/test/fixtures/db_definitions/db2-drop-tables.sql +1 -1
  13. data/test/fixtures/db_definitions/mysql.sql +5 -13
  14. data/test/fixtures/db_definitions/oracle.drop.sql +1 -2
  15. data/test/fixtures/db_definitions/oracle.sql +4 -13
  16. data/test/fixtures/db_definitions/postgresql.sql +5 -13
  17. data/test/fixtures/db_definitions/sqlite.sql +4 -13
  18. data/test/fixtures/department.rb +1 -0
  19. data/test/fixtures/departments.yml +5 -1
  20. data/test/fixtures/employees.yml +12 -2
  21. data/test/fixtures/membership.rb +0 -2
  22. data/test/fixtures/product.rb +4 -2
  23. data/test/fixtures/restaurant.rb +4 -1
  24. data/test/fixtures/restaurants.yml +8 -1
  25. data/test/fixtures/tariff.rb +0 -1
  26. data/test/fixtures/tariffs.yml +2 -0
  27. data/test/test_associations.rb +6 -23
  28. data/test/test_attribute_methods.rb +5 -6
  29. data/test/test_delete.rb +35 -2
  30. data/test/test_habtm.rb +42 -0
  31. data/test/test_ids.rb +0 -8
  32. data/test/test_suite.rb +1 -0
  33. metadata +6 -23
  34. data/lib/composite_primary_keys/associations/association.rb +0 -23
  35. data/lib/composite_primary_keys/associations/association_scope.rb +0 -67
  36. data/lib/composite_primary_keys/associations/join_dependency/join_association.rb +0 -22
  37. data/lib/composite_primary_keys/associations/join_dependency/join_part.rb +0 -39
  38. data/lib/composite_primary_keys/associations/preloader/association.rb +0 -61
  39. data/lib/composite_primary_keys/associations/preloader/belongs_to.rb +0 -13
  40. data/lib/composite_primary_keys/associations/preloader/has_and_belongs_to_many.rb +0 -46
  41. data/lib/composite_primary_keys/attribute_methods/primary_key.rb +0 -19
  42. data/lib/composite_primary_keys/attribute_methods/read.rb +0 -88
  43. data/lib/composite_primary_keys/attribute_methods/write.rb +0 -40
  44. data/lib/composite_primary_keys/composite_predicates.rb +0 -44
  45. data/lib/composite_primary_keys/named_scope.rb +0 -29
  46. data/lib/composite_primary_keys/relation/finder_methods.rb +0 -119
  47. data/lib/composite_primary_keys/relation/query_methods.rb +0 -24
  48. data/test/fixtures/article_group.rb +0 -4
  49. data/test/fixtures/article_groups.yml +0 -7
  50. data/test/fixtures/kitchen_sink.rb +0 -3
  51. data/test/fixtures/kitchen_sinks.yml +0 -5
  52. data/test/fixtures/way_node.rb +0 -3
@@ -1,13 +0,0 @@
1
- module ActiveRecord
2
- module Associations
3
- class Preloader
4
- class BelongsTo
5
- def records_for(ids)
6
- # CPK
7
- predicate = cpk_in_predicate(table, association_key_name, ids)
8
- scoped.where(predicate)
9
- end
10
- end
11
- end
12
- end
13
- end
@@ -1,46 +0,0 @@
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 = scoped.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,19 +0,0 @@
1
- module ActiveRecord
2
- module AttributeMethods #:nodoc:
3
- module PrimaryKey
4
- def to_key
5
- # CPK
6
- #key = send(self.class.primary_key)
7
- #[key] if key
8
-
9
- primary_key = self.class.primary_key
10
- if primary_key.is_a?(Array)
11
- primary_key.collect{|k| send(k)}
12
- else
13
- key = send(primary_key)
14
- [key] if key
15
- end
16
- end
17
- end
18
- end
19
- end
@@ -1,88 +0,0 @@
1
- module CompositePrimaryKeys
2
- module ActiveRecord
3
- module AttributeMethods
4
- module Read
5
- def self.included(base)
6
- base.send(:extend, ClassMethods)
7
- alias [] read_attribute
8
- end
9
-
10
- module ClassMethods
11
- def define_read_method(method_name, attr_name, column)
12
- cast_code = column.type_cast_code('v')
13
- # CPK - this is a really horrid hack, needed to get
14
- # right class namespace :(
15
- if cast_code.match(/^ActiveRecord/)
16
- cast_code = "::#{cast_code}"
17
- end
18
-
19
- access_code = "(v=@attributes['#{attr_name}']) && #{cast_code}"
20
-
21
- # CPK
22
- # unless attr_name.to_s == self.primary_key.to_s
23
- # access_code.insert(0, "missing_attribute('#{attr_name}', caller) unless @attributes.has_key?('#{attr_name}'); ")
24
- # end
25
- unless self.primary_keys.include?(attr_name.to_sym)
26
- access_code = access_code.insert(0, "missing_attribute('#{attr_name}', caller) unless @attributes.has_key?('#{attr_name}'); ")
27
- end
28
-
29
- if cache_attribute?(attr_name)
30
- access_code = "@attributes_cache['#{attr_name}'] ||= (#{access_code})"
31
- end
32
-
33
- # Where possible, generate the method by evalling a string, as this will result in
34
- # faster accesses because it avoids the block eval and then string eval incurred
35
- # by the second branch.
36
- #
37
- # The second, slower, branch is necessary to support instances where the database
38
- # returns columns with extra stuff in (like 'my_column(omg)').
39
- if method_name =~ ActiveModel::AttributeMethods::COMPILABLE_REGEXP
40
- generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__
41
- def _#{method_name}
42
- #{access_code}
43
- end
44
-
45
- alias #{method_name} _#{method_name}
46
- STR
47
- else
48
- generated_attribute_methods.module_eval do
49
- define_method("_#{method_name}") { eval(access_code) }
50
- alias_method(method_name, "_#{method_name}")
51
- end
52
- end
53
- end
54
- end
55
-
56
- def read_attribute(attr_name)
57
- # CPK
58
- if attr_name.kind_of?(Array)
59
- attr_name.map {|name| read_attribute(name)}.to_composite_keys
60
- elsif respond_to? "_#{attr_name}"
61
- send "_#{attr_name}" if @attributes.has_key?(attr_name.to_s)
62
- else
63
- _read_attribute attr_name
64
- end
65
- end
66
-
67
- def _read_attribute(attr_name)
68
- attr_name = attr_name.to_s
69
- # CPK
70
- # attr_name = self.class.primary_key if attr_name == 'id'
71
- attr_name = self.class.primary_key if (attr_name == 'id' and !self.composite?)
72
- value = @attributes[attr_name]
73
- unless value.nil?
74
- if column = column_for_attribute(attr_name)
75
- if unserializable_attribute?(attr_name, column)
76
- unserialize_attribute(attr_name)
77
- else
78
- column.type_cast(value)
79
- end
80
- else
81
- value
82
- end
83
- end
84
- end
85
- end
86
- end
87
- end
88
- end
@@ -1,40 +0,0 @@
1
- module CompositePrimaryKeys
2
- module ActiveRecord
3
- module AttributeMethods
4
- module Write
5
- def self.included(base)
6
- alias []= write_attribute
7
- alias_method :raw_write_attribute, :write_attribute
8
- end
9
-
10
- def write_attribute(attr_name, value)
11
- if attr_name.kind_of?(Array)
12
- unless value.length == attr_name.length
13
- raise "Number of attr_names and values do not match"
14
- end
15
- [attr_name, value].transpose.map {|name,val| _write_attribute(name, val)}
16
- value
17
- else
18
- _write_attribute(attr_name, value)
19
- end
20
- end
21
-
22
- def _write_attribute(attr_name, value)
23
- attr_name = attr_name.to_s
24
- # CPK
25
- # attr_name = self.class.primary_key if attr_name == 'id'
26
- attr_name = self.class.primary_key if (attr_name == 'id' and !self.composite?)
27
- @attributes_cache.delete(attr_name)
28
- if (column = column_for_attribute(attr_name)) && column.number?
29
- @attributes[attr_name] = convert_number_column_value(value)
30
- else
31
- @attributes[attr_name] = value
32
- end
33
- end
34
-
35
-
36
-
37
- end
38
- end
39
- end
40
- end
@@ -1,44 +0,0 @@
1
- module CompositePrimaryKeys
2
- module Predicates
3
- def cpk_or_predicate(predicates)
4
- result = predicates.shift
5
- predicates.each do |predicate|
6
- result = result.or(predicate)
7
- end
8
- result
9
- end
10
-
11
- def cpk_id_predicate(table, keys, values)
12
- eq_predicates = keys.zip(values).map do |key, value|
13
- table[key].eq(value)
14
- end
15
- Arel::Nodes::And.new(eq_predicates)
16
- end
17
-
18
- def cpk_join_predicate(table1, key1, table2, key2)
19
- key1_fields = Array(key1).map {|key| table1[key]}
20
- key2_fields = Array(key2).map {|key| table2[key]}
21
-
22
- predicates = key1_fields.zip(key2_fields).map do |key_field1, key_field2|
23
- key_field1.eq(key_field2)
24
- end
25
- Arel::Nodes::And.new(predicates)
26
- end
27
-
28
- def cpk_in_predicate(table, primary_keys, ids)
29
- and_predicates = ids.map do |id_set|
30
- eq_predicates = Array(primary_keys).zip(id_set).map do |primary_key, value|
31
- table[primary_key].eq(value)
32
- end
33
- Arel::Nodes::And.new(eq_predicates)
34
- end
35
-
36
- cpk_or_predicate(and_predicates)
37
- end
38
- end
39
- end
40
-
41
- ActiveRecord::Associations::AssociationScope.send(:include, CompositePrimaryKeys::Predicates)
42
- ActiveRecord::Associations::JoinDependency::JoinAssociation.send(:include, CompositePrimaryKeys::Predicates)
43
- ActiveRecord::Associations::Preloader::Association.send(:include, CompositePrimaryKeys::Predicates)
44
- ActiveRecord::Relation.send(:include, CompositePrimaryKeys::Predicates)
@@ -1,29 +0,0 @@
1
- module CompositePrimaryKeys
2
- module ActiveRecord
3
- module NamedScope
4
- module ClassMethods
5
- def scoped(options = nil)
6
- result = if options
7
- scoped.apply_finder_options(options)
8
- else
9
- if current_scope
10
- current_scope.clone
11
- else
12
- scope = relation.clone
13
- scope.default_scoped = true
14
- scope
15
- end
16
- end
17
-
18
- # CPK
19
- class << result
20
- include CompositePrimaryKeys::ActiveRecord::FinderMethods
21
- include CompositePrimaryKeys::ActiveRecord::QueryMethods
22
- include CompositePrimaryKeys::ActiveRecord::Relation
23
- end
24
- result
25
- end
26
- end
27
- end
28
- end
29
- end
@@ -1,119 +0,0 @@
1
- module CompositePrimaryKeys
2
- module ActiveRecord
3
- module FinderMethods
4
- def construct_limited_ids_condition(relation)
5
- orders = relation.order_values
6
- # CPK
7
- # values = @klass.connection.distinct("#{@klass.connection.quote_table_name table_name}.#{primary_key}", orders)
8
- keys = @klass.primary_keys.map do |key|
9
- "#{@klass.connection.quote_table_name @klass.table_name}.#{key}"
10
- end
11
- values = @klass.connection.distinct(keys.join(', '), orders)
12
-
13
- relation = relation.dup
14
-
15
- ids_array = relation.select(values).collect {|row| row[primary_key]}
16
- # CPK
17
- # ids_array.empty? ? raise(ThrowResult) : table[primary_key].in(ids_array)
18
-
19
- # OR together each and expression (key=value and key=value) that matches an id set
20
- # since we only need to match 0 or more records
21
- or_expressions = ids_array.map do |id_set|
22
- # AND together "key=value" exprssios to match each id set
23
- and_expressions = [self.primary_keys, id_set].transpose.map do |key, id|
24
- table[key].eq(id)
25
- end
26
- Arel::Nodes::And.new(and_expressions)
27
- end
28
-
29
- first = or_expressions.shift
30
- Arel::Nodes::Grouping.new(or_expressions.inject(first) do |memo, expr|
31
- Arel::Nodes::Or.new(memo, expr)
32
- end)
33
- end
34
-
35
- def exists?(id = nil)
36
- # ID can be:
37
- # Array - ['department_id = ? and location_id = ?', 1, 1]
38
- # Array -> [1,2]
39
- # CompositeKeys -> [1,2]
40
-
41
- id = id.id if ::ActiveRecord::Base === id
42
-
43
- join_dependency = construct_join_dependency_for_association_find
44
- relation = construct_relation_for_association_find(join_dependency)
45
- relation = relation.except(:select).select("1").limit(1)
46
-
47
- # CPK
48
- #case id
49
- #when Array, Hash
50
- # relation = relation.where(id)
51
- #else
52
- # relation = relation.where(table[primary_key].eq(id)) if id
53
- #end
54
-
55
- case id
56
- when CompositePrimaryKeys::CompositeKeys
57
- relation = relation.where(cpk_id_predicate(table, primary_key, id))
58
- when Array
59
- if !id.first.kind_of?(String)
60
- return self.exists?(id.to_composite_keys)
61
- else
62
- relation = relation.where(id)
63
- end
64
- when Hash
65
- relation = relation.where(id)
66
- else
67
- raise(ArgumentError, "Unsupported id sent to exists?")
68
- end
69
- connection.select_value(relation.to_sql) ? true : false
70
- end
71
-
72
- def find_with_ids(*ids, &block)
73
- return to_a.find { |*block_args| yield(*block_args) } if block_given?
74
-
75
- # Supports:
76
- # find('1,2') -> ['1,2']
77
- # find(1,2) -> [1,2]
78
- # find([1,2]) -> [['1,2']]
79
- # find([1,2], [3,4]) -> [[1,2],[3,4]]
80
- #
81
- # Does *not* support:
82
- # find('1,2', '3,4') -> ['1,2','3,4']
83
-
84
- # Normalize incoming data. Note the last arg can be nil. Happens
85
- # when find is called with nil options like the reload method does.
86
- ids.compact!
87
- ids = [ids] unless ids.first.kind_of?(Array)
88
-
89
- results = ids.map do |cpk_ids|
90
- cpk_ids = if cpk_ids.length == 1
91
- cpk_ids.first.split(CompositePrimaryKeys::ID_SEP).to_composite_keys
92
- else
93
- cpk_ids.to_composite_keys
94
- end
95
-
96
- unless cpk_ids.length == @klass.primary_keys.length
97
- raise "#{cpk_ids.inspect}: Incorrect number of primary keys for #{@klass.name}: #{@klass.primary_keys.inspect}"
98
- end
99
-
100
- new_relation = clone
101
- [@klass.primary_keys, cpk_ids].transpose.map do |key, id|
102
- new_relation = new_relation.where(key => id)
103
- end
104
-
105
- records = new_relation.to_a
106
-
107
- if records.empty?
108
- conditions = new_relation.arel.where_sql
109
- raise(::ActiveRecord::RecordNotFound,
110
- "Couldn't find #{@klass.name} with ID=#{cpk_ids} #{conditions}")
111
- end
112
- records
113
- end.flatten
114
-
115
- ids.length == 1 ? results.first : results
116
- end
117
- end
118
- end
119
- end
@@ -1,24 +0,0 @@
1
- module CompositePrimaryKeys
2
- module ActiveRecord
3
- module QueryMethods
4
- def reverse_order
5
- order_clause = arel.order_clauses
6
-
7
- # CPK
8
- # order = order_clause.empty? ?
9
- # "#{table_name}.#{primary_key} DESC" :
10
- # reverse_sql_order(order_clause).join(', ')
11
-
12
- order = unless order_clause.empty?
13
- reverse_sql_order(order_clause).join(', ')
14
- else
15
- klass.primary_key.map do |key|
16
- "#{table_name}.#{key} DESC"
17
- end.join(", ")
18
- end
19
-
20
- except(:order).order(Arel.sql(order))
21
- end
22
- end
23
- end
24
- end
@@ -1,4 +0,0 @@
1
- class ArticleGroup < ActiveRecord::Base
2
- belongs_to :article
3
- belongs_to :group
4
- end
@@ -1,7 +0,0 @@
1
- cpk:
2
- article_id: 1
3
- group_id: 1
4
-
5
- transformers:
6
- article_id: 1
7
- group_id: 2