activecube 0.1.0

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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.idea/workspace.xml +114 -0
  4. data/.rspec +3 -0
  5. data/.travis.yml +7 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Gemfile +6 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +60 -0
  10. data/Rakefile +6 -0
  11. data/activecube.gemspec +32 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +8 -0
  14. data/lib/activecube.rb +6 -0
  15. data/lib/activecube/active_record_extension.rb +20 -0
  16. data/lib/activecube/base.rb +6 -0
  17. data/lib/activecube/clickhouse/metric/count.rb +10 -0
  18. data/lib/activecube/clickhouse/metric/sum.rb +11 -0
  19. data/lib/activecube/cube_definition.rb +62 -0
  20. data/lib/activecube/dimension.rb +5 -0
  21. data/lib/activecube/dimension_definition_methods.rb +32 -0
  22. data/lib/activecube/field.rb +12 -0
  23. data/lib/activecube/metric.rb +5 -0
  24. data/lib/activecube/processor/composer.rb +76 -0
  25. data/lib/activecube/processor/index.rb +17 -0
  26. data/lib/activecube/processor/measure_tables.rb +42 -0
  27. data/lib/activecube/processor/optimizer.rb +123 -0
  28. data/lib/activecube/processor/table.rb +54 -0
  29. data/lib/activecube/query/chain_appender.rb +25 -0
  30. data/lib/activecube/query/cube_query.rb +112 -0
  31. data/lib/activecube/query/item.rb +22 -0
  32. data/lib/activecube/query/limit.rb +17 -0
  33. data/lib/activecube/query/measure.rb +40 -0
  34. data/lib/activecube/query/or_selector.rb +20 -0
  35. data/lib/activecube/query/ordering.rb +17 -0
  36. data/lib/activecube/query/selector.rb +84 -0
  37. data/lib/activecube/query/slice.rb +57 -0
  38. data/lib/activecube/query_methods.rb +11 -0
  39. data/lib/activecube/selector.rb +11 -0
  40. data/lib/activecube/version.rb +3 -0
  41. metadata +140 -0
@@ -0,0 +1,22 @@
1
+ module Activecube::Query
2
+ class Item
3
+
4
+ include ChainAppender
5
+
6
+ attr_reader :cube, :key, :definition
7
+ def initialize cube, key, definition
8
+ @key = key
9
+ @cube = cube
10
+ @definition = definition
11
+ end
12
+
13
+ def required_column_names
14
+ definition.class.column_names || []
15
+ end
16
+
17
+ def alias! new_key
18
+ self.class.new cube, new_key, definition
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ module Activecube
2
+ module Query
3
+ class Limit
4
+
5
+ attr_reader :argument, :option
6
+ def initialize argument, option
7
+ @argument = argument
8
+ @option = option
9
+ end
10
+
11
+ def append_query _cube_query, _table, query
12
+ query.send(option,argument)
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,40 @@
1
+ module Activecube::Query
2
+ class Measure < Item
3
+
4
+ attr_reader :selectors
5
+
6
+ def initialize cube, key, definition, selectors = []
7
+ super cube, key, definition
8
+ @selectors = selectors
9
+ end
10
+
11
+ def required_column_names
12
+ ((definition.class.column_names || []) + selectors.map(&:required_column_names)).flatten.uniq
13
+ end
14
+
15
+ def when *args
16
+ append *args, @selectors, Selector, cube.selectors
17
+ end
18
+
19
+ def alias! new_key
20
+ self.class.new cube, new_key, definition, selectors
21
+ end
22
+
23
+ def condition_query arel_table, cube_query
24
+ condition = nil
25
+ selectors.each do |selector|
26
+ condition = condition ?
27
+ condition.and(selector.expression(arel_table, cube_query)) :
28
+ selector.expression(arel_table, cube_query)
29
+ end
30
+ condition
31
+ end
32
+
33
+ def append_query cube_query, table, query
34
+ attr_alias = "`#{key.to_s}`"
35
+ expr = definition.expression table, self, cube_query
36
+ query.project expr.as(attr_alias)
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,20 @@
1
+ module Activecube
2
+ module Query
3
+ class OrSelector < Selector
4
+
5
+ attr_reader :selectors
6
+ def initialize selectors
7
+ @selectors = selectors
8
+ end
9
+
10
+ def append_query cube_query, table, query
11
+ expr = nil
12
+ selectors.each do |s|
13
+ expr = expr ? expr.or(s.expression table, cube_query) : s.expression(table, cube_query)
14
+ end
15
+ query.where(expr)
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ module Activecube
2
+ module Query
3
+ class Ordering
4
+
5
+ attr_reader :argument, :direction
6
+ def initialize argument, direction
7
+ @argument = argument
8
+ @direction = direction
9
+ end
10
+
11
+ def append_query _cube_query, _table, query
12
+ query.order(::Arel.sql(argument.to_s).send(direction))
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,84 @@
1
+ module Activecube::Query
2
+ class Selector < Item
3
+
4
+ OPERATORS = ['eq','ne','gt','lt','ge','le','in','not_in']
5
+ ARRAY_OPERATORS = ['in','not_in']
6
+
7
+ class Operator
8
+
9
+ attr_reader :operation, :argument
10
+
11
+ def initialize operation, argument
12
+ @operation = operation
13
+ @argument = argument
14
+ end
15
+
16
+ def expression left, right
17
+ left.send(operation, right)
18
+ end
19
+
20
+ def eql?(other)
21
+ return other.kind_of?(Operator) &&
22
+ self.operation==other.operation &&
23
+ self.argument == other.argument
24
+ end
25
+
26
+ def == other
27
+ eql? other
28
+ end
29
+
30
+ def hash
31
+ self.operation.hash + self.argument.hash
32
+ end
33
+
34
+ end
35
+
36
+ attr_reader :operator
37
+ def initialize cube, key, definition, operator = nil
38
+ super cube, key, definition
39
+ @operator = operator
40
+ end
41
+
42
+ OPERATORS.each do |method|
43
+ define_method(method) do |*args|
44
+ if ARRAY_OPERATORS.include? method
45
+ @operator = Operator.new(method, args)
46
+ else
47
+ raise ArgumentError, "Unexpected size of arguments" unless args.size==1
48
+ @operator = Operator.new(method, args.first)
49
+ end
50
+ self
51
+ end
52
+ end
53
+
54
+ def alias! new_key
55
+ self.class.new cube, new_key, definition, operator
56
+ end
57
+
58
+ def append_query cube_query, table, query
59
+ query.where(expression table, cube_query)
60
+ end
61
+
62
+ def expression arel_table, cube_query
63
+ definition.expression arel_table, self, cube_query
64
+ end
65
+
66
+ def eql?(other)
67
+ return other.kind_of?(Selector) &&
68
+ self.cube==other.cube &&
69
+ self.operator == other.operator &&
70
+ self.definition.class == other.definition.class
71
+ end
72
+
73
+ def == other
74
+ eql? other
75
+ end
76
+
77
+ def hash
78
+ self.definition.class.hash + self.operator.hash
79
+ end
80
+
81
+ end
82
+ end
83
+
84
+ Arel::Nodes::SqlLiteral
@@ -0,0 +1,57 @@
1
+ module Activecube::Query
2
+ class Slice < Item
3
+
4
+ attr_reader :field, :modifier
5
+ def initialize cube, key, dimension, field = nil, modifier = nil
6
+ super cube, key, dimension
7
+ @field = field
8
+ @modifier = modifier
9
+ field_methods! if field.try(:definition).kind_of?(Hash)
10
+ end
11
+
12
+ def [] key
13
+ unless (definition.kind_of? Activecube::Dimension) && !self.field && (field = definition.class.fields[key])
14
+ raise "Field #{key} is not defined for #{definition.name}"
15
+ end
16
+ Slice.new cube, key, definition, field
17
+ end
18
+
19
+ def alias! new_key
20
+ self.class.new cube, new_key, definition, field, modifier
21
+ end
22
+
23
+ def dimension_class
24
+ definition.class
25
+ end
26
+
27
+ def append_query _cube_query, table, query
28
+
29
+ attr_alias = "`#{key.to_s}`"
30
+ expr = field ? Arel.sql( modifier || field.definition ) : table[dimension_class.column_name]
31
+ query = query.project(expr.as(attr_alias))
32
+
33
+ if identity = dimension_class.identity
34
+ query = query.project(table[identity]).group(table[identity])
35
+ else
36
+ query = query.group(attr_alias).order(attr_alias)
37
+ end
38
+
39
+ query
40
+ end
41
+
42
+ private
43
+
44
+ def field_methods!
45
+ field.definition.each_pair do |k,v|
46
+ if v.kind_of? Proc
47
+ define_singleton_method k, ((proc {|x| @modifier = x; self}) << v)
48
+ elsif v.kind_of? String
49
+ define_singleton_method k do @modifier = v; self end
50
+ else
51
+ raise "Unexpected type #{k.class.name} for definition of #{name}[#{k}]"
52
+ end
53
+ end
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,11 @@
1
+ module Activecube
2
+ module QueryMethods
3
+
4
+ [:slice, :measure, :when].each do |method|
5
+ define_method(method) do |*args|
6
+ Query::CubeQuery.new(self).send method, *args
7
+ end
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Activecube
2
+ class Selector
3
+ extend DimensionDefinitionMethods
4
+
5
+ def expression arel_table, selector, _cube_query
6
+ op = selector.operator
7
+ op.expression arel_table[self.class.column_name.to_sym], op.argument
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module Activecube
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: activecube
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Aleksey Studnev
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-02-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '5.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '5.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.17'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.17'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description: |-
70
+ Activecube is the library to make multi-dimensional queries to data.Cube, dimensions, metrics and selectors are defined in the Model, similary to ActiveRecord.
71
+ Activecube uses Rails ActiveRecord in implementation. In particular, you have to define all tables, used in Activecube, as ActiveRecord tables.
72
+ email:
73
+ - astudnev@gmail.com
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - ".gitignore"
79
+ - ".idea/workspace.xml"
80
+ - ".rspec"
81
+ - ".travis.yml"
82
+ - CODE_OF_CONDUCT.md
83
+ - Gemfile
84
+ - LICENSE.txt
85
+ - README.md
86
+ - Rakefile
87
+ - activecube.gemspec
88
+ - bin/console
89
+ - bin/setup
90
+ - lib/activecube.rb
91
+ - lib/activecube/active_record_extension.rb
92
+ - lib/activecube/base.rb
93
+ - lib/activecube/clickhouse/metric/count.rb
94
+ - lib/activecube/clickhouse/metric/sum.rb
95
+ - lib/activecube/cube_definition.rb
96
+ - lib/activecube/dimension.rb
97
+ - lib/activecube/dimension_definition_methods.rb
98
+ - lib/activecube/field.rb
99
+ - lib/activecube/metric.rb
100
+ - lib/activecube/processor/composer.rb
101
+ - lib/activecube/processor/index.rb
102
+ - lib/activecube/processor/measure_tables.rb
103
+ - lib/activecube/processor/optimizer.rb
104
+ - lib/activecube/processor/table.rb
105
+ - lib/activecube/query/chain_appender.rb
106
+ - lib/activecube/query/cube_query.rb
107
+ - lib/activecube/query/item.rb
108
+ - lib/activecube/query/limit.rb
109
+ - lib/activecube/query/measure.rb
110
+ - lib/activecube/query/or_selector.rb
111
+ - lib/activecube/query/ordering.rb
112
+ - lib/activecube/query/selector.rb
113
+ - lib/activecube/query/slice.rb
114
+ - lib/activecube/query_methods.rb
115
+ - lib/activecube/selector.rb
116
+ - lib/activecube/version.rb
117
+ homepage: https://github.com/bitquery/activecube
118
+ licenses:
119
+ - MIT
120
+ metadata: {}
121
+ post_install_message:
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubygems_version: 3.0.4
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: Multi-Dimensional Queries with Rails
140
+ test_files: []