timescaledb 0.1.0 → 0.1.2

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: d2088f631818f19cc92ea997dea0fe5a929263c5100abb3e4c640a52de0a1c94
4
- data.tar.gz: 111d3b028355623ff1b4954491c3e4a9d92dd3d491c243fd7a9d6615596ac822
3
+ metadata.gz: 69db00d0dc568db01a5bd739183cd5615dbdc66267ad1441502d5c3774753dcb
4
+ data.tar.gz: be2271adcbc9e9b81302d9597824d18462ff64530c095c9e4a3239db1ccbaa51
5
5
  SHA512:
6
- metadata.gz: c2461c306c4812a37b740ff5d0be84bb971aba512d5e7ba523f5b36a16811b3d85708a82646b5f2f4659cf82a0310723fe3fb84579aa2d8bca809942a759b125
7
- data.tar.gz: 78629e727c3125ec055d17806c476c2ca7908a35386e89b52b67de3f8c07a26460d783df69425b7ac6c869c2f70e77986d672460f1c3a8b554f2b55f9aa64443
6
+ metadata.gz: cc6a3bf67e7c73096d6a9a739d1a52ca0f4c560c80e1a7febf90a8e99d3f1009bd282ad16dfeb235b03c6613e27d7d35938a51a10314a1ffb83209b81686e748
7
+ data.tar.gz: effbd8f2686a312671c9275945a8705ec64453687699935872e7cb5e3445e1edcd982ee86b625dc69ba673166b13c9839d11a5756e95212b3dab4cca59055eeb
data/Gemfile CHANGED
@@ -2,9 +2,3 @@ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in timescale.gemspec
4
4
  gemspec
5
-
6
- gem 'dotenv'
7
- gem "rake", "~> 12.0"
8
- gem "rspec", "~> 3.0"
9
- gem 'rspec-its'
10
- gem 'pry'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- timescale (0.1.0)
4
+ timescaledb (0.1.1)
5
5
  activerecord
6
6
  pg (~> 1.2)
7
7
 
@@ -61,7 +61,7 @@ DEPENDENCIES
61
61
  rake (~> 12.0)
62
62
  rspec (~> 3.0)
63
63
  rspec-its
64
- timescale!
64
+ timescaledb!
65
65
 
66
66
  BUNDLED WITH
67
67
  2.1.4
data/README.md CHANGED
@@ -7,12 +7,13 @@ repository:
7
7
  git clone https://github.com/jonatas/timescale.git
8
8
  cd timescale
9
9
  bundle install
10
+ rake install
10
11
  ```
11
12
 
12
- Then you can run `bin/console` for an interactive prompt.
13
+ Then, with `rake install` or installing the gem in your computer, you can run `tsdb` for an interactive prompt.
13
14
 
14
15
  ```bash
15
- bin/console
16
+ tsdb postgres://<user>@localhost:5432/<dbname> --stats --flags
16
17
  ```
17
18
 
18
19
  You can create a `.env` file locally to run tests locally. Make sure to put your
@@ -22,14 +23,35 @@ own credentials there!
22
23
  PG_URI_TEST="postgres://<user>@localhost:5432/<dbname>"
23
24
  ```
24
25
 
25
- You can also use `bin/console` without any parameters and it will use the
26
- `PG_URI_TEST` from your `.env` file.
26
+ You can put some postgres URI directly as a parameter of
27
+ `tsdb`. Here is an example from the console:
27
28
 
28
- Alternatively, you can also put some postgres URI directly as a parameter of
29
- `bin/console`. Here is an example from my console:
29
+ ```bash
30
+ tsdb "postgres://jonatasdp@localhost:5432/timescale_test"
31
+ ```
32
+
33
+ To join the console use `--console`:
30
34
 
31
35
  ```bash
32
- bin/console "postgres://jonatasdp@localhost:5432/timescale_test"
36
+ tsdb "postgres://jonatasdp@localhost:5432/timescale_test" --console
37
+ ```
38
+
39
+ Or just check the stats:
40
+
41
+ ```bash
42
+ tsdb "postgres://jonatasdp@localhost:5432/timescale_test" --stats
43
+ ```
44
+
45
+ These is a sample output from an almost empty database:
46
+
47
+ ```ruby
48
+ {:hypertables=>
49
+ {:count=>3,
50
+ :uncompressed=>2,
51
+ :chunks=>{:total=>1, :compressed=>0, :uncompressed=>1},
52
+ :size=>{:before_compressing=>"80 KB", :after_compressing=>"0 Bytes"}},
53
+ :continuous_aggregates=>{:count=>1},
54
+ :jobs_stats=>[{:success=>nil, :runs=>nil, :failures=>nil}]}
33
55
  ```
