composite_primary_keys 8.1.0 → 8.1.1
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.
- checksums.yaml +4 -4
- data/History.rdoc +642 -625
- data/README.rdoc +5 -2
- data/lib/composite_primary_keys.rb +115 -115
- data/lib/composite_primary_keys/associations/association.rb +23 -23
- data/lib/composite_primary_keys/associations/association_scope.rb +73 -73
- data/lib/composite_primary_keys/associations/collection_association.rb +14 -14
- data/lib/composite_primary_keys/associations/has_many_association.rb +69 -69
- data/lib/composite_primary_keys/associations/join_dependency.rb +87 -87
- data/lib/composite_primary_keys/associations/preloader/association.rb +90 -90
- data/lib/composite_primary_keys/associations/singular_association.rb +18 -18
- data/lib/composite_primary_keys/attribute_methods.rb +9 -9
- data/lib/composite_primary_keys/attribute_methods/dirty.rb +29 -29
- data/lib/composite_primary_keys/attribute_methods/read.rb +24 -24
- data/lib/composite_primary_keys/attribute_methods/write.rb +30 -30
- data/lib/composite_primary_keys/attribute_set/builder.rb +19 -19
- data/lib/composite_primary_keys/base.rb +129 -135
- data/lib/composite_primary_keys/composite_arrays.rb +43 -43
- data/lib/composite_primary_keys/connection_adapters/abstract/connection_specification_changes.rb +2 -3
- data/lib/composite_primary_keys/core.rb +60 -60
- data/lib/composite_primary_keys/persistence.rb +56 -56
- data/lib/composite_primary_keys/relation.rb +68 -68
- data/lib/composite_primary_keys/relation/calculations.rb +78 -78
- data/lib/composite_primary_keys/relation/finder_methods.rb +179 -179
- data/lib/composite_primary_keys/sanitization.rb +52 -52
- data/lib/composite_primary_keys/validations/uniqueness.rb +36 -36
- data/lib/composite_primary_keys/version.rb +8 -8
- data/tasks/databases/sqlserver.rake +27 -27
- data/test/abstract_unit.rb +114 -113
- data/test/connections/databases.example.yml +25 -25
- data/test/connections/native_sqlserver/connection.rb +11 -11
- data/test/fixtures/db_definitions/mysql.sql +218 -218
- data/test/fixtures/db_definitions/postgresql.sql +220 -220
- data/test/fixtures/db_definitions/sqlite.sql +206 -206
- data/test/fixtures/db_definitions/sqlserver.drop.sql +91 -91
- data/test/fixtures/db_definitions/sqlserver.sql +226 -226
- data/test/fixtures/employee.rb +11 -11
- data/test/fixtures/salary.rb +5 -5
- data/test/test_associations.rb +341 -340
- data/test/test_attributes.rb +60 -60
- data/test/test_create.rb +157 -157
- data/test/test_delete.rb +158 -158
- data/test/test_delete_all.rb +33 -28
- data/test/test_enum.rb +21 -21
- data/test/test_equal.rb +26 -26
- data/test/test_find.rb +119 -118
- data/test/test_habtm.rb +117 -113
- data/test/test_polymorphic.rb +27 -26
- data/test/test_tutorial_example.rb +25 -25
- metadata +44 -2
@@ -1,79 +1,79 @@
|
|
1
|
-
module CompositePrimaryKeys
|
2
|
-
module ActiveRecord
|
3
|
-
module Calculations
|
4
|
-
def aggregate_column(column_name)
|
5
|
-
# CPK
|
6
|
-
if column_name.kind_of?(Array)
|
7
|
-
column_name.map do |column|
|
8
|
-
Arel::Attribute.new(@klass.unscoped.table, column)
|
9
|
-
end
|
10
|
-
elsif @klass.column_names.include?(column_name.to_s)
|
11
|
-
Arel::Attribute.new(@klass.unscoped.table, column_name)
|
12
|
-
else
|
13
|
-
Arel.sql(column_name == :all ? "*" : column_name.to_s)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def execute_simple_calculation(operation, column_name, distinct)
|
18
|
-
# Postgresql doesn't like ORDER BY when there are no GROUP BY
|
19
|
-
relation = unscope(:order)
|
20
|
-
|
21
|
-
column_alias = column_name
|
22
|
-
|
23
|
-
bind_values = nil
|
24
|
-
|
25
|
-
# CPK
|
26
|
-
# if operation == "count" && (relation.limit_value || relation.offset_value)
|
27
|
-
if operation == "count"
|
28
|
-
# Shortcut when limit is zero.
|
29
|
-
return 0 if relation.limit_value == 0
|
30
|
-
|
31
|
-
query_builder = build_count_subquery(relation, column_name, distinct)
|
32
|
-
bind_values = query_builder.bind_values + relation.bind_values
|
33
|
-
else
|
34
|
-
column = aggregate_column(column_name)
|
35
|
-
|
36
|
-
select_value = operation_over_aggregate_column(column, operation, distinct)
|
37
|
-
|
38
|
-
column_alias = select_value.alias
|
39
|
-
relation.select_values = [select_value]
|
40
|
-
|
41
|
-
query_builder = relation.arel
|
42
|
-
bind_values = query_builder.bind_values + relation.bind_values
|
43
|
-
end
|
44
|
-
|
45
|
-
result = @klass.connection.select_all(query_builder, nil, bind_values)
|
46
|
-
row = result.first
|
47
|
-
value = row && row.values.first
|
48
|
-
column = result.column_types.fetch(column_alias) do
|
49
|
-
type_for(column_name)
|
50
|
-
end
|
51
|
-
|
52
|
-
type_cast_calculated_value(value, column, operation)
|
53
|
-
end
|
54
|
-
|
55
|
-
def build_count_subquery(relation, column_name, distinct)
|
56
|
-
return super(relation, column_name, distinct) unless column_name.kind_of?(Array)
|
57
|
-
# CPK
|
58
|
-
# column_alias = Arel.sql('count_column')
|
59
|
-
subquery_alias = Arel.sql('subquery_for_count')
|
60
|
-
|
61
|
-
# CPK
|
62
|
-
# aliased_column = aggregate_column(column_name == :all ? 1 : column_name).as(column_alias)
|
63
|
-
# relation.select_values = [aliased_column]
|
64
|
-
relation.select_values = column_name.map do |column|
|
65
|
-
Arel::Attribute.new(@klass.unscoped.table, column)
|
66
|
-
end
|
67
|
-
|
68
|
-
relation = relation.distinct(true)
|
69
|
-
subquery = relation.arel.as(subquery_alias)
|
70
|
-
|
71
|
-
sm = Arel::SelectManager.new relation.engine
|
72
|
-
# CPK
|
73
|
-
# select_value = operation_over_aggregate_column(column_alias, 'count', distinct)
|
74
|
-
select_value = operation_over_aggregate_column(Arel.sql("*"), 'count', false)
|
75
|
-
sm.project(select_value).from(subquery)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
1
|
+
module CompositePrimaryKeys
|
2
|
+
module ActiveRecord
|
3
|
+
module Calculations
|
4
|
+
def aggregate_column(column_name)
|
5
|
+
# CPK
|
6
|
+
if column_name.kind_of?(Array)
|
7
|
+
column_name.map do |column|
|
8
|
+
Arel::Attribute.new(@klass.unscoped.table, column)
|
9
|
+
end
|
10
|
+
elsif @klass.column_names.include?(column_name.to_s)
|
11
|
+
Arel::Attribute.new(@klass.unscoped.table, column_name)
|
12
|
+
else
|
13
|
+
Arel.sql(column_name == :all ? "*" : column_name.to_s)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute_simple_calculation(operation, column_name, distinct)
|
18
|
+
# Postgresql doesn't like ORDER BY when there are no GROUP BY
|
19
|
+
relation = unscope(:order)
|
20
|
+
|
21
|
+
column_alias = column_name
|
22
|
+
|
23
|
+
bind_values = nil
|
24
|
+
|
25
|
+
# CPK
|
26
|
+
# if operation == "count" && (relation.limit_value || relation.offset_value)
|
27
|
+
if operation == "count"
|
28
|
+
# Shortcut when limit is zero.
|
29
|
+
return 0 if relation.limit_value == 0
|
30
|
+
|
31
|
+
query_builder = build_count_subquery(relation, column_name, distinct)
|
32
|
+
bind_values = query_builder.bind_values + relation.bind_values
|
33
|
+
else
|
34
|
+
column = aggregate_column(column_name)
|
35
|
+
|
36
|
+
select_value = operation_over_aggregate_column(column, operation, distinct)
|
37
|
+
|
38
|
+
column_alias = select_value.alias
|
39
|
+
relation.select_values = [select_value]
|
40
|
+
|
41
|
+
query_builder = relation.arel
|
42
|
+
bind_values = query_builder.bind_values + relation.bind_values
|
43
|
+
end
|
44
|
+
|
45
|
+
result = @klass.connection.select_all(query_builder, nil, bind_values)
|
46
|
+
row = result.first
|
47
|
+
value = row && row.values.first
|
48
|
+
column = result.column_types.fetch(column_alias) do
|
49
|
+
type_for(column_name)
|
50
|
+
end
|
51
|
+
|
52
|
+
type_cast_calculated_value(value, column, operation)
|
53
|
+
end
|
54
|
+
|
55
|
+
def build_count_subquery(relation, column_name, distinct)
|
56
|
+
return super(relation, column_name, distinct) unless column_name.kind_of?(Array)
|
57
|
+
# CPK
|
58
|
+
# column_alias = Arel.sql('count_column')
|
59
|
+
subquery_alias = Arel.sql('subquery_for_count')
|
60
|
+
|
61
|
+
# CPK
|
62
|
+
# aliased_column = aggregate_column(column_name == :all ? 1 : column_name).as(column_alias)
|
63
|
+
# relation.select_values = [aliased_column]
|
64
|
+
relation.select_values = column_name.map do |column|
|
65
|
+
Arel::Attribute.new(@klass.unscoped.table, column)
|
66
|
+
end
|
67
|
+
|
68
|
+
relation = relation.distinct(true)
|
69
|
+
subquery = relation.arel.as(subquery_alias)
|
70
|
+
|
71
|
+
sm = Arel::SelectManager.new relation.engine
|
72
|
+
# CPK
|
73
|
+
# select_value = operation_over_aggregate_column(column_alias, 'count', distinct)
|
74
|
+
select_value = operation_over_aggregate_column(Arel.sql("*"), 'count', false)
|
75
|
+
sm.project(select_value).from(subquery)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
79
|
end
|
@@ -1,179 +1,179 @@
|
|
1
|
-
module CompositePrimaryKeys
|
2
|
-
module ActiveRecord
|
3
|
-
module FinderMethods
|
4
|
-
def apply_join_dependency(relation, join_dependency)
|
5
|
-
relation = relation.except(:includes, :eager_load, :preload)
|
6
|
-
relation = relation.joins join_dependency
|
7
|
-
|
8
|
-
if using_limitable_reflections?(join_dependency.reflections)
|
9
|
-
relation
|
10
|
-
else
|
11
|
-
if relation.limit_value
|
12
|
-
limited_ids = limited_ids_for(relation)
|
13
|
-
# CPK
|
14
|
-
#limited_ids.empty? ? relation.none! : relation.where!(table[primary_key].in(limited_ids))
|
15
|
-
limited_ids.empty? ? relation.none! : relation.where!(cpk_in_predicate(table, self.primary_keys, limited_ids))
|
16
|
-
end
|
17
|
-
relation.except(:limit, :offset)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def limited_ids_for(relation)
|
22
|
-
# CPK
|
23
|
-
#values = @klass.connection.columns_for_distinct(
|
24
|
-
# "#{quoted_table_name}.#{quoted_primary_key}", relation.order_values)
|
25
|
-
columns = @klass.primary_keys.map do |key|
|
26
|
-
"#{quoted_table_name}.#{connection.quote_column_name(key)}"
|
27
|
-
end
|
28
|
-
values = @klass.connection.columns_for_distinct(columns, relation.order_values)
|
29
|
-
|
30
|
-
relation = relation.except(:select).select(values).distinct!
|
31
|
-
|
32
|
-
id_rows = @klass.connection.select_all(relation.arel, 'SQL', relation.bind_values)
|
33
|
-
|
34
|
-
# CPK
|
35
|
-
#id_rows.map {|row| row[primary_key]}
|
36
|
-
id_rows.map {|row| row.values}
|
37
|
-
end
|
38
|
-
|
39
|
-
def exists?(conditions = :none)
|
40
|
-
# conditions can be:
|
41
|
-
# Array - ['department_id = ? and location_id = ?', 1, 1]
|
42
|
-
# Array -> [1,2]
|
43
|
-
# CompositeKeys -> [1,2]
|
44
|
-
|
45
|
-
conditions = conditions.id if ::ActiveRecord::Base === conditions
|
46
|
-
return false if !conditions
|
47
|
-
|
48
|
-
relation = apply_join_dependency(self, construct_join_dependency)
|
49
|
-
return false if ::ActiveRecord::NullRelation === relation
|
50
|
-
|
51
|
-
relation = relation.except(:select, :order).select(::ActiveRecord::FinderMethods::ONE_AS_ONE).limit(1)
|
52
|
-
|
53
|
-
# CPK
|
54
|
-
#case conditions
|
55
|
-
#when Array, Hash
|
56
|
-
# relation = relation.where(conditions)
|
57
|
-
#else
|
58
|
-
# relation = relation.where(table[primary_key].eq(conditions)) if conditions != :none
|
59
|
-
#end
|
60
|
-
|
61
|
-
case conditions
|
62
|
-
when CompositePrimaryKeys::CompositeKeys
|
63
|
-
relation = relation.where(cpk_id_predicate(table, primary_key, conditions))
|
64
|
-
when Array
|
65
|
-
pk_length = @klass.primary_keys.length
|
66
|
-
|
67
|
-
if conditions.length == pk_length # E.g. conditions = ['France', 'Paris']
|
68
|
-
return self.exists?(conditions.to_composite_keys)
|
69
|
-
else # Assume that conditions contains where relation
|
70
|
-
relation = relation.where(conditions)
|
71
|
-
end
|
72
|
-
when Hash
|
73
|
-
relation = relation.where(conditions)
|
74
|
-
end
|
75
|
-
|
76
|
-
connection.select_value(relation, "#{name} Exists", relation.bind_values) ? true : false
|
77
|
-
end
|
78
|
-
|
79
|
-
def find_with_ids(*ids)
|
80
|
-
raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
|
81
|
-
|
82
|
-
# CPK
|
83
|
-
#expects_array = ids.first.kind_of?(Array)
|
84
|
-
ids = CompositePrimaryKeys.normalize(ids)
|
85
|
-
expects_array = ids.flatten != ids.flatten(1)
|
86
|
-
|
87
|
-
return ids.first if expects_array && ids.first.empty?
|
88
|
-
|
89
|
-
# CPK
|
90
|
-
#ids = ids.flatten.compact.uniq
|
91
|
-
ids = expects_array ? ids.first : ids
|
92
|
-
|
93
|
-
case ids.size
|
94
|
-
when 0
|
95
|
-
raise RecordNotFound, "Couldn't find #{@klass.name} without an ID"
|
96
|
-
when 1
|
97
|
-
result = find_one(ids.first)
|
98
|
-
expects_array ? [ result ] : result
|
99
|
-
else
|
100
|
-
find_some(ids)
|
101
|
-
end
|
102
|
-
rescue RangeError
|
103
|
-
raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID"
|
104
|
-
end
|
105
|
-
|
106
|
-
def find_one(id)
|
107
|
-
# CPK
|
108
|
-
#id = id.id if ActiveRecord::Base === id
|
109
|
-
id = id.id if ::ActiveRecord::Base === id
|
110
|
-
|
111
|
-
# CPK
|
112
|
-
#column = columns_hash[primary_key]
|
113
|
-
#substitute = connection.substitute_at(column, bind_values.length)
|
114
|
-
#relation = where(table[primary_key].eq(substitute))
|
115
|
-
#relation.bind_values += [[column, id]]
|
116
|
-
#record = relation.take
|
117
|
-
relation = self
|
118
|
-
values = primary_keys.each_with_index.map do |primary_key, i|
|
119
|
-
column = columns_hash[primary_key]
|
120
|
-
relation.bind_values += [[column, id[i]]]
|
121
|
-
connection.substitute_at(column, bind_values.length - 1)
|
122
|
-
end
|
123
|
-
relation = relation.where(cpk_id_predicate(table, primary_keys, values))
|
124
|
-
record = relation.take
|
125
|
-
raise_record_not_found_exception!(id, 0, 1) unless record
|
126
|
-
record
|
127
|
-
end
|
128
|
-
|
129
|
-
def find_some(ids)
|
130
|
-
# CPK
|
131
|
-
# result = where(table[primary_key].in(ids)).to_a
|
132
|
-
|
133
|
-
result = ids.map do |cpk_ids|
|
134
|
-
cpk_ids = if cpk_ids.length == 1
|
135
|
-
cpk_ids.first.split(CompositePrimaryKeys::ID_SEP).to_composite_keys
|
136
|
-
else
|
137
|
-
cpk_ids.to_composite_keys
|
138
|
-
end
|
139
|
-
|
140
|
-
unless cpk_ids.length == @klass.primary_keys.length
|
141
|
-
raise "#{cpk_ids.inspect}: Incorrect number of primary keys for #{@klass.name}: #{@klass.primary_keys.inspect}"
|
142
|
-
end
|
143
|
-
|
144
|
-
new_relation = clone
|
145
|
-
[@klass.primary_keys, cpk_ids].transpose.map do |key, id|
|
146
|
-
new_relation = new_relation.where(key => id)
|
147
|
-
end
|
148
|
-
|
149
|
-
records = new_relation.to_a
|
150
|
-
|
151
|
-
if records.empty?
|
152
|
-
conditions = new_relation.arel.where_sql
|
153
|
-
raise(::ActiveRecord::RecordNotFound,
|
154
|
-
"Couldn't find #{@klass.name} with ID=#{cpk_ids} #{conditions}")
|
155
|
-
end
|
156
|
-
records
|
157
|
-
end.flatten
|
158
|
-
|
159
|
-
expected_size =
|
160
|
-
if limit_value && ids.size > limit_value
|
161
|
-
limit_value
|
162
|
-
else
|
163
|
-
ids.size
|
164
|
-
end
|
165
|
-
|
166
|
-
# 11 ids with limit 3, offset 9 should give 2 results.
|
167
|
-
if offset_value && (ids.size - offset_value < expected_size)
|
168
|
-
expected_size = ids.size - offset_value
|
169
|
-
end
|
170
|
-
|
171
|
-
if result.size == expected_size
|
172
|
-
result
|
173
|
-
else
|
174
|
-
raise_record_not_found_exception!(ids, result.size, expected_size)
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|
1
|
+
module CompositePrimaryKeys
|
2
|
+
module ActiveRecord
|
3
|
+
module FinderMethods
|
4
|
+
def apply_join_dependency(relation, join_dependency)
|
5
|
+
relation = relation.except(:includes, :eager_load, :preload)
|
6
|
+
relation = relation.joins join_dependency
|
7
|
+
|
8
|
+
if using_limitable_reflections?(join_dependency.reflections)
|
9
|
+
relation
|
10
|
+
else
|
11
|
+
if relation.limit_value
|
12
|
+
limited_ids = limited_ids_for(relation)
|
13
|
+
# CPK
|
14
|
+
#limited_ids.empty? ? relation.none! : relation.where!(table[primary_key].in(limited_ids))
|
15
|
+
limited_ids.empty? ? relation.none! : relation.where!(cpk_in_predicate(table, self.primary_keys, limited_ids))
|
16
|
+
end
|
17
|
+
relation.except(:limit, :offset)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def limited_ids_for(relation)
|
22
|
+
# CPK
|
23
|
+
#values = @klass.connection.columns_for_distinct(
|
24
|
+
# "#{quoted_table_name}.#{quoted_primary_key}", relation.order_values)
|
25
|
+
columns = @klass.primary_keys.map do |key|
|
26
|
+
"#{quoted_table_name}.#{connection.quote_column_name(key)}"
|
27
|
+
end
|
28
|
+
values = @klass.connection.columns_for_distinct(columns, relation.order_values)
|
29
|
+
|
30
|
+
relation = relation.except(:select).select(values).distinct!
|
31
|
+
|
32
|
+
id_rows = @klass.connection.select_all(relation.arel, 'SQL', relation.bind_values)
|
33
|
+
|
34
|
+
# CPK
|
35
|
+
#id_rows.map {|row| row[primary_key]}
|
36
|
+
id_rows.map {|row| row.values}
|
37
|
+
end
|
38
|
+
|
39
|
+
def exists?(conditions = :none)
|
40
|
+
# conditions can be:
|
41
|
+
# Array - ['department_id = ? and location_id = ?', 1, 1]
|
42
|
+
# Array -> [1,2]
|
43
|
+
# CompositeKeys -> [1,2]
|
44
|
+
|
45
|
+
conditions = conditions.id if ::ActiveRecord::Base === conditions
|
46
|
+
return false if !conditions
|
47
|
+
|
48
|
+
relation = apply_join_dependency(self, construct_join_dependency)
|
49
|
+
return false if ::ActiveRecord::NullRelation === relation
|
50
|
+
|
51
|
+
relation = relation.except(:select, :order).select(::ActiveRecord::FinderMethods::ONE_AS_ONE).limit(1)
|
52
|
+
|
53
|
+
# CPK
|
54
|
+
#case conditions
|
55
|
+
#when Array, Hash
|
56
|
+
# relation = relation.where(conditions)
|
57
|
+
#else
|
58
|
+
# relation = relation.where(table[primary_key].eq(conditions)) if conditions != :none
|
59
|
+
#end
|
60
|
+
|
61
|
+
case conditions
|
62
|
+
when CompositePrimaryKeys::CompositeKeys
|
63
|
+
relation = relation.where(cpk_id_predicate(table, primary_key, conditions))
|
64
|
+
when Array
|
65
|
+
pk_length = @klass.primary_keys.length
|
66
|
+
|
67
|
+
if conditions.length == pk_length # E.g. conditions = ['France', 'Paris']
|
68
|
+
return self.exists?(conditions.to_composite_keys)
|
69
|
+
else # Assume that conditions contains where relation
|
70
|
+
relation = relation.where(conditions)
|
71
|
+
end
|
72
|
+
when Hash
|
73
|
+
relation = relation.where(conditions)
|
74
|
+
end
|
75
|
+
|
76
|
+
connection.select_value(relation, "#{name} Exists", relation.bind_values) ? true : false
|
77
|
+
end
|
78
|
+
|
79
|
+
def find_with_ids(*ids)
|
80
|
+
raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
|
81
|
+
|
82
|
+
# CPK
|
83
|
+
#expects_array = ids.first.kind_of?(Array)
|
84
|
+
ids = CompositePrimaryKeys.normalize(ids)
|
85
|
+
expects_array = ids.flatten != ids.flatten(1)
|
86
|
+
|
87
|
+
return ids.first if expects_array && ids.first.empty?
|
88
|
+
|
89
|
+
# CPK
|
90
|
+
#ids = ids.flatten.compact.uniq
|
91
|
+
ids = expects_array ? ids.first : ids
|
92
|
+
|
93
|
+
case ids.size
|
94
|
+
when 0
|
95
|
+
raise RecordNotFound, "Couldn't find #{@klass.name} without an ID"
|
96
|
+
when 1
|
97
|
+
result = find_one(ids.first)
|
98
|
+
expects_array ? [ result ] : result
|
99
|
+
else
|
100
|
+
find_some(ids)
|
101
|
+
end
|
102
|
+
rescue RangeError
|
103
|
+
raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID"
|
104
|
+
end
|
105
|
+
|
106
|
+
def find_one(id)
|
107
|
+
# CPK
|
108
|
+
#id = id.id if ActiveRecord::Base === id
|
109
|
+
id = id.id if ::ActiveRecord::Base === id
|
110
|
+
|
111
|
+
# CPK
|
112
|
+
#column = columns_hash[primary_key]
|
113
|
+
#substitute = connection.substitute_at(column, bind_values.length)
|
114
|
+
#relation = where(table[primary_key].eq(substitute))
|
115
|
+
#relation.bind_values += [[column, id]]
|
116
|
+
#record = relation.take
|
117
|
+
relation = self
|
118
|
+
values = primary_keys.each_with_index.map do |primary_key, i|
|
119
|
+
column = columns_hash[primary_key]
|
120
|
+
relation.bind_values += [[column, id[i]]]
|
121
|
+
connection.substitute_at(column, bind_values.length - 1)
|
122
|
+
end
|
123
|
+
relation = relation.where(cpk_id_predicate(table, primary_keys, values))
|
124
|
+
record = relation.take
|
125
|
+
raise_record_not_found_exception!(id, 0, 1) unless record
|
126
|
+
record
|
127
|
+
end
|
128
|
+
|
129
|
+
def find_some(ids)
|
130
|
+
# CPK
|
131
|
+
# result = where(table[primary_key].in(ids)).to_a
|
132
|
+
|
133
|
+
result = ids.map do |cpk_ids|
|
134
|
+
cpk_ids = if cpk_ids.length == 1
|
135
|
+
cpk_ids.first.split(CompositePrimaryKeys::ID_SEP).to_composite_keys
|
136
|
+
else
|
137
|
+
cpk_ids.to_composite_keys
|
138
|
+
end
|
139
|
+
|
140
|
+
unless cpk_ids.length == @klass.primary_keys.length
|
141
|
+
raise "#{cpk_ids.inspect}: Incorrect number of primary keys for #{@klass.name}: #{@klass.primary_keys.inspect}"
|
142
|
+
end
|
143
|
+
|
144
|
+
new_relation = clone
|
145
|
+
[@klass.primary_keys, cpk_ids].transpose.map do |key, id|
|
146
|
+
new_relation = new_relation.where(key => id)
|
147
|
+
end
|
148
|
+
|
149
|
+
records = new_relation.to_a
|
150
|
+
|
151
|
+
if records.empty?
|
152
|
+
conditions = new_relation.arel.where_sql
|
153
|
+
raise(::ActiveRecord::RecordNotFound,
|
154
|
+
"Couldn't find #{@klass.name} with ID=#{cpk_ids} #{conditions}")
|
155
|
+
end
|
156
|
+
records
|
157
|
+
end.flatten
|
158
|
+
|
159
|
+
expected_size =
|
160
|
+
if limit_value && ids.size > limit_value
|
161
|
+
limit_value
|
162
|
+
else
|
163
|
+
ids.size
|
164
|
+
end
|
165
|
+
|
166
|
+
# 11 ids with limit 3, offset 9 should give 2 results.
|
167
|
+
if offset_value && (ids.size - offset_value < expected_size)
|
168
|
+
expected_size = ids.size - offset_value
|
169
|
+
end
|
170
|
+
|
171
|
+
if result.size == expected_size
|
172
|
+
result
|
173
|
+
else
|
174
|
+
raise_record_not_found_exception!(ids, result.size, expected_size)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|