activecube 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +45 -6
- data/lib/activecube.rb +1 -2
- data/lib/activecube/common/metrics.rb +25 -0
- data/lib/activecube/{dimension_definition_methods.rb → definition_methods.rb} +34 -5
- data/lib/activecube/dimension.rb +1 -1
- data/lib/activecube/metric.rb +2 -2
- data/lib/activecube/modifier.rb +12 -0
- data/lib/activecube/processor/table.rb +2 -2
- data/lib/activecube/query/cube_query.rb +10 -3
- data/lib/activecube/query/item.rb +4 -0
- data/lib/activecube/query/limit.rb +1 -1
- data/lib/activecube/query/measure.rb +34 -9
- data/lib/activecube/query/modification.rb +14 -0
- data/lib/activecube/query/or_selector.rb +2 -2
- data/lib/activecube/query/ordering.rb +1 -1
- data/lib/activecube/query/selector.rb +28 -7
- data/lib/activecube/query/slice.rb +11 -2
- data/lib/activecube/query_methods.rb +28 -1
- data/lib/activecube/selector.rb +4 -4
- data/lib/activecube/version.rb +1 -1
- metadata +6 -5
- data/lib/activecube/common/count.rb +0 -10
- data/lib/activecube/common/sum.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fc8d353c9c9d670cda8c4f9de4a3e59994c4f8e6ebd2d25551a5bf712f53db00
|
4
|
+
data.tar.gz: 55ac707acc8dd783318739e8f4bb424454da0c597a54ab89b09c76a16982ac23
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7652d255be72680539226092333c4c1fa081a0416b4ef50a13de17d40385c45628be5e761d1191b9e7e5ab1b55c26ca613012d9e601fda4c44984249bd7053e2
|
7
|
+
data.tar.gz: b20ad10bbec9f17cc95a879f84690739fcb3109e451797e954efd720a0de3fbaeac0a38e7b4a0ab1e647d2f3666d0b4b3de7c93d6bd3441897d3a72ab9db03f2
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -2,8 +2,7 @@
|
|
2
2
|
|
3
3
|
Activecube is the library to make multi-dimensional queries to data warehouse, such as:
|
4
4
|
|
5
|
-
```
|
6
|
-
|
5
|
+
```ruby
|
7
6
|
Cube.slice(
|
8
7
|
date: cube.dimensions[:date][:date].format('%Y-%m'),
|
9
8
|
currency: cube.dimensions[:currency][:symbol]
|
@@ -132,8 +131,10 @@ The methods used to contruct the query:
|
|
132
131
|
|
133
132
|
- **slice** defines which dimensions slices the results
|
134
133
|
- **measure** defines what to measure
|
135
|
-
- **
|
136
|
-
- **desc, asc, take,
|
134
|
+
- **when** defines which selectors to apply
|
135
|
+
- **desc, asc, take, skip** are for ordering and limiting result set
|
136
|
+
|
137
|
+
(take and skip have aliases: offset and limit).
|
137
138
|
|
138
139
|
After the query contructed, the following methods can be applied:
|
139
140
|
|
@@ -141,11 +142,13 @@ After the query contructed, the following methods can be applied:
|
|
141
142
|
- **to_query** to generate Arel query
|
142
143
|
- **query** to execute query and return ResultSet
|
143
144
|
|
144
|
-
|
145
|
+
### Managing Connections
|
146
|
+
|
147
|
+
|
148
|
+
You can control the connection used to construct and execute query by
|
145
149
|
ActiveRecord standard API:
|
146
150
|
|
147
151
|
```ruby
|
148
|
-
|
149
152
|
ApplicationRecord.connected_to(database: :data_warehouse) do
|
150
153
|
cube = My::TransfersCube
|
151
154
|
cube.slice(
|
@@ -158,6 +161,42 @@ ApplicationRecord.connected_to(database: :data_warehouse) do
|
|
158
161
|
will query using data_warehouse configuraton.
|
159
162
|
|
160
163
|
|
164
|
+
Alternatively you can use the method provided by activecube. It will
|
165
|
+
make the connection for the model or abstract class, which is super class for your models:
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
My::TransfersCube.connected_to(database: :data_warehouse) do |cube|
|
169
|
+
cube.slice(
|
170
|
+
date: cube.dimensions[:date][:date].format('%Y-%m'),
|
171
|
+
currency: cube.dimensions[:currency][:symbol]
|
172
|
+
).measure(:count).query
|
173
|
+
end
|
174
|
+
```
|
175
|
+
|
176
|
+
## How it works
|
177
|
+
|
178
|
+
When you construct and execute cube query with any outcome ( sql, Arel query or ResultSet),
|
179
|
+
the same sequence of operations happen:
|
180
|
+
|
181
|
+
1) Cube is collecting the query into a set of objects from the chain method call;
|
182
|
+
2) Query is matched against the physical tables, the tables are selected that can serve the query or its part. For example, one table can provide one set of metrics, and the other can provide remaining;
|
183
|
+
3) If possible, the variant is selected from all possible options, which uses indexes with the most cardinality
|
184
|
+
4) Query is constructed using Arel SQL engine ( included in ActiveRecord ) using selected tables, and possibly joins
|
185
|
+
5) If requested, the query is converted to sql ( using Arel visitor ) or executed with database connection
|
186
|
+
|
187
|
+
## Optimization
|
188
|
+
|
189
|
+
The optimization on step #3 try to minimize the total cost of execution:
|
190
|
+
|
191
|
+
![Formula min max](https://latex.codecogs.com/png.latex?min(\sum_{tables}max_{metrics}(cost))))
|
192
|
+
|
193
|
+
where
|
194
|
+
|
195
|
+
![Formula cost](https://latex.codecogs.com/png.latex?\inline&space;cost(metric,table)&space;=&space;1&space;/&space;(1&space;+&space;cardinality(metric,&space;table)))
|
196
|
+
|
197
|
+
Optimization is done using the algorithm, which checks possible combinations of metrics and tables.
|
198
|
+
|
199
|
+
|
161
200
|
## Development
|
162
201
|
|
163
202
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/lib/activecube.rb
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Activecube::Common
|
2
|
+
|
3
|
+
module Metrics
|
4
|
+
|
5
|
+
METHODS = [:count, :minimum,:maximum,:average,:sum,:uniqueExact,:unique,:median,:any,:anyLast]
|
6
|
+
|
7
|
+
METHODS.each do |fname|
|
8
|
+
|
9
|
+
if fname==:count
|
10
|
+
define_method fname do |model, arel_table, measure, cube_query|
|
11
|
+
measure.selectors.empty? ? Arel.star.count : Arel.star.countIf(measure.condition_query model, arel_table, cube_query)
|
12
|
+
end
|
13
|
+
else
|
14
|
+
define_method fname do |model, arel_table, measure, cube_query|
|
15
|
+
column = arel_table[self.class.column_name.to_sym]
|
16
|
+
measure.selectors.empty? ? column.send(fname) : column.send(fname.to_s+'If', measure.condition_query(model, arel_table, cube_query))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -1,10 +1,12 @@
|
|
1
1
|
require 'activecube/cube_definition'
|
2
2
|
require 'activecube/field'
|
3
|
+
require 'activecube/modifier'
|
3
4
|
|
4
5
|
module Activecube
|
5
|
-
module DimensionDefinitionMethods
|
6
6
|
|
7
|
-
|
7
|
+
module DefinitionMethods
|
8
|
+
|
9
|
+
attr_reader :column_names
|
8
10
|
|
9
11
|
def column_name
|
10
12
|
raise "Not defined column for a metric #{self.name}" if column_names.empty?
|
@@ -22,14 +24,41 @@ module Activecube
|
|
22
24
|
array.concat data
|
23
25
|
end
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
-
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
module DimensionDefinitionMethods
|
31
|
+
|
32
|
+
include DefinitionMethods
|
33
|
+
|
34
|
+
attr_reader :identity, :fields
|
35
|
+
|
36
|
+
private
|
28
37
|
|
29
38
|
def identity_column *args
|
30
39
|
raise "Identity already defined as #{identity} for #{self.name}" if @identity
|
31
40
|
@identity = args.first
|
32
41
|
end
|
33
42
|
|
43
|
+
def field *args
|
44
|
+
(@fields ||= {} )[args.first.to_sym] = Field.new( *args)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
module MetricDefinitionMethods
|
51
|
+
|
52
|
+
include DefinitionMethods
|
53
|
+
|
54
|
+
attr_reader :modifiers
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def modifier *args
|
59
|
+
(@modifiers ||= {} )[args.first.to_sym] = Modifier.new( *args)
|
60
|
+
end
|
61
|
+
|
34
62
|
end
|
63
|
+
|
35
64
|
end
|
data/lib/activecube/dimension.rb
CHANGED
data/lib/activecube/metric.rb
CHANGED
@@ -25,7 +25,7 @@ module Activecube::Processor
|
|
25
25
|
query = table
|
26
26
|
|
27
27
|
(cube_query.slices + cube_query.measures + cube_query.selectors + cube_query.options).each do |s|
|
28
|
-
query = s.append_query cube_query, table, query
|
28
|
+
query = s.append_query model, cube_query, table, query
|
29
29
|
end
|
30
30
|
|
31
31
|
query
|
@@ -42,7 +42,7 @@ module Activecube::Processor
|
|
42
42
|
using(*dimension_names)
|
43
43
|
|
44
44
|
cube_query.options.each do |option|
|
45
|
-
query = option.append_query cube_query, outer_table, query
|
45
|
+
query = option.append_query model, cube_query, outer_table, query
|
46
46
|
end
|
47
47
|
|
48
48
|
|
@@ -14,7 +14,7 @@ module Activecube::Query
|
|
14
14
|
|
15
15
|
include ChainAppender
|
16
16
|
|
17
|
-
attr_reader :cube, :slices, :measures, :selectors, :
|
17
|
+
attr_reader :cube, :slices, :measures, :selectors, :options
|
18
18
|
def initialize cube, slices = [], measures = [], selectors = [], options = []
|
19
19
|
@cube = cube
|
20
20
|
@slices = slices
|
@@ -31,7 +31,7 @@ module Activecube::Query
|
|
31
31
|
append *args, @measures, Measure, cube.metrics
|
32
32
|
end
|
33
33
|
|
34
|
-
def
|
34
|
+
def when *args
|
35
35
|
append *args, @selectors, Selector, cube.selectors
|
36
36
|
end
|
37
37
|
|
@@ -63,6 +63,9 @@ module Activecube::Query
|
|
63
63
|
self
|
64
64
|
end
|
65
65
|
|
66
|
+
alias_method :limit, :take
|
67
|
+
alias_method :offset, :skip
|
68
|
+
|
66
69
|
def query
|
67
70
|
composer = Activecube::Processor::Composer.new(self)
|
68
71
|
sql = composer.build_query.to_sql
|
@@ -101,7 +104,7 @@ module Activecube::Query
|
|
101
104
|
reduced_selectors = self.selectors
|
102
105
|
else
|
103
106
|
reduced_measures = other_measures.collect{|m|
|
104
|
-
Measure.new m.cube, m.key, m.definition, (m.selectors - common_selectors)
|
107
|
+
Measure.new m.cube, m.key, m.definition, (m.selectors - common_selectors), m.modifications
|
105
108
|
}
|
106
109
|
reduced_selectors = self.selectors + common_selectors
|
107
110
|
end
|
@@ -119,5 +122,9 @@ module Activecube::Query
|
|
119
122
|
slices.map{|s| s.dimension_class.identity || s.key }.uniq
|
120
123
|
end
|
121
124
|
|
125
|
+
def orderings
|
126
|
+
options.select{|s| s.kind_of? Ordering}
|
127
|
+
end
|
128
|
+
|
122
129
|
end
|
123
130
|
end
|
@@ -1,11 +1,16 @@
|
|
1
|
+
require 'activecube/modifier'
|
2
|
+
require 'activecube/query/modification'
|
3
|
+
|
1
4
|
module Activecube::Query
|
2
5
|
class Measure < Item
|
6
|
+
attr_reader :selectors, :modifications
|
3
7
|
|
4
|
-
|
5
|
-
|
6
|
-
def initialize cube, key, definition, selectors = []
|
8
|
+
def initialize cube, key, definition, selectors = [], modifications = []
|
7
9
|
super cube, key, definition
|
8
10
|
@selectors = selectors
|
11
|
+
@modifications = modifications
|
12
|
+
|
13
|
+
modifier_methods! if definition.class.modifiers
|
9
14
|
end
|
10
15
|
|
11
16
|
def required_column_names
|
@@ -17,24 +22,44 @@ module Activecube::Query
|
|
17
22
|
end
|
18
23
|
|
19
24
|
def alias! new_key
|
20
|
-
self.class.new cube, new_key, definition, selectors
|
25
|
+
self.class.new cube, new_key, definition, selectors, modifications
|
21
26
|
end
|
22
27
|
|
23
|
-
def condition_query arel_table, cube_query
|
28
|
+
def condition_query model, arel_table, cube_query
|
24
29
|
condition = nil
|
25
30
|
selectors.each do |selector|
|
26
31
|
condition = condition ?
|
27
|
-
condition.and(selector.expression(arel_table, cube_query)) :
|
28
|
-
selector.expression(arel_table, cube_query)
|
32
|
+
condition.and(selector.expression(model, arel_table, cube_query)) :
|
33
|
+
selector.expression(model, arel_table, cube_query)
|
29
34
|
end
|
30
35
|
condition
|
31
36
|
end
|
32
37
|
|
33
|
-
def append_query cube_query, table, query
|
38
|
+
def append_query model, cube_query, table, query
|
34
39
|
attr_alias = "`#{key.to_s}`"
|
35
|
-
expr = definition.expression table, self, cube_query
|
40
|
+
expr = definition.expression model, table, self, cube_query
|
36
41
|
query.project expr.as(attr_alias)
|
37
42
|
end
|
38
43
|
|
44
|
+
def to_s
|
45
|
+
"Metric #{super}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def modifier name
|
49
|
+
ms = modifications.select{|m| m.modifier.name==name}
|
50
|
+
raise "Found multiple (#{ms.count}) definitions for #{name} in #{self}" if ms.count>1
|
51
|
+
ms.first
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def modifier_methods!
|
57
|
+
definition.class.modifiers.each_pair do |key, modifier|
|
58
|
+
define_singleton_method key do |*args|
|
59
|
+
(@modifications ||= []) << Modification.new(modifier, *args)
|
60
|
+
self
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
39
64
|
end
|
40
65
|
end
|
@@ -9,10 +9,10 @@ module Activecube
|
|
9
9
|
@selectors = selectors
|
10
10
|
end
|
11
11
|
|
12
|
-
def append_query cube_query, table, query
|
12
|
+
def append_query model, cube_query, table, query
|
13
13
|
expr = nil
|
14
14
|
selectors.each do |s|
|
15
|
-
expr = expr ? expr.or(s.expression table, cube_query) : s.expression(table, cube_query)
|
15
|
+
expr = expr ? expr.or(s.expression model, table, cube_query) : s.expression(model, table, cube_query)
|
16
16
|
end
|
17
17
|
query.where(expr)
|
18
18
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Activecube::Query
|
2
2
|
class Selector < Item
|
3
3
|
|
4
|
-
OPERATORS = ['eq','ne','gt','lt','
|
4
|
+
OPERATORS = ['eq','ne','gt','lt','gteq','lteq','in','not_in','between']
|
5
5
|
ARRAY_OPERATORS = ['in','not_in']
|
6
6
|
|
7
7
|
class Operator
|
@@ -13,7 +13,7 @@ module Activecube::Query
|
|
13
13
|
@argument = argument
|
14
14
|
end
|
15
15
|
|
16
|
-
def expression left, right
|
16
|
+
def expression _model, left, right
|
17
17
|
left.send(operation, right)
|
18
18
|
end
|
19
19
|
|
@@ -33,6 +33,7 @@ module Activecube::Query
|
|
33
33
|
|
34
34
|
end
|
35
35
|
|
36
|
+
|
36
37
|
attr_reader :operator
|
37
38
|
def initialize cube, key, definition, operator = nil
|
38
39
|
super cube, key, definition
|
@@ -41,26 +42,42 @@ module Activecube::Query
|
|
41
42
|
|
42
43
|
OPERATORS.each do |method|
|
43
44
|
define_method(method) do |*args|
|
45
|
+
raise ArgumentError, "Selector for #{method} already set" if operator
|
44
46
|
if ARRAY_OPERATORS.include? method
|
45
47
|
@operator = Operator.new(method, args)
|
48
|
+
elsif method=='between'
|
49
|
+
if args.kind_of?(Range)
|
50
|
+
@operator = Operator.new(method, args)
|
51
|
+
elsif args.kind_of?(Array) && (arg = args.flatten).count==2
|
52
|
+
@operator = Operator.new(method, arg[0]..arg[1])
|
53
|
+
else
|
54
|
+
raise ArgumentError, "Unexpected size of arguments for #{method}, must be Range or Array of 2"
|
55
|
+
end
|
46
56
|
else
|
47
|
-
raise ArgumentError, "Unexpected size of arguments" unless args.size==1
|
57
|
+
raise ArgumentError, "Unexpected size of arguments for #{method}" unless args.size==1
|
48
58
|
@operator = Operator.new(method, args.first)
|
49
59
|
end
|
50
60
|
self
|
51
61
|
end
|
52
62
|
end
|
53
63
|
|
64
|
+
alias_method :since, :gteq
|
65
|
+
alias_method :till, :lteq
|
66
|
+
alias_method :is, :eq
|
67
|
+
alias_method :not, :ne
|
68
|
+
alias_method :after, :gt
|
69
|
+
alias_method :before, :lt
|
70
|
+
|
54
71
|
def alias! new_key
|
55
72
|
self.class.new cube, new_key, definition, operator
|
56
73
|
end
|
57
74
|
|
58
|
-
def append_query cube_query, table, query
|
59
|
-
query.where(expression table, cube_query)
|
75
|
+
def append_query model, cube_query, table, query
|
76
|
+
query.where(expression model, table, cube_query)
|
60
77
|
end
|
61
78
|
|
62
|
-
def expression arel_table, cube_query
|
63
|
-
definition.expression arel_table, self, cube_query
|
79
|
+
def expression model, arel_table, cube_query
|
80
|
+
definition.expression model, arel_table, self, cube_query
|
64
81
|
end
|
65
82
|
|
66
83
|
def eql?(other)
|
@@ -78,5 +95,9 @@ module Activecube::Query
|
|
78
95
|
self.definition.class.hash + self.operator.hash
|
79
96
|
end
|
80
97
|
|
98
|
+
def to_s
|
99
|
+
"Selector #{super}"
|
100
|
+
end
|
101
|
+
|
81
102
|
end
|
82
103
|
end
|
@@ -24,7 +24,7 @@ module Activecube::Query
|
|
24
24
|
definition.class
|
25
25
|
end
|
26
26
|
|
27
|
-
def append_query
|
27
|
+
def append_query _model, cube_query, table, query
|
28
28
|
|
29
29
|
attr_alias = "`#{key.to_s}`"
|
30
30
|
expr = field ? Arel.sql( modifier || field.definition ) : table[dimension_class.column_name]
|
@@ -33,12 +33,21 @@ module Activecube::Query
|
|
33
33
|
if identity = dimension_class.identity
|
34
34
|
query = query.project(table[identity]).group(table[identity])
|
35
35
|
else
|
36
|
-
query = query.group(attr_alias)
|
36
|
+
query = query.group(attr_alias)
|
37
|
+
end
|
38
|
+
|
39
|
+
if cube_query.orderings.empty?
|
40
|
+
query = query.order(attr_alias)
|
37
41
|
end
|
38
42
|
|
39
43
|
query
|
40
44
|
end
|
41
45
|
|
46
|
+
def to_s
|
47
|
+
"Dimension #{super}"
|
48
|
+
end
|
49
|
+
|
50
|
+
|
42
51
|
private
|
43
52
|
|
44
53
|
def field_methods!
|
@@ -3,11 +3,38 @@ require 'activecube/query/cube_query'
|
|
3
3
|
module Activecube
|
4
4
|
module QueryMethods
|
5
5
|
|
6
|
-
|
6
|
+
attr_reader :database, :role
|
7
|
+
|
8
|
+
[:slice, :measure, :when, :skip, :take, :desc, :asc].each do |method|
|
7
9
|
define_method(method) do |*args|
|
8
10
|
Query::CubeQuery.new(self).send method, *args
|
9
11
|
end
|
10
12
|
end
|
11
13
|
|
14
|
+
def connected_to database: nil, role: nil, &block
|
15
|
+
raise ArgumentError, "Must pass block to method" unless block_given?
|
16
|
+
super_model.connected_to(database: database, role: role) do
|
17
|
+
@database = database
|
18
|
+
@role = role
|
19
|
+
block.call self
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
|
26
|
+
def super_model
|
27
|
+
raise ArgumentError, "No tables specified for cube #{name}" if tables.count==0
|
28
|
+
return tables.first.model if tables.count==1
|
29
|
+
|
30
|
+
tables.collect{ |t|
|
31
|
+
t.model.ancestors.select{|c| c <= ActiveRecord::Base }.reverse
|
32
|
+
}.transpose.select{|c|
|
33
|
+
c.uniq.count==1
|
34
|
+
}.last.first
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
|
12
39
|
end
|
13
40
|
end
|
data/lib/activecube/selector.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
require 'activecube/
|
1
|
+
require 'activecube/definition_methods'
|
2
2
|
|
3
3
|
module Activecube
|
4
4
|
class Selector
|
5
|
-
extend
|
5
|
+
extend DefinitionMethods
|
6
6
|
|
7
|
-
def expression arel_table, selector, _cube_query
|
7
|
+
def expression model, arel_table, selector, _cube_query
|
8
8
|
op = selector.operator
|
9
|
-
op.expression arel_table[self.class.column_name.to_sym], op.argument
|
9
|
+
op.expression model, arel_table[self.class.column_name.to_sym], op.argument
|
10
10
|
end
|
11
11
|
|
12
12
|
end
|
data/lib/activecube/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activecube
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aleksey Studnev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-02-
|
11
|
+
date: 2020-02-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -91,13 +91,13 @@ files:
|
|
91
91
|
- lib/activecube.rb
|
92
92
|
- lib/activecube/active_record_extension.rb
|
93
93
|
- lib/activecube/base.rb
|
94
|
-
- lib/activecube/common/
|
95
|
-
- lib/activecube/common/sum.rb
|
94
|
+
- lib/activecube/common/metrics.rb
|
96
95
|
- lib/activecube/cube_definition.rb
|
96
|
+
- lib/activecube/definition_methods.rb
|
97
97
|
- lib/activecube/dimension.rb
|
98
|
-
- lib/activecube/dimension_definition_methods.rb
|
99
98
|
- lib/activecube/field.rb
|
100
99
|
- lib/activecube/metric.rb
|
100
|
+
- lib/activecube/modifier.rb
|
101
101
|
- lib/activecube/processor/composer.rb
|
102
102
|
- lib/activecube/processor/index.rb
|
103
103
|
- lib/activecube/processor/measure_tables.rb
|
@@ -108,6 +108,7 @@ files:
|
|
108
108
|
- lib/activecube/query/item.rb
|
109
109
|
- lib/activecube/query/limit.rb
|
110
110
|
- lib/activecube/query/measure.rb
|
111
|
+
- lib/activecube/query/modification.rb
|
111
112
|
- lib/activecube/query/or_selector.rb
|
112
113
|
- lib/activecube/query/ordering.rb
|
113
114
|
- lib/activecube/query/selector.rb
|
@@ -1,11 +0,0 @@
|
|
1
|
-
module Activecube::Common
|
2
|
-
|
3
|
-
class Sum < Activecube::Metric
|
4
|
-
|
5
|
-
def expression arel_table, measure, cube_query
|
6
|
-
column = arel_table[self.class.column_name.to_sym]
|
7
|
-
measure.selectors.empty? ? column.sum : column.sumIf(measure.condition_query arel_table, cube_query)
|
8
|
-
end
|
9
|
-
|
10
|
-
end
|
11
|
-
end
|