activecube 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9a7d156d972363abe7b4b6fcd10ca0198701ffae6378546ec8d9d6167ffbd031
4
- data.tar.gz: 3cb7a21db62dd00b5047db0625e429462f8d2654d54395f74cd1833500a896a7
3
+ metadata.gz: baf4f5a3146bb1c03244f62328b0af901ae7882e41ff4234a86e1deb6cd881a9
4
+ data.tar.gz: 44ca0d2eefbf2b4cc38e95aa9ab2b352607b4817b5c5aaebce8b2a04022037f6
5
5
  SHA512:
6
- metadata.gz: 15afed4e4c5f034fa0284ae345486e4783ed50fa4a2c525b7c03dd4fa06ab44ddd732eb74b9c3a4cab7efa4bd56fdf2d23b6e361f9fd565c23976bb85374997d
7
- data.tar.gz: 845d64b1bbd1a555c3ff8273f96769021baffe84768e4db792ad579e3d548acd6e2a7634565902d7b643af81600cf57379ea6ab3dbdd99f9a6e656a552de5f3b
6
+ metadata.gz: ac3b3dd34000d54054eba5a0fc7b6aa9803f7643f4f1cc67c88fc603c9e34d07a7ae7ef2eed755efca7bdcd60f532c25b67962b45f20550df98bcb2fc2e13a19
7
+ data.tar.gz: 408881f9f8f5c3c3b2af544f320846f8f9765cf3f9673e196c9d2f32555901c221539786eb4c3fa487a082f1d62bf2939442f836fe73cdf6e559bea4ba5f8945
@@ -10,10 +10,7 @@
10
10
  <select />
11
11
  </component>
12
12
  <component name="ChangeListManager">
13
- <list default="true" id="77368870-4045-496a-9737-2c7f83086a16" name="Default Changelist" comment="initial implementation">
14
- <change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
15
- <change beforePath="$PROJECT_DIR$/activecube.gemspec" beforeDir="false" afterPath="$PROJECT_DIR$/activecube.gemspec" afterDir="false" />
16
- </list>
13
+ <list default="true" id="77368870-4045-496a-9737-2c7f83086a16" name="Default Changelist" comment="initial implementation" />
17
14
  <option name="SHOW_DIALOG" value="false" />
18
15
  <option name="HIGHLIGHT_CONFLICTS" value="true" />
19
16
  <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
@@ -31,11 +28,20 @@
31
28
  <component name="PropertiesComponent">
32
29
  <property name="WebServerToolWindowFactoryState" value="false" />
33
30
  <property name="last_opened_file_path" value="$PROJECT_DIR$/lib/activecube" />
31
+ <property name="node.js.detected.package.eslint" value="true" />
32
+ <property name="node.js.detected.package.tslint" value="true" />
33
+ <property name="node.js.path.for.package.eslint" value="project" />
34
+ <property name="node.js.path.for.package.tslint" value="project" />
35
+ <property name="node.js.selected.package.eslint" value="(autodetect)" />
36
+ <property name="node.js.selected.package.tslint" value="(autodetect)" />
34
37
  <property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
35
38
  <property name="nodejs_npm_path_reset_for_default_project" value="true" />
36
39
  <property name="settings.editor.selected.configurable" value="preferences.lookFeel" />
37
40
  </component>
38
41
  <component name="RecentsManager">
42
+ <key name="MoveFile.RECENT_KEYS">
43
+ <recent name="$PROJECT_DIR$/lib/activecube" />
44
+ </key>
39
45
  <key name="CopyFile.RECENT_KEYS">
40
46
  <recent name="$PROJECT_DIR$/lib/activecube" />
41
47
  </key>
@@ -51,7 +57,7 @@
51
57
  <option name="number" value="Default" />
52
58
  <option name="presentableId" value="Default" />
53
59
  <updated>1581885096407</updated>
54
- <workItem from="1581885099890" duration="963000" />
60
+ <workItem from="1581885099890" duration="3547000" />
55
61
  </task>
56
62
  <task id="LOCAL-00001" summary="initial commit">
57
63
  <created>1581885128091</created>
@@ -67,7 +73,28 @@
67
73
  <option name="project" value="LOCAL" />
68
74
  <updated>1581885329956</updated>
69
75
  </task>
