timescaledb 0.1.2 → 0.2.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.
- checksums.yaml +4 -4
- data/.ruby-version +1 -0
- data/.tool-versions +1 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +11 -3
- data/Gemfile.scenic +7 -0
- data/Gemfile.scenic.lock +121 -0
- data/README.md +267 -121
- data/Rakefile +16 -1
- data/bin/console +2 -2
- data/bin/setup +2 -0
- data/bin/tsdb +30 -6
- data/examples/{Gemfile → all_in_one/Gemfile} +1 -1
- data/examples/{Gemfile.lock → all_in_one/Gemfile.lock} +2 -2
- data/examples/{all_in_one.rb → all_in_one/all_in_one.rb} +3 -6
- 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/timescaledb/acts_as_hypertable/core.rb +87 -0
- data/lib/timescaledb/acts_as_hypertable.rb +62 -0
- data/lib/{timescale → timescaledb}/chunk.rb +9 -1
- data/lib/{timescale → timescaledb}/compression_settings.rb +3 -2
- data/lib/timescaledb/continuous_aggregates.rb +19 -0
- data/lib/timescaledb/dimensions.rb +6 -0
- data/lib/{timescale → timescaledb}/hypertable.rb +9 -5
- data/lib/timescaledb/job.rb +10 -0
- data/lib/{timescale → timescaledb}/job_stats.rb +3 -4
- data/lib/{timescale → timescaledb}/migration_helpers.rb +35 -5
- data/lib/timescaledb/scenic/adapter.rb +55 -0
- data/lib/timescaledb/scenic/extension.rb +72 -0
- data/lib/timescaledb/schema_dumper.rb +88 -0
- data/lib/timescaledb/stats_report.rb +35 -0
- data/lib/timescaledb/version.rb +3 -0
- data/lib/timescaledb.rb +64 -0
- data/{timescale.gemspec → timescaledb.gemspec} +6 -4
- metadata +106 -20
- data/lib/timescale/acts_as_hypertable.rb +0 -114
- data/lib/timescale/continuous_aggregates.rb +0 -9
- data/lib/timescale/job.rb +0 -13
- data/lib/timescale/stats_report.rb +0 -28
- data/lib/timescale/version.rb +0 -3
- data/lib/timescale.rb +0 -52
data/README.md
CHANGED
@@ -1,48 +1,38 @@
|
|
1
|
-
#
|
1
|
+
# TimescaleDB
|
2
2
|
|
3
|
-
Welcome to the
|
4
|
-
|
3
|
+
Welcome to the TimescaleDB gem! To experiment with the code, start installing the
|
4
|
+
gem:
|
5
5
|
|
6
6
|
```bash
|
7
|
-
|
8
|
-
cd timescale
|
9
|
-
bundle install
|
10
|
-
rake install
|
7
|
+
gem install timescaledb
|
11
8
|
```
|
12
9
|
|
13
|
-
|
10
|
+
## The `tsdb` CLI
|
14
11
|
|
15
|
-
|
16
|
-
|
17
|
-
```
|
12
|
+
When you install the gem locally, a new command line application named `tsdb`
|
13
|
+
will be linked in your command line.
|
18
14
|
|
19
|
-
|
20
|
-
|
15
|
+
It accepts a Postgresql URI and some extra flags that can help you to get more
|
16
|
+
info from your TimescaleDB server:
|
21
17
|
|
22
18
|
```bash
|
23
|
-
|
19
|
+
tsdb <uri> --stats
|
24
20
|
```
|
25
21
|
|
26
|
-
|
27
|
-
`tsdb`. Here is an example from the console:
|
22
|
+
Where the `<uri>` is replaced with params from your connection like:
|
28
23
|
|
29
24
|
```bash
|
30
|
-
tsdb
|
25
|
+
tsdb postgres://<user>@localhost:5432/<dbname> --stats
|
31
26
|
```
|
32
27
|
|
33
|
-
To join the console use `--console`:
|
34
|
-
|
35
|
-
```bash
|
36
|
-
tsdb "postgres://jonatasdp@localhost:5432/timescale_test" --console
|
37
|
-
```
|
38
28
|
|
39
29
|
Or just check the stats:
|
40
30
|
|
41
31
|
```bash
|
42
|
-
tsdb "postgres://jonatasdp@localhost:5432/
|
32
|
+
tsdb "postgres://jonatasdp@localhost:5432/timescaledb_test" --stats
|
43
33
|
```
|
44
34
|
|
45
|
-
These is a sample output from
|
35
|
+
These is a sample output from database example with almost no data:
|
46
36
|
|
47
37
|
```ruby
|
48
38
|
{:hypertables=>
|
@@ -54,19 +44,153 @@ These is a sample output from an almost empty database:
|
|
54
44
|
:jobs_stats=>[{:success=>nil, :runs=>nil, :failures=>nil}]}
|
55
45
|
```
|
56
46
|
|
47
|
+
To start a interactive ruby/[pry](https://github.com/pry/pry) console use `--console`:
|
57
48
|
The console will dynamically create models for all hypertables that it finds
|
58
49
|
in the database.
|
59
50
|
|
60
|
-
|
61
|
-
|
51
|
+
Let's consider the [caggs.sql](https://gist.github.com/jonatas/95573ad8744994094ec9f284150004f9#file-caggs-sql)
|
52
|
+
as the example of database.
|
62
53
|
|
63
|
-
This library was started on [twitch.tv/timescaledb](https://twitch.tv/timescaledb).
|
64
|
-
You can watch all episodes here:
|
65
54
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
55
|
+
```bash
|
56
|
+
psql postgres://jonatasdp@localhost:5432/playground -f caggs.sql
|
57
|
+
```
|
58
|
+
|
59
|
+
Then use `tsdb` in the command line with the same URI and `--stats`:
|
60
|
+
|
61
|
+
```bash
|
62
|
+
tsdb postgres://jonatasdp@localhost:5432/playground --stats
|
63
|
+
{:hypertables=>
|
64
|
+
{:count=>1,
|
65
|
+
:uncompressed=>1,
|
66
|
+
:approximate_row_count=>{"ticks"=>352},
|
67
|
+
:chunks=>{:total=>1, :compressed=>0, :uncompressed=>1},
|
68
|
+
:size=>{:uncompressed=>"88 KB", :compressed=>"0 Bytes"}},
|
69
|
+
:continuous_aggregates=>{:total=>1},
|
70
|
+
:jobs_stats=>[{:success=>nil, :runs=>nil, :failures=>nil}]}
|
71
|
+
```
|
72
|
+
|
73
|
+
To have some interactive playground with the actual database using ruby, just
|
74
|
+
try the same command before changing from `--stats` to `--console`:
|
75
|
+
|
76
|
+
### tsdb --console
|
77
|
+
|
78
|
+
The same database from previous example, is used so
|
79
|
+
the context has a hypertable named `ticks` and a view named `ohlc_1m`.
|
80
|
+
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
tsdb postgres://jonatasdp@localhost:5432/playground --console
|
84
|
+
pry(Timescale)>
|
85
|
+
```
|
86
|
+
|
87
|
+
The `tsdb` CLI will automatically create ActiveRecord models for hypertables and
|
88
|
+
continuous aggregates views.
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
Tick
|
92
|
+
=> Timescaledb::Tick(time: datetime, symbol: string, price: decimal, volume: integer)
|
93
|
+
```
|
94
|
+
|
95
|
+
Note that it's only created for this session and will never be cached in the
|
96
|
+
library or any other place.
|
97
|
+
|
98
|
+
In this case, `Tick` model comes from `ticks` hypertable that was found in the database.
|
99
|
+
It contains several extra methods inherited from `acts_as_hypertable` macro.
|
100
|
+
|
101
|
+
Let's start with the `.hypertable` method.
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
Tick.hypertable
|
105
|
+
=> #<Timescaledb::Hypertable:0x00007fe99c258900
|
106
|
+
hypertable_schema: "public",
|
107
|
+
hypertable_name: "ticks",
|
108
|
+
owner: "jonatasdp",
|
109
|
+
num_dimensions: 1,
|
110
|
+
num_chunks: 1,
|
111
|
+
compression_enabled: false,
|
112
|
+
is_distributed: false,
|
113
|
+
replication_factor: nil,
|
114
|
+
data_nodes: nil,
|
115
|
+
tablespaces: nil>
|
116
|
+
```
|
117
|
+
|
118
|
+
The core of the hypertables are the fragmentation of the data into chunks that
|
119
|
+
are the child tables that distribute the data. You can check all chunks directly
|
120
|
+
from the hypertable relation.
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
Tick.hypertable.chunks
|
124
|
+
unknown OID 2206: failed to recognize type of 'primary_dimension_type'. It will be treated as String.
|
125
|
+
=> [#<Timescaledb::Chunk:0x00007fe99c31b068
|
126
|
+
hypertable_schema: "public",
|
127
|
+
hypertable_name: "ticks",
|
128
|
+
chunk_schema: "_timescaledb_internal",
|
129
|
+
chunk_name: "_hyper_33_17_chunk",
|
130
|
+
primary_dimension: "time",
|
131
|
+
primary_dimension_type: "timestamp without time zone",
|
132
|
+
range_start: 1999-12-30 00:00:00 +0000,
|
133
|
+
range_end: 2000-01-06 00:00:00 +0000,
|
134
|
+
range_start_integer: nil,
|
135
|
+
range_end_integer: nil,
|
136
|
+
is_compressed: false,
|
137
|
+
chunk_tablespace: nil,
|
138
|
+
data_nodes: nil>]
|
139
|
+
```
|
140
|
+
|
141
|
+
> Chunks are created by partitioning a hypertable's data into one
|
142
|
+
> (or potentially multiple) dimensions. All hypertables are partitioned by the
|
143
|
+
> values belonging to a time column, which may be in timestamp, date, or
|
144
|
+
> various integer forms. If the time partitioning interval is one day,
|
145
|
+
> for example, then rows with timestamps that belong to the same day are co-located
|
146
|
+
> within the same chunk, while rows belonging to different days belong to different chunks.
|
147
|
+
> Learn more [here](https://docs.timescale.com/timescaledb/latest/overview/core-concepts/hypertables-and-chunks/).
|
148
|
+
|
149
|
+
Another core concept of TimescaleDB is compression. With data partitioned, it
|
150
|
+
becomes very convenient to compress and decompress chunks independently.
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
Tick.hypertable.chunks.first.compress!
|
154
|
+
ActiveRecord::StatementInvalid: PG::FeatureNotSupported: ERROR: compression not enabled on "ticks"
|
155
|
+
DETAIL: It is not possible to compress chunks on a hypertable that does not have compression enabled.
|
156
|
+
HINT: Enable compression using ALTER TABLE with the timescaledb.compress option.
|
157
|
+
```
|
158
|
+
|
159
|
+
As compression is not enabled, let's do it executing a plain SQL directly from
|
160
|
+
the actual context. To borrow a connection, let's use the Tick object.
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
Tick.connection.execute("ALTER TABLE ticks SET (timescaledb.compress)") # => PG_OK
|
164
|
+
```
|
165
|
+
|
166
|
+
And now, it's possible to compress and decompress:
|
167
|
+
|
168
|
+
```ruby
|
169
|
+
Tick.hypertable.chunks.first.compress!
|
170
|
+
Tick.hypertable.chunks.first.decompress!
|
171
|
+
```
|
172
|
+
Learn more about TimescaleDB compression [here](https://docs.timescale.com/timescaledb/latest/overview/core-concepts/compression/).
|
173
|
+
|
174
|
+
The `ohlc_1m` view is also available as an ActiveRecord:
|
175
|
+
|
176
|
+
```ruby
|
177
|
+
Ohlc1m
|
178
|
+
=> Timescaledb::Ohlc1m(bucket: datetime, symbol: string, open: decimal, high: decimal, low: decimal, close: decimal, volume: integer)
|
179
|
+
```
|
180
|
+
|
181
|
+
And you can run any query as you do with regular active record queries.
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
Ohlc1m.order(bucket: :desc).last
|
185
|
+
=> #<Timescaledb::Ohlc1m:0x00007fe99c2c38e0
|
186
|
+
bucket: 2000-01-01 00:00:00 UTC,
|
187
|
+
symbol: "SYMBOL",
|
188
|
+
open: 0.13e2,
|
189
|
+
high: 0.3e2,
|
190
|
+
low: 0.1e1,
|
191
|
+
close: 0.1e2,
|
192
|
+
volume: 27600>
|
193
|
+
```
|
70
194
|
|
71
195
|
## Installation
|
72
196
|
|
@@ -84,18 +208,26 @@ Or install it yourself as:
|
|
84
208
|
|
85
209
|
$ gem install timescaledb
|
86
210
|
|
211
|
+
|
87
212
|
## Usage
|
88
213
|
|
89
|
-
|
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:
|
90
217
|
|
91
218
|
1. Create hypertable with compression settings
|
92
219
|
2. Insert data
|
93
|
-
3. Run some queries
|
220
|
+
3. Run some queries
|
94
221
|
4. Check chunk size per model
|
95
222
|
5. Compress a chunk
|
96
223
|
6. Check chunk status
|
97
224
|
7. Decompress a chunk
|
98
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
|
+
|
99
231
|
### Migrations
|
100
232
|
|
101
233
|
Create table is now with the `hypertable` keyword allowing to pass a few options
|
@@ -118,7 +250,7 @@ create_table(:events, id: false, hypertable: hypertable_options) do |t|
|
|
118
250
|
end
|
119
251
|
```
|
120
252
|
|
121
|
-
####
|
253
|
+
#### create_continuous_aggregate
|
122
254
|
|
123
255
|
This example shows a ticks table grouping ticks as OHLCV histograms for every
|
124
256
|
minute.
|
@@ -140,7 +272,7 @@ end
|
|
140
272
|
Tick = Class.new(ActiveRecord::Base) do
|
141
273
|
self.table_name = 'ticks'
|
142
274
|
self.primary_key = 'symbol'
|
143
|
-
|
275
|
+
acts_as_hypertable
|
144
276
|
end
|
145
277
|
|
146
278
|
query = Tick.select(<<~QUERY)
|
@@ -162,142 +294,156 @@ options = {
|
|
162
294
|
}
|
163
295
|
}
|
164
296
|
|
165
|
-
|
297
|
+
create_continuous_aggregate('ohlc_1m', query, **options)
|
166
298
|
```
|
167
299
|
|
168
|
-
|
300
|
+
#### Scenic integration
|
301
|
+
|
302
|
+
The [Scenic](https://github.com/scenic-views/scenic) gem is an easy way to
|
303
|
+
manage database view definitions for a Rails application. TimescaleDB's
|
304
|
+
continuous aggregates are more complex than regular PostgreSQL views, and
|
305
|
+
the schema dumper included with Scenic can't dump a complete definition.
|
169
306
|
|
170
|
-
|
307
|
+
This gem automatically configures Scenic to use a `Timescaledb::Scenic::Adapter`
|
308
|
+
which will correctly handle schema dumping.
|
309
|
+
|
310
|
+
### Enable ActsAsHypertable
|
311
|
+
|
312
|
+
You can declare a Rails model as a Hypertable by invoking the `acts_as_hypertable` macro. This macro extends your existing model with timescaledb-related functionality.
|
171
313
|
model:
|
172
314
|
|
173
315
|
```ruby
|
174
316
|
class Event < ActiveRecord::Base
|
175
|
-
|
176
|
-
|
177
|
-
include Timescale::HypertableHelpers
|
317
|
+
acts_as_hypertable
|
178
318
|
end
|
179
319
|
```
|
180
320
|
|
181
|
-
|
182
|
-
model.
|
321
|
+
By default, ActsAsHypertable assumes a record's _time_column_ is called `created_at`.
|
183
322
|
|
184
|
-
###
|
323
|
+
### Options
|
185
324
|
|
186
|
-
|
187
|
-
the model name.
|
325
|
+
If you are using a different time_column name, you can specify it as follows when invoking the `acts_as_hypertable` macro:
|
188
326
|
|
189
327
|
```ruby
|
190
|
-
Event
|
191
|
-
|
192
|
-
|
193
|
-
# hypertable_schema: "public",
|
194
|
-
# hypertable_name: "events",
|
195
|
-
# chunk_schema: "_timescaledb_internal",
|
196
|
-
# chunk_name: "_hyper_180_74_chunk",
|
197
|
-
# primary_dimension: "created_at",
|
198
|
-
# primary_dimension_type: "timestamp without time zone",
|
199
|
-
# range_start: 2021-09-22 21:28:00 +0000,
|
200
|
-
# range_end: 2021-09-22 21:29:00 +0000,
|
201
|
-
# range_start_integer: nil,
|
202
|
-
# range_end_integer: nil,
|
203
|
-
# is_compressed: false,
|
204
|
-
# chunk_tablespace: nil,
|
205
|
-
# data_nodes: nil>
|
328
|
+
class Event < ActiveRecord::Base
|
329
|
+
acts_as_hypertable time_column: :timestamp
|
330
|
+
end
|
206
331
|
```
|
207
332
|
|
208
|
-
|
333
|
+
### Chunks
|
334
|
+
|
335
|
+
To get all the chunks from a model's hypertable, you can use `.chunks`.
|
336
|
+
|
337
|
+
```ruby
|
338
|
+
Event.chunks # => [#<Timescaledb::Chunk>, ...]
|
339
|
+
```
|
209
340
|
|
210
|
-
### Hypertable metadata
|
341
|
+
### Hypertable metadata
|
211
342
|
|
212
|
-
To get
|
213
|
-
model.
|
343
|
+
To get the models' hypertable metadata, you can use `.hypertable`.
|
214
344
|
|
215
345
|
```ruby
|
216
|
-
Event.hypertable
|
217
|
-
# Timescale::Hypertable Load (4.8ms) SELECT "timescaledb_information"."hypertables".* FROM "timescaledb_information"."hypertables" WHERE "timescaledb_information"."hypertables"."hypertable_name" = $1 LIMIT $2 [["hypertable_name", "events"], ["LIMIT", 1]]
|
218
|
-
# => #<Timescale::Hypertable:0x00007f94c3151cd8
|
219
|
-
# hypertable_schema: "public",
|
220
|
-
# hypertable_name: "events",
|
221
|
-
# owner: "jonatasdp",
|
222
|
-
# num_dimensions: 1,
|
223
|
-
# num_chunks: 1,
|
224
|
-
# compression_enabled: true,
|
225
|
-
# is_distributed: false,
|
226
|
-
# replication_factor: nil,
|
227
|
-
# data_nodes: nil,
|
228
|
-
# tablespaces: nil>
|
346
|
+
Event.hypertable # => #<Timescaledb::Hypertable>
|
229
347
|
```
|
230
348
|
|
231
|
-
|
232
|
-
metadata.
|
349
|
+
To get hypertable metadata for all hypertables: `Timescaledb.hypertables`.
|
233
350
|
|
234
351
|
### Compression Settings
|
235
352
|
|
236
353
|
Compression settings are accessible through the hypertable.
|
237
354
|
|
238
355
|
```ruby
|
239
|
-
Event.hypertable.compression_settings
|
240
|
-
# Timescale::Hypertable Load (1.2ms) SELECT "timescaledb_information"."hypertables".* FROM "timescaledb_information"."hypertables" WHERE "timescaledb_information"."hypertables"."hypertable_name" = $1 LIMIT $2 [["hypertable_name", "events"], ["LIMIT", 1]]
|
241
|
-
# Timescale::CompressionSettings Load (1.2ms) SELECT "timescaledb_information"."compression_settings".* FROM "timescaledb_information"."compression_settings" WHERE "timescaledb_information"."compression_settings"."hypertable_name" = $1 [["hypertable_name", "events"]]
|
242
|
-
# => [#<Timescale::CompressionSettings:0x00007f94b0bf7010
|
243
|
-
# hypertable_schema: "public",
|
244
|
-
# hypertable_name: "events",
|
245
|
-
# attname: "identifier",
|
246
|
-
# segmentby_column_index: 1,
|
247
|
-
# orderby_column_index: nil,
|
248
|
-
# orderby_asc: nil,
|
249
|
-
# orderby_nullsfirst: nil>,
|
250
|
-
# #<Timescale::CompressionSettings:0x00007f94b0c3e460
|
251
|
-
# hypertable_schema: "public",
|
252
|
-
# hypertable_name: "events",
|
253
|
-
# attname: "created_at",
|
254
|
-
# segmentby_column_index: nil,
|
255
|
-
# orderby_column_index: 1,
|
256
|
-
# orderby_asc: true,
|
257
|
-
# orderby_nullsfirst: false>]
|
356
|
+
Event.hypertable.compression_settings # => [#<Timescaledb::CompressionSettings>, ...]
|
258
357
|
```
|
259
358
|
|
260
|
-
|
359
|
+
To get compression settings for all hypertables: `Timescaledb.compression_settings`.
|
360
|
+
|
361
|
+
### Scopes
|
362
|
+
|
363
|
+
When you enable ActsAsHypertable on your model, we include a couple default scopes. They are:
|
364
|
+
|
365
|
+
| Scope name | What they return |
|
366
|
+
|------------------------|---------------------------------------|
|
367
|
+
| `Model.previous_month` | Records created in the previous month |
|
368
|
+
| `Model.previous_week` | Records created in the previous week |
|
369
|
+
| `Model.this_month` | Records created this month |
|
370
|
+
| `Model.this_week` | Records created this week |
|
371
|
+
| `Model.yesterday` | Records created yesterday |
|
372
|
+
| `Model.today` | Records created today |
|
373
|
+
| `Model.last_hour` | Records created in the last hour |
|
261
374
|
|
262
|
-
|
375
|
+
All time-related scopes respect your application's timezone.
|
376
|
+
|
377
|
+
## RSpec Hooks
|
263
378
|
|
264
379
|
In case you want to use TimescaleDB on a Rails environment, you may have some
|
265
|
-
issues as the schema dump used for tests
|
266
|
-
metadata.
|
380
|
+
issues as the schema dump used for tests does not consider hypertables metadata.
|
267
381
|
|
268
|
-
|
269
|
-
|
382
|
+
As a work around, you can dynamically create the hypertables yourself for
|
383
|
+
testing environments using the following hook which you can
|
384
|
+
define in `spec/rspec_helper.rb`:
|
270
385
|
|
271
386
|
```ruby
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
SELECT create_hypertable('#{clazz.table_name}', 'created_at')
|
283
|
-
SQL
|
387
|
+
config.before(:suite) do
|
388
|
+
hypertable_models = ActiveRecord::Base.descendants.select(&:acts_as_hypertable?)
|
389
|
+
|
390
|
+
hypertable_models.each do |klass|
|
391
|
+
table_name = klass.table_name
|
392
|
+
time_column = klass.hypertable_options[:time_column]
|
393
|
+
|
394
|
+
if klass.try(:hypertable).present?
|
395
|
+
ApplicationRecord.logger.info "hypertable already created for '#{table_name}', skipping."
|
396
|
+
next
|
284
397
|
end
|
398
|
+
|
399
|
+
ApplicationRecord.connection.execute <<~SQL
|
400
|
+
SELECT create_hypertable('#{table_name}', '#{time_column.to_s}')
|
401
|
+
SQL
|
285
402
|
end
|
403
|
+
end
|
286
404
|
```
|
287
405
|
|
288
406
|
## Development
|
289
407
|
|
290
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then,
|
408
|
+
After checking out the repo, run `bin/setup` to install the development dependencies. Then, `bundle exec rake test:setup` to setup the test database and tables. Finally, run `bundle exec rake` to run the tests.
|
409
|
+
|
410
|
+
You can also run `tsdb` for an interactive prompt that will allow you to experiment.
|
291
411
|
|
292
412
|
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).
|
293
413
|
|
414
|
+
You can create a `.env` file locally to run tests locally. Make sure to put your
|
415
|
+
own credentials there!
|
416
|
+
|
417
|
+
```bash
|
418
|
+
PG_URI_TEST="postgres://<user>@localhost:5432/<dbname>"
|
419
|
+
```
|
420
|
+
|
421
|
+
You can put some postgres URI directly as a parameter of
|
422
|
+
`tsdb`. Here is an example from the console:
|
423
|
+
|
424
|
+
```bash
|
425
|
+
tsdb "postgres://jonatasdp@localhost:5432/timescaledb_test"
|
426
|
+
```
|
427
|
+
|
428
|
+
## More resources
|
429
|
+
|
430
|
+
This library was started on [twitch.tv/timescaledb](https://twitch.tv/timescaledb).
|
431
|
+
You can watch all episodes here:
|
432
|
+
|
433
|
+
1. [Wrapping Functions to Ruby Helpers](https://www.youtube.com/watch?v=hGPsUxLFAYk).
|
434
|
+
2. [Extending ActiveRecord with Timescale Helpers](https://www.youtube.com/watch?v=IEyJIHk1Clk).
|
435
|
+
3. [Setup Hypertables for Rails testing environment](https://www.youtube.com/watch?v=wM6hVrZe7xA).
|
436
|
+
4. [Packing the code to this repository](https://www.youtube.com/watch?v=CMdGAl_XlL4).
|
437
|
+
4. [the code to this repository](https://www.youtube.com/watch?v=CMdGAl_XlL4).
|
438
|
+
5. [Working with Timescale continuous aggregates](https://youtu.be/co4HnBkHzVw).
|
439
|
+
6. [Creating the command-line application in Ruby to explore the Timescale API](https://www.youtube.com/watch?v=I3vM_q2m7T0).
|
440
|
+
|
294
441
|
### TODO
|
295
442
|
|
296
443
|
Here is a list of functions that would be great to have:
|
297
444
|
|
298
445
|
- [ ] Dump and Restore Timescale metadata - Like db/schema.rb but for Timescale configuration.
|
299
446
|
- [ ] Add data nodes support
|
300
|
-
- [ ] Implement the `timescale` CLI to explore the full API.
|
301
447
|
|
302
448
|
## Contributing
|
303
449
|
|
data/Rakefile
CHANGED
@@ -1,6 +1,21 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
require "rspec/core/rake_task"
|
3
3
|
|
4
|
+
begin
|
5
|
+
require "gemika/tasks"
|
6
|
+
rescue LoadError
|
7
|
+
puts "Run `gem install gemika` for additional tasks"
|
8
|
+
end
|
9
|
+
|
4
10
|
RSpec::Core::RakeTask.new(:spec)
|
5
11
|
|
6
|
-
task :
|
12
|
+
task default: "matrix:spec"
|
13
|
+
|
14
|
+
namespace :test do
|
15
|
+
task :setup do
|
16
|
+
require_relative "spec/spec_helper"
|
17
|
+
|
18
|
+
teardown_tables
|
19
|
+
setup_tables
|
20
|
+
end
|
21
|
+
end
|
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/setup
CHANGED
data/bin/tsdb
CHANGED
@@ -1,24 +1,48 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require "bundler/setup"
|
3
3
|
require "timescale"
|
4
|
+
require "pry"
|
4
5
|
|
5
6
|
ActiveRecord::Base.establish_connection(ARGV[0])
|
6
7
|
|
7
|
-
|
8
|
+
Timescaledb::Hypertable.find_each do |hypertable|
|
8
9
|
class_name = hypertable.hypertable_name.singularize.camelize
|
9
10
|
model = Class.new(ActiveRecord::Base) do
|
10
11
|
self.table_name = hypertable.hypertable_name
|
11
|
-
|
12
|
-
include Timescale::HypertableHelpers
|
12
|
+
acts_as_hypertable
|
13
13
|
end
|
14
|
-
|
14
|
+
Timescaledb.const_set(class_name, model)
|
15
|
+
end
|
16
|
+
|
17
|
+
Timescaledb::ContinuousAggregates.find_each do |cagg|
|
18
|
+
class_name = cagg.view_name.singularize.camelize
|
19
|
+
model = Class.new(ActiveRecord::Base) do
|
20
|
+
self.table_name = cagg.view_name
|
21
|
+
acts_as_hypertable
|
22
|
+
end
|
23
|
+
Timescaledb.const_set(class_name, model)
|
24
|
+
end
|
25
|
+
|
26
|
+
def show(obj)
|
27
|
+
Pry::ColorPrinter.pp(obj)
|
15
28
|
end
|
16
29
|
|
17
30
|
if ARGV.index("--stats")
|
18
|
-
|
31
|
+
scope = Timescaledb::Hypertable.all
|
32
|
+
|
33
|
+
if (only = ARGV.index("--only"))
|
34
|
+
only_hypertables = ARGV[only+1].split(",")
|
35
|
+
scope = scope.where({hypertable_name: only_hypertables})
|
36
|
+
end
|
37
|
+
|
38
|
+
if (except = ARGV.index("--except"))
|
39
|
+
except_hypertables = ARGV[except+1].split(",")
|
40
|
+
scope = scope.where.not(hypertable_name: except_hypertables)
|
41
|
+
end
|
42
|
+
|
43
|
+
show(Timescaledb.stats(scope))
|
19
44
|
end
|
20
45
|
|
21
46
|
if ARGV.index("--console")
|
22
|
-
require "pry"
|
23
47
|
Pry.start(Timescale)
|
24
48
|
end
|
@@ -2,16 +2,13 @@ require 'bundler/setup'
|
|
2
2
|
require 'timescale'
|
3
3
|
require 'pp'
|
4
4
|
require 'pry'
|
5
|
-
|
6
|
-
|
7
|
-
# set PG_URI=postgres://user:pass@host:port/db_name
|
8
|
-
ActiveRecord::Base.establish_connection(ENV['PG_URI_TEST'])
|
5
|
+
# ruby all_in_one.rb postgres://user:pass@host:port/db_name
|
6
|
+
ActiveRecord::Base.establish_connection( ARGV.last)
|
9
7
|
|
10
8
|
# Simple example
|
11
9
|
class Event < ActiveRecord::Base
|
12
10
|
self.primary_key = "identifier"
|
13
|
-
|
14
|
-
include Timescale::HypertableHelpers
|
11
|
+
acts_as_hypertable
|
15
12
|
end
|
16
13
|
|
17
14
|
# Setup Hypertable as in a migration
|