34
56
 
35
57
  The console will dynamically create models for all hypertables that it finds
@@ -265,7 +287,7 @@ create the hypertable adding this hook to your `spec/rspec_helper.rb` file:
265
287
 
266
288
  ## Development
267
289
 
268
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
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.
269
291
 
270
292
  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).
271
293
 
data/bin/console CHANGED
@@ -13,11 +13,14 @@ ActiveRecord::Base.establish_connection(ARGV[0] || uri_from_test)
13
13
 
14
14
  Timescale::Hypertable.find_each do |hypertable|
15
15
  class_name = hypertable.hypertable_name.singularize.camelize
16
+
16
17
  model = Class.new(ActiveRecord::Base) do
17
18
  self.table_name = hypertable.hypertable_name
18
19
  self.primary_key = self.column_names.first
19
- include Timescale::HypertableHelpers
20
+
21
+ acts_as_hypertable
20
22
  end
23
+
21
24
  Timescale.const_set(class_name, model)
22
25
  end
23
26
 
data/bin/tsdb ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+ require "bundler/setup"
3
+ require "timescale"
4
+
5
+ ActiveRecord::Base.establish_connection(ARGV[0])
6
+
7
+ Timescale::Hypertable.find_each do |hypertable|
8
+ class_name = hypertable.hypertable_name.singularize.camelize
9
+ model = Class.new(ActiveRecord::Base) do
10
+ self.table_name = hypertable.hypertable_name
11
+ self.primary_key = self.column_names.first
12
+ include Timescale::HypertableHelpers
13
+ end
14
+ Timescale.const_set(class_name, model)
15
+ end
16
+
17
+ if ARGV.index("--stats")
18
+ pp Timescale.show_stats
19
+ end
20
+
21
+ if ARGV.index("--console")
22
+ require "pry"
23
+ Pry.start(Timescale)
24
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Timescale
4
+ # If you want your model to hook into its underlying hypertable
5
+ # as well as have access to TimescaleDB specific data, methods, and more,
6
+ # specify this macro in your model.
7
+ #
8
+ # @note Your model's table needs to have already been converted to a hypertable
9
+ # via the TimescaleDB `create_hypertable` function for this to work.
10
+ #
11
+ # @see https://docs.timescale.com/api/latest/hypertable/create_hypertable/ for
12
+ # how to use the SQL `create_hypertable` function.
13
+ # @see Timescale::MigrationHelpers#create_table for how to create a new hypertable
14
+ # via a Rails migration utilizing the standard `create_table` method.
15
+ #
16
+ # @example Enabling the macro on your model
17
+ # class Event < ActiveRecord::Base
18
+ # acts_as_hypertable
19
+ # end
20
+ #
21
+ # @see Timescale::ActsAsHypertable::ClassMethods#acts_as_hypertable
22
+ # for configuration options
23
+ module ActsAsHypertable
24
+ extend ActiveSupport::Concern
25
+
26
+ DEFAULT_OPTIONS = {
27
+ time_column: :created_at
28
+ }.freeze
29
+
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
100
+ end
101
+
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
112
+ end
113
+ end
114
+ end
@@ -15,12 +15,28 @@ module Timescale
15
15
  foreign_key: "hypertable_name",
16
16
  class_name: "Timescale::ContinuousAggregates"
17
17
 
18
- def detailed_size
18
+ def chunks_detailed_size
19
19
  struct_from "SELECT * from chunks_detailed_size('#{self.hypertable_name}')"
20
20
  end
21
21
 
22
+ def approximate_row_count
23
+ struct_from("SELECT * FROM approximate_row_count('#{self.hypertable_name}')").first.approximate_row_count
24
+ end
25
+
22
26
  def compression_stats
