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.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -0
  3. data/.tool-versions +1 -0
  4. data/.travis.yml +3 -0
  5. data/Gemfile +4 -0
  6. data/Gemfile.lock +11 -3
  7. data/Gemfile.scenic +7 -0
  8. data/Gemfile.scenic.lock +121 -0
  9. data/README.md +267 -121
  10. data/Rakefile +16 -1
  11. data/bin/console +2 -2
  12. data/bin/setup +2 -0
  13. data/bin/tsdb +30 -6
  14. data/examples/{Gemfile → all_in_one/Gemfile} +1 -1
  15. data/examples/{Gemfile.lock → all_in_one/Gemfile.lock} +2 -2
  16. data/examples/{all_in_one.rb → all_in_one/all_in_one.rb} +3 -6
  17. data/examples/ranking/.gitattributes +7 -0
  18. data/examples/ranking/.gitignore +29 -0
  19. data/examples/ranking/.ruby-version +1 -0
  20. data/examples/ranking/Gemfile +33 -0
  21. data/examples/ranking/Gemfile.lock +189 -0
  22. data/examples/ranking/README.md +166 -0
  23. data/examples/ranking/Rakefile +6 -0
  24. data/examples/ranking/app/controllers/application_controller.rb +2 -0
  25. data/examples/ranking/app/controllers/concerns/.keep +0 -0
  26. data/examples/ranking/app/jobs/application_job.rb +7 -0
  27. data/examples/ranking/app/models/application_record.rb +3 -0
  28. data/examples/ranking/app/models/concerns/.keep +0 -0
  29. data/examples/ranking/app/models/game.rb +2 -0
  30. data/examples/ranking/app/models/play.rb +7 -0
  31. data/examples/ranking/bin/bundle +114 -0
  32. data/examples/ranking/bin/rails +4 -0
  33. data/examples/ranking/bin/rake +4 -0
  34. data/examples/ranking/bin/setup +33 -0
  35. data/examples/ranking/config/application.rb +39 -0
  36. data/examples/ranking/config/boot.rb +4 -0
  37. data/examples/ranking/config/credentials.yml.enc +1 -0
  38. data/examples/ranking/config/database.yml +86 -0
  39. data/examples/ranking/config/environment.rb +5 -0
  40. data/examples/ranking/config/environments/development.rb +60 -0
  41. data/examples/ranking/config/environments/production.rb +75 -0
  42. data/examples/ranking/config/environments/test.rb +53 -0
  43. data/examples/ranking/config/initializers/cors.rb +16 -0
  44. data/examples/ranking/config/initializers/filter_parameter_logging.rb +8 -0
  45. data/examples/ranking/config/initializers/inflections.rb +16 -0
  46. data/examples/ranking/config/initializers/timescale.rb +3 -0
  47. data/examples/ranking/config/locales/en.yml +33 -0
  48. data/examples/ranking/config/puma.rb +43 -0
  49. data/examples/ranking/config/routes.rb +6 -0
  50. data/examples/ranking/config/storage.yml +34 -0
  51. data/examples/ranking/config.ru +6 -0
  52. data/examples/ranking/db/migrate/20220209120747_create_games.rb +10 -0
  53. data/examples/ranking/db/migrate/20220209120910_create_plays.rb +19 -0
  54. data/examples/ranking/db/migrate/20220209143347_create_score_per_hours.rb +5 -0
  55. data/examples/ranking/db/schema.rb +47 -0
  56. data/examples/ranking/db/seeds.rb +7 -0
  57. data/examples/ranking/db/views/score_per_hours_v01.sql +7 -0
  58. data/examples/ranking/lib/tasks/.keep +0 -0
  59. data/examples/ranking/log/.keep +0 -0
  60. data/examples/ranking/public/robots.txt +1 -0
  61. data/examples/ranking/storage/.keep +0 -0
  62. data/examples/ranking/tmp/.keep +0 -0
  63. data/examples/ranking/tmp/pids/.keep +0 -0
  64. data/examples/ranking/tmp/storage/.keep +0 -0
  65. data/examples/ranking/vendor/.keep +0 -0
  66. data/lib/timescaledb/acts_as_hypertable/core.rb +87 -0
  67. data/lib/timescaledb/acts_as_hypertable.rb +62 -0
  68. data/lib/{timescale → timescaledb}/chunk.rb +9 -1
  69. data/lib/{timescale → timescaledb}/compression_settings.rb +3 -2
  70. data/lib/timescaledb/continuous_aggregates.rb +19 -0
  71. data/lib/timescaledb/dimensions.rb +6 -0
  72. data/lib/{timescale → timescaledb}/hypertable.rb +9 -5
  73. data/lib/timescaledb/job.rb +10 -0
  74. data/lib/{timescale → timescaledb}/job_stats.rb +3 -4
  75. data/lib/{timescale → timescaledb}/migration_helpers.rb +35 -5
  76. data/lib/timescaledb/scenic/adapter.rb +55 -0
  77. data/lib/timescaledb/scenic/extension.rb +72 -0
  78. data/lib/timescaledb/schema_dumper.rb +88 -0
  79. data/lib/timescaledb/stats_report.rb +35 -0
  80. data/lib/timescaledb/version.rb +3 -0
  81. data/lib/timescaledb.rb +64 -0
  82. data/{timescale.gemspec → timescaledb.gemspec} +6 -4
  83. metadata +106 -20
  84. data/lib/timescale/acts_as_hypertable.rb +0 -114
  85. data/lib/timescale/continuous_aggregates.rb +0 -9
  86. data/lib/timescale/job.rb +0 -13
  87. data/lib/timescale/stats_report.rb +0 -28
  88. data/lib/timescale/version.rb +0 -3
  89. data/lib/timescale.rb +0 -52
