composite_primary_keys 12.0.8 → 13.0.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 +888 -874
- data/README.rdoc +181 -180
- data/lib/composite_primary_keys/active_model/attribute_assignment.rb +19 -19
- data/lib/composite_primary_keys/associations/association_scope.rb +66 -68
- data/lib/composite_primary_keys/associations/join_dependency.rb +137 -103
- data/lib/composite_primary_keys/attribute_methods/primary_key.rb +0 -2
- data/lib/composite_primary_keys/attribute_methods/read.rb +30 -30
- data/lib/composite_primary_keys/attribute_methods/write.rb +35 -35
- data/lib/composite_primary_keys/attribute_methods.rb +21 -9
- data/lib/composite_primary_keys/base.rb +141 -141
- data/lib/composite_primary_keys/composite_predicates.rb +2 -1
- data/lib/composite_primary_keys/connection_adapters/abstract/database_statements.rb +37 -22
- data/lib/composite_primary_keys/connection_adapters/sqlserver/database_statements.rb +44 -44
- data/lib/composite_primary_keys/core.rb +48 -48
- data/lib/composite_primary_keys/nested_attributes.rb +1 -1
- data/lib/composite_primary_keys/persistence.rb +82 -81
- data/lib/composite_primary_keys/reflection.rb +91 -29
- data/lib/composite_primary_keys/relation/batches.rb +15 -7
- data/lib/composite_primary_keys/relation/calculations.rb +104 -81
- data/lib/composite_primary_keys/relation/finder_methods.rb +235 -235
- data/lib/composite_primary_keys/relation/predicate_builder/association_query_value.rb +39 -20
- data/lib/composite_primary_keys/relation/query_methods.rb +42 -42
- data/lib/composite_primary_keys/relation/where_clause.rb +18 -23
- data/lib/composite_primary_keys/relation.rb +197 -193
- data/lib/composite_primary_keys/table_metadata.rb +11 -0
- data/lib/composite_primary_keys/version.rb +8 -8
- data/lib/composite_primary_keys.rb +119 -119
- data/test/abstract_unit.rb +114 -114
- data/test/connections/databases.ci.yml +22 -22
- data/test/fixtures/db_definitions/db2-create-tables.sql +112 -112
- data/test/fixtures/db_definitions/db2-drop-tables.sql +16 -16
- data/test/fixtures/db_definitions/mysql.sql +180 -180
- data/test/fixtures/db_definitions/oracle.drop.sql +41 -41
- data/test/fixtures/db_definitions/oracle.sql +199 -199
- data/test/fixtures/db_definitions/postgresql.sql +182 -182
- data/test/fixtures/db_definitions/sqlite.sql +169 -169
- data/test/fixtures/db_definitions/sqlserver.sql +176 -176
- data/test/fixtures/department.rb +16 -16
- data/test/fixtures/departments.yml +19 -15
- data/test/fixtures/employees.yml +33 -28
- data/test/fixtures/membership.rb +8 -6
- data/test/fixtures/restaurants_suburbs.yml +10 -10
- data/test/fixtures/streets.yml +16 -16
- data/test/fixtures/suburbs.yml +14 -14
- data/test/fixtures/user.rb +11 -11
- data/test/test_associations.rb +372 -358
- data/test/test_attributes.rb +75 -60
- data/test/test_calculations.rb +49 -42
- data/test/test_create.rb +218 -206
- data/test/test_delete.rb +188 -179
- data/test/test_exists.rb +39 -39
- data/test/test_find.rb +170 -164
- data/test/test_ids.rb +112 -112
- data/test/test_nested_attributes.rb +67 -67
- data/test/test_update.rb +102 -96
- metadata +6 -6
- data/lib/composite_primary_keys/connection_adapters/mysql/database_statements.rb +0 -24
@@ -1,81 +1,82 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module Persistence
|
3
|
-
module ClassMethods
|
4
|
-
def delete(id_or_array)
|
5
|
-
# CPK
|
6
|
-
if self.composite?
|
7
|
-
id_or_array = if id_or_array.is_a?(CompositePrimaryKeys::CompositeKeys)
|
8
|
-
[id_or_array]
|
9
|
-
else
|
10
|
-
Array(id_or_array)
|
11
|
-
end
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
dm.
|
54
|
-
dm.
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
end
|
1
|
+
module ActiveRecord
|
2
|
+
module Persistence
|
3
|
+
module ClassMethods
|
4
|
+
def delete(id_or_array)
|
5
|
+
# CPK
|
6
|
+
if self.composite?
|
7
|
+
id_or_array = if id_or_array.is_a?(CompositePrimaryKeys::CompositeKeys)
|
8
|
+
[id_or_array]
|
9
|
+
else
|
10
|
+
Array(id_or_array)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Delete should return the number of deleted records
|
14
|
+
id_or_array.map do |id|
|
15
|
+
# Is the passed in id actually a record?
|
16
|
+
id = id.kind_of?(::ActiveRecord::Base) ? id.id : id
|
17
|
+
delete_by(cpk_id_predicate(self.arel_table, self.primary_key, id))
|
18
|
+
end.sum
|
19
|
+
else
|
20
|
+
delete_by(primary_key => id_or_array)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def _update_record(values, constraints) # :nodoc:
|
25
|
+
# CPK
|
26
|
+
if self.composite? && constraints[primary_key]
|
27
|
+
primary_key_values = constraints.delete(primary_key)
|
28
|
+
primary_key.each_with_index do |key, i|
|
29
|
+
constraints[key] = primary_key_values[i]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
constraints = _substitute_values(constraints).map { |attr, bind| attr.eq(bind) }
|
34
|
+
|
35
|
+
um = arel_table.where(
|
36
|
+
constraints.reduce(&:and)
|
37
|
+
).compile_update(_substitute_values(values), primary_key)
|
38
|
+
|
39
|
+
connection.update(um, "#{self} Update")
|
40
|
+
end
|
41
|
+
|
42
|
+
def _delete_record(constraints) # :nodoc:
|
43
|
+
# CPK
|
44
|
+
if self.composite? && constraints[primary_key]
|
45
|
+
primary_key_values = constraints.delete(primary_key)
|
46
|
+
primary_key.each_with_index do |key, i|
|
47
|
+
constraints[key] = primary_key_values[i]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
constraints = _substitute_values(constraints).map { |attr, bind| attr.eq(bind) }
|
52
|
+
|
53
|
+
dm = Arel::DeleteManager.new
|
54
|
+
dm.from(arel_table)
|
55
|
+
dm.wheres = constraints
|
56
|
+
|
57
|
+
connection.delete(dm, "#{self} Destroy")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def _create_record(attribute_names = self.attribute_names)
|
62
|
+
attribute_names = attributes_for_create(attribute_names)
|
63
|
+
|
64
|
+
new_id = self.class._insert_record(
|
65
|
+
attributes_with_values(attribute_names)
|
66
|
+
)
|
67
|
+
|
68
|
+
# CPK
|
69
|
+
if self.composite?
|
70
|
+
self.id = self.id.zip(Array(new_id)).map {|id1, id2| id2.nil? ? id1 : id2}
|
71
|
+
else
|
72
|
+
self.id ||= new_id if self.class.primary_key
|
73
|
+
end
|
74
|
+
|
75
|
+
@new_record = false
|
76
|
+
|
77
|
+
yield(self) if block_given?
|
78
|
+
|
79
|
+
id
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -1,29 +1,91 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module Reflection
|
3
|
-
class AbstractReflection
|
4
|
-
def join_scope(table, foreign_table, foreign_klass)
|
5
|
-
predicate_builder = predicate_builder(table)
|
6
|
-
scope_chain_items = join_scopes(table, predicate_builder)
|
7
|
-
klass_scope = klass_join_scope(table, predicate_builder)
|
8
|
-
|
9
|
-
key =
|
10
|
-
foreign_key =
|
11
|
-
|
12
|
-
# CPK
|
13
|
-
#klass_scope.where!(table[key].eq(foreign_table[foreign_key]))
|
14
|
-
constraint = cpk_join_predicate(table, key, foreign_table, foreign_key)
|
15
|
-
klass_scope.where!(constraint)
|
16
|
-
|
17
|
-
if type
|
18
|
-
klass_scope.where!(type => foreign_klass.polymorphic_name)
|
19
|
-
end
|
20
|
-
|
21
|
-
if klass.finder_needs_type_condition?
|
22
|
-
klass_scope.where!(klass.send(:type_condition, table))
|
23
|
-
end
|
24
|
-
|
25
|
-
scope_chain_items.inject(klass_scope, &:merge!)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
|
1
|
+
module ActiveRecord
|
2
|
+
module Reflection
|
3
|
+
class AbstractReflection
|
4
|
+
def join_scope(table, foreign_table, foreign_klass)
|
5
|
+
predicate_builder = predicate_builder(table)
|
6
|
+
scope_chain_items = join_scopes(table, predicate_builder)
|
7
|
+
klass_scope = klass_join_scope(table, predicate_builder)
|
8
|
+
|
9
|
+
key = join_primary_key
|
10
|
+
foreign_key = join_foreign_key
|
11
|
+
|
12
|
+
# CPK
|
13
|
+
#klass_scope.where!(table[key].eq(foreign_table[foreign_key]))
|
14
|
+
constraint = cpk_join_predicate(table, key, foreign_table, foreign_key)
|
15
|
+
klass_scope.where!(constraint)
|
16
|
+
|
17
|
+
if type
|
18
|
+
klass_scope.where!(type => foreign_klass.polymorphic_name)
|
19
|
+
end
|
20
|
+
|
21
|
+
if klass.finder_needs_type_condition?
|
22
|
+
klass_scope.where!(klass.send(:type_condition, table))
|
23
|
+
end
|
24
|
+
|
25
|
+
scope_chain_items.inject(klass_scope, &:merge!)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class AssociationReflection < MacroReflection
|
30
|
+
def foreign_key
|
31
|
+
# CPK
|
32
|
+
# @foreign_key ||= -(options[:foreign_key]&.to_s || derive_foreign_key)
|
33
|
+
@foreign_key ||= extract_keys(options[:foreign_key]) || derive_foreign_key
|
34
|
+
end
|
35
|
+
|
36
|
+
def association_foreign_key
|
37
|
+
# CPK
|
38
|
+
# @association_foreign_key ||= -(options[:association_foreign_key]&.to_s || class_name.foreign_key)
|
39
|
+
@association_foreign_key ||= extract_keys(options[:association_foreign_key]) || class_name.foreign_key
|
40
|
+
end
|
41
|
+
|
42
|
+
def active_record_primary_key
|
43
|
+
# CPK (Rails freezes the string returned in the expression that calculates PK here. But Rails uses the `-` method which is not available on Array for CPK, so we calculate it in one line and freeze it on the next)
|
44
|
+
# @active_record_primary_key ||= -(options[:primary_key]&.to_s || primary_key(active_record))
|
45
|
+
@active_record_primary_key ||= begin
|
46
|
+
pk = options[:primary_key] || primary_key(active_record)
|
47
|
+
pk.freeze
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def extract_keys(keys)
|
54
|
+
case keys
|
55
|
+
when Array
|
56
|
+
keys.map { |k| k.to_s }
|
57
|
+
when NilClass
|
58
|
+
nil
|
59
|
+
else
|
60
|
+
keys.to_s
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class BelongsToReflection < AssociationReflection
|
66
|
+
def association_primary_key(klass = nil)
|
67
|
+
if primary_key = options[:primary_key]
|
68
|
+
# CPK
|
69
|
+
# @association_primary_key ||= -primary_key.to_s
|
70
|
+
@association_primary_key ||= primary_key.freeze
|
71
|
+
else
|
72
|
+
primary_key(klass || self.klass)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class ThroughReflection < AbstractReflection #:nodoc:
|
78
|
+
def association_primary_key(klass = nil)
|
79
|
+
# Get the "actual" source reflection if the immediate source reflection has a
|
80
|
+
# source reflection itself
|
81
|
+
if primary_key = actual_source_reflection.options[:primary_key]
|
82
|
+
# CPK
|
83
|
+
# @association_primary_key ||= -primary_key.to_s
|
84
|
+
@association_primary_key ||= primary_key.freeze
|
85
|
+
else
|
86
|
+
primary_key(klass || self.klass)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -1,12 +1,16 @@
|
|
1
1
|
module CompositePrimaryKeys
|
2
2
|
module ActiveRecord
|
3
3
|
module Batches
|
4
|
-
def in_batches(of: 1000, start: nil, finish: nil, load: false, error_on_ignore: nil)
|
4
|
+
def in_batches(of: 1000, start: nil, finish: nil, load: false, error_on_ignore: nil, order: :asc)
|
5
5
|
relation = self
|
6
6
|
unless block_given?
|
7
7
|
return ::ActiveRecord::Batches::BatchEnumerator.new(of: of, start: start, finish: finish, relation: self)
|
8
8
|
end
|
9
9
|
|
10
|
+
unless [:asc, :desc].include?(order)
|
11
|
+
raise ArgumentError, ":order must be :asc or :desc, got #{order.inspect}"
|
12
|
+
end
|
13
|
+
|
10
14
|
if arel.orders.present?
|
11
15
|
act_on_ignored_order(error_on_ignore)
|
12
16
|
end
|
@@ -17,8 +21,8 @@ module CompositePrimaryKeys
|
|
17
21
|
batch_limit = remaining if remaining < batch_limit
|
18
22
|
end
|
19
23
|
|
20
|
-
relation = relation.reorder(batch_order).limit(batch_limit)
|
21
|
-
relation = apply_limits(relation, start, finish)
|
24
|
+
relation = relation.reorder(batch_order(order)).limit(batch_limit)
|
25
|
+
relation = apply_limits(relation, start, finish, order)
|
22
26
|
relation.skip_query_cache! # Retaining the results in the query cache would undermine the point of batching
|
23
27
|
batch_relation = relation
|
24
28
|
|
@@ -61,7 +65,9 @@ module CompositePrimaryKeys
|
|
61
65
|
end
|
62
66
|
|
63
67
|
# CPK
|
64
|
-
#
|
68
|
+
#batch_relation = relation.where(
|
69
|
+
# predicate_builder[primary_key, primary_key_offset, order == :desc ? :lt : :gt]
|
70
|
+
#)
|
65
71
|
batch_relation = if composite?
|
66
72
|
# CPK
|
67
73
|
# Lexicographically select records
|
@@ -81,7 +87,9 @@ module CompositePrimaryKeys
|
|
81
87
|
end.reduce(:or)
|
82
88
|
relation.where(query)
|
83
89
|
else
|
84
|
-
relation.where(
|
90
|
+
batch_relation = relation.where(
|
91
|
+
predicate_builder[primary_key, primary_key_offset, order == :desc ? :lt : :gt]
|
92
|
+
)
|
85
93
|
end
|
86
94
|
end
|
87
95
|
end
|
@@ -95,9 +103,9 @@ module CompositePrimaryKeys
|
|
95
103
|
ary.length.times.reduce([]) { |results, i| results << ary[0..i] }
|
96
104
|
end
|
97
105
|
|
98
|
-
def batch_order
|
106
|
+
def batch_order(order)
|
99
107
|
self.primary_key.map do |key|
|
100
|
-
|
108
|
+
table[key].public_send(order)
|
101
109
|
end
|
102
110
|
end
|
103
111
|
end
|
@@ -1,81 +1,104 @@
|
|
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
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
select_value = operation_over_aggregate_column(column, operation, distinct)
|
36
|
-
if operation == "sum" && distinct
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
relation.select_values = [ Arel.sql(::ActiveRecord::FinderMethods::ONE_AS_ONE) ] unless distinct
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
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
|
+
# Note: Test don't seem to run this code?
|
8
|
+
column_name.map do |column|
|
9
|
+
@klass.arel_table[column]
|
10
|
+
end
|
11
|
+
elsif @klass.has_attribute?(column_name) || @klass.attribute_alias?(column_name)
|
12
|
+
@klass.arel_table[column_name]
|
13
|
+
else
|
14
|
+
Arel.sql(column_name == :all ? "*" : column_name.to_s)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
|
19
|
+
column_alias = column_name
|
20
|
+
|
21
|
+
# CPK
|
22
|
+
# if operation == "count" && (column_name == :all && distinct || has_limit_or_offset?)
|
23
|
+
# # Shortcut when limit is zero.
|
24
|
+
# return 0 if limit_value == 0
|
25
|
+
#
|
26
|
+
# query_builder = build_count_subquery(spawn, column_name, distinct)
|
27
|
+
if operation == "count"
|
28
|
+
relation = unscope(:order)
|
29
|
+
query_builder = build_count_subquery(spawn, column_name, distinct)
|
30
|
+
else
|
31
|
+
# PostgreSQL doesn't like ORDER BY when there are no GROUP BY
|
32
|
+
relation = unscope(:order).distinct!(false)
|
33
|
+
|
34
|
+
column = aggregate_column(column_name)
|
35
|
+
select_value = operation_over_aggregate_column(column, operation, distinct)
|
36
|
+
select_value.distinct = true if operation == "sum" && distinct
|
37
|
+
|
38
|
+
relation.select_values = [select_value]
|
39
|
+
|
40
|
+
query_builder = relation.arel
|
41
|
+
end
|
42
|
+
|
43
|
+
result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder) }
|
44
|
+
|
45
|
+
type_cast_calculated_value(result.cast_values.first, operation) do |value|
|
46
|
+
type = column.try(:type_caster) ||
|
47
|
+
# CPK
|
48
|
+
# lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
|
49
|
+
lookup_cast_type_from_join_dependencies(column_name.to_s) || ::ActiveRecord::Type.default_value
|
50
|
+
type.deserialize(value)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def build_count_subquery(relation, column_name, distinct)
|
55
|
+
if column_name == :all
|
56
|
+
column_alias = Arel.star
|
57
|
+
# CPK
|
58
|
+
# relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
|
59
|
+
relation.select_values = [ Arel.sql(::ActiveRecord::FinderMethods::ONE_AS_ONE) ] unless distinct
|
60
|
+
elsif column_name.is_a?(Array)
|
61
|
+
column_alias = Arel.star
|
62
|
+
relation.select_values = column_name.map do |column|
|
63
|
+
Arel::Attribute.new(@klass.unscoped.table, column)
|
64
|
+
end
|
65
|
+
else
|
66
|
+
column_alias = Arel.sql("count_column")
|
67
|
+
relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
|
68
|
+
end
|
69
|
+
|
70
|
+
subquery_alias = Arel.sql("subquery_for_count")
|
71
|
+
select_value = operation_over_aggregate_column(column_alias, "count", false)
|
72
|
+
|
73
|
+
relation.build_subquery(subquery_alias, select_value)
|
74
|
+
end
|
75
|
+
|
76
|
+
def calculate(operation, column_name)
|
77
|
+
if has_include?(column_name)
|
78
|
+
relation = apply_join_dependency
|
79
|
+
|
80
|
+
if operation.to_s.downcase == "count"
|
81
|
+
unless distinct_value || distinct_select?(column_name || select_for_count)
|
82
|
+
relation.distinct!
|
83
|
+
# CPK
|
84
|
+
# relation.select_values = [ klass.primary_key || table[Arel.star] ]
|
85
|
+
if klass.primary_key.present? && klass.primary_key.is_a?(Array)
|
86
|
+
relation.select_values = klass.primary_key.map do |k|
|
87
|
+
"#{connection.quote_table_name(klass.table_name)}.#{connection.quote_column_name(k)}"
|
88
|
+
end
|
89
|
+
else
|
90
|
+
relation.select_values = [ klass.primary_key || table[Arel.star] ]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
# PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
|
94
|
+
relation.order_values = [] if group_values.empty?
|
95
|
+
end
|
96
|
+
|
97
|
+
relation.calculate(operation, column_name)
|
98
|
+
else
|
99
|
+
perform_calculation(operation, column_name)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|