23
- struct_from "SELECT * from hypertable_compression_stats('#{self.hypertable_name}')"
27
+ struct_from("SELECT * from hypertable_compression_stats('#{self.hypertable_name}')").first || {}
28
+ end
29
+
30
+ def detailed_size
31
+ struct_from("SELECT * FROM hypertable_detailed_size('#{self.hypertable_name}')").first
32
+ end
33
+
34
+ def before_total_bytes
35
+ compression_stats["before_compression_total_bytes"] || detailed_size.total_bytes
36
+ end
37
+
38
+ def after_total_bytes
39
+ compression_stats["after_compression_total_bytes"] || 0
24
40
  end
25
41
 
26
42
  private
@@ -8,5 +8,11 @@ module Timescale
8
8
 
9
9
  scope :success, -> { where(last_run_status: "Success") }
10
10
  scope :scheduled, -> { where(job_status: "Scheduled") }
11
+ scope :resume, -> do
12
+ select("sum(total_successes)::int as success,
13
+ sum(total_runs)::int as runs,
14
+ sum(total_failures)::int as failures")
15
+ .to_a.map{|e|e.attributes.transform_keys(&:to_sym) }
16
+ end
11
17
  end
12
18
  end
@@ -0,0 +1,28 @@
1
+ require "active_support/core_ext/numeric/conversions"
2
+ module Timescale
3
+ module StatsReport
4
+ module_function
5
+ def resume
6
+ {
7
+ hypertables: {
8
+ count: Hypertable.count,
9
+ uncompressed: Hypertable.all.to_a.count { |h| h.compression_stats.empty? },
10
+ approximate_row_count: Hypertable.all.to_a.map do |hypertable|
11
+ { hypertable.hypertable_name => hypertable.approximate_row_count }
12
+ end.inject(&:merge!),
13
+ chunks: {
14
+ total: Chunk.count,
15
+ compressed: Chunk.compressed.count,
16
+ uncompressed: Chunk.uncompressed.count
17
+ },
18
+ size: {
19
+ before_compressing: Hypertable.all.map{|h|h.before_total_bytes}.inject(:+).to_s(:human_size),
20
+ after_compressing: Hypertable.all.map{|h|h.after_total_bytes}.inject(:+).to_s(:human_size)
21
+ }
22
+ },
23
+ continuous_aggregates: { count: ContinuousAggregates.count },
24
+ jobs_stats: JobStats.resume
25
+ }
26
+ end
27
+ end
28
+ end
@@ -1,3 +1,3 @@
1
1
  module Timescale
2
- VERSION = "0.1.0"
2
+ VERSION = '0.1.2'
3
3
  end
data/lib/timescale.rb CHANGED
@@ -1,16 +1,19 @@
1
- require "timescale/version"
2
1
  require 'active_record'
2
+
3
+ require_relative 'timescale/acts_as_hypertable'
3
4
  require_relative 'timescale/chunk'
5
+ require_relative 'timescale/compression_settings'
6
+ require_relative 'timescale/continuous_aggregates'
4
7
  require_relative 'timescale/hypertable'
5
8
  require_relative 'timescale/job'
6
9
  require_relative 'timescale/job_stats'
7
- require_relative 'timescale/continuous_aggregates'
8
- require_relative 'timescale/compression_settings'
9
- require_relative 'timescale/hypertable_helpers'
10
+ require_relative 'timescale/stats_report'
10
11
  require_relative 'timescale/migration_helpers'
12
+ require_relative 'timescale/version'
11
13
 
12
14
  module Timescale
13
15
  module_function
16
+
14
17
  def chunks
15
18
  Chunk.all
16
19
  end
@@ -34,4 +37,16 @@ module Timescale
34
37
  def job_stats
35
38
  JobStats.all
36
39
  end
40
+
41
+ def show_stats
42
+ StatsReport.resume
43
+ end
44
+
45
+ def default_hypertable_options
46
+ Timescale::ActsAsHypertable::DEFAULT_OPTIONS
47
+ end
48
+ end
49
+
50
+ ActiveSupport.on_load :active_record do
51
+ include Timescale::ActsAsHypertable
37
52
  end
data/timescale.gemspec CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |spec|
6
6
  spec.authors = ["Jônatas Davi Paganini"]
7
7
  spec.email = ["jonatasdp@gmail.com"]
8
8
 
9
- spec.summary = %q{TimesaleDB helpers for Ruby ecosystem.}
9
+ spec.summary = %q{TimescaleDB helpers for Ruby ecosystem.}
10
10
  spec.description = %q{Functions from timescaledb available in the ActiveRecord models.}
11
11
  spec.homepage = "https://github.com/jonatas/timescale"
12
12
  spec.license = "MIT"
@@ -23,10 +23,16 @@ Gem::Specification.new do |spec|
23
23
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
24
24
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
25
  end
26
- spec.bindir = "exe"
27
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
+ spec.bindir = "bin"
27
+ spec.executables = spec.files.grep(%r{^bin/tsdb}) { |f| File.basename(f) }
28
28
  spec.require_paths = ["lib"]
29
29
 
30
30
  spec.add_dependency "pg", "~> 1.2"
31
- spec.add_dependency 'activerecord'
31
+ spec.add_dependency "activerecord"
32
+
33
+ spec.add_development_dependency "pry"
34
+ spec.add_development_dependency "rspec-its"
35
+ spec.add_development_dependency "rspec", "~> 3.0"
36
+ spec.add_development_dependency "dotenv"
37
+ spec.add_development_dependency "rake", "~> 12.0"
32
38
  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.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jônatas Davi Paganini
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-24 00:00:00.000000000 Z
11
+ date: 2021-10-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pg
@@ -38,10 +38,81 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-its
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: dotenv
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '12.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '12.0'
41
111
  description: Functions from timescaledb available in the ActiveRecord models.
42
112
  email:
43
113
  - jonatasdp@gmail.com
44
- executables: []
114
+ executables:
115
+ - tsdb
45
116
  extensions: []
46
117
  extra_rdoc_files: []
47
118
  files:
@@ -56,18 +127,20 @@ files:
56
127
  - Rakefile
57
128
  - bin/console
58
129
  - bin/setup
130
+ - bin/tsdb
59
131
  - examples/Gemfile
60
132
  - examples/Gemfile.lock
61
133
  - examples/all_in_one.rb
62
134
  - lib/timescale.rb
135
+ - lib/timescale/acts_as_hypertable.rb
63
136
  - lib/timescale/chunk.rb
64
137
  - lib/timescale/compression_settings.rb
65
138
  - lib/timescale/continuous_aggregates.rb
66
139
  - lib/timescale/hypertable.rb
67
- - lib/timescale/hypertable_helpers.rb
68
140
  - lib/timescale/job.rb
69
141
  - lib/timescale/job_stats.rb
70
142
  - lib/timescale/migration_helpers.rb
143
+ - lib/timescale/stats_report.rb
71
144
  - lib/timescale/version.rb
72
145
  - timescale.gemspec
73
146
  homepage: https://github.com/jonatas/timescale
@@ -94,5 +167,5 @@ requirements: []
94
167
  rubygems_version: 3.0.3
95
168
  signing_key:
96
169
  specification_version: 4
97
- summary: TimesaleDB helpers for Ruby ecosystem.
170
+ summary: TimescaleDB helpers for Ruby ecosystem.
98
171
  test_files: []
@@ -1,39 +0,0 @@
1
- require_relative 'chunk'
2
- require_relative 'hypertable'
3
- module Timescale
4
- module HypertableHelpers
5
- extend ActiveSupport::Concern
6
-
7
- included do
8
- scope :chunks, -> () do
9
- Chunk.where(hypertable_name: self.table_name)
10
- end
11
-
12
- scope :hypertable, -> () do
13
- Hypertable.find_by(hypertable_name: self.table_name)
14
- end
15
-
16
- scope :jobs, -> () do
17
- Job.where(hypertable_name: self.table_name)
18
- end
19
-
20
- scope :job_stats, -> () do
21
- JobStats.where(hypertable_name: self.table_name)
22
- end
23
-
24
- scope :compression_settings, -> () do
25
- CompressionSettings.where(hypertable_name: self.table_name)
26
- end
27
-
28
- scope :continuous_aggregates, -> () do
29
- ContinuousAggregates.where(hypertable_name: self.table_name)
30
- end
31
-
32
- scope :last_month, -> { where('created_at > ?', 1.month.ago) }
33
- scope :last_week, -> { where('created_at > ?', 1.week.ago) }
34
- scope :last_hour, -> { where('created_at > ?', 1.hour.ago) }
35
- scope :yesterday, -> { where('DATE(created_at) = ?', 1.day.ago.to_date) }
36
- scope :today, -> { where('DATE(created_at) = ?', Date.today) }
37
- end
38
- end
39
- end