data/README.md CHANGED
@@ -1,48 +1,38 @@
1
- # Timescale
1
+ # TimescaleDB
2
2
 
3
- Welcome to the Timescale gem! To experiment with the code, start cloning the
4
- repository:
3
+ Welcome to the TimescaleDB gem! To experiment with the code, start installing the
4
+ gem:
5
5
 
6
6
  ```bash
7
- git clone https://github.com/jonatas/timescale.git
8
- cd timescale
9
- bundle install
10
- rake install
7
+ gem install timescaledb
11
8
  ```
12
9
 
13
- Then, with `rake install` or installing the gem in your computer, you can run `tsdb` for an interactive prompt.
10
+ ## The `tsdb` CLI
14
11
 
15
- ```bash
16
- tsdb postgres://<user>@localhost:5432/<dbname> --stats --flags
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
- You can create a `.env` file locally to run tests locally. Make sure to put your
20
- own credentials there!
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
- PG_URI_TEST="postgres://<user>@localhost:5432/<dbname>"
19
+ tsdb <uri> --stats
24
20
  ```
25
21
 
26
- You can put some postgres URI directly as a parameter of
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 "postgres://jonatasdp@localhost:5432/timescale_test"
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/timescale_test" --stats
32
+ tsdb "postgres://jonatasdp@localhost:5432/timescaledb_test" --stats
43
33
  ```
44
34
 
45
- These is a sample output from an almost empty database:
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
- It will allow you to visit any database and have all models mapped as ActiveRecord
61
- with the [HypertableHelpers](lib/timescale/hypertable_helpers.rb).
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
- 1. [Wrapping Functions to Ruby Helpers](https://www.youtube.com/watch?v=hGPsUxLFAYk).
67
- 2. [Extending ActiveRecord with Timescale Helpers](https://www.youtube.com/watch?v=IEyJIHk1Clk).
68
- 3. [Setup Hypertables for Rails testing environment](https://www.youtube.com/watch?v=wM6hVrZe7xA).
69
- 4. [Packing the code to this repository](https://www.youtube.com/watch?v=CMdGAl_XlL4).
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
- You can check the [all_in_one.rb](examples/all_in_one.rb) that will:
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 from HypertableHelpers
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
- #### create_continuous_aggregates
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
- include Timescale::HypertableHelpers
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
- create_continuous_aggregates('ohlc_1m', query, **options)
297
+ create_continuous_aggregate('ohlc_1m', query, **options)
166
298
  ```
167
299
 
168
- ### Hypertable Helpers
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
- You can also use `HypertableHelpers` to get access to some basic scopes for your
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
- self.primary_key = "identifier"
176
-
177
- include Timescale::HypertableHelpers
317
+ acts_as_hypertable
178
318
  end
