timescaledb 0.2.8 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 240bc1a55d3955c734d79946868b5e878cacfa354f7b0a843b72f78c26a85c83
4
- data.tar.gz: 23ccc7e91c0da1ea522e5c8a71cd4522478aa1c73ff0e9ee6f61e42b26f9955c
3
+ metadata.gz: a20c2f12a3673694b39fd99aa005d743bbc027031d3abc7c25fda904f71ee33f
4
+ data.tar.gz: fd27816a15c114baa3d75a08bd083de5493efd7ce60ebe200d6543a3dcb266bf
5
5
  SHA512:
6
- metadata.gz: 3ae2cda69cc099ad24a47aa4125ee10db96eb8186e261125f1e56ad6f4f2d805888d02d9eee92d48d18eab49d628918fef4e33234edc48ddb4ecb402d4518207
7
- data.tar.gz: 65ee70a4b17944880979e71d1abee756a5f398f48cb048b575afbe4a0412f91d993ec97723c2b10d472ceafd405d7d013480824702c2a5db11e23f6eacb7f69a
6
+ metadata.gz: db6642dbdb2588359fc63fff080f34479725cef75d7972f081aa2a1beb680314cf1555ba7ec94956d16cceb3ac3b7724de131e010ba1d06361350f162ed3250c
7
+ data.tar.gz: df04ac079954e4b815d922d2a076929e6c4d5f5e9c11d46a54287138e8485fb171b276361a3bae43618c068709fa9f07c0ec34faa88c3afff18ac9d65d511766
@@ -62,4 +62,3 @@ module Timescaledb
62
62
  end
63
63
  end
64
64
 
65
- ActiveRecord::Base.extend Timescaledb::ActsAsHypertable
@@ -1,6 +1,11 @@
1
1
  require 'singleton'
2
2
 
3
3
  module Timescaledb
4
+ # Minimal connection setup for Timescaledb directly with the PG.
5
+ # The concept is use a singleton component that can query
6
+ # independently of the ActiveRecord::Base connections.
7
+ # This is useful for the extension and hypertable metadata.
8
+ # It can also #use_connection from active record if needed.
4
9
  class Connection
5
10
  include Singleton
6
11
 
@@ -34,10 +39,16 @@ module Timescaledb
34
39
  !@config.nil?
35
40
  end
36
41
 
42
+ # Override the connection with a raw PG connection.
43
+ # @param [PG::Connection] connection The raw PG connection.
44
+ def use_connection connection
45
+ @connection = connection
46
+ end
47
+
37
48
  private
38
49
 
39
50
  def connection
40
51
  @connection ||= PG.connect(@config)
41
52
  end
42
53
  end
43
- end
54
+ end
@@ -1,16 +1,21 @@
1
1
  module Timescaledb
2
2
  class ConnectionNotEstablishedError < StandardError; end
3
3
 
4
- # @param [String] config The postgres connection string.
4
+ module_function
5
+
6
+ # @param [String] config with the postgres connection string.
5
7
  def establish_connection(config)
6
8
  Connection.instance.config = config
7
9
  end
8
- module_function :establish_connection
10
+
11
+ # @param [PG::Connection] to use it directly from a raw connection
12
+ def use_connection conn
13
+ Connection.instance.use_connection conn
14
+ end
9
15
 
10
16
  def connection
11
17
  raise ConnectionNotEstablishedError.new unless Connection.instance.connected?
12
18
 
13
19
  Connection.instance
14
20
  end
15
- module_function :connection
16
- end
21
+ end
@@ -14,6 +14,30 @@ module Timescaledb
14
14
  total: count
15
15
  }
16
16
  end
17
+
18
+ scope :hierarchical, -> do
19
+ with_recursive = <<~SQL
20
+ WITH RECURSIVE caggs AS (
21
+ SELECT mat_hypertable_id, parent_mat_hypertable_id, user_view_name
22
+ FROM _timescaledb_catalog.continuous_agg
23
+ UNION ALL
24
+ SELECT continuous_agg.mat_hypertable_id, continuous_agg.parent_mat_hypertable_id, continuous_agg.user_view_name
25
+ FROM _timescaledb_catalog.continuous_agg
26
+ JOIN caggs ON caggs.parent_mat_hypertable_id = continuous_agg.mat_hypertable_id
27
+ )
28
+ SELECT * FROM caggs
29
+ ORDER BY mat_hypertable_id
30
+ SQL
31
+ views = unscoped
32
+ .select("distinct user_view_name")
33
+ .from("(#{with_recursive}) as caggs")
34
+ .pluck(:user_view_name)
35
+ .uniq
36
+
37
+ views.map do |view|
38
+ find_by(view_name: view)
39
+ end
40
+ end
17
41
  end
