timescaledb 0.1.3 → 0.1.4

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: 91dfb6aac43ec8ab347ac9cf1bc553631310259cd4f6726c42f466c08f74c761
4
- data.tar.gz: 4436ff5f2067264fc814592efebaa9ce32d69ece7607e7d728a95356db04f739
3
+ metadata.gz: c64be262fa0fbecf13ec6b6b8820b471c9d83e6842306efc59b950a693d4755b
4
+ data.tar.gz: d702011692906410bd38107d16f9f20801977deb8f4a0cc3372dc5f61aed29ae
5
5
  SHA512:
6
- metadata.gz: 71492adbe4cd1771db48b2b796affa50d3f3157b420f59482e61d4a76dfc8fcec52f5face66047fc8069f5bcdd35bace4c8ff4e0fec88ffe1331872b3d625862
7
- data.tar.gz: 4ecf26d66361af9d79cf33f99b9a25b8233df229a0ffa6ac33afe54d4f4c4d03e6c13609c60cceabc95dc30d8e49f7343588174fb0715bda044942360ebed53b
6
+ metadata.gz: bc45bab9ddc1e32c1630bb4258299ee1a74b5b7991eb9281332d7de77161e4ad76cedb0cc2ddb30dbf609b68607a2cf0d7799c11130348bda94974fd46d152c1
7
+ data.tar.gz: 4b6e7da46622c902fc1960fcba1b4d41b4674a8490eef2025f835b767efd3838573befffaed7fffceb65de5e65c793453d3eacfc681a1846f13ba2b485897ce6
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- timescaledb (0.1.2)
4
+ timescaledb (0.1.4)
5
5
  activerecord
6
6
  pg (~> 1.2)
7
7
 
@@ -21,6 +21,10 @@ GEM
21
21
  zeitwerk (~> 2.3)
22
22
  coderay (1.1.3)
23
23
  concurrent-ruby (1.1.9)
24
+ database_cleaner-active_record (2.0.1)
25
+ activerecord (>= 5.a)
26
+ database_cleaner-core (~> 2.0.0)
27
+ database_cleaner-core (2.0.1)
24
28
  diff-lcs (1.4.4)
25
29
  dotenv (2.7.6)
26
30
  i18n (1.8.10)
@@ -56,6 +60,7 @@ PLATFORMS
56
60
  ruby
57
61
 
58
62
  DEPENDENCIES
63
+ database_cleaner-active_record
59
64
  dotenv
60
65
  pry
61
66
  rake (~> 12.0)