70
- <option name="localTasksCounter" value="3" />
76
+ <task id="LOCAL-00003" summary="initial implementation">
77
+ <created>1581886068687</created>
78
+ <option name="number" value="00003" />
79
+ <option name="presentableId" value="LOCAL-00003" />
80
+ <option name="project" value="LOCAL" />
81
+ <updated>1581886068687</updated>
82
+ </task>
83
+ <task id="LOCAL-00004" summary="initial implementation">
84
+ <created>1581888304903</created>
85
+ <option name="number" value="00004" />
86
+ <option name="presentableId" value="LOCAL-00004" />
87
+ <option name="project" value="LOCAL" />
88
+ <updated>1581888304904</updated>
89
+ </task>
90
+ <task id="LOCAL-00005" summary="initial implementation">
91
+ <created>1581888510999</created>
92
+ <option name="number" value="00005" />
93
+ <option name="presentableId" value="LOCAL-00005" />
94
+ <option name="project" value="LOCAL" />
95
+ <updated>1581888510999</updated>
96
+ </task>
97
+ <option name="localTasksCounter" value="6" />
71
98
  <servers />
72
99
  </component>
73
100
  <component name="TypeScriptGeneratedFilesManager">
@@ -90,22 +117,26 @@
90
117
  <option name="LAST_COMMIT_MESSAGE" value="initial implementation" />
91
118
  </component>
92
119
  <component name="WindowStateProjectService">
93
- <state width="1207" height="201" key="GridCell.Tab.0.bottom" timestamp="1581885116972">
120
+ <state width="1207" height="48" key="GridCell.Tab.0.bottom" timestamp="1581888894138">
121
+ <screen x="0" y="23" width="1440" height="786" />
122
+ </state>
123
+ <state width="1207" height="48" key="GridCell.Tab.0.bottom/0.23.1440.786@0.23.1440.786" timestamp="1581888894138" />
124
+ <state width="1207" height="48" key="GridCell.Tab.0.center" timestamp="1581888894135">
94
125
  <screen x="0" y="23" width="1440" height="786" />
95
126
  </state>
96
- <state width="1207" height="201" key="GridCell.Tab.0.bottom/0.23.1440.786@0.23.1440.786" timestamp="1581885116972" />
97
- <state width="1207" height="201" key="GridCell.Tab.0.center" timestamp="1581885116972">
127
+ <state width="1207" height="48" key="GridCell.Tab.0.center/0.23.1440.786@0.23.1440.786" timestamp="1581888894135" />
128
+ <state width="1207" height="48" key="GridCell.Tab.0.left" timestamp="1581888894133">
98
129
  <screen x="0" y="23" width="1440" height="786" />
99
130
  </state>
100
- <state width="1207" height="201" key="GridCell.Tab.0.center/0.23.1440.786@0.23.1440.786" timestamp="1581885116972" />
101
- <state width="1207" height="201" key="GridCell.Tab.0.left" timestamp="1581885116971">
131
+ <state width="1207" height="48" key="GridCell.Tab.0.left/0.23.1440.786@0.23.1440.786" timestamp="1581888894133" />
132
+ <state width="1207" height="48" key="GridCell.Tab.0.right" timestamp="1581888894136">
102
133
  <screen x="0" y="23" width="1440" height="786" />
103
134
  </state>
104
- <state width="1207" height="201" key="GridCell.Tab.0.left/0.23.1440.786@0.23.1440.786" timestamp="1581885116971" />
105
- <state width="1207" height="201" key="GridCell.Tab.0.right" timestamp="1581885116972">
135
+ <state width="1207" height="48" key="GridCell.Tab.0.right/0.23.1440.786@0.23.1440.786" timestamp="1581888894136" />
136
+ <state x="537" y="156" key="Vcs.Push.Dialog.v2" timestamp="1581888518182">
106
137
  <screen x="0" y="23" width="1440" height="786" />
107
138
  </state>
108
- <state width="1207" height="201" key="GridCell.Tab.0.right/0.23.1440.786@0.23.1440.786" timestamp="1581885116972" />
139
+ <state x="537" y="156" key="Vcs.Push.Dialog.v2/0.23.1440.786@0.23.1440.786" timestamp="1581888518182" />
109
140
  <state x="352" y="201" width="819" height="558" key="find.popup" timestamp="1581885294826">
110
141
  <screen x="0" y="23" width="1440" height="786" />
111
142
  </state>
data/Gemfile CHANGED
@@ -4,3 +4,8 @@ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  # Specify your gem's dependencies in activecube.gemspec
6
6
  gemspec
