timescaledb 0.1.5 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/Gemfile.scenic.lock +2 -2
- data/README.md +23 -16
- data/bin/console +2 -2
- data/bin/tsdb +6 -6
- data/examples/{Gemfile → all_in_one/Gemfile} +0 -0
- data/examples/{Gemfile.lock → all_in_one/Gemfile.lock} +0 -0
- data/examples/{all_in_one.rb → all_in_one/all_in_one.rb} +0 -0
- data/examples/ranking/.gitattributes +7 -0
- data/examples/ranking/.gitignore +29 -0
- data/examples/ranking/.ruby-version +1 -0
- data/examples/ranking/Gemfile +33 -0
- data/examples/ranking/Gemfile.lock +189 -0
- data/examples/ranking/README.md +166 -0
- data/examples/ranking/Rakefile +6 -0
- data/examples/ranking/app/controllers/application_controller.rb +2 -0
- data/examples/ranking/app/controllers/concerns/.keep +0 -0
- data/examples/ranking/app/jobs/application_job.rb +7 -0
- data/examples/ranking/app/models/application_record.rb +3 -0
- data/examples/ranking/app/models/concerns/.keep +0 -0
- data/examples/ranking/app/models/game.rb +2 -0
- data/examples/ranking/app/models/play.rb +7 -0
- data/examples/ranking/bin/bundle +114 -0
- data/examples/ranking/bin/rails +4 -0
- data/examples/ranking/bin/rake +4 -0
- data/examples/ranking/bin/setup +33 -0
- data/examples/ranking/config/application.rb +39 -0
- data/examples/ranking/config/boot.rb +4 -0
- data/examples/ranking/config/credentials.yml.enc +1 -0
- data/examples/ranking/config/database.yml +86 -0
- data/examples/ranking/config/environment.rb +5 -0
- data/examples/ranking/config/environments/development.rb +60 -0
- data/examples/ranking/config/environments/production.rb +75 -0
- data/examples/ranking/config/environments/test.rb +53 -0
- data/examples/ranking/config/initializers/cors.rb +16 -0
- data/examples/ranking/config/initializers/filter_parameter_logging.rb +8 -0
- data/examples/ranking/config/initializers/inflections.rb +16 -0
- data/examples/ranking/config/initializers/timescale.rb +3 -0
- data/examples/ranking/config/locales/en.yml +33 -0
- data/examples/ranking/config/puma.rb +43 -0
- data/examples/ranking/config/routes.rb +6 -0
- data/examples/ranking/config/storage.yml +34 -0
- data/examples/ranking/config.ru +6 -0
- data/examples/ranking/db/migrate/20220209120747_create_games.rb +10 -0
- data/examples/ranking/db/migrate/20220209120910_create_plays.rb +19 -0
- data/examples/ranking/db/migrate/20220209143347_create_score_per_hours.rb +5 -0
- data/examples/ranking/db/schema.rb +47 -0
- data/examples/ranking/db/seeds.rb +7 -0
- data/examples/ranking/db/views/score_per_hours_v01.sql +7 -0
- data/examples/ranking/lib/tasks/.keep +0 -0
- data/examples/ranking/log/.keep +0 -0
- data/examples/ranking/public/robots.txt +1 -0
- data/examples/ranking/storage/.keep +0 -0
- data/examples/ranking/tmp/.keep +0 -0
- data/examples/ranking/tmp/pids/.keep +0 -0
- data/examples/ranking/tmp/storage/.keep +0 -0
- data/examples/ranking/vendor/.keep +0 -0
- data/lib/{timescale → timescaledb}/acts_as_hypertable/core.rb +1 -1
- data/lib/{timescale → timescaledb}/acts_as_hypertable.rb +6 -6
- data/lib/{timescale → timescaledb}/chunk.rb +1 -1
- data/lib/{timescale → timescaledb}/compression_settings.rb +1 -1
- data/lib/{timescale → timescaledb}/continuous_aggregates.rb +3 -3
- data/lib/{timescale → timescaledb}/dimensions.rb +1 -1
- data/lib/{timescale → timescaledb}/hypertable.rb +4 -4
- data/lib/{timescale → timescaledb}/job.rb +1 -1
- data/lib/{timescale → timescaledb}/job_stats.rb +1 -1
- data/lib/{timescale → timescaledb}/migration_helpers.rb +2 -2
- data/lib/{timescale → timescaledb}/scenic/adapter.rb +2 -2
- data/lib/timescaledb/scenic/extension.rb +72 -0
- data/lib/{timescale → timescaledb}/schema_dumper.rb +4 -4
- data/lib/{timescale → timescaledb}/stats_report.rb +2 -2
- data/lib/timescaledb/version.rb +3 -0
- data/lib/timescaledb.rb +64 -0
- data/{timescale.gemspec → timescaledb.gemspec} +3 -3
- metadata +73 -23
- data/lib/timescale/version.rb +0 -3
- data/lib/timescale.rb +0 -62
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 128f81d085e998eb85b11ae08b9647880e5da2033fe8c845716fb5cb0a231cb8
|
4
|
+
data.tar.gz: 95c934194cad90f67d4f058491b011935f1da4bf62d40c82bbc85fb293a3189c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 589909dd6e1baa40199c0147d8b6e65a4848090d9c7ec9575be64ca841e8e690554ada570136a8b32e60c93f0b155c0cf1a9ba80c601c3923146690e102382ce
|
7
|
+
data.tar.gz: ca63b74219756fa81ca586ad78b55e597a86f96a354b53a5c20e531925e02bb12aad7ebff000a90082040158e1ddfa6974c97e927c40c2ec65c46c2375656c67
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
timescaledb (0.
|
4
|
+
timescaledb (0.2.0)
|
5
5
|
activerecord
|
6
6
|
activesupport
|
7
7
|
pg (~> 1.2)
|
@@ -33,7 +33,7 @@ GEM
|
|
33
33
|
concurrent-ruby (~> 1.0)
|
34
34
|
method_source (1.0.0)
|
35
35
|
minitest (5.14.4)
|
36
|
-
pg (1.
|
36
|
+
pg (1.3.1)
|
37
37
|
pry (0.14.1)
|
38
38
|
coderay (~> 1.1)
|
39
39
|
method_source (~> 1.0)
|
data/Gemfile.scenic.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
timescaledb (0.1.
|
4
|
+
timescaledb (0.1.5)
|
5
5
|
activerecord
|
6
6
|
activesupport
|
7
7
|
pg (~> 1.2)
|
@@ -58,7 +58,7 @@ GEM
|
|
58
58
|
racc (~> 1.4)
|
59
59
|
nokogiri (1.12.5-x86_64-darwin)
|
60
60
|
racc (~> 1.4)
|
61
|
-
pg (1.
|
61
|
+
pg (1.3.0)
|
62
62
|
pry (0.14.1)
|
63
63
|
coderay (~> 1.1)
|
64
64
|
method_source (~> 1.0)
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# TimescaleDB
|
2
2
|
|
3
|
-
Welcome to the
|
3
|
+
Welcome to the TimescaleDB gem! To experiment with the code, start installing the
|
4
4
|
gem:
|
5
5
|
|
6
6
|
```bash
|
@@ -29,7 +29,7 @@ tsdb postgres://<user>@localhost:5432/<dbname> --stats
|
|
29
29
|
Or just check the stats:
|
30
30
|
|
31
31
|
```bash
|
32
|
-
tsdb "postgres://jonatasdp@localhost:5432/
|
32
|
+
tsdb "postgres://jonatasdp@localhost:5432/timescaledb_test" --stats
|
33
33
|
```
|
34
34
|
|
35
35
|
These is a sample output from database example with almost no data:
|
@@ -89,7 +89,7 @@ continuous aggregates views.
|
|
89
89
|
|
90
90
|
```ruby
|
91
91
|
Tick
|
92
|
-
=>
|
92
|
+
=> Timescaledb::Tick(time: datetime, symbol: string, price: decimal, volume: integer)
|
93
93
|
```
|
94
94
|
|
95
95
|
Note that it's only created for this session and will never be cached in the
|
@@ -102,7 +102,7 @@ Let's start with the `.hypertable` method.
|
|
102
102
|
|
103
103
|
```ruby
|
104
104
|
Tick.hypertable
|
105
|
-
=> #<
|
105
|
+
=> #<Timescaledb::Hypertable:0x00007fe99c258900
|
106
106
|
hypertable_schema: "public",
|
107
107
|
hypertable_name: "ticks",
|
108
108
|
owner: "jonatasdp",
|
@@ -122,7 +122,7 @@ from the hypertable relation.
|
|
122
122
|
```ruby
|
123
123
|
Tick.hypertable.chunks
|
124
124
|
unknown OID 2206: failed to recognize type of 'primary_dimension_type'. It will be treated as String.
|
125
|
-
=> [#<
|
125
|
+
=> [#<Timescaledb::Chunk:0x00007fe99c31b068
|
126
126
|
hypertable_schema: "public",
|
127
127
|
hypertable_name: "ticks",
|
128
128
|
chunk_schema: "_timescaledb_internal",
|
@@ -175,14 +175,14 @@ The `ohlc_1m` view is also available as an ActiveRecord:
|
|
175
175
|
|
176
176
|
```ruby
|
177
177
|
Ohlc1m
|
178
|
-
=>
|
178
|
+
=> Timescaledb::Ohlc1m(bucket: datetime, symbol: string, open: decimal, high: decimal, low: decimal, close: decimal, volume: integer)
|
179
179
|
```
|
180
180
|
|
181
181
|
And you can run any query as you do with regular active record queries.
|
182
182
|
|
183
183
|
```ruby
|
184
184
|
Ohlc1m.order(bucket: :desc).last
|
185
|
-
=> #<
|
185
|
+
=> #<Timescaledb::Ohlc1m:0x00007fe99c2c38e0
|
186
186
|
bucket: 2000-01-01 00:00:00 UTC,
|
187
187
|
symbol: "SYMBOL",
|
188
188
|
open: 0.13e2,
|
@@ -211,7 +211,9 @@ Or install it yourself as:
|
|
211
211
|
|
212
212
|
## Usage
|
213
213
|
|
214
|
-
|
214
|
+
Check the [examples/ranking](examples/ranking) to get a Rails complete example.
|
215
|
+
|
216
|
+
You can check the [all_in_one.rb](examples/all_in_one/all_in_one.rb) example that will:
|
215
217
|
|
216
218
|
1. Create hypertable with compression settings
|
217
219
|
2. Insert data
|
@@ -221,6 +223,11 @@ You can check the [all_in_one.rb](examples/all_in_one.rb) example that will:
|
|
221
223
|
6. Check chunk status
|
222
224
|
7. Decompress a chunk
|
223
225
|
|
226
|
+
### Testing
|
227
|
+
|
228
|
+
If you need some inspiration for how are you going to test your hypertables,
|
229
|
+
please check the [spec/spec_helper.rb](spec/spec_helper.rb) for inspiration.
|
230
|
+
|
224
231
|
### Migrations
|
225
232
|
|
226
233
|
Create table is now with the `hypertable` keyword allowing to pass a few options
|
@@ -297,7 +304,7 @@ manage database view definitions for a Rails application. TimescaleDB's
|
|
297
304
|
continuous aggregates are more complex than regular PostgreSQL views, and
|
298
305
|
the schema dumper included with Scenic can't dump a complete definition.
|
299
306
|
|
300
|
-
This gem automatically configures Scenic to use a `
|
307
|
+
This gem automatically configures Scenic to use a `Timescaledb::Scenic::Adapter`
|
301
308
|
which will correctly handle schema dumping.
|
302
309
|
|
303
310
|
### Enable ActsAsHypertable
|
@@ -328,7 +335,7 @@ end
|
|
328
335
|
To get all the chunks from a model's hypertable, you can use `.chunks`.
|
329
336
|
|
330
337
|
```ruby
|
331
|
-
Event.chunks # => [#<
|
338
|
+
Event.chunks # => [#<Timescaledb::Chunk>, ...]
|
332
339
|
```
|
333
340
|
|
334
341
|
### Hypertable metadata
|
@@ -336,20 +343,20 @@ Event.chunks # => [#<Timescale::Chunk>, ...]
|
|
336
343
|
To get the models' hypertable metadata, you can use `.hypertable`.
|
337
344
|
|
338
345
|
```ruby
|
339
|
-
Event.hypertable # => #<
|
346
|
+
Event.hypertable # => #<Timescaledb::Hypertable>
|
340
347
|
```
|
341
348
|
|
342
|
-
To get hypertable metadata for all hypertables: `
|
349
|
+
To get hypertable metadata for all hypertables: `Timescaledb.hypertables`.
|
343
350
|
|
344
351
|
### Compression Settings
|
345
352
|
|
346
353
|
Compression settings are accessible through the hypertable.
|
347
354
|
|
348
355
|
```ruby
|
349
|
-
Event.hypertable.compression_settings # => [#<
|
356
|
+
Event.hypertable.compression_settings # => [#<Timescaledb::CompressionSettings>, ...]
|
350
357
|
```
|
351
358
|
|
352
|
-
To get compression settings for all hypertables: `
|
359
|
+
To get compression settings for all hypertables: `Timescaledb.compression_settings`.
|
353
360
|
|
354
361
|
### Scopes
|
355
362
|
|
@@ -415,7 +422,7 @@ You can put some postgres URI directly as a parameter of
|
|
415
422
|
`tsdb`. Here is an example from the console:
|
416
423
|
|
417
424
|
```bash
|
418
|
-
tsdb "postgres://jonatasdp@localhost:5432/
|
425
|
+
tsdb "postgres://jonatasdp@localhost:5432/timescaledb_test"
|
419
426
|
```
|
420
427
|
|
421
428
|
## More resources
|
data/bin/console
CHANGED
@@ -11,7 +11,7 @@ end
|
|
11
11
|
|
12
12
|
ActiveRecord::Base.establish_connection(ARGV[0] || uri_from_test)
|
13
13
|
|
14
|
-
|
14
|
+
Timescaledb::Hypertable.find_each do |hypertable|
|
15
15
|
class_name = hypertable.hypertable_name.singularize.camelize
|
16
16
|
|
17
17
|
model = Class.new(ActiveRecord::Base) do
|
@@ -21,7 +21,7 @@ Timescale::Hypertable.find_each do |hypertable|
|
|
21
21
|
acts_as_hypertable
|
22
22
|
end
|
23
23
|
|
24
|
-
|
24
|
+
Timescaledb.const_set(class_name, model)
|
25
25
|
end
|
26
26
|
|
27
27
|
require "pry"
|
data/bin/tsdb
CHANGED
@@ -5,22 +5,22 @@ require "pry"
|
|
5
5
|
|
6
6
|
ActiveRecord::Base.establish_connection(ARGV[0])
|
7
7
|
|
8
|
-
|
8
|
+
Timescaledb::Hypertable.find_each do |hypertable|
|
9
9
|
class_name = hypertable.hypertable_name.singularize.camelize
|
10
10
|
model = Class.new(ActiveRecord::Base) do
|
11
11
|
self.table_name = hypertable.hypertable_name
|
12
12
|
acts_as_hypertable
|
13
13
|
end
|
14
|
-
|
14
|
+
Timescaledb.const_set(class_name, model)
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
Timescaledb::ContinuousAggregates.find_each do |cagg|
|
18
18
|
class_name = cagg.view_name.singularize.camelize
|
19
19
|
model = Class.new(ActiveRecord::Base) do
|
20
20
|
self.table_name = cagg.view_name
|
21
21
|
acts_as_hypertable
|
22
22
|
end
|
23
|
-
|
23
|
+
Timescaledb.const_set(class_name, model)
|
24
24
|
end
|
25
25
|
|
26
26
|
def show(obj)
|
@@ -28,7 +28,7 @@ def show(obj)
|
|
28
28
|
end
|
29
29
|
|
30
30
|
if ARGV.index("--stats")
|
31
|
-
scope =
|
31
|
+
scope = Timescaledb::Hypertable.all
|
32
32
|
|
33
33
|
if (only = ARGV.index("--only"))
|
34
34
|
only_hypertables = ARGV[only+1].split(",")
|
@@ -40,7 +40,7 @@ if ARGV.index("--stats")
|
|
40
40
|
scope = scope.where.not(hypertable_name: except_hypertables)
|
41
41
|
end
|
42
42
|
|
43
|
-
show(
|
43
|
+
show(Timescaledb.stats(scope))
|
44
44
|
end
|
45
45
|
|
46
46
|
if ARGV.index("--console")
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
|
2
|
+
#
|
3
|
+
# If you find yourself ignoring temporary files generated by your text editor
|
4
|
+
# or operating system, you probably want to add a global ignore instead:
|
5
|
+
# git config --global core.excludesfile '~/.gitignore_global'
|
6
|
+
|
7
|
+
# Ignore bundler config.
|
8
|
+
/.bundle
|
9
|
+
|
10
|
+
# Ignore all logfiles and tempfiles.
|
11
|
+
/log/*
|
12
|
+
/tmp/*
|
13
|
+
!/log/.keep
|
14
|
+
!/tmp/.keep
|
15
|
+
|
16
|
+
# Ignore pidfiles, but keep the directory.
|
17
|
+
/tmp/pids/*
|
18
|
+
!/tmp/pids/
|
19
|
+
!/tmp/pids/.keep
|
20
|
+
|
21
|
+
# Ignore uploaded files in development.
|
22
|
+
/storage/*
|
23
|
+
!/storage/.keep
|
24
|
+
/tmp/storage/*
|
25
|
+
!/tmp/storage/
|
26
|
+
!/tmp/storage/.keep
|
27
|
+
|
28
|
+
# Ignore master key for decrypting credentials and more.
|
29
|
+
/config/master.key
|
@@ -0,0 +1 @@
|
|
1
|
+
2.7.1
|
@@ -0,0 +1,33 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
3
|
+
|
4
|
+
ruby "2.7.1"
|
5
|
+
|
6
|
+
# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
|
7
|
+
gem "rails", "~> 7.0.2"
|
8
|
+
|
9
|
+
gem "timescaledb", path: "../../"
|
10
|
+
gem "pg", "~> 1.1"
|
11
|
+
gem "puma", "~> 5.0"
|
12
|
+
gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ]
|
13
|
+
|
14
|
+
# Reduces boot times through caching; required in config/boot.rb
|
15
|
+
gem "bootsnap", require: false
|
16
|
+
|
17
|
+
# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
|
18
|
+
# gem "image_processing", "~> 1.2"
|
19
|
+
|
20
|
+
# Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible
|
21
|
+
# gem "rack-cors"
|
22
|
+
|
23
|
+
group :development, :test do
|
24
|
+
gem "pry-rails"
|
25
|
+
end
|
26
|
+
|
27
|
+
group :development do
|
28
|
+
# Speed up commands on slow machines / big apps [https://github.com/rails/spring]
|
29
|
+
# gem "spring"
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
gem "scenic", "~> 1.5"
|
@@ -0,0 +1,189 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../..
|
3
|
+
specs:
|
4
|
+
timescaledb (0.1.5)
|
5
|
+
activerecord
|
6
|
+
activesupport
|
7
|
+
pg (~> 1.2)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
actioncable (7.0.2)
|
13
|
+
actionpack (= 7.0.2)
|
14
|
+
activesupport (= 7.0.2)
|
15
|
+
nio4r (~> 2.0)
|
16
|
+
websocket-driver (>= 0.6.1)
|
17
|
+
actionmailbox (7.0.2)
|
18
|
+
actionpack (= 7.0.2)
|
19
|
+
activejob (= 7.0.2)
|
20
|
+
activerecord (= 7.0.2)
|
21
|
+
activestorage (= 7.0.2)
|
22
|
+
activesupport (= 7.0.2)
|
23
|
+
mail (>= 2.7.1)
|
24
|
+
net-imap
|
25
|
+
net-pop
|
26
|
+
net-smtp
|
27
|
+
actionmailer (7.0.2)
|
28
|
+
actionpack (= 7.0.2)
|
29
|
+
actionview (= 7.0.2)
|
30
|
+
activejob (= 7.0.2)
|
31
|
+
activesupport (= 7.0.2)
|
32
|
+
mail (~> 2.5, >= 2.5.4)
|
33
|
+
net-imap
|
34
|
+
net-pop
|
35
|
+
net-smtp
|
36
|
+
rails-dom-testing (~> 2.0)
|
37
|
+
actionpack (7.0.2)
|
38
|
+
actionview (= 7.0.2)
|
39
|
+
activesupport (= 7.0.2)
|
40
|
+
rack (~> 2.0, >= 2.2.0)
|
41
|
+
rack-test (>= 0.6.3)
|
42
|
+
rails-dom-testing (~> 2.0)
|
43
|
+
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
44
|
+
actiontext (7.0.2)
|
45
|
+
actionpack (= 7.0.2)
|
46
|
+
activerecord (= 7.0.2)
|
47
|
+
activestorage (= 7.0.2)
|
48
|
+
activesupport (= 7.0.2)
|
49
|
+
globalid (>= 0.6.0)
|
50
|
+
nokogiri (>= 1.8.5)
|
51
|
+
actionview (7.0.2)
|
52
|
+
activesupport (= 7.0.2)
|
53
|
+
builder (~> 3.1)
|
54
|
+
erubi (~> 1.4)
|
55
|
+
rails-dom-testing (~> 2.0)
|
56
|
+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
57
|
+
activejob (7.0.2)
|
58
|
+
activesupport (= 7.0.2)
|
59
|
+
globalid (>= 0.3.6)
|
60
|
+
activemodel (7.0.2)
|
61
|
+
activesupport (= 7.0.2)
|
62
|
+
activerecord (7.0.2)
|
63
|
+
activemodel (= 7.0.2)
|
64
|
+
activesupport (= 7.0.2)
|
65
|
+
activestorage (7.0.2)
|
66
|
+
actionpack (= 7.0.2)
|
67
|
+
activejob (= 7.0.2)
|
68
|
+
activerecord (= 7.0.2)
|
69
|
+
activesupport (= 7.0.2)
|
70
|
+
marcel (~> 1.0)
|
71
|
+
mini_mime (>= 1.1.0)
|
72
|
+
activesupport (7.0.2)
|
73
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
74
|
+
i18n (>= 1.6, < 2)
|
75
|
+
minitest (>= 5.1)
|
76
|
+
tzinfo (~> 2.0)
|
77
|
+
bootsnap (1.10.3)
|
78
|
+
msgpack (~> 1.2)
|
79
|
+
builder (3.2.4)
|
80
|
+
coderay (1.1.3)
|
81
|
+
concurrent-ruby (1.1.9)
|
82
|
+
crass (1.0.6)
|
83
|
+
digest (3.1.0)
|
84
|
+
erubi (1.10.0)
|
85
|
+
globalid (1.0.0)
|
86
|
+
activesupport (>= 5.0)
|
87
|
+
i18n (1.9.1)
|
88
|
+
concurrent-ruby (~> 1.0)
|
89
|
+
io-wait (0.2.1)
|
90
|
+
loofah (2.13.0)
|
91
|
+
crass (~> 1.0.2)
|
92
|
+
nokogiri (>= 1.5.9)
|
93
|
+
mail (2.7.1)
|
94
|
+
mini_mime (>= 0.1.1)
|
95
|
+
marcel (1.0.2)
|
96
|
+
method_source (1.0.0)
|
97
|
+
mini_mime (1.1.2)
|
98
|
+
mini_portile2 (2.7.1)
|
99
|
+
minitest (5.15.0)
|
100
|
+
msgpack (1.4.4)
|
101
|
+
net-imap (0.2.3)
|
102
|
+
digest
|
103
|
+
net-protocol
|
104
|
+
strscan
|
105
|
+
net-pop (0.1.1)
|
106
|
+
digest
|
107
|
+
net-protocol
|
108
|
+
timeout
|
109
|
+
net-protocol (0.1.2)
|
110
|
+
io-wait
|
111
|
+
timeout
|
112
|
+
net-smtp (0.3.1)
|
113
|
+
digest
|
114
|
+
net-protocol
|
115
|
+
timeout
|
116
|
+
nio4r (2.5.8)
|
117
|
+
nokogiri (1.13.1)
|
118
|
+
mini_portile2 (~> 2.7.0)
|
119
|
+
racc (~> 1.4)
|
120
|
+
pg (1.3.1)
|
121
|
+
pry (0.14.1)
|
122
|
+
coderay (~> 1.1)
|
123
|
+
method_source (~> 1.0)
|
124
|
+
pry-rails (0.3.9)
|
125
|
+
pry (>= 0.10.4)
|
126
|
+
puma (5.6.1)
|
127
|
+
nio4r (~> 2.0)
|
128
|
+
racc (1.6.0)
|
129
|
+
rack (2.2.3)
|
130
|
+
rack-test (1.1.0)
|
131
|
+
rack (>= 1.0, < 3)
|
132
|
+
rails (7.0.2)
|
133
|
+
actioncable (= 7.0.2)
|
134
|
+
actionmailbox (= 7.0.2)
|
135
|
+
actionmailer (= 7.0.2)
|
136
|
+
actionpack (= 7.0.2)
|
137
|
+
actiontext (= 7.0.2)
|
138
|
+
actionview (= 7.0.2)
|
139
|
+
activejob (= 7.0.2)
|
140
|
+
activemodel (= 7.0.2)
|
141
|
+
activerecord (= 7.0.2)
|
142
|
+
activestorage (= 7.0.2)
|
143
|
+
activesupport (= 7.0.2)
|
144
|
+
bundler (>= 1.15.0)
|
145
|
+
railties (= 7.0.2)
|
146
|
+
rails-dom-testing (2.0.3)
|
147
|
+
activesupport (>= 4.2.0)
|
148
|
+
nokogiri (>= 1.6)
|
149
|
+
rails-html-sanitizer (1.4.2)
|
150
|
+
loofah (~> 2.3)
|
151
|
+
railties (7.0.2)
|
152
|
+
actionpack (= 7.0.2)
|
153
|
+
activesupport (= 7.0.2)
|
154
|
+
method_source
|
155
|
+
rake (>= 12.2)
|
156
|
+
thor (~> 1.0)
|
157
|
+
zeitwerk (~> 2.5)
|
158
|
+
rake (13.0.6)
|
159
|
+
scenic (1.5.5)
|
160
|
+
activerecord (>= 4.0.0)
|
161
|
+
railties (>= 4.0.0)
|
162
|
+
strscan (3.0.1)
|
163
|
+
thor (1.2.1)
|
164
|
+
timeout (0.2.0)
|
165
|
+
tzinfo (2.0.4)
|
166
|
+
concurrent-ruby (~> 1.0)
|
167
|
+
websocket-driver (0.7.5)
|
168
|
+
websocket-extensions (>= 0.1.0)
|
169
|
+
websocket-extensions (0.1.5)
|
170
|
+
zeitwerk (2.5.4)
|
171
|
+
|
172
|
+
PLATFORMS
|
173
|
+
ruby
|
174
|
+
|
175
|
+
DEPENDENCIES
|
176
|
+
bootsnap
|
177
|
+
pg (~> 1.1)
|
178
|
+
pry-rails
|
179
|
+
puma (~> 5.0)
|
180
|
+
rails (~> 7.0.2)
|
181
|
+
scenic (~> 1.5)
|
182
|
+
timescaledb!
|
183
|
+
tzinfo-data
|
184
|
+
|
185
|
+
RUBY VERSION
|
186
|
+
ruby 2.7.1p83
|
187
|
+
|
188
|
+
BUNDLED WITH
|
189
|
+
2.1.4
|
@@ -0,0 +1,166 @@
|
|
1
|
+
# README
|
2
|
+
|
3
|
+
This example application is a "Scoring" service that stores "games" and "plays" of the games in question.
|
4
|
+
|
5
|
+
There are two tables:
|
6
|
+
|
7
|
+
* `games` that holds a name and description
|
8
|
+
* `plays` is a [hypertable][hypertable] that references a `game`, storing `score` and `total_time`.
|
9
|
+
|
10
|
+
Interesting things to observe here:
|
11
|
+
|
12
|
+
* The gem is required on [config/initializers/timescale.rb](./config/initializers/timescale.rb).
|
13
|
+
* The [hypertable creation](db/migrate/20220209120910_create_plays.rb) is also with the `enable_extension` command time.
|
14
|
+
* See how the [play model](app/models/play.rb) uses [acts_as_hypertable](../../lib/timescale/acts_as_hypertable.rb).
|
15
|
+
|
16
|
+
## Walkthrough
|
17
|
+
|
18
|
+
Use `bin/console` to preload the environment and follow the next steps.
|
19
|
+
|
20
|
+
Let's start by creating a game and a single play.
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
lol = Game.create(name: "LoL", description: "League of Legends")
|
24
|
+
Play.create(game: lol,
|
25
|
+
score: (rand * 100).to_i,
|
26
|
+
total_time: (rand * 1000).to_i)
|
27
|
+
```
|
28
|
+
You can also insert a few hundreds/thousands/millions of records to test it properly.
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
100.times do
|
32
|
+
Play.create(game: lol,
|
33
|
+
score: (rand * 100).to_i,
|
34
|
+
total_time: (rand * 1000).to_i)
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
You can play with multiple games and millions of play records to make it an impressive playground if you want :wink:
|
39
|
+
|
40
|
+
|
41
|
+
Then you can experiment with the [time_bucket][time_bucket] funciton.
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
Play.group("time_bucket('1 min',created_at)").count
|
45
|
+
# => {2022-02-09 12:34:00 UTC=>1, 2022-02-09 12:39:00 UTC=>10100}
|
46
|
+
```
|
47
|
+
|
48
|
+
> Hypertables in TimescaleDB are designed to be easy to manage and to behave predictably to users familiar with standard PostgreSQL tables. Along those lines, SQL commands to create, alter, or delete hypertables in TimescaleDB are identical to those in PostgreSQL. Even though hypertables are comprised of many interlinked chunks, commands made to the hypertable automatically propagate changes down to all of the chunks belonging to that hypertable.
|
49
|
+
|
50
|
+
When the model contains the `acts_as_hypertable` macro, it's possible to navigate into the hypertable internals:
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
Play.hypertable
|
54
|
+
# => #<Timescaledb::Hypertable:0x00007faa97df7e30
|
55
|
+
# hypertable_schema: "public",
|
56
|
+
# hypertable_name: "plays",
|
57
|
+
# owner: "jonatasdp",
|
58
|
+
# num_dimensions: 1,
|
59
|
+
# num_chunks: 2,
|
60
|
+
# compression_enabled: true,
|
61
|
+
# is_distributed: false,
|
62
|
+
# replication_factor: nil,
|
63
|
+
# data_nodes: nil,
|
64
|
+
# tablespaces: nil>
|
65
|
+
```
|
66
|
+
|
67
|
+
Each hypertable has many chunks. Chunks are the subtables spread accross the time. You can check chunks metadata from the `hypertable` relation here:
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
Play.hypertable.chunks.pluck(:chunk_name)
|
71
|
+
# => ["_hyper_1_1_chunk", "_hyper_1_2_chunk"]
|
72
|
+
```
|
73
|
+
|
74
|
+
Chunks can also be compressed/decompressed and you can check the state using scopes:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
Play.hypertable.chunks.compressed.count # => 2
|
78
|
+
```
|
79
|
+
|
80
|
+
Get a resume from chunks status:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
Play.hypertable.chunks.resume
|
84
|
+
# => {:total=>2, :compressed=>0, :uncompressed=>2}
|
85
|
+
```
|
86
|
+
|
87
|
+
To get a full stats from all hypertables, you can see `Timescaledb.stats`:
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
Timescaledb.stats
|
91
|
+
# => {:hypertables=>
|
92
|
+
# {:count=>1,
|
93
|
+
# :uncompressed=>0,
|
94
|
+
# :approximate_row_count=>{"plays"=>10100},
|
95
|
+
# :chunks=>{:total=>2, :compressed=>0, :uncompressed=>2},
|
96
|
+
# :size=>{:uncompressed=>"1.3 MB", :compressed=>"0 Bytes"}},
|
97
|
+
# :continuous_aggregates=>{:total=>0},
|
98
|
+
# :jobs_stats=>[{:success=>100, :runs=>100, :failures=>0}]}
|
99
|
+
```
|
100
|
+
Note that we haven't used compression yet. So, we can force compression directly from the `chunk` relation:
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
Play.hypertable.chunks.each(&:compress!)
|
104
|
+
```
|
105
|
+
|
106
|
+
Calling `stats` to check the compressed size:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
Timescaledb.stats
|
110
|
+
# {:count=>1, ...
|
111
|
+
# :size=>
|
112
|
+
# {:uncompressed=>"1.2 MB",
|
113
|
+
# :compressed=>"180 KB"}},
|
114
|
+
# :continuous_aggregates=>{:total=>0},
|
115
|
+
# :jobs_stats=>
|
116
|
+
# [{:success=>107,
|
117
|
+
# :runs=>107,
|
118
|
+
# :failures=>0}]}
|
119
|
+
```
|
120
|
+
|
121
|
+
> :warning: Note that the chunks are not very effective compressing here because of the example is incomplete and with a little amount of records.
|
122
|
+
|
123
|
+
You can decompress as the system will make the compression in the background as it already have a policy.
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
Play.hypertable.chunks.each(&:decompress!)
|
127
|
+
```
|
128
|
+
|
129
|
+
## Dump schema
|
130
|
+
|
131
|
+
The lib also contains a [schema_dumper](../../lib/timescale/schema_dumper.rb) that allows you to dump the schema and reload with the same hypertable options.
|
132
|
+
|
133
|
+
```bash
|
134
|
+
rails db:schema:dump
|
135
|
+
```
|
136
|
+
|
137
|
+
Confirm that the hypertable is on [db/schema.rb](db/schema.rb) file:
|
138
|
+
|
139
|
+
```
|
140
|
+
grep hypertable db/schema.rb
|
141
|
+
create_hypertable "plays", time_column: "created_at", chunk_time_interval: "1
|
142
|
+
minute", compress_segmentby: "game_id", compress_orderby: "created_at ASC",
|
143
|
+
compression_interval: "P7D"
|
144
|
+
```
|
145
|
+
|
146
|
+
And you can also reload the configuration manually in the test environment:
|
147
|
+
|
148
|
+
```bash
|
149
|
+
RAILS_ENV=test rails db:schema:load
|
150
|
+
```
|
151
|
+
|
152
|
+
## Scenic views
|
153
|
+
|
154
|
+
If you use [scenic](https://github.com/scenic-views/scenic) views, it will
|
155
|
+
automatically recognize and dump the views.
|
156
|
+
|
157
|
+
Check the [view migration](db/migrate/20220209143347_create_score_per_hours.rb)
|
158
|
+
and the correspondent view defined in the [sql file](db/views/score_per_hours_v01.sql).
|
159
|
+
|
160
|
+
> Note that scenic is not fully compatible with timescaledb continous aggregates
|
161
|
+
> and we created a [helper](../../lib/timescale/scenic/extension.rb) to make it
|
162
|
+
> easy to use along with scenic.
|
163
|
+
|
164
|
+
[hypertable]: https://docs.timescale.com/timescaledb/latest/how-to-guides/hypertables/
|
165
|
+
[time_bucket]: https://docs.timescale.com/api/latest/hyperfunctions/time_bucket/
|
166
|
+
|