composite_primary_keys 3.1.11 → 4.0.0.beta1
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.
- data/History.txt +6 -8
- data/lib/composite_primary_keys.rb +53 -36
- data/lib/composite_primary_keys/associations/association.rb +23 -0
- data/lib/composite_primary_keys/associations/association_scope.rb +67 -0
- data/lib/composite_primary_keys/associations/has_and_belongs_to_many_association.rb +31 -121
- data/lib/composite_primary_keys/associations/has_many_association.rb +27 -66
- data/lib/composite_primary_keys/associations/join_dependency/join_association.rb +22 -0
- data/lib/composite_primary_keys/associations/join_dependency/join_part.rb +39 -0
- data/lib/composite_primary_keys/associations/preloader/association.rb +61 -0
- data/lib/composite_primary_keys/associations/preloader/belongs_to.rb +13 -0
- data/lib/composite_primary_keys/associations/preloader/has_and_belongs_to_many.rb +46 -0
- data/lib/composite_primary_keys/attribute_methods/dirty.rb +30 -0
- data/lib/composite_primary_keys/attribute_methods/read.rb +88 -0
- data/lib/composite_primary_keys/attribute_methods/write.rb +33 -0
- data/lib/composite_primary_keys/base.rb +18 -70
- data/lib/composite_primary_keys/composite_predicates.rb +53 -0
- data/lib/composite_primary_keys/connection_adapters/abstract_adapter.rb +6 -4
- data/lib/composite_primary_keys/connection_adapters/postgresql_adapter.rb +19 -41
- data/lib/composite_primary_keys/fixtures.rb +19 -6
- data/lib/composite_primary_keys/persistence.rb +32 -13
- data/lib/composite_primary_keys/relation.rb +23 -16
- data/lib/composite_primary_keys/relation/calculations.rb +48 -0
- data/lib/composite_primary_keys/relation/finder_methods.rb +117 -0
- data/lib/composite_primary_keys/relation/query_methods.rb +24 -0
- data/lib/composite_primary_keys/validations/uniqueness.rb +19 -23
- data/lib/composite_primary_keys/version.rb +5 -5
- data/test/connections/native_mysql/connection.rb +1 -1
- data/test/fixtures/articles.yml +1 -0
- data/test/fixtures/products.yml +2 -4
- data/test/fixtures/readings.yml +1 -0
- data/test/fixtures/suburbs.yml +1 -4
- data/test/fixtures/users.yml +1 -0
- data/test/test_associations.rb +61 -63
- data/test/test_attributes.rb +16 -21
- data/test/test_create.rb +3 -3
- data/test/test_delete.rb +87 -84
- data/test/{test_clone.rb → test_dup.rb} +8 -5
- data/test/test_exists.rb +22 -10
- data/test/test_habtm.rb +0 -74
- data/test/test_ids.rb +2 -1
- data/test/test_miscellaneous.rb +2 -2
- data/test/test_polymorphic.rb +1 -1
- data/test/test_suite.rb +1 -1
- data/test/test_update.rb +3 -3
- metadata +76 -75
- data/lib/composite_primary_keys/association_preload.rb +0 -158
- data/lib/composite_primary_keys/associations.rb +0 -155
- data/lib/composite_primary_keys/associations/association_proxy.rb +0 -33
- data/lib/composite_primary_keys/associations/has_one_association.rb +0 -27
- data/lib/composite_primary_keys/associations/through_association_scope.rb +0 -103
- data/lib/composite_primary_keys/attribute_methods.rb +0 -84
- data/lib/composite_primary_keys/calculations.rb +0 -31
- data/lib/composite_primary_keys/connection_adapters/ibm_db_adapter.rb +0 -21
- data/lib/composite_primary_keys/connection_adapters/oracle_adapter.rb +0 -15
- data/lib/composite_primary_keys/connection_adapters/oracle_enhanced_adapter.rb +0 -17
- data/lib/composite_primary_keys/connection_adapters/sqlite3_adapter.rb +0 -15
- data/lib/composite_primary_keys/finder_methods.rb +0 -123
- data/lib/composite_primary_keys/primary_key.rb +0 -19
- data/lib/composite_primary_keys/query_methods.rb +0 -24
- data/lib/composite_primary_keys/read.rb +0 -25
- data/lib/composite_primary_keys/reflection.rb +0 -37
- data/lib/composite_primary_keys/write.rb +0 -18
@@ -0,0 +1,53 @@
|
|
1
|
+
module CompositePrimaryKeys
|
2
|
+
module Predicates
|
3
|
+
def cpk_and_predicate(predicates)
|
4
|
+
if predicates.length == 1
|
5
|
+
predicates.first
|
6
|
+
else
|
7
|
+
Arel::Nodes::And.new(predicates)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def cpk_or_predicate(predicates)
|
12
|
+
result = predicates.shift
|
13
|
+
predicates.each do |predicate|
|
14
|
+
result = result.or(predicate)
|
15
|
+
end
|
16
|
+
result
|
17
|
+
end
|
18
|
+
|
19
|
+
def cpk_id_predicate(table, keys, values)
|
20
|
+
eq_predicates = keys.zip(values).map do |key, value|
|
21
|
+
table[key].eq(value)
|
22
|
+
end
|
23
|
+
cpk_and_predicate(eq_predicates)
|
24
|
+
end
|
25
|
+
|
26
|
+
def cpk_join_predicate(table1, key1, table2, key2)
|
27
|
+
key1_fields = Array(key1).map {|key| table1[key]}
|
28
|
+
key2_fields = Array(key2).map {|key| table2[key]}
|
29
|
+
|
30
|
+
eq_predicates = key1_fields.zip(key2_fields).map do |key_field1, key_field2|
|
31
|
+
key_field1.eq(key_field2)
|
32
|
+
end
|
33
|
+
cpk_and_predicate(eq_predicates)
|
34
|
+
end
|
35
|
+
|
36
|
+
def cpk_in_predicate(table, primary_keys, ids)
|
37
|
+
and_predicates = ids.map do |id_set|
|
38
|
+
eq_predicates = Array(primary_keys).zip(Array(id_set)).map do |primary_key, value|
|
39
|
+
table[primary_key].eq(value)
|
40
|
+
end
|
41
|
+
cpk_and_predicate(eq_predicates)
|
42
|
+
end
|
43
|
+
|
44
|
+
cpk_or_predicate(and_predicates)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
ActiveRecord::Associations::AssociationScope.send(:include, CompositePrimaryKeys::Predicates)
|
50
|
+
ActiveRecord::Associations::HasAndBelongsToManyAssociation.send(:include, CompositePrimaryKeys::Predicates)
|
51
|
+
ActiveRecord::Associations::JoinDependency::JoinAssociation.send(:include, CompositePrimaryKeys::Predicates)
|
52
|
+
ActiveRecord::Associations::Preloader::Association.send(:include, CompositePrimaryKeys::Predicates)
|
53
|
+
ActiveRecord::Relation.send(:include, CompositePrimaryKeys::Predicates)
|
@@ -1,9 +1,11 @@
|
|
1
1
|
module ActiveRecord
|
2
|
-
module ConnectionAdapters
|
2
|
+
module ConnectionAdapters
|
3
3
|
class AbstractAdapter
|
4
|
-
def
|
5
|
-
|
4
|
+
def quote_column_names(name)
|
5
|
+
Array(name).map do |col|
|
6
|
+
quote_column_name(col.to_s)
|
7
|
+
end.join(CompositePrimaryKeys::ID_SEP)
|
6
8
|
end
|
7
9
|
end
|
8
10
|
end
|
9
|
-
end
|
11
|
+
end
|
@@ -1,52 +1,30 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module ConnectionAdapters
|
3
|
-
class PostgreSQLAdapter
|
4
|
-
|
5
|
-
# This mightn't be in Core, but count(distinct x,y) doesn't work for me
|
6
|
-
def supports_count_distinct? #:nodoc:
|
7
|
-
false
|
8
|
-
end
|
9
|
-
|
10
|
-
def concat(*columns)
|
11
|
-
columns = columns.map { |c| "CAST(#{c} AS varchar)" }
|
12
|
-
"(#{columns.join('||')})"
|
13
|
-
end
|
14
|
-
|
15
|
-
# Executes an INSERT query and returns the new record's ID
|
16
|
-
def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
3
|
+
class PostgreSQLAdapter
|
4
|
+
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
17
5
|
# Extract the table from the insert sql. Yuck.
|
18
|
-
table = sql.split(" ", 4)[2]
|
6
|
+
_, table = extract_schema_and_table(sql.split(" ", 4)[2])
|
19
7
|
|
20
|
-
|
21
|
-
if supports_insert_with_returning?
|
22
|
-
pk, sequence_name = *pk_and_sequence_for(table) unless pk
|
23
|
-
if pk
|
24
|
-
quoted_pk = if pk.is_a?(Array)
|
25
|
-
pk.map { |col| quote_column_name(col) }.join(CompositePrimaryKeys::ID_SEP)
|
26
|
-
else
|
27
|
-
quote_column_name(pk)
|
28
|
-
end
|
29
|
-
id = select_value("#{sql} RETURNING #{quoted_pk}")
|
30
|
-
clear_query_cache
|
31
|
-
return id
|
32
|
-
end
|
33
|
-
end
|
8
|
+
pk ||= primary_key(table)
|
34
9
|
|
35
|
-
|
36
|
-
|
37
|
-
insert_id
|
10
|
+
if pk
|
11
|
+
select_value("#{sql} RETURNING #{quote_column_names(pk)}")
|
38
12
|
else
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
alias :create :insert
|
17
|
+
|
18
|
+
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
|
19
|
+
unless pk
|
20
|
+
_, table = extract_schema_and_table(sql.split(" ", 4)[2])
|
43
21
|
|
44
|
-
|
45
|
-
# Don't fetch last insert id for a table without a pk.
|
46
|
-
if pk && sequence_name ||= default_sequence_name(table, pk)
|
47
|
-
last_insert_id(table, sequence_name)
|
48
|
-
end
|
22
|
+
pk = primary_key(table)
|
49
23
|
end
|
24
|
+
|
25
|
+
sql = "#{sql} RETURNING #{quote_column_names(pk)}" if pk
|
26
|
+
|
27
|
+
[sql, binds]
|
50
28
|
end
|
51
29
|
end
|
52
30
|
end
|
@@ -1,9 +1,22 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
module ActiveRecord
|
2
|
+
class Fixture
|
3
|
+
def find
|
4
|
+
if model_class
|
5
|
+
# CPK
|
6
|
+
# model_class.find(fixture[model_class.primary_key])
|
7
|
+
ids = self.ids(model_class.primary_key)
|
8
|
+
model_class.find(ids)
|
9
|
+
else
|
10
|
+
raise FixtureClassNotFound, "No class attached to find."
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def ids(key)
|
15
|
+
if key.is_a? Array
|
16
|
+
key.map {|a_key| fixture[a_key.to_s] }
|
17
|
+
else
|
18
|
+
fixture[key]
|
19
|
+
end
|
7
20
|
end
|
8
21
|
end
|
9
22
|
end
|
@@ -1,17 +1,30 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module Persistence
|
3
|
-
def cpk_conditions
|
4
|
-
if self.composite?
|
5
|
-
ids_hash
|
6
|
-
else
|
7
|
-
self.class.arel_table[self.class.primary_key].eq(id)
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
3
|
def destroy
|
12
4
|
if persisted?
|
13
|
-
|
14
|
-
|
5
|
+
::ActiveRecord::IdentityMap.remove(self) if ::ActiveRecord::IdentityMap.enabled?
|
6
|
+
|
7
|
+
# CPK
|
8
|
+
#pk = self.class.primary_key
|
9
|
+
#column = self.class.columns_hash[pk]
|
10
|
+
#substitute = connection.substitute_at(column, 0)
|
11
|
+
primary_keys = Array(self.class.primary_key)
|
12
|
+
bind_values = Array.new
|
13
|
+
eq_predicates = Array.new
|
14
|
+
primary_keys.each_with_index do |key, i|
|
15
|
+
column = self.class.columns_hash[key.to_s]
|
16
|
+
bind_values << [column, self[key]]
|
17
|
+
substitute = connection.substitute_at(column, i)
|
18
|
+
eq_predicates << self.class.arel_table[key].eq(substitute)
|
19
|
+
end
|
20
|
+
predicate = Arel::Nodes::And.new(eq_predicates)
|
21
|
+
relation = self.class.unscoped.where(predicate)
|
22
|
+
|
23
|
+
# CPK
|
24
|
+
#relation.bind_values = [[column, id]]
|
25
|
+
relation.bind_values = bind_values
|
26
|
+
|
27
|
+
relation.delete_all
|
15
28
|
end
|
16
29
|
|
17
30
|
@destroyed = true
|
@@ -21,9 +34,15 @@ module ActiveRecord
|
|
21
34
|
def update(attribute_names = @attributes.keys)
|
22
35
|
attributes_with_values = arel_attributes_values(false, false, attribute_names)
|
23
36
|
return 0 if attributes_with_values.empty?
|
37
|
+
klass = self.class
|
24
38
|
# CPK
|
25
|
-
|
26
|
-
|
39
|
+
if !self.composite?
|
40
|
+
stmt = klass.unscoped.where(klass.arel_table[klass.primary_key].eq(id)).arel.compile_update(attributes_with_values)
|
41
|
+
else
|
42
|
+
# CPK
|
43
|
+
stmt = klass.unscoped.where(ids_hash).arel.compile_update(attributes_with_values)
|
44
|
+
end
|
45
|
+
klass.connection.update stmt.to_sql
|
27
46
|
end
|
28
47
|
end
|
29
|
-
end
|
48
|
+
end
|
@@ -1,20 +1,15 @@
|
|
1
|
-
module
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
predicates = self.primary_keys.zip(Array(id)).map do |key, value|
|
9
|
-
table[key].eq(value)
|
10
|
-
end
|
11
|
-
relation.where_values += predicates
|
12
|
-
relation
|
13
|
-
end
|
1
|
+
module ActiveRecord
|
2
|
+
class Relation
|
3
|
+
def add_cpk_support
|
4
|
+
class << self
|
5
|
+
include CompositePrimaryKeys::ActiveRecord::Calculations
|
6
|
+
include CompositePrimaryKeys::ActiveRecord::FinderMethods
|
7
|
+
include CompositePrimaryKeys::ActiveRecord::QueryMethods
|
14
8
|
|
15
9
|
def delete(id_or_array)
|
10
|
+
::ActiveRecord::IdentityMap.remove_by_id(self.symbolized_base_class, id_or_array) if ::ActiveRecord::IdentityMap.enabled?
|
16
11
|
# CPK
|
17
|
-
# where(
|
12
|
+
# where(primary_key => id_or_array).delete_all
|
18
13
|
|
19
14
|
id_or_array = if id_or_array.kind_of?(CompositePrimaryKeys::CompositeKeys)
|
20
15
|
[id_or_array]
|
@@ -23,7 +18,7 @@ module CompositePrimaryKeys
|
|
23
18
|
end
|
24
19
|
|
25
20
|
id_or_array.each do |id|
|
26
|
-
|
21
|
+
where(cpk_id_predicate(table, self.primary_key, id)).delete_all
|
27
22
|
end
|
28
23
|
end
|
29
24
|
|
@@ -41,12 +36,24 @@ module CompositePrimaryKeys
|
|
41
36
|
end
|
42
37
|
|
43
38
|
id_or_array.each do |id|
|
44
|
-
|
39
|
+
where(cpk_id_predicate(table, self.primary_key, id)).each do |record|
|
45
40
|
record.destroy
|
46
41
|
end
|
47
42
|
end
|
48
43
|
end
|
49
44
|
end
|
50
45
|
end
|
46
|
+
|
47
|
+
alias :initialize_cpk :initialize
|
48
|
+
def initialize(klass, table)
|
49
|
+
initialize_cpk(klass, table)
|
50
|
+
add_cpk_support if klass.composite?
|
51
|
+
end
|
52
|
+
|
53
|
+
alias :initialize_copy_cpk :initialize_copy
|
54
|
+
def initialize_copy(other)
|
55
|
+
initialize_copy_cpk(other)
|
56
|
+
add_cpk_support if klass.composite?
|
57
|
+
end
|
51
58
|
end
|
52
59
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module CompositePrimaryKeys
|
2
|
+
module ActiveRecord
|
3
|
+
module Calculations
|
4
|
+
def execute_simple_calculation(operation, column_name, distinct)
|
5
|
+
# Postgresql doesn't like ORDER BY when there are no GROUP BY
|
6
|
+
relation = reorder(nil)
|
7
|
+
|
8
|
+
# CPK
|
9
|
+
#if operation == "count" && (relation.limit_value || relation.offset_value)
|
10
|
+
if operation == "count"
|
11
|
+
# Shortcut when limit is zero.
|
12
|
+
return 0 if relation.limit_value == 0
|
13
|
+
|
14
|
+
query_builder = build_count_subquery(relation, column_name, distinct)
|
15
|
+
else
|
16
|
+
column = aggregate_column(column_name)
|
17
|
+
|
18
|
+
select_value = operation_over_aggregate_column(column, operation, distinct)
|
19
|
+
|
20
|
+
relation.select_values = [select_value]
|
21
|
+
|
22
|
+
query_builder = relation.arel
|
23
|
+
end
|
24
|
+
|
25
|
+
type_cast_calculated_value(@klass.connection.select_value(query_builder.to_sql), column_for(column_name), operation)
|
26
|
+
end
|
27
|
+
|
28
|
+
def build_count_subquery(relation, column_name, distinct)
|
29
|
+
# CPK
|
30
|
+
# column_alias = Arel.sql('count_column')
|
31
|
+
subquery_alias = Arel.sql('subquery_for_count')
|
32
|
+
|
33
|
+
# CPK
|
34
|
+
# aliased_column = aggregate_column(column_name == :all ? 1 : column_name).as(column_alias)
|
35
|
+
# relation.select_values = [aliased_column]
|
36
|
+
column = aggregate_column(column_name)
|
37
|
+
relation.select_values = ["DISTINCT #{column.to_s}"]
|
38
|
+
subquery = relation.arel.as(subquery_alias)
|
39
|
+
|
40
|
+
sm = Arel::SelectManager.new relation.engine
|
41
|
+
# CPK
|
42
|
+
# select_value = operation_over_aggregate_column(column_alias, 'count', distinct)
|
43
|
+
select_value = operation_over_aggregate_column(Arel.sql("*"), 'count', false)
|
44
|
+
sm.project(select_value).from(subquery)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,117 @@
|
|
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
|
+
end
|
67
|
+
connection.select_value(relation.to_sql) ? true : false
|
68
|
+
end
|
69
|
+
|
70
|
+
def find_with_ids(*ids, &block)
|
71
|
+
return to_a.find { |*block_args| yield(*block_args) } if block_given?
|
72
|
+
|
73
|
+
# Supports:
|
74
|
+
# find('1,2') -> ['1,2']
|
75
|
+
# find(1,2) -> [1,2]
|
76
|
+
# find([1,2]) -> [['1,2']]
|
77
|
+
# find([1,2], [3,4]) -> [[1,2],[3,4]]
|
78
|
+
#
|
79
|
+
# Does *not* support:
|
80
|
+
# find('1,2', '3,4') -> ['1,2','3,4']
|
81
|
+
|
82
|
+
# Normalize incoming data. Note the last arg can be nil. Happens
|
83
|
+
# when find is called with nil options like the reload method does.
|
84
|
+
ids.compact!
|
85
|
+
ids = [ids] unless ids.first.kind_of?(Array)
|
86
|
+
|
87
|
+
results = ids.map do |cpk_ids|
|
88
|
+
cpk_ids = if cpk_ids.length == 1
|
89
|
+
cpk_ids.first.split(CompositePrimaryKeys::ID_SEP).to_composite_keys
|
90
|
+
else
|
91
|
+
cpk_ids.to_composite_keys
|
92
|
+
end
|
93
|
+
|
94
|
+
unless cpk_ids.length == @klass.primary_keys.length
|
95
|
+
raise "#{cpk_ids.inspect}: Incorrect number of primary keys for #{@klass.name}: #{@klass.primary_keys.inspect}"
|
96
|
+
end
|
97
|
+
|
98
|
+
new_relation = clone
|
99
|
+
[@klass.primary_keys, cpk_ids].transpose.map do |key, id|
|
100
|
+
new_relation = new_relation.where(key => id)
|
101
|
+
end
|
102
|
+
|
103
|
+
records = new_relation.to_a
|
104
|
+
|
105
|
+
if records.empty?
|
106
|
+
conditions = new_relation.arel.where_sql
|
107
|
+
raise(::ActiveRecord::RecordNotFound,
|
108
|
+
"Couldn't find #{@klass.name} with ID=#{cpk_ids} #{conditions}")
|
109
|
+
end
|
110
|
+
records
|
111
|
+
end.flatten
|
112
|
+
|
113
|
+
ids.length == 1 ? results.first : results
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|