activecube 0.1.18 → 0.1.26

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 774718534987fd65114b6d33ef5ea98f28ffc146bc1cb9e3299d4ec6b571f2cc
4
- data.tar.gz: 317c3d6e4472c20724ccf6d31202842623ddb05725b002baf8d0224d4bb42af4
3
+ metadata.gz: d0c91dca78a440d0db5b8b0a28531d4c922a9dc81062aad663052afd671a500d
4
+ data.tar.gz: da104891e98f8cfcb14f91dcc74db0a2e418209e1380baf93a4a03d9653454d0
5
5
  SHA512:
6
- metadata.gz: bef4f7a62f25b52eb6ef8b07d89248b7a579c6f329bb3e645e7d59dd96d336fa7534e6669c6bb598d70392220e00d854a9481d956b6eeac8ad020cd728473dc9
7
- data.tar.gz: b7152cde69fc96042edbe3be784c5d857def4984d07776da95c5af2d24bab45d0a9cf9afc716eb317b27e5eed204a76478cf32d37d9aaeac2456edd4ced05eb4
6
+ metadata.gz: d381b939daec89b03e758a595959fa903ace82f958402c6b7a595b00e28fa1a16593201dc6daec6af99d79faa4e82ab4f76a81c153780eaf890cdc853edbd11b
7
+ data.tar.gz: d9e9c8d31921dbb6fa43843a35da245594de76182bf85ee207d1bfd19d92ad099ffbe74391ddd0b08d4f3c34aaf443d21a5cbc8b31321a1ae7aa030e88fe1b35
@@ -9,7 +9,7 @@ GIT
9
9
  PATH
10
10
  remote: .
11
11
  specs:
12
- activecube (0.1.17)
12
+ activecube (0.1.25)
13
13
  activerecord (>= 5.2)
14
14
 
15
15
  GEM
@@ -18,7 +18,7 @@ module Activecube
18
18
 
19
19
  end
20
20
 
21
- attr_reader :dimensions, :metrics, :selectors, :models
21
+ attr_reader :dimensions, :metrics, :selectors, :models, :options
22
22
 
23
23
  def inspect
24
24
  name +
@@ -46,6 +46,10 @@ module Activecube
46
46
  store_definition_array! 'model', (@models ||= []), [*args].flatten.map{|t| t }
47
47
  end
48
48
 
49
+ def option *args
50
+ store_definition_array! 'option', (@options ||= []), [*args].flatten.map{|t| t }
51
+ end
52
+
49
53
  def dim_column column_name
50
54
  Class.new(Activecube::Dimension) do
51
55
  column column_name
@@ -7,13 +7,13 @@ require 'activecube/query/measure_nothing'
7
7
  module Activecube::Processor
8
8
  class Composer
9
9
 
10
- attr_reader :cube_query, :models
10
+ attr_reader :cube_query, :models, :query
11
11
  def initialize cube_query
12
12
  @cube_query = cube_query
13
13
  end
14
14
 
15
15
  def build_query
16
- compose_queries optimize! ranked_tables
16
+ @query = compose_queries optimize! ranked_tables
17
17
  end
18
18
 
19
19
  def connection
@@ -41,7 +41,7 @@ module Activecube::Processor
41
41
  end
42
42
  after = total_cost measure_tables
43
43
 
44
- raise "Optimizer made it worth #{before} -> #{after} for #{cost_matrix}" unless after <= before
44
+ raise "Optimizer made it worse #{before} -> #{after} for #{cost_matrix}" unless after <= before
45
45
  measure_tables
46
46
 
47
47
  end
@@ -18,7 +18,7 @@ module Activecube::Processor
18
18
  @tables_count = cost_matrix.map(&:count).max
19
19
  @metrics_count = cost_matrix.count
20
20
 
21
- tables_count==1 ? [0]*metrics_count : do_optimize
21
+ (tables_count==1 || metrics_count==0) ? [0]*metrics_count : do_optimize
22
22
 
23
23
  end
24
24
 
@@ -27,95 +27,41 @@ module Activecube::Processor
27
27
 
28
28
  private
29
29
 
30
+ def generate_variants vs, metric_i
30
31
 
31
- def do_optimize
32
- @tables_by_metrics = []
32
+ return vs if metric_i==metrics_count
33
33
 
34
- # sort metrics from low min cost to higher min costs ( by all applicable tables )
35
- sort_metrics
34
+ metric_tables = cost_matrix[metric_i].map.with_index do |c, index|
35
+ [index] if c
36
+ end.compact
36
37
 