18
42
  ContinuousAggregates = ContinuousAggregate
19
43
  end
@@ -0,0 +1,23 @@
1
+ module Timescaledb
2
+
3
+ # Provides metadata around the extension in the database
4
+ module Extension
5
+ module_function
6
+ # @return String version of the timescaledb extension
7
+ def version
8
+ @version ||= Timescaledb.connection.query_first(<<~SQL)&.version
9
+ SELECT extversion as version
10
+ FROM pg_extension
11
+ WHERE extname = 'timescaledb'
12
+ SQL
13
+ end
14
+
15
+ def installed?
16
+ version.present?
17
+ end
18
+
19
+ def update!
20
+ Timescaledb.connection.execute('ALTER EXTENSION timescaledb UPDATE')
21
+ end
22
+ end
23
+ end
@@ -49,7 +49,7 @@ module Timescaledb
49
49
  original_logger = ActiveRecord::Base.logger
50
50
  ActiveRecord::Base.logger = Logger.new(STDOUT)
51
51
 
52
- options = ["chunk_time_interval => INTERVAL '#{chunk_time_interval}'"]
52
+ options = ["chunk_time_interval => #{chunk_time_interval_clause(chunk_time_interval)}"]
53
53
  options += hypertable_options.map { |k, v| "#{k} => #{quote(v)}" }
54
54
 
