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