7
+
8
+
9
+ group :test do
10
+ gem 'clickhouse-activerecord', git: 'https://github.com/bitquery/clickhouse-activerecord.git'
11
+ end
@@ -0,0 +1,64 @@
1
+ GIT
2
+ remote: https://github.com/bitquery/clickhouse-activerecord.git
3
+ revision: 14e02bb475bb4974cc4d853b055b147fe4d59171
4
+ specs:
5
+ clickhouse-activerecord (0.3.9)
6
+ activerecord (>= 5.2)
7
+ bundler (>= 1.13.4)
8
+
9
+ PATH
10
+ remote: .
11
+ specs:
12
+ activecube (0.1.0)
13
+ activerecord (>= 5.2)
14
+
15
+ GEM
16
+ remote: https://rubygems.org/
17
+ specs:
18
+ activemodel (6.0.2.1)
19
+ activesupport (= 6.0.2.1)
20
+ activerecord (6.0.2.1)
21
+ activemodel (= 6.0.2.1)
22
+ activesupport (= 6.0.2.1)
23
+ activesupport (6.0.2.1)
24
+ concurrent-ruby (~> 1.0, >= 1.0.2)
25
+ i18n (>= 0.7, < 2)
26
+ minitest (~> 5.1)
27
+ tzinfo (~> 1.1)
28
+ zeitwerk (~> 2.2)
29
+ concurrent-ruby (1.1.6)
30
+ diff-lcs (1.3)
31
+ i18n (1.8.2)
32
+ concurrent-ruby (~> 1.0)
33
+ minitest (5.14.0)
34
+ rake (10.5.0)
35
+ rspec (3.9.0)
36
+ rspec-core (~> 3.9.0)
37
+ rspec-expectations (~> 3.9.0)
38
+ rspec-mocks (~> 3.9.0)
39
+ rspec-core (3.9.1)
40
+ rspec-support (~> 3.9.1)
41
+ rspec-expectations (3.9.0)
42
+ diff-lcs (>= 1.2.0, < 2.0)
43
+ rspec-support (~> 3.9.0)
44
+ rspec-mocks (3.9.1)
45
+ diff-lcs (>= 1.2.0, < 2.0)
46
+ rspec-support (~> 3.9.0)
47
+ rspec-support (3.9.2)
48
+ thread_safe (0.3.6)
49
+ tzinfo (1.2.6)
50
+ thread_safe (~> 0.1)
51
+ zeitwerk (2.2.2)
52
+
53
+ PLATFORMS
54
+ ruby
55
+
56
+ DEPENDENCIES
57
+ activecube!
58
+ bundler (~> 1.17)
59
+ clickhouse-activerecord!
60
+ rake (~> 10.0)
61
+ rspec (~> 3.0)
62
+
63
+ BUNDLED WITH
64
+ 1.17.3
data/README.md CHANGED
@@ -39,7 +39,124 @@ Or install it yourself as:
39
39
 
40
40
  ## Usage
41
41
 