37
- # fill initial @tables_by_metrics by selecting tables with minimum cost for metrics.
38
- # If there are more than one table with this minimum cost, then select already selected table with maximum cost
39
- select_min_cost_by_metric
38
+ vsnew = if metric_i==0
39
+ metric_tables
40
+ else
41
+ arry = []
42
+ vs.each do |v|
43
+ metric_tables.each{|newv|
44
+ arry << (v + newv)
45
+ }
46
+ end
47
+ arry
48
+ end
40
49
 
41
- # make iterations over @tables_by_metrics ( max MAX_ITERATIONS)
42
- iterates
50
+ generate_variants vsnew, metric_i+1
43
51
 
44
- @tables_by_metrics
45
52
  end
46
53
 
47
- def sort_metrics
48
- @metrics_index_sorted = (0...metrics_count).sort_by{|m_i| cost_matrix[m_i].compact.min || UNLIM_COST }
54
+ def cost_for variant
55
+ variant.each_with_index.group_by(&:first).collect do |table_index, arry|
56
+ arry.map(&:second).map{|metric_index| cost_matrix[metric_index][table_index] }.max
57
+ end.sum
49
58
  end
50
59
 
51
- def select_min_cost_by_metric
52
-
53
- @metrics_index_sorted.collect do |m_i|
54
-
55
- table_index_cost = (0...tables_count).map{|c_i| [c_i,
56
- cost_matrix[m_i][c_i] || UNLIM_COST,
57
- (@tables_by_metrics.include?(c_i) ? -cost_matrix[@tables_by_metrics.index(c_i)][c_i] : 0)
58
- ]}.sort_by(&:third).sort_by(&:second)
59
-
60
- @tables_by_metrics[m_i] = table_index_cost.first.first
61
-
62
- end
63
- end
64
-
65
- def iterates
66
-
67
- steps = [@tables_by_metrics]
68
-
69
- (1..MAX_ITERATIONS).each do |iteration|
70
-
71
- step = []
72
- prev_step = steps.last
73
-
74
- prev_step.each_with_index {|c_i, m_i|
75
-
76
- table_included_times = prev_step.select{|c| c==c_i }.count
77
- old_cost = cost_matrix[m_i][c_i]
78
- new_c_i = (0...tables_count).detect{|c_n|
79
- new_cost = cost_matrix[m_i][c_n]
80
- next if c_i==c_n || new_cost.nil?
81
- new_table_included_times = prev_step.select{|c| c==c_n }.count
82
-
83
- if old_cost.nil?
84
- # if we have non indexed table now
85
- true
86
- elsif table_included_times>1
87
- if new_table_included_times>0
88
- # table to used table if
89
- # cost now > new cost
90
- old_cost > new_cost
91
- else
92
- # table to unused table if
93
- # cost now > new cost + max other cost in table now
94
- old_cost > new_cost + ( prev_step.select.with_index{|c,i| c==c_i && i!=m_i }.max || UNLIM_COST )
95
- end
96
- else
97
- if new_table_included_times>0
98
- # unused table to table if
99
- # new cost < cost now + max other cost in new table
100
- old_cost > new_cost - ( prev_step.select{|c| c==c_n }.max || UNLIM_COST )
101
- else
102
- # unused to unused
103
- # cost now > new cost
104
- old_cost > new_cost
105
- end
106
- end
107
-
108
- }
109
-
110
- step << c_i || new_c_i
111
-
112
- }
113
-
114
- break if steps.include? step
115
- steps << step
116
- end
60
+ def do_optimize
117
61
 
118
- @tables_by_metrics = steps.last
62
+ variants = generate_variants [], 0
63
+ variant_costs = variants.map{|v| cost_for v}
64
+ variants[variant_costs.each_with_index.min.second]
119
65
 
120
66
  end
121
67
 
@@ -3,6 +3,7 @@ require 'activecube/query/item'
3
3
  require 'activecube/query/limit'
4
4
  require 'activecube/query/measure'
5
5
  require 'activecube/query/ordering'
6
+ require 'activecube/query/option'
6
7
  require 'activecube/query/selector'
7
8
  require 'activecube/query/slice'
8
9
 
@@ -13,31 +14,44 @@ module Activecube::Query
13
14
 
14
15
  include ChainAppender
15
16
 
16
- attr_reader :cube, :slices, :measures, :selectors, :options, :tables
17
+ attr_reader :cube, :slices, :measures, :selectors, :options, :tables, :sql
17
18
  def initialize cube, slices = [], measures = [], selectors = [], options = [], model_tables = nil
18
19
  @cube = cube
19
20
  @slices = slices
20
21
  @measures = measures
21
22
  @selectors = selectors
22
23
  @options = options