55
55
  arguments = [
@@ -165,6 +165,14 @@ module Timescaledb
165
165
  value = options[option_key] ? 'true' : 'false'
166
166
  ",timescaledb.#{option_key}=#{value}"
167
167
  end
168
+
169
+ def chunk_time_interval_clause(chunk_time_interval)
170
+ if chunk_time_interval.is_a?(Numeric)
171
+ chunk_time_interval
172
+ else
173
+ "INTERVAL '#{chunk_time_interval}'"
174
+ end
175
+ end
168
176
  end
169
177
  end
170
178
 
@@ -25,7 +25,6 @@ module Timescaledb
25
25
 
26
26
  # @override Scenic::Adapters::Postgres#create_view
27
27
  # to add the `with: ` keyword that can be used for such option.
28
- #
29
28
  def create_view(name, version: nil, with: nil, sql_definition: nil, materialized: false, no_data: false)
30
29
  if version.present? && sql_definition.present?
31
30
  raise(
@@ -69,4 +68,4 @@ end
69
68
 
70
69
 
71
70
  Scenic::Adapters::Postgres.include(Timescaledb::Scenic::Extension)
72
- ActiveRecord::ConnectionAdapters::AbstractAdapter.include(Timescaledb::Scenic::MigrationHelpers)
71
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(Timescaledb::Scenic::MigrationHelpers)
@@ -7,14 +7,29 @@ module Timescaledb
7
7
  # * retention policies
8
8
  # * continuous aggregates
9
9
  # * compression settings
10
+ # It also ignores Timescale related schemas when dumping the schema.
11
+ # It also ignores dumping options as extension is not installed or no hypertables are available.
10
12
  module SchemaDumper
11
13
  def tables(stream)
12
14
  super # This will call #table for each table in the database
13
- return unless Timescaledb::Hypertable.table_exists?
14
15
 
15
- timescale_hypertables(stream)
16
- timescale_retention_policies(stream)
17
- timescale_continuous_aggregates(stream) # Define these before any Scenic views that might use them
16
+ if exports_timescaledb_metadata?
17
+ timescale_hypertables(stream)
18
+ timescale_retention_policies(stream)
19
+ timescale_continuous_aggregates(stream) # Define these before any Scenic views that might use them
20
+ end
21
+ end
22
+
23
+ # Ignore dumps in case DB is not eligible for TimescaleDB metadata.
24
+ # @return [Boolean] true if the extension is installed and hypertables are available, otherwise false.
25
+ private def exports_timescaledb_metadata?
26
+ # Note it's safe to use the raw connection here because we're only reading from the database
27
+ # and not modifying it. We're also on the same connection pool as ActiveRecord::Base.
28
+ # The dump process also runs standalone, so we don't need to worry about the connection being
29
+ # used elsewhere.
30
+ Timescaledb.use_connection @connection.raw_connection
31
+
32
+ Timescaledb.extension.installed? && Timescaledb.hypertables.any?
18
33
  end
19
34
 
20
35
  # Ignores Timescale related schemas when dumping the schema
@@ -63,7 +78,7 @@ module Timescaledb
63
78
 
64
79
  options = {
65
80
  time_column: time.column_name,
66
- chunk_time_interval: time.time_interval.inspect,
81
+ chunk_time_interval: time.time_interval ? time.time_interval.inspect : time.integer_interval,
67
82
  **timescale_compression_settings_for(hypertable),
68
83
  **timescale_space_partition_for(hypertable),
69
84
  **timescale_index_options_for(hypertable)
@@ -139,19 +154,19 @@ module Timescaledb
139
154
  def timescale_continuous_aggregates(stream)
140
155
  return unless Timescaledb::ContinuousAggregates.table_exists?
141
156
 
142
- Timescaledb::ContinuousAggregates.all.find_each do |aggregate|
157
+ Timescaledb::ContinuousAggregates.hierarchical.each do |aggregate|
143
158
  refresh_policies_opts = if (refresh_policy = aggregate.jobs.refresh_continuous_aggregate.first)
144
159
  interval = timescale_interval(refresh_policy.schedule_interval)
145
160
  end_offset = timescale_interval(refresh_policy.config["end_offset"])
146
161
  start_offset = timescale_interval(refresh_policy.config["start_offset"])
147
- %(refresh_policies: { start_offset: "#{start_offset}", end_offset: "#{end_offset}", schedule_interval: "#{interval}"})
162
+ %(refresh_policies: { start_offset: "#{start_offset}", end_offset: "#{end_offset}", schedule_interval: "#{interval}"}, )
148
163
  else
149
164
  ""
150
165
  end
151
166
 
152
167
  with_clause_opts = "materialized_only: #{aggregate[:materialized_only]}, finalized: #{aggregate[:finalized]}"
153
168
  stream.puts <<~AGG.indent(2)
154
- create_continuous_aggregate("#{aggregate.view_name}", <<-SQL, #{refresh_policies_opts}, #{with_clause_opts})
169
+ create_continuous_aggregate("#{aggregate.view_name}", <<-SQL, #{refresh_policies_opts}#{with_clause_opts})
155
170
  #{aggregate.view_definition.strip.gsub(/;$/, '')}
156
171
  SQL
157
172
  AGG
@@ -1,3 +1,3 @@
1
1
  module Timescaledb
2
- VERSION = '0.2.8'
2
+ VERSION = '0.3.0'
3
3
  end
data/lib/timescaledb.rb CHANGED
@@ -17,11 +17,20 @@ require_relative 'timescaledb/schema_dumper'
17
17
  require_relative 'timescaledb/stats'
18
18
  require_relative 'timescaledb/stats_report'
19
19
  require_relative 'timescaledb/migration_helpers'
20
+ require_relative 'timescaledb/extension'
20
21
  require_relative 'timescaledb/version'
21
22
 
22
23
  module Timescaledb
23
24
  module_function
24
25
 
26
+ def connection
27
+ Connection.instance
28
+ end
29
+
30
+ def extension
31
+ Extension
32
+ end
33
+
25
34
  def chunks
26
35
  Chunk.all
27
36
  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.2.8
4
+ version: 0.3.0
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: 2024-04-30 00:00:00.000000000 Z
11
+ date: 2024-09-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pg
@@ -163,6 +163,7 @@ files:
163
163
  - lib/timescaledb/database/schema_statements.rb
164
164
  - lib/timescaledb/database/types.rb
165
165
  - lib/timescaledb/dimensions.rb
166
+ - lib/timescaledb/extension.rb
166
167
  - lib/timescaledb/hypertable.rb
167
168
  - lib/timescaledb/job.rb
168
169
  - lib/timescaledb/job_stats.rb