42
- TBD
42
+ Basic steps to use ActiveCube are:
43
+
44
+ 1. Define your database schema in models, as you do with Rails
45
+ 2. Setup connection properties to data warehouse in config/database.yml. You can use multiple connections
46
+ if you use Rails 6 or higher
47
+ 3. Define cubes in models, sub-classed from Activecube::Base. Look
48
+ [spec/models/test/transfers_cube.rb](spec/models/test/transfers_cube.rb) as example
49
+ 4. Make queries to the cubes
50
+
51
+ Check [spec/cases/activecube_spec.rb](spec/cases/activecube_spec.rb) for more examples.
52
+
53
+
54
+ ### Cube definition
55
+
56
+ Cube defined using the following attributes:
57
+
58
+ - **table** specifies, which physical database tables can be considered to query
59
+ ```ruby
60
+ table TransfersCurrency
61
+ table TransfersFrom
62
+ table TransfersTo
63
+ ```
64
+
65
+ - **dimension** specifies classes used for slicing the cube
66
+
67
+ ```ruby
68
+ dimension date: Dimension::Date,
69
+ currency: Dimension::Currency
70
+ ```
71
+
72
+ Or
73
+
74
+ ```ruby
75
+ dimension date: Dimension::Date
76
+ dimension currency: Dimension::Currency
77
+ ```
78
+
79
+ - **metric** specifies which results expected from the cube queries
80
+
81
+ ```ruby
82
+ metric amount: Metric::Amount,
83
+ count: Metric::Count
84
+ ```
85
+
86
+ Or
87
+
88
+ ```ruby
89
+ metric amount: Metric::Amount
90
+ metric count: Metric::Count
91
+ ```
92
+
93
+ - **selector** is a set of expressions, which can filter results
94
+
95
+ ```ruby
96
+ selector currency: CurrencySelector,
97
+ transfer_from: TransferFromSelector,
98
+ transfer_to: TransferToSelector
99
+ ```
100
+
101
+ ### Table definition
102
+
103
+ Tables are defined as regular active records, with additional optional attribute 'index':
104
+ ```ruby
105
+ index 'currency_id', cardinality: 4
106
+ ```
107
+
108
+ which means that the table has an index onm currency_id field, with average number of different entries
109
+ of 10,000 ( 10^4). This creates a hint for optimizer to build queries.
110
+
111
+ Indexes can span multiple fields, as
112
+
113
+ ```ruby
114
+ index ['currency_id','date'], cardinality: 6
115
+ ```
116
+
117
+ Note, that if you created combined index in database, you most probable will need to define all
118
+ indexed combinations, for example:
119
+
120
+ ```ruby
121
+ index ['currency_id'], cardinality: 4
122
+ index ['currency_id','date'], cardinality: 6
123
+ ```
124
+
125
+ ### Query language
126
+
127
+ You use the cube class to create and execute queries.
128
+
129
+ Queries can be expressed as Arel query, SQL or executed against the database, returning results.
130
+
131
+ The methods used to contruct the query:
132
+
133
+ - **slice** defines which dimensions slices the results
134
+ - **measure** defines what to measure
135
+ - **where** defines which selectors to apply
136
+ - **desc, asc, take, limit** are for ordering and limiting result set
137
+
138
+ After the query contructed, the following methods can be applied:
139
+
140
+ - **to_sql** to generate String SQL query from cube query
141
+ - **to_query** to generate Arel query
142
+ - **query** to execute query and return ResultSet
143
+
144
+ Note, that you can control the connection used to construct and execute query by
145
+ ActiveRecord standard API:
146
+
147
+ ```ruby
148
+
149
+ ApplicationRecord.connected_to(database: :data_warehouse) do
150
+ cube = My::TransfersCube
151
+ cube.slice(
152
+ date: cube.dimensions[:date][:date].format('%Y-%m'),
153
+ currency: cube.dimensions[:currency][:symbol]
154
+ ).measure(:count).query
155
+ end
156
+ ```
157
+
158
+ will query using data_warehouse configuraton.
159
+
43
160
 
44
161
  ## Development
45
162
 
@@ -47,9 +164,20 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
47
164
 
48
165
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
49
166
 
167
+ ## RSPec tests
168
+
169
+
170
+ To run tests, you need clickhouse server installation.
171
+ Tests use database 'test' that have to be created in clickhouse as:
172
+ ```sql
173
+ CREATE DATABASE test;
174
+ ```
175
+ Check credentials for connection in [spec/spec_helper.rb](spec/spec_helper.rb) file.
176
+ By default clickhouse must reside on "clickhouse" server name, port 8123 with the default user access open.
177
+
50
178
  ## Contributing
51
179
 
52
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/activecube. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
180
+ Bug reports and pull requests are welcome on GitHub at https://github.com/bitquery/activecube. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
53
181
 
54
182
  ## License
55
183
 
@@ -57,4 +185,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
57
185
 
58
186
  ## Code of Conduct
59
187
 
60
- Everyone interacting in the Activecube project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/activecube/blob/master/CODE_OF_CONDUCT.md).
188
+ Everyone interacting in the Activecube project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/bitquery/activecube/blob/master/CODE_OF_CONDUCT.md).
@@ -1,6 +1,19 @@
1
1
  require "activecube/version"
2
+ require 'activecube/active_record_extension'
3
+
4
+ require 'activecube/base'
5
+ require 'activecube/dimension'
6
+ require 'activecube/metric'
7
+ require 'activecube/selector'
8
+
9
+ require 'activecube/common/count'
10
+ require 'activecube/common/sum'
11
+
12
+ require 'active_record'
2
13
 
3
14
  module Activecube
4
- class Error < StandardError; end
5
- # Your code goes here...
15
+
16
+ # include the extension
17
+ ActiveRecord::Base.send(:include, Activecube::ActiveRecordExtension)
18
+
6
19
  end
@@ -15,6 +15,3 @@ module Activecube::ActiveRecordExtension
15
15
  end
16
16
 
17
17
  end
18
-
19
- # include the extension
20
- ActiveRecord::Base.send(:include, Activecube::ActiveRecordExtension)
@@ -1,3 +1,6 @@
1
+ require 'activecube/cube_definition'
2
+ require 'activecube/query_methods'
3
+
1
4
  module Activecube
