activecube 0.1.0 → 0.1.1

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: 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