timescaledb 0.2.8 → 0.3.0

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: 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