data/README.md CHANGED
@@ -290,132 +290,107 @@ options = {
290
290
  create_continuous_aggregates('ohlc_1m', query, **options)
291
291
  ```
292
292
 
293
- ### Hypertable Helpers
293
+ ### Enable ActsAsHypertable
294
294
 
295
- You can say `acts_as_hypertable` to get access to some basic scopes for your
295
+ 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.
296
296
  model:
297
297
 
298
298
  ```ruby
299
299
  class Event < ActiveRecord::Base
300
- self.primary_key = "identifier"
301
-
302
300
  acts_as_hypertable
303
301
  end
304
302
  ```
305
303
 
306
- After including the helpers, several methods from timescaledb will be available in the
307
- model.
304
+ By default, ActsAsHypertable assumes a record's _time_column_ is called `created_at`.
308
305
 
309
- ### Chunks
306
+ ### Options
310
307
 
311
- To get chunks from a single hypertable, you can use the `.chunks` directly from
312
- the model name.
308
+ If you are using a different time_column name, you can specify it as follows when invoking the `acts_as_hypertable` macro:
313
309
 
314
310
  ```ruby
315
- Event.chunks
316
- # DEBUG: Timescale::Chunk Load (9.0ms) SELECT "timescaledb_information"."chunks".* FROM "timescaledb_information"."chunks" WHERE "timescaledb_information"."chunks"."hypertable_name" = $1 [["hypertable_name", "events"]]
317
- # => [#<Timescale::Chunk:0x00007f94b0c86008
318
- # hypertable_schema: "public",
319
- # hypertable_name: "events",
320
- # chunk_schema: "_timescaledb_internal",
321
- # chunk_name: "_hyper_180_74_chunk",
322
- # primary_dimension: "created_at",
323
- # primary_dimension_type: "timestamp without time zone",
324
- # range_start: 2021-09-22 21:28:00 +0000,
325
- # range_end: 2021-09-22 21:29:00 +0000,
326
- # range_start_integer: nil,
327
- # range_end_integer: nil,
328
- # is_compressed: false,
329
- # chunk_tablespace: nil,
330
- # data_nodes: nil>
311
+ class Event < ActiveRecord::Base
312
+ acts_as_hypertable time_column: :timestamp
313
+ end
331
314
  ```
332
315
 
333
- To get all hypertables you can use `Timescale.hypertables` method.
316
+ ### Chunks
317
+
318
+ To get all the chunks from a model's hypertable, you can use `.chunks`.
334
319
 
335
- ### Hypertable metadata from model
320
+ ```ruby
321
+ Event.chunks # => [#<Timescale::Chunk>, ...]
322
+ ```
336
323
 
337
- To get all details from hypertable, you can access the `.hypertable` from the
338
- model.
324
+ ### Hypertable metadata
325
+
326
+ To get the models' hypertable metadata, you can use `.hypertable`.
339
327
 
340
328
  ```ruby
341
- Event.hypertable
342
- # 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]]
343
- # => #<Timescale::Hypertable:0x00007f94c3151cd8
344
- # hypertable_schema: "public",
345
- # hypertable_name: "events",
346
- # owner: "jonatasdp",
347
- # num_dimensions: 1,
348
- # num_chunks: 1,
349
- # compression_enabled: true,
350
- # is_distributed: false,
351
- # replication_factor: nil,
352
- # data_nodes: nil,
353
- # tablespaces: nil>
329
+ Event.hypertable # => #<Timescale::Hypertable>
354
330
  ```
355
331
 
356
- You can also use `Timescale.hypertables` to have access of all hypertables
357
- metadata.
332
+ To get hypertable metadata for all hypertables: `Timescale.hypertables`.
358
333
 
359
334
  ### Compression Settings
360
335
 
361
336
  Compression settings are accessible through the hypertable.
362
337
 
363
338
  ```ruby
364
- Event.hypertable.compression_settings
365
- # 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]]
366
- # 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"]]
367
- # => [#<Timescale::CompressionSettings:0x00007f94b0bf7010
368
- # hypertable_schema: "public",
369
- # hypertable_name: "events",
370
- # attname: "identifier",
371
- # segmentby_column_index: 1,
372
- # orderby_column_index: nil,
373
- # orderby_asc: nil,
374
- # orderby_nullsfirst: nil>,
375
- # #<Timescale::CompressionSettings:0x00007f94b0c3e460
376
- # hypertable_schema: "public",
377
- # hypertable_name: "events",
378
- # attname: "created_at",
379
- # segmentby_column_index: nil,
380
- # orderby_column_index: 1,
381
- # orderby_asc: true,
382
- # orderby_nullsfirst: false>]
339
+ Event.hypertable.compression_settings # => [#<Timescale::CompressionSettings>, ...]
383
340
  ```
384
341
 
385
- It's also possible to access all data calling `Timescale.compression_settings`.
342
+ To get compression settings for all hypertables: `Timescale.compression_settings`.
386
343
 
387
- ### RSpec Hooks
344
+ ### Scopes
388
345
 
389
- In case you want to use TimescaleDB on a Rails environment, you may have some
390
- issues as the schema dump used for tests is not considering hypertables
391
- metadata.
346
+ When you enable ActsAsHypertable on your model, we include a couple default scopes. They are:
392
347
 
393
- If you add the `acts_as_hypertable` to your model, you can dynamically
394
- verify if the `Timescale::ActsAsHypertable` module is included to
395
- create the hypertable for testing environment.
348
+ | Scope name | What they return |
349
+ |------------------------|---------------------------------------|
350
+ | `Model.previous_month` | Records created in the previous month |
351
+ | `Model.previous_week` | Records created in the previous week |
352
+ | `Model.this_month` | Records created this month |
353
+ | `Model.this_week` | Records created this week |
354
+ | `Model.yesterday` | Records created yesterday |
355
+ | `Model.today` | Records created today |
356
+ | `Model.last_hour` | Records created in the last hour |
396
357
 
397
- Consider adding this hook to your `spec/rspec_helper.rb` file:
358
+ All time-related scopes respect your application's timezone.
359
+
360
+ ## RSpec Hooks
361
+
362
+ In case you want to use TimescaleDB on a Rails environment, you may have some
363
+ issues as the schema dump used for tests does not consider hypertables metadata.
364
+
365
+ As a work around, you can dynamically create the hypertables yourself for
366
+ testing environments using the following hook which you can
367
+ define in `spec/rspec_helper.rb`:
398
368
 
399
369
  ```ruby
400
- config.before(:suite) do
401
- hypertable_models = ApplicationRecord
402
- .descendants
403
- .select{|clazz| clazz.included_modules.include?(Timescale::ActsAsHypertable)
404
- hypertable_models.each do |clazz|
405
- if clazz.hypertable.exists?
406
- ApplicationRecord.logger.info "skip recreating hypertable for '#{clazz.table_name}'."
407
- next
408
- end
409
- ApplicationRecord.connection.execute <<~SQL
410
- SELECT create_hypertable('#{clazz.table_name}', 'created_at')
411
- SQL
370
+ config.before(:suite) do
371
+ hypertable_models = ActiveRecord::Base.descendants.select(&:acts_as_hypertable?)
372
+
373
+ hypertable_models.each do |klass|
374
+ table_name = klass.table_name
375
+ time_column = klass.hypertable_options[:time_column]
376
+
377
+ if klass.try(:hypertable).present?
378
+ ApplicationRecord.logger.info "hypertable already created for '#{table_name}', skipping."
379
+ next
412
380
  end
381
+
382
+ ApplicationRecord.connection.execute <<~SQL
383
+ SELECT create_hypertable('#{table_name}', '#{time_column.to_s}')
384
+ SQL
413
385
  end
386
+ end
414
387
  ```
415
388
 
416
389
  ## Development
417
390
 
418
- 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.
391
+ 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 rspec` to run the tests.
392
+
393
+ You can also run `tsdb` for an interactive prompt that will allow you to experiment.
419
394
 
420
395
  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).
421
396
 
data/Rakefile CHANGED
@@ -3,4 +3,13 @@ require "rspec/core/rake_task"
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => :spec
6
+ task default: :spec
7
+
8
+ namespace :test do
9
+ task :setup do
10
+ require_relative "spec/spec_helper"
11
+
12
+ teardown_tables
13
+ setup_tables
14
+ end
15
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Timescale
4
+ module ActsAsHypertable
5
+ module Core
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ def time_column
12
+ @time_column ||= hypertable_options[:time_column] || :created_at
13
+ end
14
+
15
+ protected
16
+
17
+ def define_association_scopes
18
+ scope :chunks, -> do
19
+ Chunk.where(hypertable_name: table_name)
20
+ end
21
+
22
+ scope :hypertable, -> do
23
+ Hypertable.find_by(hypertable_name: table_name)
24
+ end
25
+
26
+ scope :jobs, -> do
27
+ Job.where(hypertable_name: table_name)
28
+ end
29
+
30
+ scope :job_stats, -> do
31
+ JobStats.where(hypertable_name: table_name)
32
+ end
33
+
34
+ scope :compression_settings, -> do
35
+ CompressionSettings.where(hypertable_name: table_name)
36
+ end
37
+
38
+ scope :continuous_aggregates, -> do
39
+ ContinuousAggregates.where(hypertable_name: table_name)
40
+ end
41
+ end
42
+
43
+ def define_default_scopes
44
+ scope :previous_month, -> do
45
+ where(
46
+ "DATE(#{time_column}) >= :start_time AND DATE(#{time_column}) <= :end_time",
47
+ start_time: Date.today.last_month.in_time_zone.beginning_of_month.to_date,
48
+ end_time: Date.today.last_month.in_time_zone.end_of_month.to_date
49
+ )
50
+ end
51
+
52
+ scope :previous_week, -> do
53
+ where(
54
+ "DATE(#{time_column}) >= :start_time AND DATE(#{time_column}) <= :end_time",
55
+ start_time: Date.today.last_week.in_time_zone.beginning_of_week.to_date,
56
+ end_time: Date.today.last_week.in_time_zone.end_of_week.to_date
57
+ )
58
+ end
59
+
60
+ scope :this_month, -> do
61
+ where(
62
+ "DATE(#{time_column}) >= :start_time AND DATE(#{time_column}) <= :end_time",
63
+ start_time: Date.today.in_time_zone.beginning_of_month.to_date,
64
+ end_time: Date.today.in_time_zone.end_of_month.to_date
65
+ )
66
+ end
67
+
68
+ scope :this_week, -> do
69
+ where(
70
+ "DATE(#{time_column}) >= :start_time AND DATE(#{time_column}) <= :end_time",
71
+ start_time: Date.today.in_time_zone.beginning_of_week.to_date,
72
+ end_time: Date.today.in_time_zone.end_of_week.to_date
73
+ )
74
+ end
75
+
76
+ scope :yesterday, -> { where("DATE(#{time_column}) = ?", Date.yesterday.in_time_zone.to_date) }
77
+ scope :today, -> { where("DATE(#{time_column}) = ?", Date.today.in_time_zone.to_date) }
78
+ scope :last_hour, -> { where("#{time_column} > ?", 1.hour.ago.in_time_zone) }
79
+ end
80
+
81
+ def normalize_hypertable_options
82
+ hypertable_options[:time_column] = hypertable_options[:time_column].to_sym
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -18,97 +18,45 @@ module Timescale
18
18
  # acts_as_hypertable
19
19
  # end
20
20
  #
21
- # @see Timescale::ActsAsHypertable::ClassMethods#acts_as_hypertable
21
+ # @see Timescale::ActsAsHypertable#acts_as_hypertable
22
22
  # for configuration options
23
23
  module ActsAsHypertable
24
- extend ActiveSupport::Concern
25
-
26
24
  DEFAULT_OPTIONS = {
27
25
  time_column: :created_at
28
26
  }.freeze
29
27
 
30
- module ClassMethods
31
- # == Configuration options
32
- #
33
- # @param [Hash] options The options to initialize your macro with.
34
- # @option options [Symbol] :time_column The name of the column in your
35
- # model's table containing time values. The name provided should be
36
- # the same name as the `time_column_name` you passed to the
37
- # TimescaleDB `create_hypertable` function.
38
- #
39
- # @example Enabling the macro on your model with options
40
- # class Event < ActiveRecord::Base
41
- # acts_as_hypertable time_column: :timestamp
42
- # end
43
- #
44
- def acts_as_hypertable(options = {})
45
- return if already_declared_as_hypertable?
46
-
47
- extend Timescale::ActsAsHypertable::HypertableClassMethods
48
-
49
- class_attribute :hypertable_options, instance_writer: false
50
-
51
- self.hypertable_options = DEFAULT_OPTIONS.dup
52
- hypertable_options.merge!(options)
53
- normalize_hypertable_options
54
-
55
- define_association_scopes
56
- define_default_scopes
57
- end
58
-
59
- def define_association_scopes
60
- scope :chunks, -> do
61
- Chunk.where(hypertable_name: table_name)
62
- end
63
-
64
- scope :hypertable, -> do
65
- Hypertable.find_by(hypertable_name: table_name)
66
- end
67
-
68
- scope :jobs, -> do
69
- Job.where(hypertable_name: table_name)
70
- end
71
-
72
- scope :job_stats, -> do
73
- JobStats.where(hypertable_name: table_name)
74
- end
75
-
76
- scope :compression_settings, -> do
77
- CompressionSettings.where(hypertable_name: table_name)
78
- end
79
-
80
- scope :continuous_aggregates, -> do
81
- ContinuousAggregates.where(hypertable_name: table_name)
82
- end
83
- end
84
-
85
- def define_default_scopes
86
- scope :last_month, -> { where("#{time_column} > ?", 1.month.ago) }
87
- scope :last_week, -> { where("#{time_column} > ?", 1.week.ago) }
88
- scope :last_hour, -> { where("#{time_column} > ?", 1.hour.ago) }
89
- scope :yesterday, -> { where("#{time_column} = ?", 1.day.ago.to_date) }
90
- scope :today, -> { where("#{time_column} = ?", Date.today) }
91
- end
92
-
93
- private
94
-
95
- def already_declared_as_hypertable?
96
- singleton_class
97
- .included_modules
98
- .include?(Timescale::ActsAsHypertable::HypertableClassMethods)
99
- end
28
+ def acts_as_hypertable?
29
+ included_modules.include?(Timescale::ActsAsHypertable::Core)
100
30
  end
101
31
 
102
- module HypertableClassMethods
103
- def time_column
104
- @hypertable_time_column ||= hypertable_options[:time_column] || :created_at
105
- end
106
-
107
- protected
108
-
109
- def normalize_hypertable_options
110
- hypertable_options[:time_column] = hypertable_options[:time_column].to_sym
111
- end
32
+ # == Configuration options
33
+ #
34
+ # @param [Hash] options The options to initialize your macro with.
35
+ # @option options [Symbol] :time_column The name of the column in your
36
+ # model's table containing time values. The name provided should be
37
+ # the same name as the `time_column_name` you passed to the
38
+ # TimescaleDB `create_hypertable` function.
39
+ #
40
+ # @example Enabling the macro on your model with options
41
+ # class Event < ActiveRecord::Base
42
+ # acts_as_hypertable time_column: :timestamp
43
+ # end
44
+ #
45
+ def acts_as_hypertable(options = {})
46
+ return if acts_as_hypertable?
47
+
48
+ include Timescale::ActsAsHypertable::Core
49
+
50
+ class_attribute :hypertable_options, instance_writer: false
51
+
52
+ self.hypertable_options = DEFAULT_OPTIONS.dup
53
+ hypertable_options.merge!(options)
54
+ normalize_hypertable_options
55
+
56
+ define_association_scopes
57
+ define_default_scopes
112
58
  end
113
59
  end
114
60
  end
61
+
62
+ ActiveRecord::Base.extend Timescale::ActsAsHypertable
@@ -1,3 +1,3 @@
1
1
  module Timescale
2
- VERSION = '0.1.3'
2
+ VERSION = '0.1.4'
3
3
  end
data/lib/timescale.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'active_record'
2
2
 
3
3
  require_relative 'timescale/acts_as_hypertable'
4
+ require_relative 'timescale/acts_as_hypertable/core'
4
5
  require_relative 'timescale/chunk'
5
6
  require_relative 'timescale/compression_settings'
6
7
  require_relative 'timescale/continuous_aggregates'
@@ -47,7 +48,3 @@ module Timescale
47
48
  Timescale::ActsAsHypertable::DEFAULT_OPTIONS
48
49
  end
49
50
  end
50
-
51
- ActiveSupport.on_load :active_record do
52
- include Timescale::ActsAsHypertable
53
- end
data/timescale.gemspec CHANGED
@@ -35,4 +35,5 @@ Gem::Specification.new do |spec|
35
35
  spec.add_development_dependency "rspec", "~> 3.0"
36
36
  spec.add_development_dependency "dotenv"
37
37
  spec.add_development_dependency "rake", "~> 12.0"
38
+ spec.add_development_dependency "database_cleaner-active_record"
38
39
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timescaledb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jônatas Davi Paganini
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-07 00:00:00.000000000 Z
11
+ date: 2021-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pg
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: '12.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: database_cleaner-active_record
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  description: Functions from timescaledb available in the ActiveRecord models.
112
126
  email:
113
127
  - jonatasdp@gmail.com
@@ -133,6 +147,7 @@ files:
133
147
  - examples/all_in_one.rb
134
148
  - lib/timescale.rb
135
149
  - lib/timescale/acts_as_hypertable.rb
150
+ - lib/timescale/acts_as_hypertable/core.rb
136
151
  - lib/timescale/chunk.rb
137
152
  - lib/timescale/compression_settings.rb
138
153
  - lib/timescale/continuous_aggregates.rb