179
319
  ```
180
320
 
181
- After including the helpers, several methods from timescaledb will be available in the
182
- model.
321
+ By default, ActsAsHypertable assumes a record's _time_column_ is called `created_at`.
183
322
 
184
- ### Chunks
323
+ ### Options
185
324
 
186
- To get chunks from a single hypertable, you can use the `.chunks` directly from
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.chunks
191
- # DEBUG: Timescale::Chunk Load (9.0ms) SELECT "timescaledb_information"."chunks".* FROM "timescaledb_information"."chunks" WHERE "timescaledb_information"."chunks"."hypertable_name" = $1 [["hypertable_name", "events"]]
192
- # => [#<Timescale::Chunk:0x00007f94b0c86008
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
- To get all hypertables you can use `Timescale.hypertables` method.
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 from model
341
+ ### Hypertable metadata
211
342
 
212
- To get all details from hypertable, you can access the `.hypertable` from the
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
- You can also use `Timescale.hypertables` to have access of all hypertables
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
- It's also possible to access all data calling `Timescale.compression_settings`.
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
- ### RSpec Hooks
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 is not considering hypertables
266
- metadata.
380
+ issues as the schema dump used for tests does not consider hypertables metadata.
267
381
 
268
- If you add the `Timescale::HypertableHelpers` to your model, you can dynamically
269
- create the hypertable adding this hook to your `spec/rspec_helper.rb` file:
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
- config.before(:suite) do
273
- hypertable_models = ApplicationRecord
274
- .descendants
275
- .select{|clazz| clazz.ancestors.include?( Timescale::HypertableHelpers)}
276
- hypertable_models.each do |clazz|
277
- if clazz.hypertable.exists?
278
- ApplicationRecord.logger.info "skip recreating hypertable for '#{clazz.table_name}'."
279
- next
280
- end
281
- ApplicationRecord.connection.execute <<~SQL
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, run `rake spec` to run the tests. You can also run `tsdb` for an interactive prompt that will allow you to experiment.
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 :default => :spec
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
- Timescale::Hypertable.find_each do |hypertable|
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
- Timescale.const_set(class_name, model)
24
+ Timescaledb.const_set(class_name, model)
25
25
  end
26
26
 
27
27
  require "pry"
data/bin/setup CHANGED
@@ -7,5 +7,7 @@ set -vx
7
7
 
8
8
  bundle install
9
9
 
10
+ bundle install --gemfile Gemfile.scenic
11
+
10
12
  # For running tests it's going to use PG_URI_TEST env variable.
11
13
  # Please make sure you set it properly to a TEST database!"
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
- Timescale::Hypertable.find_each do |hypertable|
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
- self.primary_key = self.column_names.first
12
- include Timescale::HypertableHelpers
12
+ acts_as_hypertable
13
13
  end
14
- Timescale.const_set(class_name, model)
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
- pp Timescale.show_stats
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
@@ -1,7 +1,7 @@
1
1
 
2
2
  source 'https://rubygems.org'
3
3
 
4
- gem "timescale", path: "../"
4
+ gem "timescaledb", path: "../"
5
5
  gem "pg"
6
6
  gem "activerecord"
7
7
  gem "composite_primary_keys", "~> 6.0"
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- timescale (0.1.0)
4
+ timescaledb (0.1.2)
5
5
  activerecord
6
6
  pg (~> 1.2)
7
7
 
@@ -45,7 +45,7 @@ DEPENDENCIES
45
45
  dotenv (~> 2.7)
46
46
  pg
47
47
  pry
48
- timescale!
48
+ timescaledb!
49
49
 
50
50
  BUNDLED WITH
51
51
  2.1.4
@@ -2,16 +2,13 @@ require 'bundler/setup'
2
2
  require 'timescale'
3
3
  require 'pp'
4
4
  require 'pry'
5
- require 'dotenv'
6
- Dotenv.load!
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
@@ -0,0 +1,7 @@
1
+ # See https://git-scm.com/docs/gitattributes for more about git attribute files.
2
+
3
+ # Mark the database schema as having been generated.
4
+ db/schema.rb linguist-generated
5
+
6
+ # Mark any vendored files as having been vendored.
7
+ vendor/* linguist-vendored