timescaledb 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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