2
5
  class Base
3
6
  extend CubeDefinition
@@ -1,4 +1,4 @@
1
- module Activecube::Clickhouse::Metric
1
+ module Activecube::Common
2
2
 
3
3
  class Count < Activecube::Metric
4
4
 
@@ -1,4 +1,4 @@
1
- module Activecube::Clickhouse::Metric
1
+ module Activecube::Common
2
2
 
3
3
  class Sum < Activecube::Metric
4
4
 
@@ -1,3 +1,5 @@
1
+ require 'activecube/dimension_definition_methods'
2
+
1
3
  module Activecube
2
4
  class Dimension
3
5
  extend DimensionDefinitionMethods
@@ -1,3 +1,6 @@
1
+ require 'activecube/cube_definition'
2
+ require 'activecube/field'
3
+
1
4
  module Activecube
2
5
  module DimensionDefinitionMethods
3
6
 
@@ -1,3 +1,5 @@
1
+ require 'activecube/dimension_definition_methods'
2
+
1
3
  module Activecube
2
4
  class Metric
3
5
  extend DimensionDefinitionMethods
@@ -1,3 +1,8 @@
1
+ require 'activecube/processor/index'
2
+ require 'activecube/processor/measure_tables'
3
+ require 'activecube/processor/optimizer'
4
+ require 'activecube/processor/table'
5
+
1
6
  module Activecube::Processor
2
7
  class Composer
3
8
 
@@ -8,11 +8,12 @@ module Activecube::Processor
8
8
  attr_reader :tables_count, :metrics_count, :cost_matrix
9
9
  def initialize cost_matrix
10
10
  @cost_matrix = cost_matrix
11
+ @cache = ActiveSupport::Cache::MemoryStore.new
11
12
  end
12
13
 
13
14
  def optimize
14
15
 
15
- Rails.cache.fetch(cost_matrix, expires_in: 12.hours) do
16
+ @cache.fetch(cost_matrix, expires_in: 12.hours) do
16
17
 
17
18
  @tables_count = cost_matrix.map(&:count).max
18
19
  @metrics_count = cost_matrix.count
@@ -1,3 +1,14 @@
1
+ require 'activecube/query/chain_appender'
2
+ require 'activecube/query/item'
3
+ require 'activecube/query/limit'
4
+ require 'activecube/query/measure'
5
+ require 'activecube/query/or_selector'
6
+ require 'activecube/query/ordering'
7
+ require 'activecube/query/selector'
8
+ require 'activecube/query/slice'
9
+
10
+ require 'activecube/processor/composer'
11
+
1
12
  module Activecube::Query
2
13
  class CubeQuery
3
14
 
@@ -1,3 +1,5 @@
1
+ require 'activecube/query/selector'
2
+
1
3
  module Activecube
2
4
  module Query
3
5
  class OrSelector < Selector
@@ -80,5 +80,3 @@ module Activecube::Query
80
80
 
81
81
  end
82
82
  end
83
-
84
- Arel::Nodes::SqlLiteral
@@ -1,3 +1,5 @@
1
+ require 'activecube/query/cube_query'
2
+
1
3
  module Activecube
2
4
  module QueryMethods
3
5
 
@@ -1,3 +1,5 @@
1
+ require 'activecube/dimension_definition_methods'
2
+
1
3
  module Activecube
2
4
  class Selector
3
5
  extend DimensionDefinitionMethods
@@ -1,3 +1,3 @@
1
1
  module Activecube
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  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.0
4
+ version: 0.1.1
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-16 00:00:00.000000000 Z
11
+ date: 2020-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -81,6 +81,7 @@ files:
81
81
  - ".travis.yml"
82
82
  - CODE_OF_CONDUCT.md
83
83
  - Gemfile
84
+ - Gemfile.lock
84
85
  - LICENSE.txt
85
86
  - README.md
86
87
  - Rakefile
@@ -90,8 +91,8 @@ files:
90
91
  - lib/activecube.rb
91
92
  - lib/activecube/active_record_extension.rb
92
93
  - lib/activecube/base.rb
93
- - lib/activecube/clickhouse/metric/count.rb
94
- - lib/activecube/clickhouse/metric/sum.rb
94
+ - lib/activecube/common/count.rb
95
+ - lib/activecube/common/sum.rb
95
96
  - lib/activecube/cube_definition.rb
96
97
  - lib/activecube/dimension.rb
97
98
  - lib/activecube/dimension_definition_methods.rb