24
+
23
25
  @tables = model_tables || cube.models.map{|m|
24
26
  m < Activecube::View ? m.new : Activecube::Processor::Table.new(m)
25
27
  }
28
+
29
+ cube.options && cube.options.each do |option|
30
+ define_singleton_method option.to_s.underscore do |*args|
31
+ @options << Option.new(option, *args)
32
+ self
33
+ end
34
+ end
35
+
26
36
  end
27
37
 
28
38
  def slice *args
39
+ clear_sql
29
40
  append *args, @slices, Slice, cube.dimensions
30
41
  end
31
42
 
32
43
  def measure *args
44
+ clear_sql
33
45
  append *args, @measures, Measure, cube.metrics
34
46
  end
35
47
 
36
48
  def when *args
49
+ clear_sql
37
50
  append *args, @selectors, Selector, cube.selectors
38
51
  end
39
52
 
40
53
  def desc *args
54
+ clear_sql
41
55
  args.each{|arg|
42
56
  options << Ordering.new(arg, :desc)
43
57
  }
@@ -45,6 +59,7 @@ module Activecube::Query
45
59
  end
46
60
 
47
61
  def asc *args
62
+ clear_sql
48
63
  args.each{|arg|
49
64
  options << Ordering.new( arg, :asc)
50
65
  }
@@ -52,6 +67,7 @@ module Activecube::Query
52
67
  end
53
68
 
54
69
  def offset *args
70
+ clear_sql
55
71
  args.each{|arg|
56
72
  options << Limit.new( arg, :skip)
57
73
  }
@@ -59,6 +75,7 @@ module Activecube::Query
59
75
  end
60
76
 
61
77
  def limit *args
78
+ clear_sql
62
79
  args.each{|arg|
63
80
  options << Limit.new( arg, :take)
64
81
  }
@@ -67,13 +84,12 @@ module Activecube::Query
67
84
 
68
85
 
69
86
  def query
70
- composer = Activecube::Processor::Composer.new(self)
71
- sql = composer.build_query.to_sql
72
- composer.connection.exec_query(sql)
87
+ sql = to_query.to_sql
88
+ @composed.connection.exec_query(sql)
73
89
  end
74
90
 
75
91
  def to_query
76
- Activecube::Processor::Composer.new(self).build_query
92
+ @composed.try(:query) || (@composed = Activecube::Processor::Composer.new(self)).build_query
77
93
  end
78
94
 
79
95
  def to_sql
@@ -126,5 +142,10 @@ module Activecube::Query
126
142
  options.select{|s| s.kind_of? Ordering}
127
143
  end
128
144
 
145
+ private
146
+
147
+ def clear_sql
148
+ @composed = nil
149
+ end
129
150
  end
130
151
  end
@@ -0,0 +1,17 @@
1
+ module Activecube
2
+ module Query
3
+ class Option
4
+
5
+ attr_reader :argument, :value
6
+ def initialize argument, value
7
+ @argument = argument
8
+ @value = value
9
+ end
10
+
11
+ def append_query _model, _cube_query, _table, query
12
+ query
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -1,3 +1,3 @@
1
1
  module Activecube
2
- VERSION = "0.1.18"
2
+ VERSION = "0.1.26"
3
3
  end
@@ -1,8 +1,10 @@
1
1
  require 'activecube/view_definition'
2
+ require 'activecube/view_connection'
2
3
 
3
4
  module Activecube
4
5
  class View
5
6
  extend ViewDefinition
7
+ extend ViewConnection
6
8
 
7
9
  def model
8
10
  self.class
@@ -0,0 +1,11 @@
1
+ require 'active_support/concern'
2
+
3
+ module Activecube::ViewConnection
4
+
5
+ attr_reader :connection
6
+
7
+ def connect_to connection
8
+ @connection = connection
9
+ end
10
+
11
+ end
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.18
4
+ version: 0.1.26
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-05-21 00:00:00.000000000 Z
11
+ date: 2020-07-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -111,6 +111,7 @@ files:
111
111
  - lib/activecube/query/measure.rb
112
112
  - lib/activecube/query/measure_nothing.rb
113
113
  - lib/activecube/query/modification.rb
114
+ - lib/activecube/query/option.rb
114
115
  - lib/activecube/query/ordering.rb
115
116
  - lib/activecube/query/selector.rb
116
117
  - lib/activecube/query/slice.rb
@@ -118,6 +119,7 @@ files:
118
119
  - lib/activecube/selector.rb
119
120
  - lib/activecube/version.rb
120
121
  - lib/activecube/view.rb
122
+ - lib/activecube/view_connection.rb
121
123
  - lib/activecube/view_definition.rb
122
124
  homepage: https://github.com/bitquery/activecube
123
125
  licenses: