activecube 0.1.2 → 0.1.3
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/Gemfile.lock +1 -1
- data/README.md +1 -3
- data/lib/activecube/common/metrics.rb +5 -1
- data/lib/activecube/definition_methods.rb +2 -1
- data/lib/activecube/field.rb +22 -3
- data/lib/activecube/processor/composer.rb +2 -1
- data/lib/activecube/query/cube_query.rb +5 -7
- data/lib/activecube/query/ordering.rb +2 -1
- data/lib/activecube/query/selector.rb +1 -1
- data/lib/activecube/query/slice.rb +51 -30
- data/lib/activecube/query_methods.rb +2 -3
- data/lib/activecube/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ef6448e22d9122edb34207112002802381c6f807a60a73150add0dfba415eff2
|
|
4
|
+
data.tar.gz: f1db99febe43eb9943f96c344bbd77c2c3a42e6619225b9266980b6b2e3c486b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c4ea5bf5ac7fc108a1868cdffc4b12a7c916d34b4f93bc9c094f930a405dd27e989e60287d39ebe2ed136add74de86bd0849dcd47122e54489e5a02ddb9276ca
|
|
7
|
+
data.tar.gz: d67e1cd6832b0c4bbc1ce2669ca145359b34e31ba5182392ff25d5b7e13b9bc639ae4822121821739b52bb7c0f2b829d06fb76c51cbd15b346db5f8a1488a26a
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -132,9 +132,7 @@ The methods used to contruct the query:
|
|
|
132
132
|
- **slice** defines which dimensions slices the results
|
|
133
133
|
- **measure** defines what to measure
|
|
134
134
|
- **when** defines which selectors to apply
|
|
135
|
-
- **desc, asc,
|
|
136
|
-
|
|
137
|
-
(take and skip have aliases: offset and limit).
|
|
135
|
+
- **desc, asc, offset, limit** are for ordering and limiting result set
|
|
138
136
|
|
|
139
137
|
After the query contructed, the following methods can be applied:
|
|
140
138
|
|
|
@@ -12,7 +12,7 @@ module Activecube::Common
|
|
|
12
12
|
end
|
|
13
13
|
else
|
|
14
14
|
define_method fname do |model, arel_table, measure, cube_query|
|
|
15
|
-
column = arel_table
|
|
15
|
+
column = pre_aggregate_value model, arel_table, measure, cube_query
|
|
16
16
|
measure.selectors.empty? ? column.send(fname) : column.send(fname.to_s+'If', measure.condition_query(model, arel_table, cube_query))
|
|
17
17
|
end
|
|
18
18
|
end
|
|
@@ -21,5 +21,9 @@ module Activecube::Common
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
def pre_aggregate_value _model, arel_table, _measure, _cube_query
|
|
25
|
+
arel_table[self.class.column_name.to_sym]
|
|
26
|
+
end
|
|
27
|
+
|
|
24
28
|
end
|
|
25
29
|
end
|
data/lib/activecube/field.rb
CHANGED
|
@@ -2,11 +2,30 @@ module Activecube
|
|
|
2
2
|
class Field
|
|
3
3
|
|
|
4
4
|
attr_reader :name, :definition
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
|
|
6
|
+
def self.build name, arg
|
|
7
|
+
if arg.kind_of? String
|
|
8
|
+
Field.new name, arg
|
|
9
|
+
elsif arg.kind_of? Hash
|
|
10
|
+
Field.new name, arg.symbolize_keys
|
|
11
|
+
elsif arg.kind_of?(Class) && arg < Field
|
|
12
|
+
arg.new name
|
|
13
|
+
else
|
|
14
|
+
raise ArgumentError, "Unexpected field #{name} definition with #{arg.class.name}"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def initialize name, arg = nil
|
|
19
|
+
@name = name
|
|
20
|
+
@definition = arg
|
|
8
21
|
end
|
|
9
22
|
|
|
23
|
+
def expression _model, _arel_table, _slice, _cube_query
|
|
24
|
+
raise ArgumentError, "String expression expected for #{name} field, instead #{definition.class.name} is found" unless definition.kind_of?(String)
|
|
25
|
+
definition
|
|
26
|
+
end
|
|
10
27
|
|
|
11
28
|
end
|
|
29
|
+
|
|
30
|
+
|
|
12
31
|
end
|
|
@@ -70,7 +70,8 @@ module Activecube::Processor
|
|
|
70
70
|
@models = []
|
|
71
71
|
measure_tables.group_by(&:table).each_pair do |table, list|
|
|
72
72
|
@models << table.model
|
|
73
|
-
|
|
73
|
+
reduce_options = measure_tables.count==1 ? cube_query.options : []
|
|
74
|
+
reduced = cube_query.reduced list.map(&:measure), reduce_options
|
|
74
75
|
table_query = table.query reduced
|
|
75
76
|
composed_query = composed_query ? table.join(cube_query, composed_query, table_query) : table_query
|
|
76
77
|
end
|
|
@@ -49,22 +49,20 @@ module Activecube::Query
|
|
|
49
49
|
self
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
def
|
|
52
|
+
def offset *args
|
|
53
53
|
args.each{|arg|
|
|
54
54
|
options << Limit.new( arg, :skip)
|
|
55
55
|
}
|
|
56
56
|
self
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
-
def
|
|
59
|
+
def limit *args
|
|
60
60
|
args.each{|arg|
|
|
61
61
|
options << Limit.new( arg, :take)
|
|
62
62
|
}
|
|
63
63
|
self
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
-
alias_method :limit, :take
|
|
67
|
-
alias_method :offset, :skip
|
|
68
66
|
|
|
69
67
|
def query
|
|
70
68
|
composer = Activecube::Processor::Composer.new(self)
|
|
@@ -88,7 +86,7 @@ module Activecube::Query
|
|
|
88
86
|
(measures.map(&:selectors) + selectors).flatten.map(&:required_column_names).flatten.uniq
|
|
89
87
|
end
|
|
90
88
|
|
|
91
|
-
def reduced other_measures
|
|
89
|
+
def reduced other_measures, other_options
|
|
92
90
|
|
|
93
91
|
common_selectors = []
|
|
94
92
|
other_measures.each_with_index do |m,i|
|
|
@@ -115,11 +113,11 @@ module Activecube::Query
|
|
|
115
113
|
|
|
116
114
|
return self if (reduced_measures == self.measures) && (reduced_selectors == self.selectors)
|
|
117
115
|
|
|
118
|
-
CubeQuery.new cube, slices, reduced_measures, reduced_selectors
|
|
116
|
+
CubeQuery.new cube, slices, reduced_measures, reduced_selectors, other_options
|
|
119
117
|
end
|
|
120
118
|
|
|
121
119
|
def join_fields
|
|
122
|
-
slices.map{|s| s.
|
|
120
|
+
slices.map{|s| s.dimension.class.identity || s.key }.uniq
|
|
123
121
|
end
|
|
124
122
|
|
|
125
123
|
def orderings
|
|
@@ -9,7 +9,8 @@ module Activecube
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def append_query _model, _cube_query, _table, query
|
|
12
|
-
|
|
12
|
+
text = argument.to_s.split(',').map{|s| "`#{s}`"}.join(',')
|
|
13
|
+
query.order(::Arel.sql(text).send(direction))
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
end
|
|
@@ -44,7 +44,7 @@ module Activecube::Query
|
|
|
44
44
|
define_method(method) do |*args|
|
|
45
45
|
raise ArgumentError, "Selector for #{method} already set" if operator
|
|
46
46
|
if ARRAY_OPERATORS.include? method
|
|
47
|
-
@operator = Operator.new(method, args)
|
|
47
|
+
@operator = Operator.new(method, args.flatten)
|
|
48
48
|
elsif method=='between'
|
|
49
49
|
if args.kind_of?(Range)
|
|
50
50
|
@operator = Operator.new(method, args)
|
|
@@ -1,36 +1,59 @@
|
|
|
1
1
|
module Activecube::Query
|
|
2
2
|
class Slice < Item
|
|
3
3
|
|
|
4
|
-
attr_reader :
|
|
5
|
-
def initialize cube, key,
|
|
6
|
-
super cube, key,
|
|
7
|
-
@
|
|
8
|
-
@
|
|
9
|
-
|
|
4
|
+
attr_reader :dimension, :parent
|
|
5
|
+
def initialize cube, key, definition, parent = nil
|
|
6
|
+
super cube, key, definition
|
|
7
|
+
@dimension = parent ? parent.dimension : definition
|
|
8
|
+
@parent = parent
|
|
9
|
+
|
|
10
|
+
if parent
|
|
11
|
+
raise "Unexpected class #{definition.class.name}" unless definition.kind_of?(Activecube::Field)
|
|
12
|
+
field_methods! if definition.class < Activecube::Field
|
|
13
|
+
end
|
|
14
|
+
|
|
10
15
|
end
|
|
11
16
|
|
|
12
|
-
def
|
|
13
|
-
|
|
14
|
-
raise "Field #{key} is not defined for #{definition.name}"
|
|
15
|
-
end
|
|
16
|
-
Slice.new cube, key, definition, field
|
|
17
|
+
def required_column_names
|
|
18
|
+
dimension.class.column_names || []
|
|
17
19
|
end
|
|
18
20
|
|
|
19
|
-
def
|
|
20
|
-
|
|
21
|
+
def [] arg
|
|
22
|
+
|
|
23
|
+
key = arg.to_sym
|
|
24
|
+
|
|
25
|
+
child = if definition.kind_of? Activecube::Dimension
|
|
26
|
+
definition.class.fields[key]
|
|
27
|
+
elsif definition.kind_of?(Activecube::Field) && (hash = definition.definition).kind_of?(Hash)
|
|
28
|
+
hash[key]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
raise "Field #{key} is not defined for #{definition}" unless child
|
|
32
|
+
|
|
33
|
+
if child.kind_of?(Class) && child <= Activecube::Field
|
|
34
|
+
child = child.new key
|
|
35
|
+
elsif !child.kind_of?(Activecube::Field)
|
|
36
|
+
child = Activecube::Field.new(key, child)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
Slice.new cube, key, child, self
|
|
40
|
+
|
|
21
41
|
end
|
|
22
42
|
|
|
23
|
-
def
|
|
24
|
-
|
|
43
|
+
def alias! new_key
|
|
44
|
+
self.class.new cube, new_key, definition, parent
|
|
25
45
|
end
|
|
26
46
|
|
|
27
|
-
def append_query
|
|
47
|
+
def append_query model, cube_query, table, query
|
|
28
48
|
|
|
29
49
|
attr_alias = "`#{key.to_s}`"
|
|
30
|
-
expr =
|
|
50
|
+
expr = parent ?
|
|
51
|
+
Arel.sql(definition.expression( model, table, self, cube_query) ) :
|
|
52
|
+
table[dimension.class.column_name]
|
|
53
|
+
|
|
31
54
|
query = query.project(expr.as(attr_alias))
|
|
32
55
|
|
|
33
|
-
if identity =
|
|
56
|
+
if identity = dimension.class.identity
|
|
34
57
|
query = query.project(table[identity]).group(table[identity])
|
|
35
58
|
else
|
|
36
59
|
query = query.group(attr_alias)
|
|
@@ -44,23 +67,21 @@ module Activecube::Query
|
|
|
44
67
|
end
|
|
45
68
|
|
|
46
69
|
def to_s
|
|
47
|
-
"Dimension #{super}"
|
|
70
|
+
parent ? "Dimension #{dimension}[#{super}]" : "Dimension #{super}"
|
|
48
71
|
end
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
private
|
|
52
|
-
|
|
72
|
+
|
|
53
73
|
def field_methods!
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
74
|
+
excluded = [:expression] + self.class.instance_methods(false)
|
|
75
|
+
definition.class.instance_methods(false).each do |name|
|
|
76
|
+
unless excluded.include?(name)
|
|
77
|
+
define_singleton_method name do |*args|
|
|
78
|
+
definition.send name, *args
|
|
79
|
+
self
|
|
80
|
+
end
|
|
61
81
|
end
|
|
62
82
|
end
|
|
63
83
|
end
|
|
84
|
+
|
|
64
85
|
|
|
65
86
|
end
|
|
66
87
|
end
|
|
@@ -5,7 +5,7 @@ module Activecube
|
|
|
5
5
|
|
|
6
6
|
attr_reader :database, :role
|
|
7
7
|
|
|
8
|
-
[:slice, :measure, :when, :
|
|
8
|
+
[:slice, :measure, :when, :desc, :asc, :limit, :offset].each do |method|
|
|
9
9
|
define_method(method) do |*args|
|
|
10
10
|
Query::CubeQuery.new(self).send method, *args
|
|
11
11
|
end
|
|
@@ -25,10 +25,9 @@ module Activecube
|
|
|
25
25
|
|
|
26
26
|
def super_model
|
|
27
27
|
raise ArgumentError, "No tables specified for cube #{name}" if tables.count==0
|
|
28
|
-
return tables.first.model if tables.count==1
|
|
29
28
|
|
|
30
29
|
tables.collect{ |t|
|
|
31
|
-
t.model.ancestors.select{|c| c
|
|
30
|
+
t.model.ancestors.select{|c| c < ActiveRecord::Base }
|
|
32
31
|
}.transpose.select{|c|
|
|
33
32
|
c.uniq.count==1
|
|
34
33
|
}.last.first
|
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.3
|
|
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-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|